/home/preegmxb/bricks.theoriginalsstudios.com/wp-content/themes/bricks/includes/assets/files.php
<?php
namespace Bricks;
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
class Assets_Files {
public function __construct() {
if ( ! bricks_is_builder() ) {
add_action( 'wp_enqueue_scripts', [ $this, 'load_css_files' ] );
}
add_action( 'save_post', [ $this, 'save_post' ], 10, 2 );
add_action( 'deleted_post', [ $this, 'deleted_post' ], 10, 2 );
add_action( 'wp_ajax_bricks_get_css_files_list', [ $this, 'get_css_files_list' ] );
add_action( 'wp_ajax_bricks_regenerate_css_file', [ $this, 'regenerate_css_file' ] );
// add_action( 'upgrader_process_complete', [ $this, 'upgrader_process_complete' ], 10, 2 );
add_action( 'upgrader_post_install', [ $this, 'upgrader_post_install' ], 10, 3 );
// Cron job to regenerate CSS files after theme update using the code base of the uploaded, not the installed version
add_action( 'bricks_regenerate_css_files', [ $this, 'regenerate_css_files' ] );
}
/**
* Auto-regenerate CSS files after theme update
*
* Runs after updating the theme via the one-click updater!
*
* NOTE: Not in use
*
* @since 1.8.1
*/
public function __upgrader_process_complete( $upgrader, $hook_extra ) { // phpcs:ignore
if ( $hook_extra['action'] === 'update' && $hook_extra['type'] === 'theme' ) {
$theme = wp_get_theme();
if ( $theme->get( 'Name' ) === 'Bricks' ) {
if ( Database::get_setting( 'cssLoading' ) === 'file' ) {
self::schedule_css_file_regeneration();
// Show admin notice after theme update
update_option( BRICKS_CSS_FILES_ADMIN_NOTICE, time() );
}
}
}
}
/**
* Auto-regenerate CSS files after theme update
*
* Runs after manual theme upload!
*
* @since 1.8.1
*/
public function upgrader_post_install( $response, $hook_extra, $result ) {
$is_bricks = false;
// Manual upload
if ( isset( $hook_extra['type'] ) ? $hook_extra['type'] === 'theme' : false ) {
$theme = wp_get_theme();
$active_theme_name = $theme->parent() ? $theme->parent()->get( 'Name' ) : $theme->get( 'Name' );
$is_bricks = $active_theme_name === 'Bricks';
}
// One-click update
elseif ( isset( $hook_extra['theme'] ) ? $hook_extra['theme'] === 'bricks' : false ) {
$is_bricks = true;
}
if ( $is_bricks ) {
if ( Database::get_setting( 'cssLoading' ) === 'file' ) {
self::schedule_css_file_regeneration();
// Show admin notice after theme update
update_option( BRICKS_CSS_FILES_ADMIN_NOTICE, time() );
}
}
return $result; // true
}
/**
* Schedule single WP cron job to regenerate CSS files after theme update (one-click & manual upload)
*
* Runs 'bricks_regenerate_css_files' after 1 second to make sure the theme is updated.
*
* @since 1.8.1
*/
public static function schedule_css_file_regeneration() {
// Regenerate CSS files immediately after theme update
if ( ! wp_next_scheduled( 'bricks_regenerate_css_files' ) ) {
$timestamp = time() + 1;
$hook = 'bricks_regenerate_css_files';
wp_schedule_single_event( $timestamp, $hook );
}
}
/**
* Regenerate CSS files automatically after theme update
*
* @since 1.8.1
*/
public static function regenerate_css_files() {
$css_files = self::get_css_files_list( true );
$generated_css_file_names = [];
if ( is_array( $css_files ) ) {
foreach ( $css_files as $index => $css_file ) {
$file_name = self::regenerate_css_file( $css_file, $index, true );
if ( is_array( $file_name ) ) {
foreach ( $file_name as $name ) {
$generated_css_file_names[] = $name;
}
}
// Single post, etc.
else {
if ( $file_name ) {
$generated_css_file_names[] = $file_name;
}
}
}
}
return $generated_css_file_names;
}
/**
* Regenerate CSS file on every post save
*
* Catches Bricks builder & WordPress editor saves (CU #3kavbt2)
*
* Example: User updates a custom field like ACF color, etc. in WP editor
*
* @since 1.5.7
*/
public function save_post( $post_id, $post ) {
if ( wp_is_post_revision( $post ) ) {
return;
}
if ( Database::get_setting( 'cssLoading' ) !== 'file' ) {
return;
}
if ( ! Helpers::render_with_bricks( $post_id ) ) {
return;
}
$area = Templates::get_template_type( $post_id );
$elements = Database::get_data( $post_id, $area );
self::generate_post_css_file( $post_id, $area, $elements );
}
/**
* Post deleted: Delete post CSS file
*
* @param int $post_id The post ID.
* @param object $post The post object.
*
* @since 1.3.4
*/
public function deleted_post( $post_id, $post ) {
$post_css_file_dir = Assets::$css_dir . "/post-$post_id.min.css";
if ( file_exists( $post_css_file_dir ) ) {
unlink( $post_css_file_dir );
}
}
/**
* Frontend: Load assets (CSS & JS files) on requested page
*
* @since 1.3.4
*/
public function load_css_files() {
// STEP: Color palettes
$color_palettes_css_file_dir = Assets::$css_dir . '/color-palettes.min.css';
$color_palettes_css_file_url = Assets::$css_url . '/color-palettes.min.css';
if ( file_exists( $color_palettes_css_file_dir ) ) {
wp_enqueue_style( 'bricks-color-palettes', $color_palettes_css_file_url, [], filemtime( $color_palettes_css_file_dir ) );
}
// STEP: Global variables (if not disabled in Bricks settings)
if ( ! Database::get_setting( 'disableVariablesManager', false ) ) {
$global_variables_css_file_dir = Assets::$css_dir . '/global-variables.min.css';
$global_variables_css_file_url = Assets::$css_url . '/global-variables.min.css';
if ( file_exists( $global_variables_css_file_dir ) ) {
wp_enqueue_style( 'bricks-global-variables', $global_variables_css_file_url, [], filemtime( $global_variables_css_file_dir ) );
}
}
// STEP: Global settings "Custom CSS"
$global_custom_css_file_dir = Assets::$css_dir . '/global-custom-css.min.css';
$global_custom_css_file_url = Assets::$css_url . '/global-custom-css.min.css';
if ( file_exists( $global_custom_css_file_dir ) ) {
wp_enqueue_style( 'bricks-global-custom-css', $global_custom_css_file_url, [], filemtime( $global_custom_css_file_dir ) );
}
// STEP: Active theme style
$active_theme_style = Theme_Styles::$active_id;
if ( $active_theme_style ) {
$theme_style_file_dir = Assets::$css_dir . "/theme-style-$active_theme_style.min.css";
$theme_style_file_url = Assets::$css_url . "/theme-style-$active_theme_style.min.css";
if ( file_exists( $theme_style_file_dir ) ) {
wp_enqueue_style( "bricks-theme-style-$active_theme_style", $theme_style_file_url, [], filemtime( $theme_style_file_dir ) );
}
}
// STEP: Enqueue header, content, footer, popup (= array) CSS files
$types = [
'header',
'content',
'footer',
'popup',
];
foreach ( $types as $type ) {
$template_id = Database::$active_templates[ $type ];
// Skip enqueuing CSS file for disabled header/footer template (@since 1.7)
if ( ( $type === 'header' || $type === 'footer' ) && Database::is_template_disabled( $type ) ) {
continue;
}
// Template type 'popup' is array of template IDs
$template_ids = is_array( $template_id ) ? $template_id : [ $template_id ];
foreach ( $template_ids as $template_id ) {
$css_file_dir = Assets::$css_dir . "/post-$template_id.min.css";
$css_file_url = Assets::$css_url . "/post-$template_id.min.css";
if ( file_exists( $css_file_dir ) ) {
wp_enqueue_style( "bricks-post-$template_id", $css_file_url, [], filemtime( $css_file_dir ) );
}
}
}
// STEP: Load CSS files for default layouts (frontpage, single post, archive)
if ( ! Helpers::get_bricks_data() ) {
if (
is_home() ||
is_archive() ||
is_search()
) {
wp_enqueue_style( 'bricks-element-posts', BRICKS_URL_ASSETS . 'css/elements/posts.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/posts.min.css' ) );
wp_enqueue_style( 'bricks-isotope' );
} elseif ( is_single() ) {
wp_enqueue_style( 'bricks-element-post-author', BRICKS_URL_ASSETS . 'css/elements/post-author.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-author.min.css' ) );
wp_enqueue_style( 'bricks-element-post-comments', BRICKS_URL_ASSETS . 'css/elements/post-comments.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-comments.min.css' ) );
wp_enqueue_style( 'bricks-element-post-navigation', BRICKS_URL_ASSETS . 'css/elements/post-navigation.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-navigation.min.css' ) );
wp_enqueue_style( 'bricks-element-post-sharing', BRICKS_URL_ASSETS . 'css/elements/post-sharing.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-sharing.min.css' ) );
wp_enqueue_style( 'bricks-element-post-taxonomy', BRICKS_URL_ASSETS . 'css/elements/post-taxonomy.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-taxonomy.min.css' ) );
wp_enqueue_style( 'bricks-element-related-posts', BRICKS_URL_ASSETS . 'css/elements/related-posts.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/related-posts.min.css' ) );
wp_enqueue_style( 'bricks-element-post-content', BRICKS_URL_ASSETS . 'css/elements/post-content.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/elements/post-content.min.css' ) );
} elseif ( is_404() ) {
wp_enqueue_style( 'bricks-404' );
}
}
// Prepare to load CSS file for Template elements or Post Content element (with render as Bricks)
$content_template_id = Database::$active_templates['content'];
$content_elements = get_post_meta( $content_template_id, BRICKS_DB_PAGE_CONTENT, true );
$this->load_content_extra_css_files( $content_elements ); // Recursive
}
/**
* Check inside template elements and post content for other CSS file needs
*
* @since 1.5.7
*/
public function load_content_extra_css_files( $content_elements = [] ) {
if ( empty( $content_elements ) ) {
return;
}
static $extra_files_ids = [];
foreach ( $content_elements as $element ) {
$check_content_id = 0;
// STEP: Load CSS file for "Template" elements used on this page (check for content should be enough)
$template_id = $element['name'] === 'template' && ! empty( $element['settings']['template'] ) ? $element['settings']['template'] : 0;
if ( $template_id ) {
$template_css_file_dir = Assets::$css_dir . "/post-$template_id.min.css";
$template_css_file_url = Assets::$css_url . "/post-$template_id.min.css";
// Generate template inline CSS to load template webfonts (load_webfonts)
$template_inline_css = Assets::generate_inline_css( $template_id );
if ( file_exists( $template_css_file_dir ) ) {
wp_enqueue_style( "bricks-post-$template_id", $template_css_file_url, [], filemtime( $template_css_file_dir ) );
}
$check_content_id = $template_id;
}
// STEP: Check for Post Content elements (with render as Bricks) inside the content (check for content should be enough)
if ( $element['name'] === 'post-content' && isset( $element['settings']['dataSource'] ) && $element['settings']['dataSource'] === 'bricks' ) {
$post_id = Database::$page_data['preview_or_post_id'];
// Do not remove this line to avoid infinite loops
if ( get_post_type( $post_id ) === BRICKS_DB_TEMPLATE_SLUG ) {
$post_id = Helpers::get_template_setting( 'templatePreviewPostId', $post_id );
}
$css_file_dir = Assets::$css_dir . "/post-$post_id.min.css";
$css_file_url = Assets::$css_url . "/post-$post_id.min.css";
// Generate template inline CSS to load template webfonts (load_webfonts)
$page_inline_css = Assets::generate_inline_css( $post_id );
if ( file_exists( $css_file_dir ) ) {
wp_enqueue_style( "bricks-post-$post_id", $css_file_url, [], filemtime( $css_file_dir ) );
}
$check_content_id = $post_id;
}
// STEP: Check inside the template (or post-content) content elements for other template elements (@since 1.5.7)
if ( ! empty( $check_content_id ) && ! in_array( $check_content_id, $extra_files_ids ) ) {
$extra_files_ids[] = $check_content_id;
$template_content = get_post_meta( $check_content_id, BRICKS_DB_PAGE_CONTENT, true );
$this->load_content_extra_css_files( $template_content ); // Recursive
}
}
}
/**
* Builder: Generate page-specific CSS file (on builder save)
*
* @param int $post_id Post ID.
* @param string $content_type header/content/footer (to get correct Bricks post meta data).
* @param array $elements Array of elements.
*
* @return void|string File name
*
* @since 1.3.4
*/
public static function generate_post_css_file( $post_id, $content_type, $elements ) {
// Check: Only run when "CSS loading method" is set to "External Files"
if ( Database::get_setting( 'cssLoading' ) !== 'file' ) {
return;
}
// Directory doesn't exist: Create recursively
if ( ! is_dir( Assets::$css_dir ) ) {
$directory_created = wp_mkdir_p( Assets::$css_dir );
if ( ! $directory_created ) {
return;
}
}
// Set the post_id
Assets::$post_id = $post_id;
$element_css = '';
$element_css_default = [];
// STEP: Page settings
$page_settings = get_post_meta( $post_id, BRICKS_DB_PAGE_SETTINGS, true );
if ( $page_settings ) {
if ( ! isset( Settings::$controls['page'] ) ) {
Settings::set_controls();
}
$page_settings_controls = Settings::get_controls_data( 'page' );
$element_css .= Assets::generate_inline_css_from_element(
[ 'settings' => $page_settings ],
$page_settings_controls['controls'],
'page'
);
}
// STEP: Page settings: Custom CSS
$page_settings_css = ! empty( $page_settings['customCss'] ) ? trim( $page_settings['customCss'] ) : false;
$page_settings_css = Helpers::parse_css( $page_settings_css );
// Add if not already added via Assets::generate_inline_css_from_element() (@since 1.7)
if ( $page_settings_css && strpos( $element_css, $page_settings_css ) === false ) {
$element_css .= $page_settings_css;
}
// Header template settings (scrolling background, etc.)
if ( $content_type === 'header' ) {
$template_header_settings = Helpers::get_template_settings( $post_id );
if ( $template_header_settings ) {
if ( ! isset( Settings::$controls['template'] ) ) {
Settings::set_controls();
}
$template_settings_controls = Settings::get_controls_data( 'template' );
$element_css .= Assets::generate_inline_css_from_element(
[ 'settings' => $template_header_settings ],
$template_settings_controls['controls'],
'template'
);
}
}
// STEP: Load style files of every element of requested page
if ( is_array( $elements ) ) {
foreach ( $elements as $element ) {
if ( ! isset( $element_css_default[ $element['name'] ] ) ) {
$element_css_file_path = BRICKS_PATH_ASSETS . 'css/elements/' . $element['name'] . '.min.css';
if ( file_exists( $element_css_file_path ) ) {
$element_css_default[ $element['name'] ] = file_get_contents( $element_css_file_path );
}
}
}
}
// STEP: Generate final elements CSS string (default styles first, then individual element styles)
foreach ( $element_css_default as $element_name => $default_css_string ) {
// Audio element control assets URL
if ( $element_name === 'audio' ) {
$default_css_string = str_replace( 'url(../svg/audio/control-', 'url(' . BRICKS_URL_ASSETS . 'svg/audio/control-', $default_css_string );
}
$element_css = $default_css_string . $element_css;
}
// STEP: Add individual element styles
Assets::$inline_css[ $content_type ] = '';
Assets::generate_css_from_elements( $elements, $content_type );
$element_css .= Assets::$inline_css[ $content_type ];
$element_css = Assets::minify_css( $element_css );
// STEP: Update OR delete CSS files
$file_name = "post-$post_id.min.css";
$css_file_path = Assets::$css_dir . "/$file_name";
// Delete empty post CSS file
if ( ! $element_css && file_exists( $css_file_path ) ) {
unlink( $css_file_path );
}
// Create/update CSS file (fopen more performant than file_put_contents as it doesn't read the content)
else {
$file = fopen( $css_file_path, 'w' );
fwrite( $file, $element_css );
fclose( $file );
// https://academy.bricksbuilder.io/article/action-bricks-generate_css_file (@since 1.9.5)
do_action( 'bricks/generate_css_file', 'post', $file_name );
return $file_name;
}
}
/**
* Generate individual CSS file
*
* @param string $data The type of CSS file to generate: colorPalettes, themeStyles, individual post ID, etc.
* @param string $index The index of the CSS file to generate (e.g. 0 = colorPalettes, 1 = themeStyles, etc.).
* @param bool $return Whether to return the generated CSS file name or not.
*
* Trigger 1: Click on "Regenerate CSS files" button under "CSS loading method - External Files" in Bricks settings.
* Trigger 2: Edit default breakpoint 'width' (@since 1.5.1)
* Trigger 3: CLI command: wp bricks regenerate_assets (@since 1.8.1)
* Trigger 4: Theme update (one-click & manual upload) (@since 1.8.1)
*/
public static function regenerate_css_file( $data = false, $index = false, $return = false ) {
if ( isset( $_POST['data'] ) ) {
$data = sanitize_text_field( $_POST['data'] );
}
if ( isset( $_POST['index'] ) ) {
$index = sanitize_text_field( $_POST['index'] );
}
if ( $data === false || $index === false ) {
wp_send_json_success(
[
'data' => $data,
'index' => $index,
'abort' => true,
]
);
}
// Flush unique inline CSS so same styles in different CSS files can be generated again (@since 1.9.4)
Assets::$unique_inline_css = [];
$file_name = '';
if ( $index == 0 ) {
// STEP Directory doesn't exist: Create recursively
if ( ! is_dir( Assets::$css_dir ) ) {
$directory_created = wp_mkdir_p( Assets::$css_dir );
if ( ! $directory_created ) {
wp_send_json_error(
[
'abort' => true,
'file_name' => esc_html__( 'Your uploads directory writing permissions are insufficient.', 'bricks' ),
]
);
}
}
// STEP: Delete all exsiting CSS files
array_map( 'unlink', array_filter( (array) glob( Assets::$css_dir . '/*' ) ) );
}
switch ( $data ) {
case 'colorPalettes':
$file_name = Assets_Color_Palettes::generate_css_file( get_option( BRICKS_DB_COLOR_PALETTE, [] ) );
break;
case 'globalCustomCss':
$file_name = Assets_Global_Custom_Css::generate_css_file( get_option( BRICKS_DB_GLOBAL_SETTINGS, [] ) );
break;
case 'globalElements':
$file_name = Assets_Global_Elements::generate_css_file( get_option( BRICKS_DB_GLOBAL_ELEMENTS, [] ) );
break;
case 'themeStyles':
$file_name = Assets_Theme_Styles::generate_css_file( get_option( BRICKS_DB_THEME_STYLES, [] ) );
break;
case 'globalVariables':
$file_name = Assets_Global_Variables::generate_css_file( get_option( BRICKS_DB_GLOBAL_VARIABLES, [] ) );
break;
// Individual post
default:
$generating_type = 'post';
$post_id = $data;
$post_type = get_post_type( $post_id );
$elements = false;
// Get content type (header, content, footer) & elements
if ( $post_type === BRICKS_DB_TEMPLATE_SLUG ) {
$elements = get_post_meta( $post_id, BRICKS_DB_PAGE_HEADER, true );
if ( $elements ) {
$content_type = 'header';
} else {
$elements = get_post_meta( $post_id, BRICKS_DB_PAGE_FOOTER, true );
if ( $elements ) {
$content_type = 'footer';
}
}
}
// No 'header', nor footer' data: Check for 'content' post meta
if ( ! $elements ) {
$elements = get_post_meta( $post_id, BRICKS_DB_PAGE_CONTENT, true );
if ( $elements ) {
$content_type = 'content';
}
}
if ( $elements && $content_type ) {
$file_name = self::generate_post_css_file( $post_id, $content_type, $elements );
if ( $file_name ) {
$post_type_object = get_post_type_object( $post_type );
$post_type = $post_type_object ? $post_type_object->labels->singular_name : $post_type;
$file_name .= " ($post_type)";
}
}
}
// STEP: Set installed theme version in options table (to hide admin_notice_regenerate_css_files)
update_option( BRICKS_CSS_FILES_LAST_GENERATED, BRICKS_VERSION );
if ( $return ) {
return $file_name;
}
wp_send_json_success( [ 'file_name' => $file_name ] );
}
/**
* Return CSS files list to frontend for processing one-by-one via AJAX 'bricks_regenerate_css_file'
*
* NOTE: Generate global CSS classes inline (need to know which element(s) a global class is actually set for).
*
* @return array
*/
public static function get_css_files_list( $return = false ) {
// Generic CSS files
$list = [
'colorPalettes',
'globalCustomCss',
'globalElements',
'themeStyles',
'globalVariables'
];
$custom_args = [
'lang' => '', // Polylang: Get posts of any language (@since 1.8, @see #86782d47m)
];
// Get all Bricks template IDs
$template_ids = Templates::get_all_template_ids( $custom_args );
$list = array_merge( $list, $template_ids );
// Get IDs of all Bricks-enabled post types
$post_ids = Helpers::get_all_bricks_post_ids( $custom_args );
$list = array_merge( $list, $post_ids );
// Add option table entry with timestamp of last CSS files generation (@since 1.8.1)
update_option( BRICKS_CSS_FILES_LAST_GENERATED_TIMESTAMP, time() );
if ( $return ) {
return $list;
}
wp_send_json_success( $list );
}
}