文件操作 - builder.php
返回文件管理
返回主菜单
删除本文件
文件: /storage/v12552/stanleysteamer/public_html/wp-content/themes/bricks/includes/builder.php
编辑文件内容
<?php namespace Bricks; if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly class Builder { public static $dynamic_data = []; // key: DD tag; value: DD tag value (@since 1.7.1) public static $html_attributes = []; // key: header, main, footer, element ID; value: array with element attributes (@since 1.10) public static $elements_html = []; // @since 2.0 public static $preview_texts = []; // @since 2.0 public static $looping_html = []; // @since 2.0 public static $templates_data = []; // @since 2.0 public static $looping_dynamic_data = []; // (#86c4tzdxq; @since 2.2) public static $query_api_cache = []; // Cached data for query API results (@since 2.1) public function __construct() { // Builder: Add login form to page if ( bricks_is_builder_main() ) { add_action( 'wp_print_footer_scripts', 'wp_auth_check_html', 5 ); } // Remove admin bar styles and disable admin bar in builder if ( BRICKS_DEBUG === false || bricks_is_builder_iframe() ) { add_action( 'wp_print_styles', [ $this, 'remove_admin_bar_inline_styles' ] ); add_filter( 'show_admin_bar', [ $this, 'show_admin_bar' ] ); } add_action( 'init', [ $this, 'set_language_direction' ] ); // @since 1.11: Changed from 'locale' to 'determine_locale' to avoid conflicts with other plugins (i.e. WPML) add_filter( 'determine_locale', [ $this, 'maybe_set_locale' ], 99999, 1 ); // Hook in after TranslatePress add_action( 'send_headers', [ $this, 'dont_cache_headers' ] ); add_action( 'wp_footer', [ $this, 'element_x_templates' ] ); add_action( 'bricks_before_site_wrapper', [ $this, 'before_site_wrapper' ] ); add_action( 'bricks_after_site_wrapper', [ $this, 'after_site_wrapper' ] ); add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ] ); add_filter( 'tiny_mce_before_init', [ $this, 'tiny_mce_before_init' ] ); add_action( 'template_redirect', [ $this, 'template_redirect' ] ); // In the builder force our own template to avoid conflicts with other builders add_filter( 'template_include', [ $this, 'template_include' ], 1001 ); // Skip loading Cloudflare Rocket Loader (@since 2.0) if ( self::cloudflare_rocket_loader_disabled() ) { add_action( 'template_redirect', [ $this, 'cloudflare_rocket_loader_modify_script_tags' ], 0 ); } } /** * Remove 'admin-bar' inline styles * * Necessary for WordPress 6.4+ as html {margin-top: 32px !important} causes gap in builder. * * @since 1.9.3 */ public function remove_admin_bar_inline_styles() { // Remove 'admin-bar' inline style if ( wp_style_is( 'admin-bar', 'enqueued' ) ) { wp_style_add_data( 'admin-bar', 'after', '' ); } } /** * Don't cache headers or browser history buffer in builder * * To fix browser back button issue. * * https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching * https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control * * "at present any pages using Cache-Control: no-store will not be eligible for bfcache." * - https://web.dev/bfcache/#minimize-use-of-cache-control-no-store * * @since 1.6.2 */ public function dont_cache_headers() { header_remove( 'Cache-Control' ); header( 'Cache-Control: no-cache, no-store, must-revalidate, max-age=0' ); // HTTP 1.1 header( 'Pragma: no-cache' ); // HTTP 1.0 header( 'Expires: 0' ); // HTTP 1.0 proxies } /** * Remove admin bar and CSS * * @since 1.0 */ public function show_admin_bar() { remove_action( 'wp_head', '_admin_bar_bump_cb' ); return false; } /** * Set a different language locale in builder if user has specified a different admin language * * @since 1.1.2 */ public function maybe_set_locale( $locale ) { // Check for builder language $builder_locale = Database::get_setting( 'builderLocale', false ); if ( $builder_locale && $builder_locale !== 'site-default' ) { do_action( 'bricks/builder/switch_locale', $builder_locale ); return $builder_locale; } // Check for specific WP dashboard user language $user = wp_get_current_user(); if ( ! empty( $user->locale ) ) { if ( $locale !== $user->locale ) { do_action( 'bricks/builder/switch_locale', $user->locale ); } $locale = $user->locale; } return $locale; } /** * Set language direction in builder (panels) * * Apply only to main window (toolbar & panels). Canvas should use frontend direction. * * @since 1.5 */ public function set_language_direction() { // Return: Window is not main builder window if ( ! bricks_is_builder_main() ) { return; } $direction = Database::get_setting( 'builderLanguageDirection', false ); if ( ! $direction ) { $builder_locale = Database::get_setting( 'builderLocale', false ); // If builderLocale is set to "site-default", get the site's default locale if ( $builder_locale === 'site-default' ) { $builder_locale = get_locale(); } // Determine if the locale is a RTL or LTR language // NOTE: Best not to hardcode RTL languages if possible! $rtl_languages = [ 'ar', 'he', 'fa', 'ur', 'yi', 'ps', 'dv', 'ckb', 'sd', 'ug' ]; // Apply filter to allow RTL languages to be added $rtl_languages = apply_filters( 'bricks/rtl_languages', $rtl_languages ); $language_code = substr( $builder_locale, 0, 2 ); $direction = in_array( $language_code, $rtl_languages ) ? 'rtl' : 'ltr'; } global $wp_locale, $wp_styles; $wp_locale->text_direction = $direction; if ( ! is_a( $wp_styles, 'WP_Styles' ) ) { $wp_styles = new \WP_Styles(); } $wp_styles->text_direction = $direction; } /** * Canvas: Add element x-template render scripts to wp_footer */ public function element_x_templates() { if ( ! bricks_is_builder_iframe() ) { return; } foreach ( Elements::$elements as $element ) { echo $element['class']::render_builder(); } } /** * Before site wrapper (opening tag to render builder) * * @since 1.0 */ public function before_site_wrapper() { if ( bricks_is_builder_main() ) { echo '<div class="brx-body main">'; } elseif ( bricks_is_builder_iframe() ) { echo '<div class="brx-body iframe">'; } } /** * After site wrapper (closing tag to render builder) * * @since 1.0 */ public function after_site_wrapper() { if ( bricks_is_builder() ) { echo '</div>'; // END .brx-body } } /** * Enqueue styles and scripts * * @since 1.0 */ public function enqueue_scripts() { // Access MediaElementsJS (element: Audio) and to get global 'wp' object to open media library (control type 'image', 'audio' etc.) wp_enqueue_media(); // Order matters for CSS flexbox (enqueue builder styles before frontend styles) if ( bricks_is_builder() ) { wp_enqueue_style( 'bricks-builder', BRICKS_URL_ASSETS . 'css/builder.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/builder.min.css' ) ); if ( is_rtl() ) { wp_enqueue_style( 'bricks-builder-rtl', BRICKS_URL_ASSETS . 'css/builder-rtl.min.css', [], filemtime( BRICKS_PATH_ASSETS . 'css/builder-rtl.min.css' ) ); } // PopupDocs.vue: Load prettify wp_enqueue_script( 'bricks-prettify' ); wp_enqueue_style( 'bricks-prettify' ); // Builder isotope (PopupUnsplash.vue) wp_enqueue_script( 'bricks-isotope' ); // Datepicker (form & countdown) wp_enqueue_script( 'bricks-flatpickr' ); wp_enqueue_style( 'bricks-flatpickr' ); // Builder Mode "Custom": Add CSS variables as inline CSS $builder_mode = Database::get_setting( 'builderMode', 'dark' ); $builder_ui_css = Database::get_setting( 'builderModeCss', '' ); if ( $builder_mode === 'custom' && ! empty( $builder_ui_css ) ) { wp_add_inline_style( 'bricks-tooltips', $builder_ui_css ); } add_filter( 'mce_buttons_2', [ $this, 'add_editor_buttons' ] ); } if ( bricks_is_builder_main() ) { // Manually enqueue dashicons for 'wp_enqueue_media' as 'get_wp_editor' prevents dashicons enqueue wp_enqueue_style( 'bricks-dashicons', includes_url( '/css/dashicons.min.css' ), [], null ); wp_enqueue_script( 'bricks-builder', BRICKS_URL_ASSETS . 'js/main.min.js', [ 'bricks-scripts', 'jquery' ], filemtime( BRICKS_PATH_ASSETS . 'js/main.min.js' ), true ); } // Load Adobe fonts file // NOTE: Enqueue in main window for Font manager (@since 2.0) $adobe_fonts_project_id = ! empty( Database::get_setting( 'adobeFontsProjectId' ) ) ? Database::get_setting( 'adobeFontsProjectId' ) : false; if ( $adobe_fonts_project_id ) { wp_enqueue_style( "adobe-fonts-project-id-$adobe_fonts_project_id", "https://use.typekit.net/$adobe_fonts_project_id.css" ); } if ( bricks_is_builder_iframe() ) { // Enqueue Dashicons for ACF icon picker (@since 2.0) wp_enqueue_style( 'bricks-dashicons', includes_url( '/css/dashicons.min.css' ), [], null ); wp_enqueue_script( 'bricks-countdown' ); wp_enqueue_script( 'bricks-counter' ); wp_enqueue_script( 'bricks-flatpickr' ); wp_enqueue_script( 'bricks-google-maps' ); wp_enqueue_script( 'bricks-piechart' ); wp_enqueue_script( 'bricks-swiper' ); wp_enqueue_script( 'bricks-typed' ); wp_enqueue_script( 'bricks-tocbot' ); // Form element richtext field TinyMCE 8 (@since 2.1) wp_enqueue_script( 'bricks-tinymce8-builder' ); wp_enqueue_script( 'bricks-builder', BRICKS_URL_ASSETS . 'js/iframe.min.js', [ 'bricks-scripts', 'jquery' ], filemtime( BRICKS_PATH_ASSETS . 'js/iframe.min.js' ), true ); } $post_id = get_the_ID(); $featured_image = false; /** * Get control options to ensure filter 'bricks/setup/control_options' ran * * Eaxmples: 'queryTypes', custom user control options, etc. * * @since 1.5.5 */ $control_options = Setup::get_control_options(); // NOTE: Set post ID to posts page if ( is_home() ) { $post_id = get_option( 'page_for_posts' ); } // NOTE: Undocumented $post_id = apply_filters( 'bricks/builder/data_post_id', $post_id ); if ( has_post_thumbnail( $post_id ) ) { $featured_image = [ 'id' => get_post_thumbnail_id(), 'url' => get_the_post_thumbnail_url( $post_id ), ]; $image_sizes = array_keys( $control_options['imageSizes'] ); foreach ( $image_sizes as $image_size ) { $featured_image[ $image_size ] = get_the_post_thumbnail_url( $post_id, $image_size ); } } wp_localize_script( 'bricks-builder', 'bricksData', [ 'loadData' => self::builder_data( $post_id ), // Initial data to bootstrap builder iframe 'dynamicWrapper' => apply_filters( 'bricks/builder/dynamic_wrapper', [] ), // Bricks settings 'classPreviewOnHover' => Database::get_setting( 'builderClassPreviewOnHover', false ), 'colorPreviewOnHover' => Database::get_setting( 'builderColorPreviewOnHover', false ), 'variablePreviewOnHover' => Database::get_setting( 'builderVariablePreviewOnHover', false ), 'customBreakpoints' => Database::get_setting( 'customBreakpoints', false ), 'disableClassManager' => Database::get_setting( 'disableClassManager', false ), 'disableVariablesManager' => Database::get_setting( 'disableVariablesManager', false ), 'disableClassChaining' => Database::get_setting( 'disableClassChaining', false ), 'defaultTemplatesDisabled' => Database::get_setting( 'defaultTemplatesDisabled' ), 'generateTemplateScreenshots' => Database::get_setting( 'generateTemplateScreenshots' ), 'disableGlobalClasses' => Database::get_setting( 'builderDisableGlobalClassesInterface', false ), 'disablePanelAutoExpand' => Database::get_setting( 'builderDisablePanelAutoExpand', false ), 'disableElementSpacing' => Database::get_setting( 'disableElementSpacing', false ), 'canvasScrollIntoView' => Database::get_setting( 'canvasScrollIntoView', false ), 'structureAutoSync' => Database::get_setting( 'structureAutoSync', false ), 'structureDuplicateElement' => Database::get_setting( 'structureDuplicateElement', false ), 'structureDeleteElement' => Database::get_setting( 'structureDeleteElement', false ), 'structureCollapsed' => Database::get_setting( 'structureCollapsed', false ), 'builderElementBreadcrumbs' => Database::get_setting( 'builderElementBreadcrumbs', false ), 'builderDisableRestApi' => Database::get_setting( 'builderDisableRestApi', false ), 'instantNavigation' => Database::get_setting( 'builderInstantNavigation', false ), 'builderResponsiveControlIndicator' => Database::get_setting( 'builderResponsiveControlIndicator', 'any' ), 'builderControlGroupVisibility' => Database::get_setting( 'builderControlGroupVisibility', 'open' ), 'builderFontFamilyControl' => Database::get_setting( 'builderFontFamilyControl', 'all' ), 'builderWrapElement' => Database::get_setting( 'builderWrapElement', 'block' ), 'builderInsertElement' => Database::get_setting( 'builderInsertElement', 'block' ), 'builderInsertLayout' => Database::get_setting( 'builderInsertLayout', 'block' ), 'enableDynamicDataPreview' => Database::get_setting( 'enableDynamicDataPreview', false ), 'enableQueryFilters' => Database::get_setting( 'enableQueryFilters', false ), 'enableQueryFiltersIntegration' => Database::get_setting( 'enableQueryFiltersIntegration', false ), 'builderQueryMaxResults' => Database::get_setting( 'builderQueryMaxResults', false ), 'builderDynamicDropdownKey' => Database::get_setting( 'builderDynamicDropdownKey', false ), 'builderDynamicDropdownNoLabel' => Database::get_setting( 'builderDynamicDropdownNoLabel', false ), 'builderDynamicDropdownExpand' => Database::get_setting( 'builderDynamicDropdownExpand', false ), 'builderGlobalClassesSync' => Database::get_setting( 'builderGlobalClassesSync', false ), 'builderVariablePickerHideValue' => Database::get_setting( 'builderVariablePickerHideValue', false ), 'builderCodeVim' => Database::get_setting( 'builderCodeVim', false ), 'builderCloudflareRocketLoader' => self::cloudflare_rocket_loader_disabled(), 'builderCheckForCorruptData' => Database::get_setting( 'builderCheckForCorruptData', false ), 'bricksComponentsInBlockEditor' => Database::get_setting( 'bricksComponentsInBlockEditor', false ), 'autosave' => [ 'disabled' => Database::get_setting( 'builderAutosaveDisabled', false ), 'interval' => Database::get_setting( 'builderAutosaveInterval', 60 ), ], 'toolbarLogoLink' => Database::get_setting( 'builderToolbarLogoLink', 'current' ), 'toolbarLogoLinkCustom' => Database::get_setting( 'builderToolbarLogoLinkCustom', '' ), 'toolbarLogoLinkNewTab' => Database::get_setting( 'builderToolbarLogoLinkNewTab', '' ), 'mode' => Database::get_setting( 'builderMode', 'dark' ), 'featuredImage' => $featured_image, 'panelWidth' => get_option( BRICKS_DB_PANEL_WIDTH, 300 ), 'structureWidth' => get_option( BRICKS_DB_STRUCTURE_WIDTH, 300 ), 'scaleOff' => get_user_meta( get_current_user_id(), BRICKS_DB_BUILDER_SCALE_OFF, true ), 'widthLocked' => get_user_meta( get_current_user_id(), BRICKS_DB_BUILDER_WIDTH_LOCKED, true ), 'allowedHtmlTags' => Helpers::get_allowed_html_tags(), 'validPseudoClasses' => Helpers::get_valid_pseudo_classes(), 'validPseudoElements' => Helpers::get_valid_pseudo_elements(), 'wp' => self::get_wordpress_data(), 'academy' => [ 'home' => 'https://academy.bricksbuilder.io/', 'article' => 'https://academy.bricksbuilder.io/article/', 'components' => 'https://academy.bricksbuilder.io/article/components/', 'layout' => 'https://academy.bricksbuilder.io/article/layout/', 'headerTemplate' => 'https://academy.bricksbuilder.io/article/create-template/', 'footerTemplate' => 'https://academy.bricksbuilder.io/article/create-template/', 'createElement' => 'https://academy.bricksbuilder.io/article/create-your-own-elements/', 'globalElement' => 'https://academy.bricksbuilder.io/article/global-elements/', 'keyboardShortcuts' => 'https://academy.bricksbuilder.io/article/keyboard-shortcuts/', 'pseudoClasses' => 'https://academy.bricksbuilder.io/article/pseudo-classes/', 'conditions' => 'https://academy.bricksbuilder.io/article/element-conditions/', 'interactions' => 'https://academy.bricksbuilder.io/article/interactions/', 'popups' => 'https://academy.bricksbuilder.io/article/popup-builder/', 'capabilities' => 'https://academy.bricksbuilder.io/article/builder-access/', ], 'version' => BRICKS_VERSION, 'debug' => isset( $_GET['debug'] ) ? sanitize_text_field( $_GET['debug'] ) : false, 'message' => isset( $_GET['message'] ) ? sanitize_text_field( $_GET['message'] ) : false, 'breakpoints' => Breakpoints::$breakpoints, 'builderPreviewParam' => BRICKS_BUILDER_IFRAME_PARAM, 'maxUploadSize' => wp_max_upload_size(), 'dynamicTags' => Integrations\Dynamic_Data\Providers::get_dynamic_tags_list(), 'dynamicTagsQueryLoop' => Integrations\Dynamic_Data\Providers::get_query_supported_tags_list(), 'dynamicTagsArraySupport' => Integrations\Dynamic_Data\Providers::get_array_supported_tags_list(), // URL to edit header/content/footer templates 'editHeaderUrl' => ! empty( Database::$active_templates['header'] ) ? Helpers::get_builder_edit_link( Database::$active_templates['header'] ) : '', 'editContentUrl' => ! empty( Database::$active_templates['content'] ) ? Helpers::get_builder_edit_link( Database::$active_templates['content'] ) : '', 'editFooterUrl' => ! empty( Database::$active_templates['footer'] ) ? Helpers::get_builder_edit_link( Database::$active_templates['footer'] ) : '', // Template IDs (@since 2.2) 'editHeaderId' => ! empty( Database::$active_templates['header'] ) ? Database::$active_templates['header'] : 0, 'editContentId' => ! empty( Database::$active_templates['content'] ) ? Database::$active_templates['content'] : 0, 'editFooterId' => ! empty( Database::$active_templates['footer'] ) ? Database::$active_templates['footer'] : 0, 'locale' => get_locale(), 'i18n' => self::i18n(), 'nonce' => wp_create_nonce( 'bricks-nonce-builder' ), 'ajaxUrl' => admin_url( 'admin-ajax.php' ), 'restApiUrl' => Api::get_rest_api_url(), 'homeUrl' => home_url( '/' ), 'adminUrl' => admin_url(), 'loginUrl' => wp_login_url(), 'themeUrl' => BRICKS_URL, 'assetsUrl' => BRICKS_URL_ASSETS, 'editPostUrl' => get_edit_post_link( $post_id ), 'previewUrl' => add_query_arg( 'bricks_preview', time(), get_the_permalink( $post_id ) ), 'siteName' => get_bloginfo( 'name' ), 'siteUrl' => get_site_url(), 'settingsUrl' => Helpers::settings_url(), 'elementsManagerUrl' => Helpers::elements_manager_url(), 'defaultImageSize' => 'large', 'author' => get_the_author_meta( 'display_name', get_post_field( 'post_author', $post_id ) ), 'canManageOptions' => current_user_can( 'manage_options' ), 'isTemplate' => get_post_type() === BRICKS_DB_TEMPLATE_SLUG, 'isRtl' => is_rtl(), 'postId' => $post_id, 'postStatus' => get_post_status( $post_id ), 'postType' => get_post_type( $post_id ), 'postTypeUrl' => admin_url( 'edit.php?post_type=' ) . get_post_type( $post_id ), 'postTypesRegistered' => Helpers::get_registered_post_types(), 'postTypesSupported' => Helpers::get_supported_post_types(), 'postsPerPage' => get_option( 'posts_per_page' ), 'elements' => Elements::$elements, 'elementsCatFirst' => self::get_first_elements_category( $post_id ), 'wpEditor' => $this->get_wp_editor(), 'recaptchaIds' => [], 'saveMessages' => $this->save_messages(), 'builderParam' => BRICKS_BUILDER_PARAM, 'animatedTypingInstances' => [], // Necessary to destroy and then reinit TypedJS instances 'videoInstances' => [], // Necessary to destroy and then reinit Plyr instances 'splideInstances' => [], // Necessary to destroy and then reinit SplideJS instances 'tocbotInstances' => [], // Necessary to destroy and then reinit Tocbot instances 'swiperInstances' => [], // Necessary to destroy and then reinit SwiperJS instances 'isotopeInstances' => [], // Necessary to destroy and then reinit Isotope instances 'filterInstances' => [], // Necessary to destroy and then reinit query filter instances 'googleMapInstances' => [], // Necessary to destroy and then reinit Google Maps instances 'leafletMapInstances' => [], // Necessary to destroy and then reinit Leaflet Maps instances 'activeFiltersCountInstances' => [], // Necessary to destroy and then reinit query filter instances 'choicesInstances' => [], // Necessary to destroy and then reinit ChoicesJS instances 'icons' => self::get_icon_font_classes(), 'controls' => [ 'themeStyles' => Theme_Styles::get_controls_data(), 'settings' => Settings::get_controls_data(), 'conditions' => Conditions::get_controls_data(), 'interactions' => Interactions::get_controls_data(), ], 'controlOptions' => $control_options, // Static data 'themeStyles' => Theme_Styles::$styles, 'remoteTemplateSettings' => Templates::get_remote_template_settings(), 'template' => [ 'orderBy' => $control_options['templatesOrderBy'], 'preview' => self::get_template_preview_data( $post_id ), 'authors' => Templates::get_template_authors(), 'bundles' => Templates::get_template_bundles(), 'tags' => Templates::get_template_tags(), 'types' => $control_options['templateTypes'], ], 'mailchimpLists' => Integrations\Form\Actions\Mailchimp::get_list_options(), 'wooCommerceActive' => Woocommerce::$is_active, 'googleFontsDisabled' => Helpers::google_fonts_disabled(), 'fonts' => self::get_fonts(), 'templateManagerThumbnailHeight' => Database::get_setting( 'templateManagerThumbnailHeight' ), 'themeStylesLoadingMethod' => Database::get_setting( 'themeStylesLoadingMethod', 'specific' ), // @since 2.0 'codeMirrorConfig' => apply_filters( 'bricks/builder/codemirror_config', [] ), 'builderGlobalClassesImport' => Database::get_setting( 'builderGlobalClassesImport' ), 'builderHtmlCssConverter' => Database::get_setting( 'builderHtmlCssConverter' ), 'placeholderImage' => [ 'img' => self::get_template_placeholder_image(), 'svg' => self::get_template_placeholder_image( true ), 'svgPath' => self::get_template_placeholder_image( true, 'path' ), ], 'pasteAndImportImage' => Database::get_setting( 'importImageOnPaste', false ), 'adobeFontsProjectId' => Database::get_setting( 'adobeFontsProjectId' ), 'bricksGoogleMarkerScript' => BRICKS_URL_ASSETS . 'js/libs/bricks-google-marker.min.js?v=' . BRICKS_VERSION, // @since 2.0 'infoboxScript' => BRICKS_URL_ASSETS . 'js/libs/infobox.min.js?v=' . BRICKS_VERSION, // @since 2.0 'markerClustererScript' => BRICKS_URL_ASSETS . 'js/libs/markerclusterer.min.js?v=' . BRICKS_VERSION, // @since 2.0 ] ); /** * Deregister wp-polyfill.min.js as it is causing performance issue for Firefox browser (in WordPress 6.4+) * * @since 1.9.5 */ if ( ! Database::get_setting( 'builderWpPolyfill', false ) && wp_script_is( 'wp-polyfill', 'registered' ) ) { wp_deregister_script( 'wp-polyfill' ); wp_register_script( 'wp-polyfill', false ); } } /** * Get WordPress data for use in builder x-template (to reduce AJAX calls) * * @return array * * @since 1.0 */ public static function get_wordpress_data() { return [ 'post' => [ 'title' => Helpers::get_the_title( get_the_ID(), false ), 'title_context' => Helpers::get_the_title( get_the_ID(), true ), ], ]; } /** * Get all fonts * * - Adobe fonts (@since 1.7.1) * - Custom fonts * - Google fonts * - Standard fonts * * @since 1.2.1 * * @return array */ public static function get_fonts() { $fonts = []; // Build font dropdown 'options' for ControlTypography.vue $options = []; // STEP: Adobe fonts $adobe_fonts = Database::$adobe_fonts; if ( is_array( $adobe_fonts ) && count( $adobe_fonts ) ) { $options['adobeFontsGroupTitle'] = 'Adobe fonts'; foreach ( $adobe_fonts as $adobe_font ) { $adobe_font_family_name = $adobe_font['name'] ?? ''; $adobe_font_family_slug = $adobe_font['slug'] ?? ''; $adobe_font_family_css_names = $adobe_font['css_names'] ?? []; if ( ! $adobe_font_family_name ) { continue; } /** * Segmented fonts: For legacy Adobe Fonts kits, a font may have multiple CSS names (is always an array, though) (@since 1.9.4) * * Example: Azo Sans (where 'slug' is 'azo-sans', but css_names[0] is 'azo-sans-web', the latter which we need). * * https://fonts.adobe.com/docs/api/css_names */ if ( is_array( $adobe_font_family_css_names ) && count( $adobe_font_family_css_names ) ) { // Concatenate CSS names $adobe_font_family_key = implode( ', ', $adobe_font_family_css_names ); $options[ $adobe_font_family_key ] = $adobe_font_family_name; } // Fallack to font slug else { $options[ $adobe_font_family_slug ] = $adobe_font_family_name; } } if ( count( $adobe_fonts ) ) { $fonts['adobe'] = $adobe_fonts; } } // STEP: Custom fonts $custom_fonts = Custom_Fonts::get_custom_fonts(); if ( $custom_fonts ) { $options['customFontsGroupTitle'] = esc_html__( 'Custom Fonts', 'bricks' ); foreach ( $custom_fonts as $custom_font_id => $custom_font ) { $options[ $custom_font_id ] = $custom_font['family']; } $fonts['custom'] = $custom_fonts; } // STEP: Google fonts (if not disabled via filter OR settings) if ( ! Helpers::google_fonts_disabled() ) { $google_fonts = self::get_google_fonts(); $options['googleFontsGroupTitle'] = 'Google fonts'; foreach ( $google_fonts as $google_font ) { $options[ $google_font['family'] ] = $google_font['family']; } $fonts['google'] = $google_fonts; } // STEP: Standard fonts $standard_fonts = self::get_standard_fonts(); $options['standardFontsGroupTitle'] = esc_html__( 'Standard fonts', 'bricks' ); foreach ( $standard_fonts as $standard_font ) { $options[ $standard_font ] = $standard_font; } $fonts['standard'] = $standard_fonts; $fonts['options'] = $options; return $fonts; } /** * Get standard (web safe) fonts * * @since 1.0 * * @return array */ public static function get_standard_fonts() { $standard_fonts = [ 'Arial', 'Helvetica', 'Helvetica Neue', 'Times New Roman', 'Times', 'Georgia', 'Courier New', ]; return apply_filters( 'bricks/builder/standard_fonts', $standard_fonts ); } /** * Get Google fonts * * Return fonts array with 'family' & 'variants' (to update font-weight for each font in builder) * * @since 1.0 * * @return array */ public static function get_google_fonts() { /** * STEP: Generate Google fonts JSON file from API response * * We only need the 'family' & 'variants' properties from the Google fonts API response. * * DEV_ONLY: Set $google_fonts_generate below to true to generate the JSON file! * NOTE First get the Google fonts JSON file from the API response (https://www.googleapis.com/webfonts/v1/webfonts) and save it to the src/assets/fonts/ folder. * * @since 1.7.1 */ $google_fonts_generate = false; if ( $google_fonts_generate ) { $google_fonts = file_get_contents( BRICKS_URL . 'src/assets/fonts/google-fonts.json', false, stream_context_create( [ 'ssl' => [ 'verify_peer' => false, 'verify_peer_name' => false, ], ] ) ); $google_fonts = json_decode( $google_fonts, true ); $google_fonts = $google_fonts['items'] ?? []; $google_fonts_processed = []; foreach ( $google_fonts as $google_font ) { $family = ! empty( $google_font['family'] ) ? $google_font['family'] : false; $variants = ! empty( $google_font['variants'] ) ? wp_json_encode( $google_font['variants'] ) : false; $variants = str_replace( 'regular', '400', $variants ); if ( ! $family ) { continue; } $google_fonts_processed[] = [ 'family' => $family, 'variants' => json_decode( $variants, true ), ]; } // Encode into minified JSON format $json = wp_json_encode( $google_fonts_processed, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ); // Save the modified JSON data back to the file file_put_contents( BRICKS_PATH . 'src/assets/fonts/google-fonts.min.json', $json ); return []; } // STEP: Get contents of the Google fonts JSON file $google_fonts = Helpers::file_get_contents( BRICKS_PATH_ASSETS . 'fonts/google-fonts.min.json' ); // Return: Empty file OR not found if ( ! $google_fonts ) { return []; } // Decode the JSON data into a PHP object $google_fonts = json_decode( $google_fonts, true ); return is_array( $google_fonts ) ? $google_fonts : []; } /** * Template placeholder image (if importImages set to false) * * @since 1.0 */ public static function get_template_placeholder_image( $is_svg = false, $format = 'url' ) { $image = $is_svg ? 'placeholder-svg.svg' : 'placeholder-image-800x600.jpg'; $default_image = $format === 'path' ? BRICKS_PATH . 'assets/images/' . $image : get_template_directory_uri() . '/assets/images/' . $image; // @see https://article.bricksbuilder.io/article/filter-placeholder_image/ (@since 2.0) return apply_filters( 'bricks/placeholder_image', $default_image, $is_svg, $format ); } /** * Template preview data * * @since 1.0 */ public static function get_template_preview_data( $post_id ) { $preview_data = []; // Placeholder HTML $placeholder = '<section class="brxe-container brxe-alert" style="cursor: pointer">'; $placeholder .= Helpers::get_element_placeholder( [ 'icon-class' => 'ti-layout', 'text' => esc_html__( 'Click to set preview content.', 'bricks' ), ] ); $placeholder .= '</section>'; $preview_data['placeholder'] = $placeholder; // Only add the preview post id if there is a preview if ( Helpers::is_bricks_template( $post_id ) ) { $preview_post_id = Helpers::get_template_setting( 'templatePreviewPostId', $post_id ); if ( $preview_post_id ) { $post_id = intval( $preview_post_id ); } $preview_data['postId'] = $post_id; } return $preview_data; } /** * Post thumbnail data (for use in _background control) * * @since 1.0 */ public function get_post_thumbnail() { return [ 'filename' => basename( get_attached_file( get_post_thumbnail_id( get_the_ID() ) ) ), 'full' => get_the_post_thumbnail_url( get_the_ID(), 'full' ), 'id' => get_post_thumbnail_id( get_the_ID() ), 'size' => BRICKS_DEFAULT_IMAGE_SIZE, 'url' => get_the_post_thumbnail_url( get_the_ID(), BRICKS_DEFAULT_IMAGE_SIZE ), ]; } /** * Custom TinyMCE settings for builder * * @since 1.0 */ public function tiny_mce_before_init( $in ) { // Remove certain TinyMCE plugins in builder $plugins = explode( ',', $in['plugins'] ); $key = array_search( 'fullscreen', $plugins ); if ( isset( $plugins[ $key ] ) ) { unset( $plugins[ $key ] ); } $in['plugins'] = join( ',', $plugins ); return $in; } /** * WordPress editor * * Without tag button, "Add media" button (use respective elements instead) * * @since 1.0 */ public function get_wp_editor() { ob_start(); $mce_buttons = add_filter( 'mce_buttons', function( $buttons ) { // NOTE: Show all editor controls @since 1.3.6 ("Basic Text" element) // Remove formatselect button (paragraph/heading/preformatted etc.) // $buttons_to_remove = [ 'formatselect' ]; // foreach ( $buttons as $index => $button_name ) { // if ( in_array( $button_name, $buttons_to_remove ) ) { // unset( $buttons[ $index ] ); // } // } // Add dynamic tag picker dropdown button to tinyMCE editor $buttons[] = 'tagPickerButton'; return $buttons; } ); $content = '%%BRICKS_EDITOR_CONTENT_PLACEHOLDER%%'; $editor_id = 'brickswpeditor'; // No dashes, see https://codex.wordpress.org/Function_Reference/wp_editor $settings = [ 'editor_class' => 'bricks-wp-editor', // 'media_buttons' => false, // Use image element instead 'quicktags' => [ 'buttons' => 'sup', // 'buttons' => 'strong,em,ul,ol,li,link,close', // No spaces ], ]; wp_editor( $content, $editor_id, $settings ); return ob_get_clean(); } /** * Add 'superscript' & 'subscript' button to TinyMCE in builder * * @since 1.4 */ public function add_editor_buttons( $buttons ) { if ( ! in_array( 'superscript', $buttons ) ) { $buttons[] = 'superscript'; } if ( ! in_array( 'subscript', $buttons ) ) { $buttons[] = 'subscript'; } return $buttons; } /** * Builder strings * * @since 1.0 */ public static function i18n() { $i18n = I18n::get_all_i18n(); return apply_filters( 'bricks/builder/i18n', $i18n ); } /** * Custom save messages * * @since 1.0 * * @return array */ public function save_messages() { $messages = [ esc_html__( 'All right', 'bricks' ), esc_html__( 'Amazing', 'bricks' ), esc_html__( 'Aye', 'bricks' ), esc_html__( 'Beautiful', 'bricks' ), esc_html__( 'Brilliant', 'bricks' ), esc_html__( 'Champ', 'bricks' ), esc_html__( 'Cool', 'bricks' ), esc_html__( 'Congrats', 'bricks' ), esc_html__( 'Done', 'bricks' ), esc_html__( 'Excellent', 'bricks' ), esc_html__( 'Exceptional', 'bricks' ), esc_html__( 'Exquisite', 'bricks' ), esc_html__( 'Enjoy', 'bricks' ), esc_html__( 'Fantastic', 'bricks' ), esc_html__( 'Fine', 'bricks' ), esc_html__( 'Good', 'bricks' ), esc_html__( 'Grand', 'bricks' ), esc_html__( 'Impressive', 'bricks' ), esc_html__( 'Incredible', 'bricks' ), esc_html__( 'Magnificent', 'bricks' ), esc_html__( 'Marvelous', 'bricks' ), esc_html__( 'Neat', 'bricks' ), esc_html__( 'Nice job', 'bricks' ), esc_html__( 'Okay', 'bricks' ), esc_html__( 'Outstanding', 'bricks' ), esc_html__( 'Remarkable', 'bricks' ), esc_html__( 'Saved', 'bricks' ), esc_html__( 'Skillful', 'bricks' ), esc_html__( 'Stunning', 'bricks' ), esc_html__( 'Superb', 'bricks' ), esc_html__( 'Sure thing', 'bricks' ), esc_html__( 'Sweet', 'bricks' ), esc_html__( 'Top', 'bricks' ), esc_html__( 'Very well', 'bricks' ), esc_html__( 'Woohoo', 'bricks' ), esc_html__( 'Wonderful', 'bricks' ), esc_html__( 'Yeah', 'bricks' ), esc_html__( 'Yep', 'bricks' ), esc_html__( 'Yes', 'bricks' ), ]; $messages = apply_filters( 'bricks/builder/save_messages', $messages ); return $messages; } /** * Get icon font classes * * @since 1.0 * * @return array */ public static function get_icon_font_classes() { return [ 'close' => 'ion-md-close', 'undo' => 'ion-ios-undo', 'redo' => 'ion-ios-redo', 'arrowRight' => 'ion-ios-arrow-forward', 'arrowDown' => 'ion-ios-arrow-down', 'arrowLeft' => 'ion-ios-arrow-back', 'arrowUp' => 'ion-ios-arrow-up', 'preview' => 'ion-ios-eye', 'settings' => 'ion-md-settings', 'structure' => 'ion-ios-albums', 'publish' => 'ion-ios-power', 'templates' => 'ion-ios-folder-open', 'page' => 'ion-md-document', 'desktop' => 'ion-md-desktop', 'mobile' => 'ion-md-phone-portrait', 'globe' => 'ion-md-globe', 'documentation' => 'ion-ios-help-buoy', 'panelMaximize' => 'ion-ios-qr-scanner', 'panelMinimize' => 'ion-ios-qr-scanner', 'add' => 'ion-md-add', 'addTi' => 'ti-plus', 'remove' => 'ion-md-remove', 'edit' => 'ion-md-create', 'clone' => 'ion-ios-copy', 'move' => 'ion-md-move', 'save' => 'ion-md-save', 'check' => 'ion-md-checkmark', 'trash' => 'ion-md-trash', 'trashTi' => 'ti-trash', 'newTab' => 'ti-new-window', 'brush' => 'ion-md-brush', 'image' => 'ion-ios-image', 'video' => 'ion-md-videocam', 'cssFilter' => 'ion-md-color-filter', 'faceSad' => 'ti-face-sad', 'heart' => 'ion-md-heart', 'refresh' => 'ti-reload', 'help' => 'ti-help-alt', 'helpIon' => 'ion-md-help-circle', 'hover' => 'ti-hand-point-up', 'more' => 'ti-more-alt', 'notifications' => 'ti-bell', 'revisions' => 'ion-md-time', 'link' => 'ion-ios-link', 'docs' => 'ti-agenda', 'email' => 'ion-ios-mail', 'search' => 'ti-search', 'wordpress' => 'ti-wordpress', 'import' => 'ti-import', 'export' => 'ti-export', 'download' => 'ti-download', 'zoomIn' => 'ti-zoom-in', ]; } /** * Based on post_type or template type select the first elements category to show up on builder. */ public static function get_first_elements_category( $post_id = 0 ) { $post_type = get_post_type( $post_id ); // NOTE: Undocumented $category = apply_filters( 'bricks/builder/first_element_category', false, $post_id, $post_type ); if ( $category ) { return $category; } if ( 'page' !== $post_type ) { return 'single'; } return ''; } /** * Check permissions for a certain user to access the Bricks builder * * @since 1.0 */ public function template_redirect() { // Redirect non-logged-in visitors to home page if ( ! is_user_logged_in() ) { wp_redirect( home_url() ); die; } // STEP: Return if license in not valid $license_is_valid = License::license_is_valid(); if ( ! $license_is_valid ) { wp_redirect( admin_url( 'admin.php?page=bricks-license' ) ); } // STEP: Return if current user can not edit this post $post_id = is_single() ? get_the_ID() : 0; if ( ! Capabilities::current_user_can_use_builder( $post_id ) ) { // Redirect users without builder capabilities back to WordPress admin area wp_redirect( admin_url( '/?action=edit&bricks_notice=error_role_manager' ) ); die(); } // NOTE: Don't check for template if ( is_home() || ( function_exists( 'is_shop' ) && is_shop() ) ) { return; } // STEP: Return if post type is not supported for editing with Bricks $current_post_type = get_post_type(); $supported_post_types = Database::get_setting( 'postTypes', [] ); // Bricks templates always have builder support if ( $current_post_type === BRICKS_DB_TEMPLATE_SLUG ) { $supported_post_types[] = BRICKS_DB_TEMPLATE_SLUG; } // NOTE: Undocumented $supported_post_types = apply_filters( 'bricks/builder/supported_post_types', $supported_post_types, $current_post_type ); if ( ! in_array( $current_post_type, $supported_post_types ) ) { wp_redirect( admin_url( "/edit.php?post_type={$current_post_type}&bricks_notice=error_post_type" ) ); } } /** * Get page data for builder * * @since 1.0 * * @return array */ public static function builder_data( $post_id ) { $global_data = Database::$global_data; $page_data = Database::$page_data; $theme_styles = Theme_Styles::$styles; $theme_style_active_ids = array_keys( Theme_Styles::$settings_by_id ); $theme_style_active_id = end( $theme_style_active_ids ); // Get most specific theme style (@since 2.0) $template_settings = Helpers::get_template_settings( $post_id ); $template_preview_post_id = Helpers::get_template_setting( 'templatePreviewPostId', $post_id ); $load_data = [ 'breakpoints' => Breakpoints::$breakpoints, 'permissions' => Builder_Permissions::get_current_user_permissions(), // @since 2.0 'breakpointActive' => Breakpoints::$base_key, 'themeStyles' => $theme_styles, 'themeStyleActiveIds' => $theme_style_active_ids, 'themeStyleActiveId' => $theme_style_active_id, 'pinnedElements' => get_option( BRICKS_DB_PINNED_ELEMENTS, [] ), 'elementManager' => Elements::$manager, 'codeExecutionEnabled' => Helpers::code_execution_enabled(), 'currentUserId' => get_current_user_id(), 'queryMaxResults' => self::get_query_max_results(), 'rememberSpacingLinkState' => Database::get_setting( 'builderRememberSpacingLinkState' ), // @since 2.2 'builderDisablePinnedControlGroups' => Database::get_setting( 'builderDisablePinnedControlGroups', false ), // @since 2.3 'userCan' => [ 'executeCode' => Capabilities::current_user_can_execute_code(), 'uploadSvg' => Capabilities::current_user_can_upload_svg(), 'editPosts' => current_user_can( 'edit_posts' ), // User can create/edit posts (@since 2.0) 'publishPosts' => current_user_can( 'publish_posts' ), 'publishPages' => current_user_can( 'publish_pages' ), ], 'blockCategories' => function_exists( 'get_block_categories' ) ? get_block_categories( null ) : [], ]; // Components if ( ! empty( $global_data['components'] ) ) { // STEP: Upgrade components to use latest data structure and add to load_data $load_data['components'] = Components::upgrade_components( $global_data['components'], false ); } // Add color palettes to load_data if ( ! empty( $global_data['colorPalette'] ) && is_array( $global_data['colorPalette'] ) ) { $load_data['colorPalette'] = $global_data['colorPalette']; } // Add styleManager settings to load_data (@since 2.2) if ( ! empty( $global_data['styleManager'] ) ) { $load_data['styleManager'] = $global_data['styleManager']; } // Set light/dark mode based on styleManager settings (@since 2.2) $mode = ! empty( $load_data['styleManager']['defaultMode'] ) ? $load_data['styleManager']['defaultMode'] : 'light'; $load_data['mode'] = $mode; // Add global queries to load_data (@since 2.1) if ( ! empty( $global_data['globalQueries'] ) && is_array( $global_data['globalQueries'] ) ) { $load_data['globalQueries'] = $global_data['globalQueries']; } // Add global queries categories to load_data (@since 2.1) if ( ! empty( $global_data['globalQueriesCategories'] ) && is_array( $global_data['globalQueriesCategories'] ) ) { $load_data['globalQueriesCategories'] = $global_data['globalQueriesCategories']; } // Add font favorites to load_data if ( ! empty( $global_data['fontFavorites'] ) ) { $load_data['fontFavorites'] = $global_data['fontFavorites']; } // Add global variables (@since 1.9.8) if ( ! empty( $global_data['globalVariables'] ) ) { $load_data['globalVariables'] = $global_data['globalVariables']; } // Add icon sets (@since 2.0) if ( ! empty( $global_data['iconSets'] ) ) { $load_data['iconSets'] = $global_data['iconSets']; } if ( ! empty( $global_data['customIcons'] ) ) { $load_data['customIcons'] = $global_data['customIcons']; } if ( ! empty( $global_data['disabledIconSets'] ) ) { $load_data['disabledIconSets'] = $global_data['disabledIconSets']; } // Add global variables categories (@since 1.9.8) if ( ! empty( $global_data['globalVariablesCategories'] ) ) { $load_data['globalVariablesCategories'] = $global_data['globalVariablesCategories']; } // Add global classes if ( ! empty( $global_data['globalClasses'] ) ) { $load_data['globalClasses'] = $global_data['globalClasses']; } // Add global classes trash (@since 1.11) if ( ! empty( $global_data['globalClassesTrash'] ) ) { $load_data['globalClassesTrash'] = $global_data['globalClassesTrash']; // Set username for global classes trash view foreach ( $load_data['globalClassesTrash'] as $key => $class ) { $trashed_by_user_id = ! empty( $class['user_id'] ) ?? false; if ( $trashed_by_user_id && $trashed_by_user_id != get_current_user_id() ) { $user = get_user_by( 'id', $class['user_id'] ); if ( $user ) { $load_data['globalClassesTrash'][ $key ]['deletedBy'] = $user->display_name; } } } } // Add global classes categories if ( ! empty( $global_data['globalClassesCategories'] ) ) { $load_data['globalClassesCategories'] = $global_data['globalClassesCategories']; } // Add global classes locked if ( ! empty( $global_data['globalClassesLocked'] ) ) { $load_data['globalClassesLocked'] = $global_data['globalClassesLocked']; } // Add global classes timestamp (@since 1.9.8) if ( ! empty( $global_data['globalClassesTimestamp'] ) ) { $load_data['globalClassesTimestamp'] = $global_data['globalClassesTimestamp']; } // Add global classes user (@since 1.9.8) if ( ! empty( $global_data['globalClassesUser'] ) ) { $load_data['globalClassesUser'] = $global_data['globalClassesUser']; } // Add pseudo classes if ( ! empty( $global_data['pseudoClasses'] ) ) { $load_data['pseudoClasses'] = $global_data['pseudoClasses']; } else { $load_data['pseudoClasses'] = [ ':hover', ':active', ':focus', ]; } // Add elements & global settings if ( ! empty( $global_data['elements'] ) ) { $load_data['globalElements'] = $global_data['elements']; } if ( ! empty( $global_data['settings'] ) ) { $load_data['globalSettings'] = $global_data['settings']; } // Add page data to load_data if ( ! empty( $page_data['header'] ) ) { $load_data['header'] = $page_data['header']; } else { // Check for header template $template_header_id = Database::$active_templates['header']; $header_template = $template_header_id ? Database::get_data( $template_header_id, 'header' ) : Database::get_data( $post_id, 'header' ); if ( ! empty( $header_template ) ) { $load_data['header'] = $header_template; // Sticky header, header postition etc. $load_data['templateHeaderSettings'] = Helpers::get_template_settings( $template_header_id ); } } // Content $template_content_id = Database::$active_templates['content']; if ( count( $page_data['content'] ) ) { $load_data['content'] = $page_data['content']; } // If content still not populated, check if populated content was set to preview it if ( empty( $load_data['content'] ) && $template_preview_post_id ) { // Template preview $content = get_post_meta( $template_preview_post_id, BRICKS_DB_PAGE_CONTENT, true ); $load_data['content'] = empty( $content ) ? [] : $content; } // Last resort for getting content: WP blocks if ( empty( $load_data['content'] ) && Database::get_setting( 'wp_to_bricks' ) ) { $template_preview_post_id = $template_preview_post_id ? $template_preview_post_id : $post_id; // Convert Gutenberg blocks to Bricks element $converter = new Blocks(); $content_from_blocks = $converter->convert_blocks_to_bricks( $template_preview_post_id ); if ( is_array( $content_from_blocks ) ) { $load_data['content'] = $content_from_blocks; // NOTE: Development-only $post = get_post( $template_content_id ); $blocks = parse_blocks( $post->post_content ); $load_data['blocks'] = $blocks; } } // Add template preview logic for single templates (@since 1.12) if ( $template_content_id && $template_content_id != $post_id ) { // Load template content for static area $template_content = Database::get_data( $template_content_id, 'content' ); if ( ! empty( $template_content ) ) { $load_data['staticContent'] = $template_content; // Add template page settings to generate CSS for static content (@since 1.12) $template_page_settings = get_post_meta( $template_content_id, BRICKS_DB_PAGE_SETTINGS, true ); if ( ! empty( $template_page_settings ) ) { $load_data['outerPostContentTemplatePageSettings'] = $template_page_settings; } } } // Footer if ( ! empty( $page_data['footer'] ) ) { $load_data['footer'] = $page_data['footer']; } else { $template_footer_id = Database::$active_templates['footer']; // Check for footer template $footer_template = $template_footer_id ? Database::get_data( $template_footer_id, 'footer' ) : []; if ( ! empty( $footer_template ) ) { $load_data['footer'] = $footer_template; } } if ( ! empty( $page_data['settings'] ) ) { $load_data['pageSettings'] = $page_data['settings']; } // Template type $template_type = Templates::get_template_type( $post_id ); // @since 1.7.1 - Default template type is 'content' (so listenHistory in builder can work properly) $load_data['templateType'] = ! empty( $template_type ) ? $template_type : 'content'; // Template settings if ( $template_settings ) { $load_data['templateSettings'] = $template_settings; } // Parse elements to replace dynamic data (needed for background image) $template_preview_post_id = $template_preview_post_id ? $template_preview_post_id : $post_id; if ( $template_type !== 'header' && ! empty( $load_data['header'] ) && is_array( $load_data['header'] ) ) { $load_data['header'] = self::render_dynamic_data_on_elements( $load_data['header'], $template_preview_post_id ); } if ( ! empty( $load_data['content'] ) && is_array( $load_data['content'] ) ) { $load_data['content'] = self::render_dynamic_data_on_elements( $load_data['content'], $template_preview_post_id ); } if ( $template_type !== 'footer' && ! empty( $load_data['footer'] ) && is_array( $load_data['footer'] ) ) { $load_data['footer'] = self::render_dynamic_data_on_elements( $load_data['footer'], $template_preview_post_id ); } /** * Generate element HTML strings in PHP for fast initial render * * Individual element HTML AJAX calls in builder are too slow. * Only load for dynamic area, but not static areas. */ $load_data['elementsHtml'] = []; // Remove setting in builder to get 'elementsHtml' with element ID for all PHP elements (@since 1.7) unset( Database::$global_settings['elementAttsAsNeeded'] ); // New rendering mode: Collect HTML strings for all elements start (@since 2.0) add_filter( 'bricks/frontend/render_element', [ __CLASS__, 'collect_elements_html' ], 10, 2 ); add_filter( 'bricks/frontend/render_loop', [ __CLASS__, 'collect_looping_html' ], 10, 3 ); add_action( 'bricks/query/query_api_response', [ __CLASS__, 'collect_query_api_results' ], 10, 2 ); add_action( 'bricks/dynamic_data/tag_value_parsed', [ __CLASS__, 'collect_looping_dynamic_data' ], 10, 7 ); // (#86c4tzdxq; @since 2.2) // Header if ( $template_type === 'header' && isset( $load_data['header'] ) && is_array( $load_data['header'] ) ) { Frontend::render_data( $load_data['header'], 'header' ); } // Content if ( ! in_array( $template_type, [ 'header', 'footer' ] ) && isset( $load_data['content'] ) && is_array( $load_data['content'] ) ) { Frontend::render_data( $load_data['content'], 'content' ); } // Footer if ( $template_type === 'footer' && isset( $load_data['footer'] ) && is_array( $load_data['footer'] ) ) { Frontend::render_data( $load_data['footer'], 'footer' ); } remove_filter( 'bricks/frontend/render_loop', [ __CLASS__, 'collect_looping_html' ], 10, 3 ); // Collect HTML strings for all elements end (@since 2.0) remove_filter( 'bricks/frontend/render_element', [ __CLASS__, 'collect_elements_html' ], 10, 2 ); remove_action( 'bricks/query/query_api_response', [ __CLASS__, 'collect_query_api_results' ], 10, 2 ); remove_action( 'bricks/dynamic_data/tag_value_parsed', [ __CLASS__, 'collect_looping_dynamic_data' ], 10, 7 ); // (#86c4tzdxq; @since 2.2) // Set collected HTML strings for all elements for fast initial render, reduce API calls (@since 2.0) $load_data['elementsHtml'] = self::$elements_html; $load_data['previewTexts'] = self::$preview_texts; $load_data['loopingHtml'] = self::$looping_html; $load_data['templatesData'] = self::$templates_data; $load_data['queryApiCache'] = self::$query_api_cache; /** * STEP: Pre-populate dynamic data to minimize AJAX requests on builder load * * Only if Bricks builder setting 'enableDynamicDataPreview' is enabled, we pre-populate. * * @see render_dynamic_data_on_elements * * @since 1.7.1 */ if ( Database::get_setting( 'enableDynamicDataPreview', false ) && is_array( self::$dynamic_data ) && count( self::$dynamic_data ) ) { $load_data['dynamicData'] = self::$dynamic_data; $load_data['loopingDynamicData'] = self::$looping_dynamic_data; } /** * STEP: Code signatures validation for builder unsignedCodeIds * * @since 2.0 */ $load_data['invalidCodeSignatures'] = self::get_invalid_code_signatures( $load_data ); /** * STEP: Add custom attributes to builder * * Keys: 'header', 'main', 'footer', or individual Bricks element ID * * @since 1.10 */ $load_data['htmlAttributes'] = self::$html_attributes; $load_data['htmlAttributes']['header'] = apply_filters( 'bricks/header/attributes', [] ); $load_data['htmlAttributes']['content'] = apply_filters( 'bricks/content/attributes', [] ); $load_data['htmlAttributes']['footer'] = apply_filters( 'bricks/footer/attributes', [] ); return $load_data; } /** * Get partial page data for builder (lighter version for instant navigation) * * NOTE: This is a dedicated function to keep things separate * But this functionality could be integrated into builder_data with a $partial_load parameter in the future * * @since 2.2 * * @return array */ public static function partial_builder_data( $post_id ) { $page_data = Database::$page_data; $template_settings = Helpers::get_template_settings( $post_id ); $template_preview_post_id = Helpers::get_template_setting( 'templatePreviewPostId', $post_id ); $load_data = [ 'header' => [], 'content' => [], 'footer' => [], 'pageSettings' => [], 'templateSettings' => [], 'templatePreview' => self::get_template_preview_data( $post_id ), ]; // Add page data to load_data if ( ! empty( $page_data['header'] ) ) { $load_data['header'] = $page_data['header']; } else { // Check for header template $template_header_id = Database::$active_templates['header']; $header_template = $template_header_id ? Database::get_data( $template_header_id, 'header' ) : Database::get_data( $post_id, 'header' ); if ( ! empty( $header_template ) ) { $load_data['header'] = $header_template; // Sticky header, header postition etc. $load_data['templateHeaderSettings'] = Helpers::get_template_settings( $template_header_id ); } } // Content $template_content_id = Database::$active_templates['content']; if ( count( $page_data['content'] ) ) { $load_data['content'] = $page_data['content']; } // If content still not populated, check if populated content was set to preview it if ( empty( $load_data['content'] ) && $template_preview_post_id ) { // Template preview $content = get_post_meta( $template_preview_post_id, BRICKS_DB_PAGE_CONTENT, true ); $load_data['content'] = empty( $content ) ? [] : $content; } // Last resort for getting content: WP blocks if ( empty( $load_data['content'] ) && Database::get_setting( 'wp_to_bricks' ) ) { $template_preview_post_id = $template_preview_post_id ? $template_preview_post_id : $post_id; // Convert Gutenberg blocks to Bricks element $converter = new Blocks(); $content_from_blocks = $converter->convert_blocks_to_bricks( $template_preview_post_id ); if ( is_array( $content_from_blocks ) ) { $load_data['content'] = $content_from_blocks; // NOTE: Development-only $post = get_post( $template_content_id ); $blocks = parse_blocks( $post->post_content ); $load_data['blocks'] = $blocks; } } // Add template preview logic for single templates (@since 1.12) if ( $template_content_id && $template_content_id != $post_id ) { // Load template content for static area $template_content = Database::get_data( $template_content_id, 'content' ); if ( ! empty( $template_content ) ) { $load_data['staticContent'] = $template_content; // Add template page settings to generate CSS for static content (@since 1.12) $template_page_settings = get_post_meta( $template_content_id, BRICKS_DB_PAGE_SETTINGS, true ); if ( ! empty( $template_page_settings ) ) { $load_data['outerPostContentTemplatePageSettings'] = $template_page_settings; } } } // Footer if ( ! empty( $page_data['footer'] ) ) { $load_data['footer'] = $page_data['footer']; } else { $template_footer_id = Database::$active_templates['footer']; // Check for footer template $footer_template = $template_footer_id ? Database::get_data( $template_footer_id, 'footer' ) : []; if ( ! empty( $footer_template ) ) { $load_data['footer'] = $footer_template; } } if ( ! empty( $page_data['settings'] ) ) { $load_data['pageSettings'] = $page_data['settings']; } // Template type $template_type = Templates::get_template_type( $post_id ); // @since 1.7.1 - Default template type is 'content' (so listenHistory in builder can work properly) $load_data['templateType'] = ! empty( $template_type ) ? $template_type : 'content'; // Refresh settings controls based on new template type $GLOBALS['post'] = get_post( $post_id ); Settings::set_controls(); $load_data['controls'] = [ 'settings' => Settings::get_controls_data(), ]; $load_data['elementsCatFirst'] = self::get_first_elements_category( $post_id ); // Template settings if ( $template_settings ) { $load_data['templateSettings'] = $template_settings; } // Parse elements to replace dynamic data (needed for background image) $template_preview_post_id = $template_preview_post_id ? $template_preview_post_id : $post_id; if ( $template_type !== 'header' && ! empty( $load_data['header'] ) && is_array( $load_data['header'] ) ) { $load_data['header'] = self::render_dynamic_data_on_elements( $load_data['header'], $template_preview_post_id ); } if ( ! empty( $load_data['content'] ) && is_array( $load_data['content'] ) ) { $load_data['content'] = self::render_dynamic_data_on_elements( $load_data['content'], $template_preview_post_id ); } if ( $template_type !== 'footer' && ! empty( $load_data['footer'] ) && is_array( $load_data['footer'] ) ) { $load_data['footer'] = self::render_dynamic_data_on_elements( $load_data['footer'], $template_preview_post_id ); } /** * Generate element HTML strings in PHP for fast initial render * * Individual element HTML AJAX calls in builder are too slow. * Only load for dynamic area, but not static areas. */ $load_data['elementsHtml'] = []; // Remove setting in builder to get 'elementsHtml' with element ID for all PHP elements (@since 1.7) unset( Database::$global_settings['elementAttsAsNeeded'] ); // New rendering mode: Collect HTML strings for all elements start (@since 2.0) add_filter( 'bricks/frontend/render_element', [ __CLASS__, 'collect_elements_html' ], 10, 2 ); add_filter( 'bricks/frontend/render_loop', [ __CLASS__, 'collect_looping_html' ], 10, 3 ); add_action( 'bricks/query/query_api_response', [ __CLASS__, 'collect_query_api_results' ], 10, 2 ); // Header if ( $template_type === 'header' && isset( $load_data['header'] ) && is_array( $load_data['header'] ) ) { Frontend::render_data( $load_data['header'], 'header' ); } // Content if ( ! in_array( $template_type, [ 'header', 'footer' ] ) && isset( $load_data['content'] ) && is_array( $load_data['content'] ) ) { Frontend::render_data( $load_data['content'], 'content' ); } // Footer if ( $template_type === 'footer' && isset( $load_data['footer'] ) && is_array( $load_data['footer'] ) ) { Frontend::render_data( $load_data['footer'], 'footer' ); } remove_filter( 'bricks/frontend/render_loop', [ __CLASS__, 'collect_looping_html' ], 10, 3 ); // Collect HTML strings for all elements end (@since 2.0) remove_filter( 'bricks/frontend/render_element', [ __CLASS__, 'collect_elements_html' ], 10, 2 ); remove_action( 'bricks/query/query_api_response', [ __CLASS__, 'collect_query_api_results' ], 10, 2 ); // Set collected HTML strings for all elements for fast initial render, reduce API calls (@since 2.0) $load_data['elementsHtml'] = self::$elements_html; $load_data['previewTexts'] = self::$preview_texts; $load_data['loopingHtml'] = self::$looping_html; $load_data['templatesData'] = self::$templates_data; $load_data['queryApiCache'] = self::$query_api_cache; /** * STEP: Pre-populate dynamic data to minimize AJAX requests on builder load * * Only if Bricks builder setting 'enableDynamicDataPreview' is enabled, we pre-populate. * * @see render_dynamic_data_on_elements * * @since 1.7.1 */ if ( Database::get_setting( 'enableDynamicDataPreview', false ) && is_array( self::$dynamic_data ) && count( self::$dynamic_data ) ) { $load_data['dynamicData'] = self::$dynamic_data; $load_data['loopingDynamicData'] = self::$looping_dynamic_data; } /** * STEP: Code signatures validation for builder unsignedCodeIds * * @since 2.0 */ $load_data['invalidCodeSignatures'] = self::get_invalid_code_signatures( $load_data ); /** * STEP: Add custom attributes to builder * * Keys: 'header', 'main', 'footer', or individual Bricks element ID * * @since 1.10 */ $load_data['htmlAttributes'] = self::$html_attributes; $load_data['htmlAttributes']['header'] = apply_filters( 'bricks/header/attributes', [] ); $load_data['htmlAttributes']['content'] = apply_filters( 'bricks/content/attributes', [] ); $load_data['htmlAttributes']['footer'] = apply_filters( 'bricks/footer/attributes', [] ); return $load_data; } /** * Bricks 2.0 render mode * * Collect HTML string of every single element for initial fast builder render * * Use Frontend::render_data() instead of Ajax::render_element so all attributes can be collected successfully as well without execute apply_filters bricks/element/render_attributes * * @since 2.0 (#86c2z8bmd) */ public static function collect_elements_html( $html, $instance ) { $element_name = $instance->element['name'] ?? ''; $settings = $instance->element['settings'] ?? []; /** * Skip: Nav menu * * As inside '.brx-dropdown-content' the nav-menu wrapper, etc. is not needed * * @since 1.11 */ if ( $element_name === 'nav-menu' ) { return $html; } // Skip: Code element to prevent critical errors with code execution enabled on builder load if ( $element_name === 'code' ) { return $html; } /** * Template element * * Skip to render template inline CSS in builder (TODO: Improve performance) * * @since 2.0: Do not skip if this is a render component call */ if ( $element_name === 'template' && empty( $_POST['isRenderComponent'] ) ) { return $html; } /** * Skip: Shortcode element with bricks_template to render nested accordions, tabs, slider in builder * * Necessary as we skip nestable elements below (line 2335) * * @since 1.11 */ if ( $element_name === 'shortcode' ) { $is_bricks_shortcode = ! empty( $settings['shortcode'] ) && strpos( $settings['shortcode'], 'bricks_template' ) !== false; if ( $is_bricks_shortcode ) { return $html; } } // Do not skip nestable elements or all inner elements wouldn't have HTML and cause extra render_elements calls in the builder // Skip nestable elements // if ( $instance->nestable ) { // return $html; // } // Handle component: Use unique ID that already considered elements inside component (@since 2.0) $element_id = $instance->uid ?? $instance->id; if ( ! empty( $_POST['isRenderComponent'] ) ) { // is RenderComponent call - always use the same instance ID so nested component's PHP element can get the correct HTML $root_instance_id = sanitize_key( $_POST['isRenderComponent'] ); $element_id = $instance->id . '-' . $root_instance_id; } if ( ! isset( self::$elements_html[ $element_id ] ) ) { // Manually run bricks_render_dynamic_data as bricks/frontend/render_data not yet triggered (#86c3reqnt) self::$elements_html[ $element_id ] = bricks_render_dynamic_data( $html ); } // Pre-populate dynamic data for all elements (Only if not looping #86c4pmh96) if ( Database::get_setting( 'enableDynamicDataPreview', false ) && ! empty( $settings ) && ! Query::is_any_looping() ) { $settings_string = wp_json_encode( $settings ); // Get all dynamic data tags inside element settings preg_match_all( '/\{([^{}"]+)\}/', $settings_string, $matches ); $dynamic_data_tags = $matches[1]; foreach ( $dynamic_data_tags as $dynamic_data_tag ) { $dynamic_data_value = \Bricks\Integrations\Dynamic_Data\Providers::render_tag( $dynamic_data_tag, $instance->post_id ); if ( $dynamic_data_value ) { self::$dynamic_data[ "{$dynamic_data_tag}" ] = $dynamic_data_value; } } } // Generate preview text for 1st looping element, exclude nestable element to avoid unnecessary HTML generation, previewTexts are used by contentEditable elements // Use Query::get_looping_level() to target 1st loop only (#86c5f59k1; @since 2.2) if ( Query::is_any_looping() && Query::get_looping_level() === 0 && ! $instance->nestable ) { if ( ! isset( self::$preview_texts[ $element_id ] ) ) { // Manually run bricks_render_dynamic_data as bricks/frontend/render_data not yet triggered (#86c3reqnt) // Do not wp_strip_all_tags so first loop node can render complete HTML (#86c5hj7au; @since 2.1) self::$preview_texts[ $element_id ] = bricks_render_dynamic_data( $html ); } } return $html; } /** * Bricks 2.0 builder render mode * * Collect query loop first node HTML string if the query located inside a component. * * @since 2.0 */ public static function collect_looping_html( $html, $element_data, $instance ) { $element_id = $instance->uid ?? $instance->id; if ( ! empty( $_POST['isRenderComponent'] ) ) { // is RenderComponent call - always use the same instance ID so nested component's PHP element can get the correct HTML $root_instance_id = sanitize_key( $_POST['isRenderComponent'] ); $element_id = $instance->id . '-' . $root_instance_id; } if ( ! isset( self::$looping_html[ $element_id ] ) ) { self::$looping_html[ $element_id ] = $html; } return $html; } /** * Collect dynamic data used inside looping * * @since 2.2 #86c4tzdxq */ public static function collect_looping_dynamic_data( $value, $tag, $original_tag, $args, $post, $context, $provider ) { // Collect dynamic data used inside looping if ( ! Query::is_any_looping() ) { return; } $query_id = Query::get_query_element_id( Query::is_any_looping() ); $key = $original_tag . '||' . $query_id; if ( ! isset( self::$looping_dynamic_data[ $key ] ) ) { self::$looping_dynamic_data[ $key ] = $value; } } /** * Collect query results for API calls * * Used in PopupQueryApi.vue * * @since 2.1 */ public static function collect_query_api_results( $results, $element_id ) { // Collect query results for external API calls if ( isset( self::$query_api_cache[ $element_id ] ) ) { return; } // Do not cache if it's error if ( isset( $results['error'] ) && ! empty( $results['error'] ) ) { return; } // Add results to cache self::$query_api_cache[ $element_id ] = $results; } /** * Screens all elements and try to convert dynamic data to enhance builder experience * * @param array $elements * @param int $post_id */ public static function render_dynamic_data_on_elements( $elements, $post_id ) { $elements_json = wp_json_encode( $elements ); if ( ! is_string( $elements_json ) ) { return $elements; } // Custom background URLs can contain dynamic tags without using the image dynamic data field. // (#86c7yzzbg; @since 2.3.6) if ( strpos( $elements_json, 'useDynamicData' ) === false && strpos( $elements_json, '_background' ) === false ) { return $elements; } foreach ( $elements as $index => $element ) { $elements[ $index ]['settings'] = self::render_dynamic_data_on_settings( $element['settings'], $post_id ); } return $elements; } /** * On the settings array, if _background exists and is set to image, get the image URL * Needed when setting element background image * Refreshes every responsive _background image that uses dynamic data. (#86c6pygjb; @since 2.3.6) * * @param array $settings * @param int $post_id */ public static function render_dynamic_data_on_settings( $settings, $post_id ) { // Return: Do not render dynamic data for elements inside a loop if ( isset( $settings['hasLoop'] ) ) { return $settings; } foreach ( $settings as $setting_key => $setting_value ) { if ( $setting_key !== '_background' && strpos( $setting_key, '_background:' ) !== 0 ) { continue; } $background_image = ! empty( $setting_value['image'] ) && is_array( $setting_value['image'] ) ? $setting_value['image'] : []; if ( empty( $background_image ) ) { continue; } $background_image_dd_tag = ! empty( $setting_value['image']['useDynamicData'] ) ? $setting_value['image']['useDynamicData'] : false; if ( is_array( $background_image_dd_tag ) ) { $background_image_dd_tag = ! empty( $background_image_dd_tag['name'] ) ? $background_image_dd_tag['name'] : false; } if ( ! $background_image_dd_tag ) { $external_url = $background_image['external'] ?? ''; if ( ! is_string( $external_url ) || strpos( $external_url, '{' ) === false ) { continue; } // Clear source-page preview fields before resolving against the active builder preview post. // (#86c7yzzbg; @since 2.3.6) unset( $settings[ $setting_key ]['image']['id'], $settings[ $setting_key ]['image']['url'], $settings[ $setting_key ]['image']['filename'], $settings[ $setting_key ]['image']['full'] ); // Resolve the editable Custom URL into a builder preview URL while preserving the original tag in 'external'. // (#86c7yzzbg; @since 2.3.6) $rendered_url = bricks_render_dynamic_data( $external_url, $post_id, 'link' ); if ( ! $rendered_url ) { continue; } $settings[ $setting_key ]['image']['url'] = $rendered_url; $rendered_url_path = wp_parse_url( $rendered_url, PHP_URL_PATH ); $filename = $rendered_url_path ? basename( $rendered_url_path ) : ''; if ( $filename ) { $settings[ $setting_key ]['image']['filename'] = $filename; } continue; } $size = ! empty( $setting_value['image']['size'] ) ? $setting_value['image']['size'] : BRICKS_DEFAULT_IMAGE_SIZE; // Clear stale source-page preview data before resolving against the current preview post. (#86c6pygjb; @since 2.3.6) unset( $settings[ $setting_key ]['image']['id'], $settings[ $setting_key ]['image']['url'], $settings[ $setting_key ]['image']['filename'], $settings[ $setting_key ]['image']['full'] ); $images = Integrations\Dynamic_Data\Providers::render_tag( $background_image_dd_tag, $post_id, 'image', [ 'size' => $size ] ); $image_id = ! empty( $images[0] ) ? $images[0] : false; if ( ! $image_id ) { continue; } if ( is_numeric( $image_id ) ) { $settings[ $setting_key ]['image']['id'] = $image_id; $settings[ $setting_key ]['image']['size'] = $size; $settings[ $setting_key ]['image']['url'] = wp_get_attachment_image_url( $image_id, $size ); } else { $settings[ $setting_key ]['image']['url'] = $image_id; } } return $settings; } /** * Builder: Force Bricks template to avoid conflicts with other builders (Elementor PRO, etc.) */ public function template_include( $template ) { if ( bricks_is_builder() ) { $template = BRICKS_PATH . 'template-parts/builder.php'; } return $template; } /** * Helper function to check if a AJAX or REST API call comes from inside the builder * * NOTE: Use bricks_is_builder_call() to check if AJAX/REST API call inside the builder * * @since 1.5.5 * * @return boolean */ public static function is_builder_call() { /** * STEP: Builder AJAX call: Check data for 'bricks-is-builder' */ if ( bricks_is_ajax_call() && check_ajax_referer( 'bricks-nonce-builder', 'nonce', false ) ) { $action = isset( $_REQUEST['action'] ) ? $_REQUEST['action'] : ''; $is_builder = isset( $_REQUEST['bricks-is-builder'] ); if ( $is_builder ) { return true; } } /** * STEP: REST API call * * Is default builder render. */ if ( bricks_is_rest_call() ) { return ! empty( $_SERVER['HTTP_X_BRICKS_IS_BUILDER'] ); } /** * STEP: Builder frontend preview (window opened via builder toolbar preview icon) * * Check needed as referrer check below is the builder. * * @since 1.6.2 */ if ( isset( $_GET['bricks_preview'] ) ) { return false; } // STEP: Check query string of referer URL (@since 1.5.5) $referer = ! empty( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : wp_get_referer(); $url_parsed = $referer ? wp_parse_url( $referer ) : ''; $url_query_string = isset( $url_parsed['query'] ) ? $url_parsed['query'] : ''; if ( $url_query_string && strpos( $url_query_string, 'bricks=run' ) !== false ) { return true; } return false; } /** * Return the maximum number of query loop results to display in the builder * * @since 1.11 */ public static function get_query_max_results() { return Database::get_setting( 'builderQueryMaxResults', false ); } /** * Get query max results info * * @since 1.11 */ public static function get_query_max_results_info() { return sprintf( esc_html__( 'Query loop results in the builder are limited to %1$s.', 'bricks' ), self::get_query_max_results() ) . ' <a href="' . admin_url( 'admin.php?page=bricks-settings#tab-builder' ) . '" target="_blank">[' . esc_html__( 'Edit', 'bricks' ) . ']</a>'; } /** * Check if user enabled through Bricks > Settings > Builder builderCloudflareRocketLoader * * - Ensure that the request is coming from Cloudflare. * - TODO: Will be set as default in a future version of Bricks. (#86c2rdm5a) * * @since 2.0 */ public static function cloudflare_rocket_loader_disabled() { return ! empty( $_SERVER['HTTP_CF_CONNECTING_IP'] ) && Database::get_setting( 'builderCloudflareRocketLoader', false ); } /** * Add data-cfasync="false" to all <script> tags to avoid Cloudflare Rocket Loader * * @since 2.0 */ public function cloudflare_rocket_loader_modify_script_tags() { ob_start( function ( $html ) { // Use preg_replace to add data-cfasync="false" to all <script> tags $html = preg_replace_callback( '/<script\b([^>]*)>/i', function ( $matches ) { // Check if the script tag already has data-cfasync="false" if ( isset( $matches[1] ) && $matches[1] !== '' && strpos( $matches[1], 'data-cfasync' ) === false ) { // Add data-cfasync="false" to the script tag return '<script data-cfasync="false" ' . $matches[1] . '>'; } // Return the original ta return $matches[0]; }, $html ); return $html; } ); } /** * Returns an array of invalid code signatures elements IDs * * @param array $data (elements data) * @since 2.0 */ public static function get_invalid_code_signatures( $data ) { $invalid_code_signatures = []; // Check from 'header', 'content', 'footer' $elements = array_merge( $data['header'] ?? [], $data['content'] ?? [], $data['footer'] ?? [] ); // Elements from components foreach ( Database::$global_data['components'] as $component ) { if ( ! empty( $component['elements'] ) && is_array( $component['elements'] ) ) { $elements = array_merge( $elements, $component['elements'] ); } } foreach ( $elements as $element ) { $element_settings = $element['settings'] ?? []; $element_name = $element['name'] ?? ''; $global_settings = Helpers::get_global_element( $element, 'settings' ); if ( $global_settings ) { $element_settings = $global_settings; } // Check: Component root $component_instance_settings = ! empty( $element['cid'] ) ? Helpers::get_component_instance( $element, 'settings' ) : false; if ( $component_instance_settings ) { $element_settings = $component_instance_settings; } if ( empty( $element_settings ) ) { continue; } // STEP: Code element if ( $element_name === 'code' ) { $element['execute_code'] = isset( $element_settings['executeCode'] ); // Execute code if ( $element['execute_code'] ) { $element_settings_code = isset( $element_settings['code'] ) ? $element_settings['code'] : ''; // Skip if no code or empty code if ( empty( $element_settings_code ) ) { continue; } $valid = false; if ( ! empty( $element_settings['signature'] ) ) { $valid = Helpers::verify_code_signature( $element_settings['signature'], $element_settings_code ); } if ( ! $valid ) { $invalid_code_signatures[] = $element['id']; } } continue; } // STEP: SVG element if ( $element_name === 'svg' ) { $element['execute_code'] = isset( $element_settings['code'] ) && ! empty( $element_settings['code'] ); if ( $element['execute_code'] ) { $element_settings_code = isset( $element_settings['code'] ) ? $element_settings['code'] : ''; // Skip if no code or empty code if ( empty( $element_settings_code ) ) { continue; } $valid = false; if ( ! empty( $element_settings['signature'] ) ) { $valid = Helpers::verify_code_signature( $element_settings['signature'], $element_settings_code ); } if ( ! $valid ) { $invalid_code_signatures[] = $element['id']; } } continue; } // STEP: Query editor element if ( isset( $element_settings['query']['queryEditor'] ) ) { $element['execute_code'] = isset( $element_settings['query']['useQueryEditor'] ); if ( $element['execute_code'] ) { $element_settings_code = isset( $element_settings['query']['queryEditor'] ) ? $element_settings['query']['queryEditor'] : ''; // Skip if no code or empty code if ( empty( $element_settings_code ) ) { continue; } $valid = false; if ( ! empty( $element_settings['query']['signature'] ) ) { $valid = Helpers::verify_code_signature( $element_settings['query']['signature'], $element_settings_code ); } if ( ! $valid ) { $invalid_code_signatures[] = $element['id']; } } continue; } } return $invalid_code_signatures; } }
修改文件时间
将文件时间修改为当前时间的前一年
删除文件