Commit realizado el 12:13:52 08-04-2024
This commit is contained in:
@@ -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