<?php /** * Parse blocks from content and widgets * * @package visual-portfolio */ /** * Visual_Portfolio_Parse_Blocks */ class Visual_Portfolio_Parse_Blocks { /** * Array of content, that already parsed. * * @var array */ public static $parsed_content = array(); /** * Array of reusable block IDs, that already parsed. * * @var array */ public static $parsed_reusable_blocks = array(); /** * Init. */ public static function init() { add_action( 'wp', function() { // Simple use `render_block` in FSE themes to enqueue assets. if ( current_theme_supports( 'block-templates' ) ) { // Parse all blocks. add_action( 'render_block', 'Visual_Portfolio_Parse_Blocks::render_block', 11, 2 ); // Parse blocks manually from content and custom locations in Classic themes. } else { // parse blocks from post content. Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_content(); // parse blocks from custom locations, that uses 'the_content' filter. add_filter( 'the_content', 'Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_custom_location', 8 ); add_filter( 'widget_block_content', 'Visual_Portfolio_Parse_Blocks::maybe_parse_blocks_from_custom_location', 8 ); } } ); } /** * Standard callback to parse blocks (mostly solves problem with FSE themes and blocks inside templates). * * @param string $block_content - block content. * @param array $block - block data. * * @return string */ public static function render_block( $block_content, $block ) { // We don't need to parse inner blocks manually, because `render_block` filter will make it for us. $block['innerBlocks'] = false; self::parse_blocks( array( $block ), 'general' ); return $block_content; } /** * Parse blocks from custom locations. * * @param string $content - custom content. */ public static function maybe_parse_blocks_from_custom_location( $content ) { if ( is_admin() ) { return $content; } if ( isset( $content ) ) { self::maybe_parse_blocks( $content, 'content' ); } return $content; } /** * Maybe parse blocks. * * @param string $content - content. * @param string $location - blocks location [content,widget]. */ public static function maybe_parse_blocks( $content, $location = 'content' ) { if ( isset( $content ) && function_exists( 'has_blocks' ) && function_exists( 'parse_blocks' ) && $content && has_blocks( $content ) ) { $is_parsed = false; // check if this content is already parsed. foreach ( self::$parsed_content as $parsed ) { $is_parsed = $is_parsed || $parsed === $content; } if ( ! $is_parsed ) { $blocks = parse_blocks( $content ); self::parse_blocks( $blocks, $location ); self::$parsed_content[] = $content; } } } /** * Parse blocks from content. */ public static function maybe_parse_blocks_from_content() { global $wp_query; if ( is_admin() || ! isset( $wp_query->posts ) ) { return; } // parse all posts content. foreach ( $wp_query->posts as $post ) { if ( isset( $post->post_content ) && function_exists( 'has_blocks' ) && function_exists( 'parse_blocks' ) && has_blocks( $post ) ) { $blocks = parse_blocks( $post->post_content ); self::parse_blocks( $blocks, 'content' ); } } } /** * Parse blocks including reusable and InnerBlocks and call action `vpf_parse_blocks`. * * @param array $blocks - blocks array. * @param string $location - blocks location [content,widget]. * @param boolean $is_reusable - is from reusable block. * @param boolean $is_inner_blocks - is from inner blocks. */ public static function parse_blocks( $blocks, $location = 'content', $is_reusable = false, $is_inner_blocks = false ) { if ( ! is_array( $blocks ) || empty( $blocks ) ) { return; } do_action( 'vpf_parse_blocks', $blocks, $location, $is_reusable, $is_inner_blocks ); foreach ( $blocks as $block ) { // Reusable Blocks. if ( isset( $block['blockName'] ) && 'core/block' === $block['blockName'] && isset( $block['attrs']['ref'] ) ) { // Check if this reusable block already parsed. // Fixes possible error with nested reusable blocks. if ( ! in_array( $block['attrs']['ref'], self::$parsed_reusable_blocks, true ) ) { self::$parsed_reusable_blocks[] = $block['attrs']['ref']; $reusable_block = get_post( $block['attrs']['ref'] ); if ( has_blocks( $reusable_block ) && isset( $reusable_block->post_content ) ) { $post_blocks = parse_blocks( $reusable_block->post_content ); self::parse_blocks( $post_blocks, $location, true ); } } } // Inner blocks. if ( isset( $block['innerBlocks'] ) ) { self::parse_blocks( $block['innerBlocks'], $location, $is_reusable, true ); } } } } Visual_Portfolio_Parse_Blocks::init();