Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
@@ -0,0 +1,388 @@
|
||||
<?php
|
||||
/**
|
||||
* Block Templates Compatibility.
|
||||
*
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Block Templates Compatibility Class.
|
||||
*
|
||||
* @since 4.9.8
|
||||
*/
|
||||
class ET_Builder_Block_Templates {
|
||||
/**
|
||||
* Instance of `ET_Builder_Block_Templates`.
|
||||
*
|
||||
* @var ET_Builder_Block_Templates
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* ET_Builder_Block_Templates constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->init_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the class instance.
|
||||
*
|
||||
* @since 4.9.8
|
||||
*
|
||||
* @return ET_Builder_Block_Templates
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( ! self::$_instance ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize some hooks to support compatibility with block templates.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*/
|
||||
public function init_hooks() {
|
||||
// Bail early if block templates compatibility is not needed.
|
||||
if ( ! self::is_block_templates_compat_needed() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Filters block template loeaders.
|
||||
add_action( 'wp_loaded', array( 'ET_Builder_Block_Templates', 'filter_template_loaders' ) );
|
||||
|
||||
// WooCommerce compatibility for themes that support FSE.
|
||||
add_action( 'template_redirect', array( 'ET_Builder_Block_Templates', 'remove_unsupported_theme_filter' ), 12 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter specific template loaders to use theme template files if any instead of
|
||||
* 'wp_template' posts.
|
||||
*
|
||||
* @since 4.17.4
|
||||
*/
|
||||
public static function filter_template_loaders() {
|
||||
$template_slugs = self::get_supported_template_slugs();
|
||||
|
||||
foreach ( $template_slugs as $template_slug ) {
|
||||
$template_name = str_replace( '-', '', $template_slug );
|
||||
$template_filter = $template_name . '_template';
|
||||
|
||||
add_filter( $template_filter, array( 'ET_Builder_Block_Templates', 'override_block_template' ), 30, 3 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe override block templates.
|
||||
*
|
||||
* This action should be executed only when:
|
||||
* - TB Template is active on current page
|
||||
* - Current template is block template canvas
|
||||
*
|
||||
* @since 4.14.7
|
||||
*
|
||||
* @param string $template Current template path.
|
||||
*/
|
||||
public static function override_block_template( $template = '', $type = '', $templates = array() ) {
|
||||
// Bail early if there is no TB templates for current page request.
|
||||
if ( empty( et_theme_builder_get_template_layouts() ) ) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$override_header = et_theme_builder_overrides_layout( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE );
|
||||
$override_body = et_theme_builder_overrides_layout( ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE );
|
||||
$override_footer = et_theme_builder_overrides_layout( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE );
|
||||
|
||||
// Bail early if TB doesn't override any layouts.
|
||||
if ( ! $override_header && ! $override_body && ! $override_footer ) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
// Bail early if current template is not `template-canvas.php`.
|
||||
if ( 'template-canvas.php' !== basename( $template ) ) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
// 1. Override the template canvas with PHP template.
|
||||
// Use `locate_template` to get the PHP template. If the template doesn't exist, use
|
||||
// default builder block template canvas as replacement.
|
||||
$canvas_template = ET_BUILDER_DIR . 'templates/block-template-canvas.php';
|
||||
$old_template = $template;
|
||||
$new_template = locate_template( $templates );
|
||||
$template = file_exists( $new_template ) ? $new_template : $canvas_template;
|
||||
|
||||
// 2. Add needed actions and remove default template canvas actions.
|
||||
// Remove viewport meta tag.
|
||||
if ( function_exists( '_block_template_viewport_meta_tag' ) ) {
|
||||
remove_action( 'wp_head', '_block_template_viewport_meta_tag', 0 );
|
||||
}
|
||||
|
||||
// Render conditional title tag for `title-tag` support.
|
||||
add_action( 'wp_head', '_wp_render_title_tag', 1 );
|
||||
|
||||
// Remove unconditional title tag.
|
||||
if ( function_exists( '_block_template_render_title_tag' ) ) {
|
||||
remove_action( 'wp_head', '_block_template_render_title_tag', 1 );
|
||||
}
|
||||
|
||||
// 3. Enqueue block templates compatibility fixes.
|
||||
// Those fixes are related to missing header and footer PHP templates.
|
||||
if ( $canvas_template === $template ) {
|
||||
// Add opening and closing wrappers for builder block template canvas because
|
||||
// there is no specific wrappers found when a page use block template canvas.
|
||||
add_action( 'et_theme_builder_template_after_header', array( 'ET_Builder_Block_Templates', 'main_content_opening_wrapper' ) );
|
||||
add_action( 'et_theme_builder_template_before_footer', array( 'ET_Builder_Block_Templates', 'main_content_closing_wrapper' ) );
|
||||
|
||||
// Add styles to fix the body layout on additional wrappers added above.
|
||||
add_action( 'wp_enqueue_scripts', array( 'ET_Builder_Block_Templates', 'block_template_styles' ) );
|
||||
|
||||
// Disable deperecated warnings on missing files.
|
||||
add_action( 'deprecated_file_included', array( 'ET_Builder_Block_Templates', 'disable_deprecated_file_warnings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires additional actions after builder override block template.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*
|
||||
* @param string $template New processed block template.
|
||||
* @param string $old_template Original block template.
|
||||
*/
|
||||
do_action( 'et_after_override_block_template', $template, $old_template );
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set main content opening wrapper.
|
||||
*
|
||||
* Provide the opening wrapper tags only to ensure TB layout works smoothly. The same
|
||||
* wrapper is being used on Divi theme.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*/
|
||||
public static function main_content_opening_wrapper() {
|
||||
// Bail early if DBP is inactive because the issue doesn't happen on Divi/Extra.
|
||||
if ( ! et_is_builder_plugin_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// By default, content class is `builder-content`. This class has no style at all
|
||||
// because it's controlled by the builder itself. This class can be useful as an
|
||||
// indicator and selector for the content built with builder.
|
||||
$content_class = 'builder-content';
|
||||
|
||||
// When current page is singular page, check builder and divi/layout block usage.
|
||||
if ( is_singular() ) {
|
||||
$post_id = get_the_ID();
|
||||
$is_page_builder_used = et_pb_is_pagebuilder_used( $post_id );
|
||||
|
||||
// The `block-content wp-site-blocks` classes will added on current page when:
|
||||
// - Builder is not used.
|
||||
// - Builder is used but it's coming from Divi Layout block.
|
||||
// The `block-content` class has style to reset content width. The `wp-site-blocks`
|
||||
// class is needed to mimic default block content styles.
|
||||
if ( ! $is_page_builder_used || ( $is_page_builder_used && has_block( 'divi/layout', $post_id ) ) ) {
|
||||
$content_class = 'block-content wp-site-blocks';
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div id="et-main-area">
|
||||
<div id="main-content" class="<?php echo esc_attr( $content_class ); ?>">
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Set main content closing wrapper.
|
||||
*
|
||||
* Provide the closing wrapper tag only to ensure TB layout works smoothly. The same
|
||||
* wrapper is being used on Divi theme.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*/
|
||||
public static function main_content_closing_wrapper() {
|
||||
// Bail early if DBP is inactive because the issue doesn't happen on Divi/Extra.
|
||||
if ( ! et_is_builder_plugin_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
</div><!-- #main-content -->
|
||||
</div><!-- #et-main-area -->
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue block templates compatibility styles.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*/
|
||||
public static function block_template_styles() {
|
||||
// Bail early if DBP is inactive because the issue doesn't happen on Divi/Extra.
|
||||
if ( ! et_is_builder_plugin_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_style( 'et-block-templates-styles', ET_BUILDER_URI . '/styles/block_templates.css', array(), ET_BUILDER_PRODUCT_VERSION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable deprecated files warnings.
|
||||
*
|
||||
* Since themes that support block template may don't have some files, the template
|
||||
* may fall into backward compatibility for those files and trigger warnings. Hence,
|
||||
* we need to disable them temporarily. The list of files:
|
||||
* - header
|
||||
* - footer
|
||||
* - comments
|
||||
*
|
||||
* @since 4.14.7
|
||||
*
|
||||
* @param string $file File info.
|
||||
*/
|
||||
public static function disable_deprecated_file_warnings( $file ) {
|
||||
// Bail early if DBP is inactive because the issue doesn't happen on Divi/Extra.
|
||||
if ( ! et_is_builder_plugin_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( strpos( $file, 'header.php' ) || strpos( $file, 'footer.php' ) || strpos( $file, 'comments.php' ) ) {
|
||||
add_filter( 'deprecated_file_trigger_error', '__return_false' );
|
||||
} else {
|
||||
add_filter( 'deprecated_file_trigger_error', '__return_true' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove unsupported theme filters for WooCommerce.
|
||||
*
|
||||
* When current theme supports FSE, WooCommerce will mark it as unsupported theme and
|
||||
* overrides some filters and few of them are related to builder. Hence, we need to
|
||||
* remove those filters to ensure Divi Builder works normally.
|
||||
*
|
||||
* @since 4.14.7
|
||||
*/
|
||||
public static function remove_unsupported_theme_filter() {
|
||||
// Bail early if WooCommerce is not active or current theme is not block theme.
|
||||
if ( ! et_is_woocommerce_plugin_active() || ! et_builder_is_block_theme() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Single Product.
|
||||
if ( is_product() ) {
|
||||
global $post;
|
||||
|
||||
$post_id = $post ? $post->ID : 0;
|
||||
|
||||
// Only remove those filters when current product uses builder.
|
||||
if ( et_pb_is_pagebuilder_used( $post_id ) ) {
|
||||
remove_filter( 'the_content', array( 'WC_Template_Loader', 'unsupported_theme_product_content_filter' ), 10 );
|
||||
remove_filter( 'woocommerce_product_tabs', array( 'WC_Template_Loader', 'unsupported_theme_remove_review_tab' ), 10 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether block templates compatibility support is needed or not.
|
||||
*
|
||||
* Support block templates compatibility only if:
|
||||
* - Current WordPress or Gutenberg supports block templates
|
||||
* - Current theme supports block templates
|
||||
*
|
||||
* @since 4.17.4
|
||||
*
|
||||
* @return boolean Compatibility status.
|
||||
*/
|
||||
public static function is_block_templates_compat_needed() {
|
||||
// Bail early if `locate_block_template` function doesn't exists (WP 5.8 above).
|
||||
if ( ! function_exists( 'locate_block_template' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Whether current theme supports block templates or block theme.
|
||||
$is_theme_supports_block_templates = current_theme_supports( 'block-templates' );
|
||||
$is_block_theme = et_builder_is_block_theme();
|
||||
$is_block_templates_compat_needed = $is_theme_supports_block_templates || $is_block_theme;
|
||||
|
||||
/**
|
||||
* Filters the result of the block templates compatibility check.
|
||||
*
|
||||
* @since 4.17.4
|
||||
*
|
||||
* @param boolean $is_block_templates_compat_needed Compatibility status.
|
||||
*/
|
||||
return (bool) apply_filters( 'et_builder_is_block_templates_compat_needed', $is_block_templates_compat_needed );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get supported template slugs.
|
||||
*
|
||||
* Those template slugs are available on TB.
|
||||
*
|
||||
* @since 4.17.4
|
||||
*
|
||||
* @return string[] List of supported template slugs.
|
||||
*/
|
||||
public static function get_supported_template_slugs() {
|
||||
/**
|
||||
* List of possible hook names:
|
||||
* - `404_template`
|
||||
* - `archive_template`
|
||||
* - `author_template`
|
||||
* - `category_template`
|
||||
* - `date_template`
|
||||
* - `frontpage_template`
|
||||
* - `home_template`
|
||||
* - `index_template`
|
||||
* - `page_template`
|
||||
* - `privacypolicy_template`
|
||||
* - `search_template`
|
||||
* - `single_template`
|
||||
* - `singular_template`
|
||||
* - `tag_template`
|
||||
* - `taxonomy_template`
|
||||
*
|
||||
* Don't include `attachment`, `embed`, `paged` because they aren't modified on TB.
|
||||
*/
|
||||
$default_template_slugs = array(
|
||||
'index',
|
||||
'home',
|
||||
'front-page',
|
||||
'singular',
|
||||
'single',
|
||||
'page',
|
||||
'archive',
|
||||
'author',
|
||||
'category',
|
||||
'taxonomy',
|
||||
'date',
|
||||
'tag',
|
||||
'search',
|
||||
'privacy-policy',
|
||||
'404',
|
||||
);
|
||||
$template_slugs = $default_template_slugs;
|
||||
|
||||
// Use `get_default_block_template_types` result if it exists.
|
||||
if ( function_exists( 'get_default_block_template_types' ) ) {
|
||||
$template_types = (array) get_default_block_template_types();
|
||||
|
||||
if ( isset( $template_types['attachment'] ) ) {
|
||||
unset( $template_types['attachment'] );
|
||||
}
|
||||
|
||||
$template_slugs = ! empty( $template_types ) ? array_keys( $template_types ) : $default_template_types;
|
||||
}
|
||||
|
||||
return $template_slugs;
|
||||
}
|
||||
}
|
||||
|
||||
ET_Builder_Block_Templates::instance();
|
@@ -0,0 +1,430 @@
|
||||
<?php
|
||||
/**
|
||||
* Gutenberg editor typography.
|
||||
*
|
||||
* @package Builder
|
||||
* @subpackage Gutenberg
|
||||
* @since 4.7.6
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Class use theme's chosen fonts in Gutenberg editor.
|
||||
*
|
||||
* Class ET_GB_Editor_Typography
|
||||
*/
|
||||
class ET_GB_Editor_Typography {
|
||||
|
||||
/**
|
||||
* `ET_GB_Editor_Typography` instance.
|
||||
*
|
||||
* @var ET_GB_Editor_Typography
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* TB's body layout post
|
||||
*
|
||||
* @var WP_Post
|
||||
*/
|
||||
private $_body_layout_post;
|
||||
|
||||
/**
|
||||
* The `et_pb_post_content` shortcode content extracted from the TB's body layout post content
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_post_content_shortcode;
|
||||
|
||||
/**
|
||||
* The `et_pb_post_title shortcode` content extracted from the TB's body layout post content
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $_post_title_shortcode;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* ET_GB_Editor_Typography constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
|
||||
if ( ! et_core_is_gutenberg_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*
|
||||
* @return object class instance.
|
||||
*/
|
||||
public static function instance() {
|
||||
|
||||
if ( null === self::$_instance ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks
|
||||
*/
|
||||
public function register_hooks() {
|
||||
add_action( 'admin_footer', array( $this, 'enqueue_block_typography_styles' ) );
|
||||
add_filter( 'block_editor_settings_all', array( $this, 'block_editor_settings_all' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter editor styles pass to the GB editor.
|
||||
*
|
||||
* @param array $editor_settings editor settings.
|
||||
* @param WP_Block_Editor_Context $block_editor_context The current block editor context.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function block_editor_settings_all( $editor_settings, $block_editor_context ) {
|
||||
|
||||
$styles = $this->get_body_styles();
|
||||
$styles .= $this->get_title_styles();
|
||||
|
||||
$post = $block_editor_context->post;
|
||||
|
||||
// If no post is found, return $error_settings early.
|
||||
if ( empty( $post ) ) {
|
||||
return $editor_settings;
|
||||
}
|
||||
|
||||
if ( $post ) {
|
||||
$tb_layouts = et_theme_builder_get_template_layouts( ET_Theme_Builder_Request::from_post( $post->ID ) );
|
||||
|
||||
if ( isset( $tb_layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ] ) ) {
|
||||
$body_layout = $tb_layouts[ ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE ];
|
||||
$body_layout_id = et_()->array_get( $body_layout, 'id' );
|
||||
$this->_body_layout_post = get_post( $body_layout_id );
|
||||
|
||||
$this->_initialize_shortcode( '_post_content_shortcode', et_theme_builder_get_post_content_modules() );
|
||||
$this->_initialize_shortcode( '_post_title_shortcode', array( 'et_pb_post_title' ) );
|
||||
$styles .= $this->get_tb_styles();
|
||||
}
|
||||
}
|
||||
|
||||
$editor_settings['styles'][] = array(
|
||||
'css' => $styles,
|
||||
'__unstableType' => 'theme',
|
||||
);
|
||||
|
||||
return $editor_settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the et_pb_post_content and et_pb_post_title shortcode from the body layout post content.
|
||||
*
|
||||
* @param string $prop {@see self::$_post_content_shortcode} or {@see self::$_post_title_shortcode} property.
|
||||
* @param array $tagnames Shortcode tagnames.
|
||||
*/
|
||||
private function _initialize_shortcode( $prop, $tagnames ) {
|
||||
$regex = get_shortcode_regex( $tagnames );
|
||||
|
||||
if ( preg_match_all( "/$regex/", $this->_body_layout_post->post_content, $matches ) ) {
|
||||
$post_title_shortcodes = et_()->array_get( $matches, '0' );
|
||||
|
||||
// Take the style from the first Post Title module that has the title enabled.
|
||||
foreach ( $post_title_shortcodes as $post_title_shortcode ) {
|
||||
if ( false === strpos( $post_title_shortcode, 'title="off"' ) ) {
|
||||
$this->{$prop} = $post_title_shortcode;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
} elseif ( preg_match_all( "/$regex/", $this->_body_layout_post->post_content, $matches, PREG_SET_ORDER ) ) {
|
||||
$this->{$prop} = et_()->array_get(
|
||||
$matches,
|
||||
'0.0'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Print GB typography style.
|
||||
*/
|
||||
public function enqueue_block_typography_styles() {
|
||||
|
||||
if ( ! ( method_exists( get_current_screen(), 'is_block_editor' ) && get_current_screen()->is_block_editor() ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
et_builder_print_font();
|
||||
}
|
||||
|
||||
/**
|
||||
* Print the post content style.
|
||||
*/
|
||||
public function get_body_styles() {
|
||||
|
||||
$body_styles = '';
|
||||
|
||||
$body_font = esc_html( et_get_option( 'body_font' ) );
|
||||
|
||||
if ( ! empty( $body_font ) && 'none' !== $body_font ) {
|
||||
et_builder_enqueue_font( $body_font );
|
||||
$font_family = et_builder_get_font_family( $body_font );
|
||||
|
||||
$body_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'font-family',
|
||||
'value' => str_replace( 'font-family: ', '', $font_family ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body_font_height = esc_html( et_get_option( 'body_font_height' ) );
|
||||
|
||||
if ( ! empty( $body_font_height ) ) {
|
||||
$body_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'line-height',
|
||||
'value' => $body_font_height,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body_font_size = esc_html( et_get_option( 'body_font_size' ) );
|
||||
|
||||
if ( ! empty( $body_font_size ) ) {
|
||||
$body_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'font-size',
|
||||
'value' => $body_font_size,
|
||||
'suffix' => 'px',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $body_styles ) ) {
|
||||
$body_styles = sprintf( 'body { %1$s }', $body_styles );
|
||||
}
|
||||
|
||||
return $body_styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print post title styles.
|
||||
*/
|
||||
public function get_title_styles() {
|
||||
|
||||
$title_styles = '';
|
||||
|
||||
$heading_font = esc_html( et_get_option( 'heading_font' ) );
|
||||
|
||||
// Fallback to the body font.
|
||||
if ( empty( $heading_font ) || 'none' === $heading_font ) {
|
||||
$heading_font = esc_html( et_get_option( 'body_font' ) );
|
||||
}
|
||||
|
||||
if ( ! empty( $heading_font ) && 'none' !== $heading_font ) {
|
||||
et_builder_enqueue_font( $heading_font );
|
||||
$font_family = et_builder_get_font_family( $heading_font );
|
||||
|
||||
$title_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'font-family',
|
||||
'value' => str_replace( 'font-family: ', '', $font_family ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body_header_spacing = esc_html( et_get_option( 'body_header_spacing' ) );
|
||||
|
||||
if ( ! empty( $body_header_spacing ) ) {
|
||||
$title_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'letter-spacing',
|
||||
'value' => $body_header_spacing,
|
||||
'suffix' => 'px',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body_header_height = esc_html( et_get_option( 'body_header_height' ) );
|
||||
|
||||
if ( ! empty( $body_header_height ) && '1' !== $body_header_height ) {
|
||||
$title_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => 'line-height',
|
||||
'value' => $body_header_height,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$body_header_style = esc_html( et_get_option( 'body_header_style' ) );
|
||||
|
||||
if ( ! empty( $body_header_style ) ) {
|
||||
// Convert string into array.
|
||||
$styles_array = explode( '|', $body_header_style );
|
||||
|
||||
$font_properties_value_map = array(
|
||||
'font-weight' => 'bold',
|
||||
'font-style' => 'italic',
|
||||
'text-transform' => 'uppercase',
|
||||
'text-decoration' => 'underline',
|
||||
);
|
||||
|
||||
foreach ( $font_properties_value_map as $css_property => $value ) {
|
||||
if ( in_array( $value, $styles_array, true ) ) {
|
||||
$title_styles .= et_builder_generate_css_style(
|
||||
array(
|
||||
'style' => $css_property,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $title_styles ) ) {
|
||||
$title_styles = sprintf( 'h1,h2,h3,h4,h5,h6,.editor-post-title__block .editor-post-title__input { %1$s }', $title_styles );
|
||||
}
|
||||
|
||||
$title_styles .= $this->get_heading_levels_font_size_style();
|
||||
|
||||
return $title_styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print TB's style.
|
||||
*/
|
||||
public function get_tb_styles() {
|
||||
|
||||
if ( empty( $this->_post_content_shortcode ) && empty( $this->_post_title_shortcode ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ET_Builder_Element' ) ) {
|
||||
require_once ET_BUILDER_DIR . 'class-et-builder-value.php';
|
||||
require_once ET_BUILDER_DIR . 'class-et-builder-element.php';
|
||||
require_once ET_BUILDER_DIR . 'ab-testing.php';
|
||||
et_builder_init_global_settings();
|
||||
et_builder_add_main_elements();
|
||||
et_builder_settings_init();
|
||||
ET_Builder_Element::set_media_queries();
|
||||
}
|
||||
|
||||
// To generate the styles from the shortcode, this do_shortcode will intialize et_pb_post_content and et_pb_post_title modules classes.
|
||||
ob_start();
|
||||
do_shortcode( $this->_post_title_shortcode . $this->_post_content_shortcode );
|
||||
ob_end_clean();
|
||||
|
||||
// Get style generated by modules.
|
||||
$tb_style = ET_Builder_Element::get_style();
|
||||
|
||||
// Remove `color` property from theme builder style.
|
||||
$tb_style = preg_replace( '/(?<=[{;\s])color:.*?;/s', '', $tb_style );
|
||||
|
||||
$have_post_content_style = preg_match( '/\.et_pb_post_content_0\s*{\s*(.*?)\s*}/s', $tb_style, $matches );
|
||||
if ( $have_post_content_style && isset( $matches[1] ) ) {
|
||||
$et_pb_post_content_styles = explode( ';', $matches[1] );
|
||||
$typography_properties = array(
|
||||
'font-family',
|
||||
'font-size',
|
||||
'font-weight',
|
||||
'font-style',
|
||||
'text-align',
|
||||
'text-shadow',
|
||||
'letter-spacing',
|
||||
'line-height',
|
||||
'text-transform',
|
||||
'text-decoration',
|
||||
'text-decoration-style',
|
||||
);
|
||||
|
||||
$post_content_style = '';
|
||||
|
||||
foreach ( $et_pb_post_content_styles as $et_pb_post_content_style ) {
|
||||
$style = explode( ':', $et_pb_post_content_style ); // explode CSS property and value.
|
||||
$css_property = trim( $style[0] );
|
||||
if ( in_array( $css_property, $typography_properties, true ) ) {
|
||||
$post_content_style .= $css_property . ':' . $style[1] . ';';
|
||||
}
|
||||
}
|
||||
|
||||
$tb_style = 'body {' . $post_content_style . '}' . $tb_style;
|
||||
}
|
||||
|
||||
foreach ( array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ) as $heading_selector ) {
|
||||
$tb_style = str_replace( ".et_pb_post_content_0 $heading_selector ", $heading_selector, $tb_style );
|
||||
}
|
||||
|
||||
foreach ( array( 'a', 'ul', 'ol', 'ul li', 'ol li', 'blockquote' ) as $selector ) {
|
||||
$search = array(
|
||||
".et_pb_post_content_0 $selector ",
|
||||
".et_pb_post_content_0.et_pb_post_content $selector",
|
||||
);
|
||||
|
||||
$tb_style = str_replace( $search, $selector, $tb_style );
|
||||
}
|
||||
|
||||
// Replace the post title style selectors with editor's post title selector.
|
||||
$tb_style = str_replace( array( '.et_pb_post_title_0 .entry-title', '.et_pb_post_title_0 .et_pb_title_container h1.entry-title, .et_pb_post_title_0 .et_pb_title_container h2.entry-title, .et_pb_post_title_0 .et_pb_title_container h3.entry-title, .et_pb_post_title_0 .et_pb_title_container h4.entry-title, .et_pb_post_title_0 .et_pb_title_container h5.entry-title, .et_pb_post_title_0 .et_pb_title_container h6.entry-title' ), '.wp-block.editor-post-title__block .editor-post-title__input', $tb_style );
|
||||
|
||||
// Enqueue fonts.
|
||||
$fonts_regex = '/font-family:\s+[\'"]([a-zA-Z0-9\s]+)[\'"]/';
|
||||
$has_fonts = preg_match_all( $fonts_regex, $tb_style, $matches, PREG_SET_ORDER );
|
||||
if ( false !== $has_fonts && isset( $match[1] ) ) {
|
||||
foreach ( $matches as $match ) {
|
||||
et_builder_enqueue_font( $match[1] );
|
||||
}
|
||||
}
|
||||
|
||||
return $tb_style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the heading levels font size from the Header Size customizer setting and return style.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_heading_levels_font_size_style() {
|
||||
|
||||
$body_header_size = esc_html( et_get_option( 'body_header_size' ) );
|
||||
|
||||
$title_styles = '';
|
||||
|
||||
if ( empty( $body_header_size ) ) {
|
||||
return $title_styles;
|
||||
}
|
||||
|
||||
$font_sizes = array(
|
||||
'h1,.editor-post-title__block .editor-post-title__input' => $body_header_size,
|
||||
'h2' => $body_header_size * .86,
|
||||
'h3' => $body_header_size * .73,
|
||||
'h4' => $body_header_size * .60,
|
||||
'h5' => $body_header_size * .53,
|
||||
'h6' => $body_header_size * .47,
|
||||
);
|
||||
|
||||
foreach ( $font_sizes as $selector => $font_size ) {
|
||||
$title_styles .= ',' . et_builder_generate_css(
|
||||
array(
|
||||
'style' => 'font-size',
|
||||
'value' => intval( $font_size ),
|
||||
'suffix' => 'px',
|
||||
'selector' => $selector,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return $title_styles;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialize ET_GB_Editor_Typography.
|
||||
ET_GB_Editor_Typography::instance();
|
@@ -0,0 +1,736 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
class ET_GB_Block_Layout {
|
||||
/**
|
||||
* @var ET_GB_Block_Layout
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
private $block_name = 'divi/layout';
|
||||
|
||||
function __construct() {
|
||||
if ( ! et_core_is_gutenberg_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_block();
|
||||
$this->register_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class instance
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @return object class instance
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( null === self::$_instance ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register block
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function register_block() {
|
||||
register_block_type(
|
||||
$this->block_name,
|
||||
array(
|
||||
'attributes' => array(
|
||||
'layoutContent' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function register_hooks() {
|
||||
// Admin screen
|
||||
add_action( 'admin_init', array( $this, 'register_portability_on_builder_page' ) );
|
||||
|
||||
// Block preview inside gutenberg
|
||||
add_action( 'template_include', array( $this, 'register_preview_template' ) );
|
||||
add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_block_preview_styles_scripts' ), 15 );
|
||||
add_action( 'wp_footer', array( $this, 'enqueue_block_preview_footer_styles_scripts' ) );
|
||||
add_action( 'pre_get_posts', array( $this, 'modify_layout_content_condition' ), 20 );
|
||||
|
||||
add_filter( 'body_class', array( $this, 'add_body_classnames' ) );
|
||||
add_filter( 'et_pb_section_data_attributes', array( $this, 'add_section_boxshadow_attributes' ), 10, 3 );
|
||||
add_filter( 'the_content', array( $this, 'modify_layout_content_output' ), 1 );
|
||||
add_filter( 'get_post_metadata', array( $this, 'modify_layout_content_builder_meta' ), 10, 4 );
|
||||
add_filter( 'et_fb_load_raw_post_content', array( $this, 'modify_layout_content_visual_builder_raw_post_content' ) );
|
||||
add_filter( 'et_builder_render_layout', array( $this, 'modify_theme_builder_body_layout' ), 7 );
|
||||
|
||||
// Block rendering on frontend
|
||||
add_filter( 'render_block', array( $this, 'render_block' ), 100, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current request is Divi Layout preview for block request. Layout block preview page
|
||||
* is only valid for logged in user with edit_posts cap with query string for activating block
|
||||
* layout preview and its nonce to verify it.
|
||||
*
|
||||
* Initially, is_singular() check existed but reusable block at `wp_block` CPT and any other CPT
|
||||
* that has no frontend due to its post type registration sets `public` attribute to `false`
|
||||
* renders layout block preview at non singular page makes is_singular() check need to be dropped
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_layout_block_preview() {
|
||||
return isset( $_GET['et_block_layout_preview'] ) && et_core_security_check(
|
||||
'edit_posts',
|
||||
'et_block_layout_preview',
|
||||
'et_block_layout_preview_nonce',
|
||||
'_GET',
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if current builder shortcode rendering is done inside layout block
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_layout_block() {
|
||||
global $et_is_layout_block;
|
||||
|
||||
// Ensure the returned value is bool
|
||||
return $et_is_layout_block ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register portability which is needed to import premade and saved Layout via Divi Library;
|
||||
* Portability is intentionally disabled on builder page by `et_builder_should_load_framework()`
|
||||
* nevertheless excluding GB there doesn't work because it is being too early before any
|
||||
* GB check is hooked. Thus Register another portability for GB + builder page
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function register_portability_on_builder_page() {
|
||||
global $pagenow;
|
||||
|
||||
// No permission, can't load library UI in the first place
|
||||
if ( ! et_pb_is_allowed( 'divi_library' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit if current page is not saved edit page
|
||||
$is_edit_page = 'post.php' === $pagenow && isset( $_GET['post'] );
|
||||
|
||||
if ( ! $is_edit_page ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$post_id = intval( $_GET['post'] );
|
||||
|
||||
// Exit if current page doesn't use Gutenberg
|
||||
if ( ! use_block_editor_for_post_type( get_post_type( $post_id ) ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Exit if current page doesn't use builder
|
||||
if ( ! et_pb_is_pagebuilder_used( $post_id ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Register portability
|
||||
et_core_portability_register(
|
||||
'et_builder',
|
||||
array(
|
||||
'title' => esc_html__( 'Import & Export Layouts', 'et_builder' ),
|
||||
'name' => esc_html__( 'Divi Builder Layout', 'et_builder' ),
|
||||
'type' => 'post',
|
||||
'view' => true,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter rendered Divi - Layout block on FE.
|
||||
*
|
||||
* @since 4.1.0
|
||||
* @since 4.10.0 Filter core/post-excerpt rendered output.
|
||||
* @since 4.14.5 Move other blocks. {@see feature/gutenberg/blocks}.
|
||||
* @since 4.14.8 Add support for WP Editor.
|
||||
*
|
||||
* @param string $block_content Saved & serialized block data.
|
||||
* @param array $block Block info.
|
||||
*/
|
||||
public function render_block( $block_content, $block ) {
|
||||
// Divi - Layout block.
|
||||
if ( 'divi/layout' !== $block['blockName'] ) {
|
||||
return $block_content;
|
||||
}
|
||||
|
||||
global $et_is_layout_block, $et_layout_block_info;
|
||||
|
||||
// Get WP Editor template data to determine whether current Divi Layout block is
|
||||
// rendered inside WP Editor template or not.
|
||||
$template = $this->get_wp_editor_template_on_render();
|
||||
$template_id = isset( $template->wp_id ) ? (int) $template->wp_id : 0;
|
||||
$block_to_render = class_exists( 'WP_Block_Supports' ) && ! empty( WP_Block_Supports::$block_to_render ) ? WP_Block_Supports::$block_to_render : array();
|
||||
|
||||
// Set flag.
|
||||
$et_is_layout_block = true;
|
||||
$et_layout_block_info = array(
|
||||
'block' => $block,
|
||||
'block_to_render' => $block_to_render,
|
||||
'template' => $template,
|
||||
);
|
||||
|
||||
// Start - Divi Layout block inside WP Editor Template or Template Part.
|
||||
if ( ! empty( $template ) && $template_id > 0 ) {
|
||||
ET_Builder_Element::begin_wp_editor_template( $template_id );
|
||||
}
|
||||
|
||||
// Render - Divi Layout block inside Post Content/Template/Template Part.
|
||||
// Render block content's shortcode. Block content actually can be rendered without this
|
||||
// method and only depending to WordPress' `do_shortcode` hooked into `the_content`. However
|
||||
// layout block need to set global for detecting that shortcode is rendered inside layout
|
||||
// block hence the early shortcode rendering between global variables.
|
||||
$block_content = do_shortcode( $block_content );
|
||||
|
||||
// End - Divi Layout block inside WP Editor Template or Template Part.
|
||||
if ( ! empty( $template ) && $template_id > 0 ) {
|
||||
// 1. Append builder layout and content wrappers.
|
||||
$block_content = et_builder_get_layout_opening_wrapper() . $block_content . et_builder_get_layout_closing_wrapper();
|
||||
|
||||
/** This filter is documented in core.php */
|
||||
$wrap = apply_filters( 'et_builder_add_outer_content_wrap', true );
|
||||
|
||||
if ( $wrap ) {
|
||||
$block_content = et_builder_get_builder_content_opening_wrapper() . $block_content . et_builder_get_builder_content_closing_wrapper();
|
||||
}
|
||||
|
||||
// 2. Pass styles to page resource which will handle their output.
|
||||
$post_id = is_singular() ? ET_Post_Stack::get_main_post_id() : $template_id;
|
||||
$result = ET_Builder_Element::setup_advanced_styles_manager( $post_id );
|
||||
|
||||
$advanced_styles_manager = $result['manager'];
|
||||
if ( isset( $result['deferred'] ) ) {
|
||||
$deferred_styles_manager = $result['deferred'];
|
||||
}
|
||||
|
||||
if ( ET_Builder_Element::$forced_inline_styles || ! $advanced_styles_manager->has_file() || $advanced_styles_manager->forced_inline ) {
|
||||
/** This filter is documented in frontend-builder/theme-builder/frontend.php */
|
||||
$is_critical_enabled = apply_filters( 'et_builder_critical_css_enabled', false );
|
||||
|
||||
$critical = $is_critical_enabled ? ET_Builder_Element::get_style( false, $template_id, true ) . ET_Builder_Element::get_style( true, $template_id, true ) : array();
|
||||
$styles = ET_Builder_Element::get_style( false, $template_id ) . ET_Builder_Element::get_style( true, $template_id );
|
||||
|
||||
if ( empty( $critical ) ) {
|
||||
// No critical styles defined, just enqueue everything as usual.
|
||||
if ( ! empty( $styles ) ) {
|
||||
if ( isset( $deferred_styles_manager ) ) {
|
||||
$deferred_styles_manager->set_data( $styles, 40 );
|
||||
} else {
|
||||
$advanced_styles_manager->set_data( $styles, 40 );
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$advanced_styles_manager->set_data( $critical, 40 );
|
||||
if ( ! empty( $styles ) ) {
|
||||
// Defer everything else.
|
||||
$deferred_styles_manager->set_data( $styles, 40 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ET_Builder_Element::end_wp_editor_template();
|
||||
}
|
||||
|
||||
// Reset flag.
|
||||
$et_is_layout_block = false;
|
||||
$et_layout_block_info = false;
|
||||
|
||||
return $block_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overwrite template path if current request is Divi Layout block preview
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function register_preview_template( $template ) {
|
||||
if ( self::is_layout_block_preview() ) {
|
||||
// disable admin bar
|
||||
show_admin_bar( false );
|
||||
|
||||
// Use layout block specific template for render layout block preview (headerless
|
||||
// and footerless templates). BFB template was initialy used for this for DRY reason
|
||||
// but its #page-container-bfb causing styling issues
|
||||
return ET_BUILDER_DIR . 'templates/block-layout-preview.php';
|
||||
}
|
||||
|
||||
// return original template
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Theme Builder's template settings of current (layout block preview) page
|
||||
*
|
||||
* @since 4.3.4
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_preview_tb_template() {
|
||||
// Identify current request, and get applicable TB template for current page
|
||||
$request = ET_Theme_Builder_Request::from_current();
|
||||
$templates = et_theme_builder_get_theme_builder_templates( true );
|
||||
$settings = et_theme_builder_get_flat_template_settings_options();
|
||||
$tb_template = $request->get_template( $templates, $settings );
|
||||
|
||||
// Define template properties as variables for readability
|
||||
$template_id = et_()->array_get( $tb_template, 'id', 0 );
|
||||
$layout_id = et_()->array_get( $tb_template, 'layouts.body.id', 0 );
|
||||
$layout_enabled = et_()->array_get( $tb_template, 'layouts.body.enabled', false );
|
||||
$layout_override = et_()->array_get( $tb_template, 'layouts.body.override', false );
|
||||
$has_layout = $layout_id && $layout_enabled && $layout_override;
|
||||
|
||||
return array(
|
||||
'layout_id' => $layout_id,
|
||||
'layout_enabled' => $layout_enabled,
|
||||
'template_id' => $template_id,
|
||||
'has_layout' => $has_layout,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Early scripts and styles queue for Layout Block Preview page
|
||||
* Need to queue early because `et-builder-modules-script` uses localize scripts on this method
|
||||
*
|
||||
* @since 4.4.1 Compatibility fixes for WP 5.4
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function enqueue_block_preview_styles_scripts() {
|
||||
if ( ! self::is_layout_block_preview() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( et_fb_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue frame helper if it hasn't been queued
|
||||
if ( ! wp_script_is( 'et-frame-helpers', 'enqueued' ) ) {
|
||||
wp_enqueue_script(
|
||||
'et-frame-helpers',
|
||||
ET_BUILDER_URI . '/frontend-builder/build/frame-helpers.js',
|
||||
array(),
|
||||
ET_BUILDER_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
wp_localize_script(
|
||||
et_get_combined_script_handle(),
|
||||
'ETBlockLayoutModulesScript',
|
||||
array(
|
||||
// blockId is dash separated alphanumeric uuid value
|
||||
'blockId' => sanitize_title( et_()->array_get( $_POST, 'et_editor_block_id', 0 ) ),
|
||||
|
||||
// Make layout shortcode available for ajax pagination request by outputting it
|
||||
// as JS params so the pagination ajax request can have identical page on next
|
||||
// request. Thus any custom script has no business being here: as long as the same
|
||||
// module shortcode exist on next page it should be okay. Hence, kses em all
|
||||
// regardless user capability to reduce security concern
|
||||
'layoutContent' => wp_kses_post( et_()->array_get( $_POST, 'et_layout_block_layout_content', '' ) ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Late scripts and styles queue for Layout Block Preview page
|
||||
* Need to queue late because localize script needs to populate settings from rendered modules
|
||||
*
|
||||
* @since 4.4.1 Renamed into `enqueue_block_preview_footer_styles_scripts`. Localize script
|
||||
* value which is used by `et-builder-modules-script` is queued on earlier hook
|
||||
* @since 4.1.0
|
||||
*/
|
||||
public function enqueue_block_preview_footer_styles_scripts() {
|
||||
if ( ! self::is_layout_block_preview() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Frontend preview adjustment should only be called on layout block preview frame
|
||||
// and shouldn't be called on layout block builder
|
||||
if ( ! et_fb_enabled() ) {
|
||||
wp_enqueue_script(
|
||||
'et-block-layout-preview',
|
||||
ET_BUILDER_URI . '/scripts/block-layout-frontend-preview.js',
|
||||
array( 'jquery' ),
|
||||
ET_BUILDER_PRODUCT_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
wp_localize_script(
|
||||
'et-block-layout-preview',
|
||||
'ETBlockLayoutPreview',
|
||||
array(
|
||||
// blockId is dash separated alphanumeric uuid value
|
||||
'blockId' => sanitize_title( et_()->array_get( $_POST, 'et_editor_block_id', 0 ) ),
|
||||
|
||||
// Exposed module settings for layout block preview for making nescessary adjustments
|
||||
'assistiveSettings' => ET_Builder_Element::get_layout_block_assistive_settings(),
|
||||
|
||||
// Exposed Divi breakpoint minimum widths
|
||||
'breakpointMinWidths' => et_pb_responsive_options()->get_breakpoint_min_widths(),
|
||||
|
||||
// Divi style mode
|
||||
'styleModes' => array(
|
||||
'desktop',
|
||||
'tablet',
|
||||
'phone',
|
||||
'hover',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Disabled link modal, originally added for classic builder preview
|
||||
wp_enqueue_style(
|
||||
'et-block-layout-preview-style',
|
||||
ET_BUILDER_URI . '/styles/preview-layout-block.css',
|
||||
array(),
|
||||
ET_BUILDER_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add builder classname on body class if layout block exist on the page
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param array classname
|
||||
*
|
||||
* @return array modified classname
|
||||
*/
|
||||
public function add_body_classnames( $classes ) {
|
||||
if ( self::is_layout_block_preview() ) {
|
||||
$classes[] = 'et-db';
|
||||
$classes[] = 'et-block-layout-preview';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add box shadow's highest offset value if box shadow is used on section so block preview area
|
||||
* can adjust its padding to make section's box shadow previewable on block preview
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function add_section_boxshadow_attributes( $attributes, $props, $render_count ) {
|
||||
$box_shadow_style = et_()->array_get( $props, 'box_shadow_style', '' );
|
||||
|
||||
// Only apply on layout block and box shadow is set
|
||||
if ( ! self::is_layout_block_preview() || '' === $box_shadow_style || 'none' === $box_shadow_style ) {
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
// List of box shadow attribute that might affect how tall the box shadow is
|
||||
$spread = et_()->array_get( $props, 'box_shadow_spread', '' );
|
||||
$blur = et_()->array_get( $props, 'box_shadow_blur', '' );
|
||||
$vertical = et_()->array_get( $props, 'box_shadow_vertical', '' );
|
||||
|
||||
$values = array(
|
||||
'spread' => absint( $spread ),
|
||||
'blur' => absint( $blur ),
|
||||
'vertical' => absint( $vertical ),
|
||||
);
|
||||
|
||||
// Sort attributes; there's no way to safely convert all unit (em, rem, etc) into one
|
||||
// specific unit accurately, so this assumes that all values are in px
|
||||
asort( $values );
|
||||
|
||||
// Point to the last array
|
||||
end( $values );
|
||||
|
||||
// Get last array keys
|
||||
$highest_attribute_key = key( $values );
|
||||
|
||||
// Add attribute with higest value into DOM data-* attribute so it can be referenced
|
||||
$attributes['box-shadow-offset'] = et_()->array_get( $props, 'box_shadow_' . $highest_attribute_key, '' );
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify layout content condition. Preview template should consider itself is_single = true
|
||||
*
|
||||
* @since 4.1.0
|
||||
* @since 4.4.1 don't overwrite `p` and `post_type` query vars if homepage displays static page
|
||||
*
|
||||
* @param object
|
||||
*/
|
||||
public function modify_layout_content_condition( $query ) {
|
||||
if ( $query->is_main_query() && self::is_layout_block_preview() ) {
|
||||
// Set to `false` to avoid home specific classname and attribute being printed. This is
|
||||
// specifically needed on CPT which is not publicly queryable / doesn't have frontend
|
||||
// page such as reusable block's `wp_block` CPT
|
||||
$query->is_home = false;
|
||||
|
||||
// Set to `true` so `#et-boc` wrapper is correctly added
|
||||
$query->is_single = true;
|
||||
$query->is_singular = true;
|
||||
|
||||
// Query name doesn't exist while post_id is passed via query string means current
|
||||
// layout block preview is rendered on CPT that doesn't publicly queryable / doesn't
|
||||
// have registered frontend page such `wp_block`. Manually set post id and post type
|
||||
// to avoid current query fetches ALL posts on `post` post type. However, bail if
|
||||
// current page has page_id. This means the current page, most likely homepage URL when
|
||||
// it has `name` query like this, renders static page on its homepage URL (defined at
|
||||
// dashboard > settings > your homepage display). Not doing this will cause current
|
||||
// homepage has incorrect post type and id which leads to 404 preview page which
|
||||
// will prevent the preview page from being rendered
|
||||
if ( ! isset( $query->query['name'] ) && 0 === $query->get( 'page_id' ) ) {
|
||||
if ( isset( $_GET['et_post_id'] ) ) {
|
||||
$query->set( 'p', intval( $_GET['et_post_id'] ) );
|
||||
}
|
||||
|
||||
if ( isset( $_GET['et_post_type'] ) ) {
|
||||
$query->set( 'post_type', sanitize_text_field( $_GET['et_post_type'] ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify layout content content output based on layout shortcode layout sent over POST for
|
||||
* previewing layout block on gutenberg editor
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param string $content post's content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function modify_layout_content_output( $content ) {
|
||||
if ( self::is_layout_block_preview() && is_main_query() ) {
|
||||
$content = et_()->array_get( $_POST, 'et_layout_block_layout_content', '' );
|
||||
|
||||
// If user don't have posting unfiltered html capability, strip scripts
|
||||
if ( ! current_user_can( 'unfiltered_html' ) ) {
|
||||
$content = wp_kses_post( $content );
|
||||
}
|
||||
|
||||
return wp_unslash( $content );
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify post meta for enabling builder status and disabling static css if current request is
|
||||
* layout block preview
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param null $value
|
||||
* @param int $object_id
|
||||
* @param string $meta_key
|
||||
* @param bool $single
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function modify_layout_content_builder_meta( $value, $object_id, $meta_key, $single ) {
|
||||
// Force enable builder on layout block preview page request
|
||||
if ( '_et_pb_use_builder' === $meta_key && self::is_layout_block_preview() ) {
|
||||
return 'on';
|
||||
}
|
||||
|
||||
// Force disable static CSS on layout block preview page request so static CSS doesn't cache
|
||||
// incorrect stylesheet and break layout block styling
|
||||
if ( '_et_pb_static_css_file' === $meta_key && self::is_layout_block_preview() ) {
|
||||
return 'off';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify raw post content for visual builder for layout content edit screen
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param string $post_content
|
||||
*
|
||||
* @return string modified post content
|
||||
*/
|
||||
public function modify_layout_content_visual_builder_raw_post_content( $post_content ) {
|
||||
if ( self::is_layout_block_preview() ) {
|
||||
// Explicitly set post_id value based on query string because layout block's edit
|
||||
// window of CPT that has no frontend page such as reusable block's `wp_block` CPT
|
||||
// might use other / last post loop for rendering visual builder structure since its
|
||||
// own post data isn't publicly queryable
|
||||
$post_id = intval( et_()->array_get( $_GET, 'et_post_id', get_the_ID() ) );
|
||||
$block_id = sanitize_title( et_()->array_get( $_GET, 'blockId' ) );
|
||||
|
||||
$key = "_et_block_layout_preview_{$block_id}";
|
||||
$post_content = wp_unslash( get_post_meta( $post_id, $key, true ) );
|
||||
}
|
||||
|
||||
return $post_content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Modify Theme Builder body layout that is used on layout block preview
|
||||
*
|
||||
* @since 4.3.4
|
||||
*
|
||||
* @param string $content
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function modify_theme_builder_body_layout( $content ) {
|
||||
// Skip if current request isn't layout block preview
|
||||
if ( ! self::is_layout_block_preview() ) {
|
||||
return $content;
|
||||
}
|
||||
|
||||
// Get `et_pb_post_content` shortcode inside layout by pulling regex and matching it.
|
||||
// `et_pb_post_content` has to exist, otherwise `the_content()` won't be rendered; Return
|
||||
// plain `et_pb_post_content` shortcode if current layout doesn't have any
|
||||
$post_content_regex = get_shortcode_regex( et_theme_builder_get_post_content_modules() );
|
||||
|
||||
preg_match_all( "/$post_content_regex/", $content, $post_content_module, PREG_SET_ORDER );
|
||||
|
||||
$post_content_shortcode = et_()->array_get(
|
||||
$post_content_module,
|
||||
'0.0',
|
||||
'[et_pb_post_content][/et_pb_post_content]'
|
||||
);
|
||||
|
||||
// Return `et_pb_post_content` wrapped by section > row > column which has no unwanted
|
||||
// styling. TB body layout might have any module imaginable while in context of layout block
|
||||
// preview, only `et_pb_post_content` matters because its typography setting can override
|
||||
// default typography styling
|
||||
return '[et_pb_section admin_label="section" custom_padding="0px|0px|0px|0px"]
|
||||
[et_pb_row admin_label="row" custom_padding="0px|0px|0px|0px" custom_margin="0px|0px|0px|0px" width="100%"]
|
||||
[et_pb_column type="4_4"]' . $post_content_shortcode . '[/et_pb_column]
|
||||
[/et_pb_row]
|
||||
[/et_pb_section]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current active WP Editor template on block render.
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @return WP_Block_Template|null Template. Return null if it doesn't exist.
|
||||
*/
|
||||
public function get_wp_editor_template_on_render() {
|
||||
global $post;
|
||||
|
||||
static $templates_result = null;
|
||||
|
||||
// Bail early if `get_block_template` function doesn't exist because we need it to
|
||||
// get template data. This function is introduced on WP 5.8 along with Template and
|
||||
// Template Parts editors.
|
||||
if ( ! function_exists( 'get_block_template' ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bail early if current post is not singular.
|
||||
if ( ! is_singular() ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Bail early if TB override current layouts.
|
||||
if ( ! empty( et_theme_builder_get_template_layouts() ) ) {
|
||||
$override_header = et_theme_builder_overrides_layout( ET_THEME_BUILDER_HEADER_LAYOUT_POST_TYPE );
|
||||
$override_body = et_theme_builder_overrides_layout( ET_THEME_BUILDER_BODY_LAYOUT_POST_TYPE );
|
||||
$override_footer = et_theme_builder_overrides_layout( ET_THEME_BUILDER_FOOTER_LAYOUT_POST_TYPE );
|
||||
|
||||
if ( $override_header || $override_body || $override_footer ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Get WP Editor template data to determine whether current Divi Layout block is
|
||||
// rendered inside WP Editor template or not.
|
||||
$block_to_render = class_exists( 'WP_Block_Supports' ) && ! empty( WP_Block_Supports::$block_to_render ) ? WP_Block_Supports::$block_to_render : array();
|
||||
$block_to_render_name = et_()->array_get( $block_to_render, 'blockName', '' );
|
||||
|
||||
// Bail early if block to render name is post content. Divi Layout block inside post
|
||||
// content will be rendered normally.
|
||||
if ( 'core/post-content' === $block_to_render_name ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 1. Generate template type and slug.
|
||||
$template_type = '';
|
||||
$template_slug = '';
|
||||
|
||||
if ( 'core/template-part' === $block_to_render_name ) {
|
||||
$template_type = ET_WP_EDITOR_TEMPLATE_PART_POST_TYPE;
|
||||
$template_slug = et_()->array_get( $block_to_render, array( 'attrs', 'slug' ), '' );
|
||||
} else {
|
||||
$template_type = ET_WP_EDITOR_TEMPLATE_POST_TYPE;
|
||||
$template_slug = ! empty( $post->page_template ) ? $post->page_template : $this->get_default_template_slug();
|
||||
}
|
||||
|
||||
$template_type_slug = "{$template_type}-{$template_slug}";
|
||||
|
||||
// Bail early if current template type + slug is already processed.
|
||||
if ( ! empty( $templates_result[ $template_type_slug ] ) ) {
|
||||
return $templates_result[ $template_type_slug ];
|
||||
}
|
||||
|
||||
// 2. Get block template data based on post slug and post type.
|
||||
$template = ! empty( $template_type ) && ! empty( $template_slug ) ? get_block_template( get_stylesheet() . '//' . $template_slug, $template_type ) : null;
|
||||
|
||||
// 3. Save the result to be used later.
|
||||
$templates_result[ $template_type_slug ] = $template;
|
||||
|
||||
return $template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default template slug.
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @return string Template type.
|
||||
*/
|
||||
public function get_default_template_slug() {
|
||||
// Bail early if current page isn't singular. At this moment, Divi Layout block only
|
||||
// support singular page. Once we solved Divi Layout block issue on Site Editor, the
|
||||
// template type check below will be updated.
|
||||
if ( ! is_singular() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// At this moment, only single.html and page.html are editable.
|
||||
if ( is_page() ) {
|
||||
return 'page';
|
||||
} elseif ( is_single() ) {
|
||||
return 'single';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ET_GB_Block_Layout
|
||||
ET_GB_Block_Layout::instance();
|
@@ -0,0 +1,201 @@
|
||||
<?php
|
||||
/**
|
||||
* ET_GB_Block_Post_Excerpt class file.
|
||||
*
|
||||
* @class ET_GB_Block_Post_Excerpt
|
||||
* @package Builder
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to handle Core - Post Excerpt block integration.
|
||||
*/
|
||||
class ET_GB_Block_Post_Excerpt {
|
||||
/**
|
||||
* Class instance.
|
||||
*
|
||||
* @var ET_GB_Block_Post_Excerpt
|
||||
*/
|
||||
private static $_instance;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
if ( ! et_core_is_gutenberg_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->register_hooks();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class instance.
|
||||
*
|
||||
* @since 4.14.5
|
||||
*
|
||||
* @return ET_GB_Block_Post_Excerpt Class instance.
|
||||
*/
|
||||
public static function instance() {
|
||||
if ( null === self::$_instance ) {
|
||||
self::$_instance = new self();
|
||||
}
|
||||
|
||||
return self::$_instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register hooks
|
||||
*
|
||||
* @since 4.14.5
|
||||
*/
|
||||
public function register_hooks() {
|
||||
add_filter( 'render_block_core/post-excerpt', array( $this, 'render_block' ), 10, 2 );
|
||||
add_filter( 'get_the_excerpt', array( $this, 'get_the_post_excerpt' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter rendered Core - Post Excerpt block on FE.
|
||||
*
|
||||
* @since 4.14.5
|
||||
*
|
||||
* @param string $block_content Saved & serialized block data.
|
||||
* @param array $parsed_block Block info.
|
||||
*
|
||||
* @return string Modified block post excerpt.
|
||||
*/
|
||||
public function render_block( $block_content, $parsed_block ) {
|
||||
$attributes = ! empty( $parsed_block['attrs'] ) ? $parsed_block['attrs'] : array();
|
||||
|
||||
return $this->get_rendered_post_excerpt( $block_content, true, $attributes );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter post excerpt of REST API request.
|
||||
*
|
||||
* Only filter post excerpt rendered from REST API request. This API request is being
|
||||
* used by Block Editor.
|
||||
*
|
||||
* @since 4.14.5
|
||||
*
|
||||
* @param string $post_excerpt Current post excerpt rendered.
|
||||
*
|
||||
* @return string Modified post excerpt.
|
||||
*/
|
||||
public function get_the_post_excerpt( $post_excerpt ) {
|
||||
// Bail early if current request is not REST API request.
|
||||
if ( ! defined( 'REST_REQUEST' ) || ! REST_REQUEST ) {
|
||||
return $post_excerpt;
|
||||
}
|
||||
|
||||
return $this->get_rendered_post_excerpt( $post_excerpt );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get rendered post excerpt built with builder. Always return rendered $block_excerpt
|
||||
* because it's already wrapped with Post Excerpt block wrapper.
|
||||
*
|
||||
* @since 4.14.5
|
||||
*
|
||||
* @param string $block_excerpt Current rendered post excerpt.
|
||||
* @param boolean $is_wrapped Whether the post excerpt is wrapped or not.
|
||||
* @param array $attributes Block attributes values.
|
||||
*
|
||||
* @return string Old or new rendered post excerpt.
|
||||
*/
|
||||
public function get_rendered_post_excerpt( $block_excerpt, $is_wrapped = false, $attributes = array() ) {
|
||||
// Bail early if no global post. Need to get the post here due to some issues with
|
||||
// 3rd party plugins regarding missing 2nd arg on the `get_the_excerpt` filter.
|
||||
$post_id = ! empty( $attributes['postId'] ) ? (int) $attributes['postId'] : 0;
|
||||
$post = $post_id ? get_post( $post_id ) : get_post();
|
||||
if ( empty( $post ) ) {
|
||||
return $block_excerpt;
|
||||
}
|
||||
|
||||
if ( ! empty( $post->post_excerpt ) ) {
|
||||
return $block_excerpt;
|
||||
}
|
||||
|
||||
// Bail early if Builder framework is not loaded. There are some cases where 3rd
|
||||
// party plugins run scan without visiting theme functions file.
|
||||
if ( ! function_exists( 'et_builder_load_framework' ) ) {
|
||||
return $block_excerpt;
|
||||
}
|
||||
|
||||
if ( ! et_pb_is_pagebuilder_used( $post->ID ) ) {
|
||||
return $block_excerpt;
|
||||
}
|
||||
|
||||
static $et_rendered_post_excerpt = array();
|
||||
|
||||
// Bail early if current post is already processed.
|
||||
if ( isset( $et_rendered_post_excerpt[ $post->ID ] ) ) {
|
||||
return $et_rendered_post_excerpt[ $post->ID ];
|
||||
}
|
||||
|
||||
// 1. Ensure all the ET shortcode are registered.
|
||||
if ( ! did_action( 'et_builder_ready' ) ) {
|
||||
// When the `get_the_excerpt` filter is called by Query Loop block on the FE,
|
||||
// the `ET_Builder_Element` class is loaded properly but no ET shortcode is
|
||||
// registered yet. In this case, we can call `et_builder_init_global_settings`
|
||||
// & `et_builder_add_main_elements` methods directly. However, this class is not
|
||||
// loaded on the Block Editor, so we have to load all related files manually
|
||||
// before we can call those methods to register the shortcode.
|
||||
if ( ! class_exists( 'ET_Builder_Element' ) ) {
|
||||
require_once ET_BUILDER_DIR . 'class-et-builder-value.php';
|
||||
require_once ET_BUILDER_DIR . 'class-et-builder-element.php';
|
||||
require_once ET_BUILDER_DIR . 'ab-testing.php';
|
||||
}
|
||||
|
||||
et_builder_init_global_settings();
|
||||
et_builder_add_main_elements();
|
||||
et_builder_settings_init();
|
||||
}
|
||||
|
||||
// 2. Generate Builder post excerpt.
|
||||
// WordPress post excerpt length comes from `excerpt_length` filter. And, it's
|
||||
// words based length, not characters based length.
|
||||
$excerpt_length = apply_filters( 'excerpt_length', 55 );
|
||||
$new_post_excerpt = et_core_intentionally_unescaped( wpautop( et_delete_post_first_video( truncate_post( $excerpt_length, false, $post, true, true ) ) ), 'html' );
|
||||
|
||||
// 3. Ensure to return the block wrapper if the $block_excerpt is already wrapped.
|
||||
if ( $is_wrapped && ! empty( $new_post_excerpt ) ) {
|
||||
$new_post_excerpt = wp_strip_all_tags( $new_post_excerpt );
|
||||
|
||||
// If generated block excerpt is not empty, we just need to replace the excerpt
|
||||
// text with the new one. Otherwise, we have to rebuilt the block excerpt.
|
||||
if ( ! empty( $block_excerpt ) ) {
|
||||
$wrapper = '/(<p class="wp-block-post-excerpt__excerpt">)(.*?)(<a|<\/p>)/';
|
||||
$new_post_excerpt = preg_replace( $wrapper, "$1{$new_post_excerpt}$3", $block_excerpt );
|
||||
} else {
|
||||
// 3.a. More Text.
|
||||
$more_text = ! empty( $attributes['moreText'] ) ? '<a class="wp-block-post-excerpt__more-link" href="' . esc_url( get_the_permalink( $post->ID ) ) . '">' . esc_html( $attributes['moreText'] ) . '</a>' : '';
|
||||
|
||||
// 3.b. Text Align Class.
|
||||
$classes = ! empty( $attributes['textAlign'] ) ? 'has-text-align-' . esc_attr( $attributes['textAlign'] ) : '';
|
||||
$wrapper_attrs = get_block_wrapper_attributes( array( 'class' => $classes ) );
|
||||
|
||||
// 3.c. Post Excerpt Content.
|
||||
$content = '<p class="wp-block-post-excerpt__excerpt">' . $new_post_excerpt;
|
||||
$show_more_on_new_line = et_()->array_get( $attributes, 'showMoreOnNewLine', true );
|
||||
if ( $show_more_on_new_line && ! empty( $more_text ) ) {
|
||||
$content .= '</p><p class="wp-block-post-excerpt__more-text">' . $more_text . '</p>';
|
||||
} else {
|
||||
$content .= $more_text . '</p>';
|
||||
}
|
||||
|
||||
$new_post_excerpt = sprintf( '<div %1$s>%2$s</div>', $wrapper_attrs, $content );
|
||||
}
|
||||
}
|
||||
|
||||
$et_rendered_post_excerpt[ $post->ID ] = $new_post_excerpt;
|
||||
|
||||
return $new_post_excerpt;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize ET_GB_Block_Post_Excerpt.
|
||||
ET_GB_Block_Post_Excerpt::instance();
|
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
/**
|
||||
* Class ET_GB_Utils_Conversion
|
||||
*
|
||||
* Handling Gutenberg serialized content conversion into builder shortcode layout
|
||||
*/
|
||||
class ET_GB_Utils_Conversion {
|
||||
// Populate all layout block which is placed inside other block. Layout block contains
|
||||
// section which has to be the first level element once converted into VB content
|
||||
private $deep_layout_blocks = array();
|
||||
|
||||
// Layout list. Layout block got its own section. Others are concatenated into text module
|
||||
private $layout_list = array();
|
||||
|
||||
// Temporary variable to hold non layout block into one
|
||||
private $text_module_content = '';
|
||||
|
||||
// Serialized layout
|
||||
private $shortcode_layout = '';
|
||||
|
||||
/**
|
||||
* Check if given block is layout block
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @todo being set as static so it is easier to be used outside this class. If being used quite
|
||||
* frequently, probably consider wrap this into function. Not needed at the moment tho
|
||||
*
|
||||
* @param array $block Parsed block.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_layout_block( $block = array() ) {
|
||||
$block_name = et_()->array_get( $block, 'blockName', '' );
|
||||
|
||||
return 'divi/layout' === $block_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if given block is reusable block
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @todo being set as static so it is easier to be used outside this class. If being used quite
|
||||
* frequently, probably consider wrap this into function. Not needed at the moment tho
|
||||
*
|
||||
* @param array $block Parsed block.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public static function is_reusable_block( $block = array() ) {
|
||||
$block_name = et_()->array_get( $block, 'blockName', '' );
|
||||
|
||||
return 'core/block' === $block_name && et_()->array_get( $block, 'attrs.ref' ) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get reusable block's parsed content. NOTE: WordPress has built in `render_block_core_block()`
|
||||
* but it renders the block and its content instead of parse its content.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @see render_block_core_block()
|
||||
*
|
||||
* @todo being set as static so it is easier to be used outside this class. If being used quite
|
||||
* frequently, probably consider wrap this into function. Not needed at the moment tho
|
||||
*
|
||||
* @param array $block Parsed block.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_reusable_block_content( $block ) {
|
||||
$block_id = et_()->array_get( $block, 'attrs.ref' );
|
||||
$block_data = get_post( $block_id );
|
||||
|
||||
if ( ! $block_data || 'wp_block' !== $block_data->post_type || 'publish' !== $block_data->post_status ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return parse_blocks( $block_data->post_content );
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse reusable block by getting its content and append it as innerBlocks
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param array Parsed block.
|
||||
*
|
||||
* @return array Modified parsed block.
|
||||
*/
|
||||
public static function parse_reusable_block( $block ) {
|
||||
$reusable_block_data = self::get_reusable_block_content( $block );
|
||||
$block['innerBlocks'] = array_merge( $block['innerBlocks'], $reusable_block_data );
|
||||
|
||||
// Unset reusable block's ref attribute so reusable block content is no longer fetched
|
||||
unset( $block['attrs']['ref'] );
|
||||
|
||||
// Change block into group so its content is being rendered
|
||||
$block['blockName'] = 'core/group';
|
||||
|
||||
// Recreate innerContent which is used by block parser to render innerBlock.
|
||||
// See: `render_block()`'s `$block['innerContent'] as $chunk` loop
|
||||
$block['innerContent'] = array_merge(
|
||||
array( '<div class="wp-block-group"><div class="wp-block-group__inner-container">' ),
|
||||
array_fill( 0, count( $block['innerBlocks'] ), null ),
|
||||
array( '</div></div>' )
|
||||
);
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull layout block that is located deep inside inner blocks. Layout block contains section;
|
||||
* in builder, section has to be on the first level of document
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param array $block Parsed block.
|
||||
*/
|
||||
private function pull_layout_block( $block ) {
|
||||
// Pull and populate layout block. Layout block contains section(s) so it should be rendered
|
||||
// on first level layout, below Gutenberg content inside text module
|
||||
if ( self::is_layout_block( $block ) ) {
|
||||
// Pull layout block and populate list of layout block located on inner blocks
|
||||
$this->deep_layout_blocks[] = $block;
|
||||
|
||||
// Remove innerContent and innerHTML value because inner block can't be simply removed
|
||||
// due to nested block rendering relies on `$block['innerContent']` making cross reference
|
||||
// on `$block['innerBlocks']` and removing them causes error (see: `render_block()`'s
|
||||
// `$block['innerContent'] as $chunk` loop). Thus, set deep layout block's content empty
|
||||
// so it doesn't get rendered
|
||||
$block['innerHTML'] = '';
|
||||
$block['innerContent'] = array();
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
// Reusable block's content is not saved inside block; Thus Get reusable block's content,
|
||||
// append it as innerBlock, and pull layout block if exist.
|
||||
if ( self::is_reusable_block( $block ) ) {
|
||||
$block = self::parse_reusable_block( $block );
|
||||
}
|
||||
|
||||
// Recursively loop over block then pull Layout Block
|
||||
if ( ! empty( $block['innerBlocks'] ) ) {
|
||||
$block['innerBlocks'] = array_map(
|
||||
array( $this, 'pull_layout_block' ),
|
||||
$block['innerBlocks']
|
||||
);
|
||||
}
|
||||
|
||||
return $block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert serialized block into shortcode layout
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param string $serialized_block
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function block_to_shortcode( $serialized_block = '' ) {
|
||||
// Wrapper div needs to be trimmed
|
||||
$layout_open_tag = '<div class="wp-block-divi-layout">';
|
||||
$layout_open_length = strlen( $layout_open_tag );
|
||||
$layout_close_tag = '</div>';
|
||||
$layout_close_length = strlen( $layout_close_tag );
|
||||
|
||||
// Parsed blocks
|
||||
$blocks = parse_blocks( $serialized_block );
|
||||
|
||||
// Loop blocks
|
||||
foreach ( $blocks as $block ) {
|
||||
if ( self::is_layout_block( $block ) ) {
|
||||
// Append currently populated non-Layout Block into one before layout block is appended
|
||||
if ( ! empty( $this->text_module_content ) ) {
|
||||
$this->layout_list[] = $this->text_module_content;
|
||||
|
||||
// Reset text module content so next non-layout block is placed below current layout block
|
||||
$this->text_module_content = '';
|
||||
}
|
||||
|
||||
$this->layout_list[] = $block;
|
||||
} else {
|
||||
// Reusable block's content is not saved inside block; Thus Get reusable block's
|
||||
// content, append it as innerBlock, and pull layout block if exist.
|
||||
if ( self::is_reusable_block( $block ) ) {
|
||||
$block = self::parse_reusable_block( $block );
|
||||
}
|
||||
|
||||
// Pull any Layout Block inside nested block if there's any
|
||||
if ( ! empty( $block['innerBlocks'] ) ) {
|
||||
$block['innerBlocks'] = array_map(
|
||||
array( $this, 'pull_layout_block' ),
|
||||
$block['innerBlocks']
|
||||
);
|
||||
}
|
||||
|
||||
// Populate block into temporary text module content buffer
|
||||
$this->text_module_content .= render_block( $block );
|
||||
}
|
||||
}
|
||||
|
||||
// Populate remaining non-layout block into layout list
|
||||
if ( ! empty( $this->text_module_content ) ) {
|
||||
$this->layout_list[] = $this->text_module_content;
|
||||
|
||||
// Reset
|
||||
$this->text_module_content = '';
|
||||
}
|
||||
|
||||
// Loop over populated content and render it into shortcode layout
|
||||
foreach ( array_merge( $this->layout_list, $this->deep_layout_blocks ) as $item ) {
|
||||
if ( self::is_layout_block( $item ) ) {
|
||||
$shortcode_layout = trim( et_()->array_get( $item, 'innerHTML', '' ) );
|
||||
|
||||
// Remove layout content opening <div>
|
||||
if ( $layout_open_tag === substr( $shortcode_layout, 0, $layout_open_length ) ) {
|
||||
$shortcode_layout = substr( $shortcode_layout, $layout_open_length );
|
||||
}
|
||||
|
||||
// Remove layout content closing </div>
|
||||
if ( $layout_close_tag === substr( $shortcode_layout, ( 0 - $layout_close_length ) ) ) {
|
||||
$shortcode_layout = substr( $shortcode_layout, 0, ( 0 - $layout_close_length ) );
|
||||
}
|
||||
|
||||
$this->shortcode_layout .= $shortcode_layout;
|
||||
} else {
|
||||
$text_module = '[et_pb_text]' . $item . '[/et_pb_text]';
|
||||
$column = '[et_pb_column type="4_4"]' . $text_module . '[/et_pb_column]';
|
||||
$row = '[et_pb_row admin_label="row"]' . $column . '[/et_pb_row]';
|
||||
$this->shortcode_layout .= '[et_pb_section admin_label="section"]' . $row . '[/et_pb_section]';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->shortcode_layout;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert gutenberg block layout into shortcode.
|
||||
* NOTE: There is JS version for activation via Gutenberg. See: `convertBlockToShortcode()`
|
||||
*
|
||||
* @since 4.1.0
|
||||
*
|
||||
* @param string $post_content Post content / serialized block.
|
||||
*
|
||||
* @return string Shortcode layout.
|
||||
*/
|
||||
function et_builder_convert_block_to_shortcode( $post_content ) {
|
||||
$conversion = new ET_GB_Utils_Conversion();
|
||||
|
||||
return $conversion->block_to_shortcode( $post_content );
|
||||
}
|
@@ -0,0 +1,198 @@
|
||||
<?php
|
||||
/**
|
||||
* Helpers needed for the WP Editor compatibility.
|
||||
*
|
||||
* @package Divi
|
||||
* @subpackage Builder
|
||||
* @since 4.14.8
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ET_WP_EDITOR_TEMPLATE_POST_TYPE' ) ) {
|
||||
define( 'ET_WP_EDITOR_TEMPLATE_POST_TYPE', 'wp_template' );
|
||||
}
|
||||
|
||||
if ( ! defined( 'ET_WP_EDITOR_TEMPLATE_PART_POST_TYPE' ) ) {
|
||||
define( 'ET_WP_EDITOR_TEMPLATE_PART_POST_TYPE', 'wp_template_part' );
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'et_builder_get_wp_editor_template_post_types' ) ) {
|
||||
/**
|
||||
* Get supported WP Editor template post types.
|
||||
*
|
||||
* At this moment, the list is:
|
||||
* - wp_template
|
||||
* - wp_template_part
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @return array List of supported WP Editor template post types.
|
||||
*/
|
||||
function et_builder_get_wp_editor_template_post_types() {
|
||||
// Supported WP Editor template post types.
|
||||
$post_types = array(
|
||||
ET_WP_EDITOR_TEMPLATE_POST_TYPE,
|
||||
ET_WP_EDITOR_TEMPLATE_PART_POST_TYPE,
|
||||
);
|
||||
|
||||
return $post_types;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'et_builder_is_wp_editor_template_post_type' ) ) {
|
||||
/**
|
||||
* Whether current post type is supported WP Editor template post type or not.
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @param string $type Template post type.
|
||||
*
|
||||
* @return boolean Post type check status.
|
||||
*/
|
||||
function et_builder_is_wp_editor_template_post_type( $type ) {
|
||||
return in_array( $type, et_builder_get_wp_editor_template_post_types(), true );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'et_builder_wp_editor_decorate_page_resource_slug' ) ) {
|
||||
/**
|
||||
* Decorate a page resource slug based on the current request and WP Editor.
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @param integer|string $post_id Post ID.
|
||||
* @param string $resource_slug Resource slug.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function et_builder_wp_editor_decorate_page_resource_slug( $post_id, $resource_slug ) {
|
||||
// Bail early if current page is not singular.
|
||||
if ( ! is_numeric( $post_id ) || ! is_singular() ) {
|
||||
return $resource_slug;
|
||||
}
|
||||
|
||||
$templates = et_builder_get_wp_editor_templates();
|
||||
|
||||
// Bail early if current page doesn't have templates.
|
||||
if ( empty( $templates ) ) {
|
||||
return $resource_slug;
|
||||
}
|
||||
|
||||
foreach ( $templates as $template ) {
|
||||
// The `wpe` is stand for WP Editor.
|
||||
$template_id = isset( $template->wp_id ) ? (int) $template->wp_id : 0;
|
||||
$resource_slug .= $template_id ? '-wpe-' . $template_id : '';
|
||||
}
|
||||
|
||||
return $resource_slug;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'et_builder_get_wp_editor_templates' ) ) {
|
||||
/**
|
||||
* Get WP Editor templates on current post.
|
||||
*
|
||||
* @since 4.14.8
|
||||
*
|
||||
* @return array List of templates and template parts.
|
||||
*/
|
||||
function et_builder_get_wp_editor_templates() {
|
||||
static $templates = null;
|
||||
|
||||
// Bail early if the list is already processed.
|
||||
if ( null !== $templates ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
$templates = array();
|
||||
|
||||
// Bail early if `get_block_template` function doesn't exist because we need it to
|
||||
// get template data. This function is introduced on WP 5.8 along with Template and
|
||||
// Template Parts editors.
|
||||
if ( ! function_exists( 'get_block_template' ) ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
// Bail early if current page is not singular.
|
||||
if ( ! is_singular() ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
global $post;
|
||||
|
||||
// Bail early if current post doesn't have page template.
|
||||
if ( empty( $post->page_template ) ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
// A. Template.
|
||||
// Get block template data based on post slug and post type.
|
||||
$template = get_block_template( get_stylesheet() . '//' . $post->page_template, ET_WP_EDITOR_TEMPLATE_POST_TYPE );
|
||||
|
||||
// Bail early if the template is empty.
|
||||
if ( empty( $template ) ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
$template_id = isset( $template->wp_id ) ? (int) $template->wp_id : 0;
|
||||
$templates[ $template_id ] = $template;
|
||||
|
||||
// Parse and fetch blocks list in the template to find the template parts.
|
||||
$blocks = parse_blocks( $template->content );
|
||||
|
||||
// Bail early if the blocks is empty.
|
||||
if ( empty( $blocks ) ) {
|
||||
return $templates;
|
||||
}
|
||||
|
||||
foreach ( $blocks as $block ) {
|
||||
$name = et_()->array_get( $block, 'blockName' );
|
||||
$slug = et_()->array_get( $block, array( 'attrs', 'slug' ) );
|
||||
|
||||
// Skip if current block is not template part.
|
||||
if ( 'core/template-part' !== $name || empty( $slug ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// B. Template Parts.
|
||||
// Get block template part data based on post slug and post type.
|
||||
$template_part = get_block_template( get_stylesheet() . '//' . $slug, ET_WP_EDITOR_TEMPLATE_PART_POST_TYPE );
|
||||
|
||||
// Skip if the template part is empty.
|
||||
if ( empty( $template_part ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$template_part_id = isset( $template_part->wp_id ) ? (int) $template_part->wp_id : 0;
|
||||
$templates[ $template_part_id ] = $template_part;
|
||||
}
|
||||
|
||||
return $templates;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! function_exists( 'et_builder_is_block_theme' ) ) {
|
||||
/**
|
||||
* Whether current theme is block theme or not.
|
||||
*
|
||||
* @since 4.17.4
|
||||
*
|
||||
* @return boolean Block theme status.
|
||||
*/
|
||||
function et_builder_is_block_theme() {
|
||||
// Use `wp_is_block_theme` on WP 5.9.
|
||||
if ( function_exists( 'wp_is_block_theme' ) ) {
|
||||
return (bool) wp_is_block_theme();
|
||||
}
|
||||
|
||||
// Use `gutenberg_is_fse_theme` on GB plugin.
|
||||
if ( function_exists( 'gutenberg_is_fse_theme' ) ) {
|
||||
return (bool) gutenberg_is_fse_theme();
|
||||
}
|
||||
|
||||
// Use manual check on WP 5.8 below.
|
||||
$block_templates_index_html_file = get_stylesheet_directory() . '/block-templates/index.html';
|
||||
$templates_index_html_file = get_stylesheet_directory() . '/templates/index.html';
|
||||
|
||||
return is_readable( $block_templates_index_html_file ) || is_readable( $templates_index_html_file );
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user