diff options
Diffstat (limited to 'wp-includes/blocks.php')
-rw-r--r-- | wp-includes/blocks.php | 537 |
1 files changed, 380 insertions, 157 deletions
diff --git a/wp-includes/blocks.php b/wp-includes/blocks.php index 34ff3a2..854992d 100644 --- a/wp-includes/blocks.php +++ b/wp-includes/blocks.php @@ -36,6 +36,7 @@ function remove_block_asset_path_prefix( $asset_handle_or_path ) { * * @since 5.5.0 * @since 6.1.0 Added `$index` parameter. + * @since 6.5.0 Added support for `viewScriptModule` field. * * @param string $block_name Name of the block. * @param string $field_name Name of the metadata field. @@ -52,6 +53,9 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { if ( str_starts_with( $field_name, 'view' ) ) { $asset_handle .= '-view'; } + if ( str_ends_with( strtolower( $field_name ), 'scriptmodule' ) ) { + $asset_handle .= '-script-module'; + } if ( $index > 0 ) { $asset_handle .= '-' . ( $index + 1 ); } @@ -59,11 +63,13 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { } $field_mappings = array( - 'editorScript' => 'editor-script', - 'script' => 'script', - 'viewScript' => 'view-script', - 'editorStyle' => 'editor-style', - 'style' => 'style', + 'editorScript' => 'editor-script', + 'editorStyle' => 'editor-style', + 'script' => 'script', + 'style' => 'style', + 'viewScript' => 'view-script', + 'viewScriptModule' => 'view-script-module', + 'viewStyle' => 'view-style', ); $asset_handle = str_replace( '/', '-', $block_name ) . '-' . $field_mappings[ $field_name ]; @@ -100,7 +106,7 @@ function get_block_asset_url( $path ) { $template = get_template(); if ( ! isset( $template_paths_norm[ $template ] ) ) { - $template_paths_norm[ $template ] = wp_normalize_path( get_template_directory() ); + $template_paths_norm[ $template ] = wp_normalize_path( realpath( get_template_directory() ) ); } if ( str_starts_with( $path, trailingslashit( $template_paths_norm[ $template ] ) ) ) { @@ -110,7 +116,7 @@ function get_block_asset_url( $path ) { if ( is_child_theme() ) { $stylesheet = get_stylesheet(); if ( ! isset( $template_paths_norm[ $stylesheet ] ) ) { - $template_paths_norm[ $stylesheet ] = wp_normalize_path( get_stylesheet_directory() ); + $template_paths_norm[ $stylesheet ] = wp_normalize_path( realpath( get_stylesheet_directory() ) ); } if ( str_starts_with( $path, trailingslashit( $template_paths_norm[ $stylesheet ] ) ) ) { @@ -122,13 +128,72 @@ function get_block_asset_url( $path ) { } /** + * Finds a script module ID for the selected block metadata field. It detects + * when a path to file was provided and optionally finds a corresponding asset + * file with details necessary to register the script module under with an + * automatically generated module ID. It returns unprocessed script module + * ID otherwise. + * + * @since 6.5.0 + * + * @param array $metadata Block metadata. + * @param string $field_name Field name to pick from metadata. + * @param int $index Optional. Index of the script module ID to register when multiple + * items passed. Default 0. + * @return string|false Script module ID or false on failure. + */ +function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { + if ( empty( $metadata[ $field_name ] ) ) { + return false; + } + + $module_id = $metadata[ $field_name ]; + if ( is_array( $module_id ) ) { + if ( empty( $module_id[ $index ] ) ) { + return false; + } + $module_id = $module_id[ $index ]; + } + + $module_path = remove_block_asset_path_prefix( $module_id ); + if ( $module_id === $module_path ) { + return $module_id; + } + + $path = dirname( $metadata['file'] ); + $module_asset_raw_path = $path . '/' . substr_replace( $module_path, '.asset.php', - strlen( '.js' ) ); + $module_id = generate_block_asset_handle( $metadata['name'], $field_name, $index ); + $module_asset_path = wp_normalize_path( + realpath( $module_asset_raw_path ) + ); + + $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) ); + $module_uri = get_block_asset_url( $module_path_norm ); + + $module_asset = ! empty( $module_asset_path ) ? require $module_asset_path : array(); + $module_dependencies = isset( $module_asset['dependencies'] ) ? $module_asset['dependencies'] : array(); + $block_version = isset( $metadata['version'] ) ? $metadata['version'] : false; + $module_version = isset( $module_asset['version'] ) ? $module_asset['version'] : $block_version; + + wp_register_script_module( + $module_id, + $module_uri, + $module_dependencies, + $module_version + ); + + return $module_id; +} + +/** * Finds a script handle for the selected block metadata field. It detects - * when a path to file was provided and finds a corresponding asset file - * with details necessary to register the script under automatically + * when a path to file was provided and optionally finds a corresponding asset + * file with details necessary to register the script under automatically * generated handle name. It returns unprocessed script handle otherwise. * * @since 5.5.0 * @since 6.1.0 Added `$index` parameter. + * @since 6.5.0 The asset file is optional. Added script handle support in the asset file. * * @param array $metadata Block metadata. * @param string $field_name Field name to pick from metadata. @@ -142,56 +207,49 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) { return false; } - $script_handle = $metadata[ $field_name ]; - if ( is_array( $script_handle ) ) { - if ( empty( $script_handle[ $index ] ) ) { + $script_handle_or_path = $metadata[ $field_name ]; + if ( is_array( $script_handle_or_path ) ) { + if ( empty( $script_handle_or_path[ $index ] ) ) { return false; } - $script_handle = $script_handle[ $index ]; + $script_handle_or_path = $script_handle_or_path[ $index ]; } - $script_path = remove_block_asset_path_prefix( $script_handle ); - if ( $script_handle === $script_path ) { - return $script_handle; + $script_path = remove_block_asset_path_prefix( $script_handle_or_path ); + if ( $script_handle_or_path === $script_path ) { + return $script_handle_or_path; } $path = dirname( $metadata['file'] ); $script_asset_raw_path = $path . '/' . substr_replace( $script_path, '.asset.php', - strlen( '.js' ) ); - $script_handle = generate_block_asset_handle( $metadata['name'], $field_name, $index ); $script_asset_path = wp_normalize_path( realpath( $script_asset_raw_path ) ); - if ( empty( $script_asset_path ) ) { - _doing_it_wrong( - __FUNCTION__, - sprintf( - /* translators: 1: Asset file location, 2: Field name, 3: Block name. */ - __( 'The asset file (%1$s) for the "%2$s" defined in "%3$s" block definition is missing.' ), - $script_asset_raw_path, - $field_name, - $metadata['name'] - ), - '5.5.0' - ); - return false; + // Asset file for blocks is optional. See https://core.trac.wordpress.org/ticket/60460. + $script_asset = ! empty( $script_asset_path ) ? require $script_asset_path : array(); + $script_handle = isset( $script_asset['handle'] ) ? + $script_asset['handle'] : + generate_block_asset_handle( $metadata['name'], $field_name, $index ); + if ( wp_script_is( $script_handle, 'registered' ) ) { + return $script_handle; } - $script_path_norm = wp_normalize_path( realpath( $path . '/' . $script_path ) ); - $script_uri = get_block_asset_url( $script_path_norm ); - - $script_args = array(); + $script_path_norm = wp_normalize_path( realpath( $path . '/' . $script_path ) ); + $script_uri = get_block_asset_url( $script_path_norm ); + $script_dependencies = isset( $script_asset['dependencies'] ) ? $script_asset['dependencies'] : array(); + $block_version = isset( $metadata['version'] ) ? $metadata['version'] : false; + $script_version = isset( $script_asset['version'] ) ? $script_asset['version'] : $block_version; + $script_args = array(); if ( 'viewScript' === $field_name && $script_uri ) { $script_args['strategy'] = 'defer'; } - $script_asset = require $script_asset_path; - $script_dependencies = isset( $script_asset['dependencies'] ) ? $script_asset['dependencies'] : array(); - $result = wp_register_script( + $result = wp_register_script( $script_handle, $script_uri, $script_dependencies, - isset( $script_asset['version'] ) ? $script_asset['version'] : false, + $script_version, $script_args ); if ( ! $result ) { @@ -326,6 +384,7 @@ function get_block_metadata_i18n_schema() { * @since 6.1.0 Added support for `render` field. * @since 6.3.0 Added `selectors` field. * @since 6.4.0 Added support for `blockHooks` field. + * @since 6.5.0 Added support for `allowedBlocks`, `viewScriptModule`, and `viewStyle` fields. * * @param string $file_or_folder Path to the JSON file with metadata definition for * the block or path to the folder where the `block.json` file is located. @@ -352,13 +411,14 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { $file_or_folder; $is_core_block = str_starts_with( $file_or_folder, ABSPATH . WPINC ); - - if ( ! $is_core_block && ! file_exists( $metadata_file ) ) { + // If the block is not a core block, the metadata file must exist. + $metadata_file_exists = $is_core_block || file_exists( $metadata_file ); + if ( ! $metadata_file_exists && empty( $args['name'] ) ) { return false; } // Try to get metadata from the static cache for core blocks. - $metadata = false; + $metadata = array(); if ( $is_core_block ) { $core_block_name = str_replace( ABSPATH . WPINC . '/blocks/', '', $file_or_folder ); if ( ! empty( $core_blocks_meta[ $core_block_name ] ) ) { @@ -367,14 +427,15 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } // If metadata is not found in the static cache, read it from the file. - if ( ! $metadata ) { + if ( $metadata_file_exists && empty( $metadata ) ) { $metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) ); } - if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) { + if ( ! is_array( $metadata ) || ( empty( $metadata['name'] ) && empty( $args['name'] ) ) ) { return false; } - $metadata['file'] = wp_normalize_path( realpath( $metadata_file ) ); + + $metadata['file'] = $metadata_file_exists ? wp_normalize_path( realpath( $metadata_file ) ) : null; /** * Filters the metadata provided for registering a block type. @@ -404,6 +465,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { $settings = array(); $property_mappings = array( 'apiVersion' => 'api_version', + 'name' => 'name', 'title' => 'title', 'category' => 'category', 'parent' => 'parent', @@ -419,6 +481,7 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { 'styles' => 'styles', 'variations' => 'variations', 'example' => 'example', + 'allowedBlocks' => 'allowed_blocks', ); $textdomain = ! empty( $metadata['textdomain'] ) ? $metadata['textdomain'] : null; $i18n_schema = get_block_metadata_i18n_schema(); @@ -426,18 +489,50 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { foreach ( $property_mappings as $key => $mapped_key ) { if ( isset( $metadata[ $key ] ) ) { $settings[ $mapped_key ] = $metadata[ $key ]; - if ( $textdomain && isset( $i18n_schema->$key ) ) { + if ( $metadata_file_exists && $textdomain && isset( $i18n_schema->$key ) ) { $settings[ $mapped_key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $settings[ $key ], $textdomain ); } } } + if ( ! empty( $metadata['render'] ) ) { + $template_path = wp_normalize_path( + realpath( + dirname( $metadata['file'] ) . '/' . + remove_block_asset_path_prefix( $metadata['render'] ) + ) + ); + if ( $template_path ) { + /** + * Renders the block on the server. + * + * @since 6.1.0 + * + * @param array $attributes Block attributes. + * @param string $content Block default content. + * @param WP_Block $block Block instance. + * + * @return string Returns the block content. + */ + $settings['render_callback'] = static function ( $attributes, $content, $block ) use ( $template_path ) { + ob_start(); + require $template_path; + return ob_get_clean(); + }; + } + } + + $settings = array_merge( $settings, $args ); + $script_fields = array( 'editorScript' => 'editor_script_handles', 'script' => 'script_handles', 'viewScript' => 'view_script_handles', ); foreach ( $script_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $settings[ $metadata_field_name ] ) ) { + $metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ]; + } if ( ! empty( $metadata[ $metadata_field_name ] ) ) { $scripts = $metadata[ $metadata_field_name ]; $processed_scripts = array(); @@ -465,11 +560,49 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } } + $module_fields = array( + 'viewScriptModule' => 'view_script_module_ids', + ); + foreach ( $module_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $settings[ $metadata_field_name ] ) ) { + $metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ]; + } + if ( ! empty( $metadata[ $metadata_field_name ] ) ) { + $modules = $metadata[ $metadata_field_name ]; + $processed_modules = array(); + if ( is_array( $modules ) ) { + for ( $index = 0; $index < count( $modules ); $index++ ) { + $result = register_block_script_module_id( + $metadata, + $metadata_field_name, + $index + ); + if ( $result ) { + $processed_modules[] = $result; + } + } + } else { + $result = register_block_script_module_id( + $metadata, + $metadata_field_name + ); + if ( $result ) { + $processed_modules[] = $result; + } + } + $settings[ $settings_field_name ] = $processed_modules; + } + } + $style_fields = array( 'editorStyle' => 'editor_style_handles', 'style' => 'style_handles', + 'viewStyle' => 'view_style_handles', ); foreach ( $style_fields as $metadata_field_name => $settings_field_name ) { + if ( ! empty( $settings[ $metadata_field_name ] ) ) { + $metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ]; + } if ( ! empty( $metadata[ $metadata_field_name ] ) ) { $styles = $metadata[ $metadata_field_name ]; $processed_styles = array(); @@ -530,33 +663,6 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { } } - if ( ! empty( $metadata['render'] ) ) { - $template_path = wp_normalize_path( - realpath( - dirname( $metadata['file'] ) . '/' . - remove_block_asset_path_prefix( $metadata['render'] ) - ) - ); - if ( $template_path ) { - /** - * Renders the block on the server. - * - * @since 6.1.0 - * - * @param array $attributes Block attributes. - * @param string $content Block default content. - * @param WP_Block $block Block instance. - * - * @return string Returns the block content. - */ - $settings['render_callback'] = static function ( $attributes, $content, $block ) use ( $template_path ) { - ob_start(); - require $template_path; - return ob_get_clean(); - }; - } - } - /** * Filters the settings determined from the block type metadata. * @@ -565,14 +671,9 @@ function register_block_type_from_metadata( $file_or_folder, $args = array() ) { * @param array $settings Array of determined settings for registering a block type. * @param array $metadata Metadata provided for registering a block type. */ - $settings = apply_filters( - 'block_type_metadata_settings', - array_merge( - $settings, - $args - ), - $metadata - ); + $settings = apply_filters( 'block_type_metadata_settings', $settings, $metadata ); + + $metadata['name'] = ! empty( $settings['name'] ) ? $settings['name'] : $metadata['name']; return WP_Block_Type_Registry::get_instance()->register( $metadata['name'], @@ -752,6 +853,156 @@ function get_hooked_blocks() { } /** + * Returns the markup for blocks hooked to the given anchor block in a specific relative position. + * + * @since 6.5.0 + * @access private + * + * @param array $parsed_anchor_block The anchor block, in parsed block array format. + * @param string $relative_position The relative position of the hooked blocks. + * Can be one of 'before', 'after', 'first_child', or 'last_child'. + * @param array $hooked_blocks An array of hooked block types, grouped by anchor block and relative position. + * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to. + * @return string + */ +function insert_hooked_blocks( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) { + $anchor_block_type = $parsed_anchor_block['blockName']; + $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) + ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] + : array(); + + /** + * Filters the list of hooked block types for a given anchor block type and relative position. + * + * @since 6.4.0 + * + * @param string[] $hooked_block_types The list of hooked block types. + * @param string $relative_position The relative position of the hooked blocks. + * Can be one of 'before', 'after', 'first_child', or 'last_child'. + * @param string $anchor_block_type The anchor block type. + * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type, + * or pattern that the anchor block belongs to. + */ + $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); + + $markup = ''; + foreach ( $hooked_block_types as $hooked_block_type ) { + $parsed_hooked_block = array( + 'blockName' => $hooked_block_type, + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerContent' => array(), + ); + + /** + * Filters the parsed block array for a given hooked block. + * + * @since 6.5.0 + * + * @param array|null $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block. + * @param string $hooked_block_type The hooked block type name. + * @param string $relative_position The relative position of the hooked block. + * @param array $parsed_anchor_block The anchor block, in parsed block array format. + * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type, + * or pattern that the anchor block belongs to. + */ + $parsed_hooked_block = apply_filters( 'hooked_block', $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ); + + /** + * Filters the parsed block array for a given hooked block. + * + * The dynamic portion of the hook name, `$hooked_block_type`, refers to the block type name of the specific hooked block. + * + * @since 6.5.0 + * + * @param array|null $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block. + * @param string $hooked_block_type The hooked block type name. + * @param string $relative_position The relative position of the hooked block. + * @param array $parsed_anchor_block The anchor block, in parsed block array format. + * @param WP_Block_Template|WP_Post|array $context The block template, template part, `wp_navigation` post type, + * or pattern that the anchor block belongs to. + */ + $parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ); + + if ( null === $parsed_hooked_block ) { + continue; + } + + // It's possible that the filter returned a block of a different type, so we explicitly + // look for the original `$hooked_block_type` in the `ignoredHookedBlocks` metadata. + if ( + ! isset( $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) || + ! in_array( $hooked_block_type, $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'], true ) + ) { + $markup .= serialize_block( $parsed_hooked_block ); + } + } + + return $markup; +} + +/** + * Adds a list of hooked block types to an anchor block's ignored hooked block types. + * + * This function is meant for internal use only. + * + * @since 6.5.0 + * @access private + * + * @param array $parsed_anchor_block The anchor block, in parsed block array format. + * @param string $relative_position The relative position of the hooked blocks. + * Can be one of 'before', 'after', 'first_child', or 'last_child'. + * @param array $hooked_blocks An array of hooked block types, grouped by anchor block and relative position. + * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to. + * @return string An empty string. + */ +function set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) { + $anchor_block_type = $parsed_anchor_block['blockName']; + $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) + ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] + : array(); + + /** This filter is documented in wp-includes/blocks.php */ + $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); + if ( empty( $hooked_block_types ) ) { + return ''; + } + + foreach ( $hooked_block_types as $index => $hooked_block_type ) { + $parsed_hooked_block = array( + 'blockName' => $hooked_block_type, + 'attrs' => array(), + 'innerBlocks' => array(), + 'innerContent' => array(), + ); + + /** This filter is documented in wp-includes/blocks.php */ + $parsed_hooked_block = apply_filters( 'hooked_block', $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ); + + /** This filter is documented in wp-includes/blocks.php */ + $parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context ); + + if ( null === $parsed_hooked_block ) { + unset( $hooked_block_types[ $index ] ); + } + } + + $previously_ignored_hooked_blocks = isset( $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] ) + ? $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] + : array(); + + $parsed_anchor_block['attrs']['metadata']['ignoredHookedBlocks'] = array_unique( + array_merge( + $previously_ignored_hooked_blocks, + $hooked_block_types + ) + ); + + // Markup for the hooked blocks has already been created (in `insert_hooked_blocks`). + return ''; +} + +/** * Returns a function that injects the theme attribute into, and hooked blocks before, a given block. * * The returned function can be used as `$pre_callback` argument to `traverse_and_serialize_block(s)`, @@ -761,14 +1012,19 @@ function get_hooked_blocks() { * This function is meant for internal use only. * * @since 6.4.0 + * @since 6.5.0 Added $callback argument. * @access private * - * @param array $hooked_blocks An array of blocks hooked to another given block. - * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to. + * @param array $hooked_blocks An array of blocks hooked to another given block. + * @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object, + * or pattern that the blocks belong to. + * @param callable $callback A function that will be called for each block to generate + * the markup for a given list of blocks that are hooked to it. + * Default: 'insert_hooked_blocks'. * @return callable A function that returns the serialized markup for the given block, * including the markup for any hooked blocks before it. */ -function make_before_block_visitor( $hooked_blocks, $context ) { +function make_before_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) { /** * Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup. * @@ -781,47 +1037,23 @@ function make_before_block_visitor( $hooked_blocks, $context ) { * @param array $prev The previous sibling block of the given block. Default null. * @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it. */ - return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context ) { + return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context, $callback ) { _inject_theme_attribute_in_template_part_block( $block ); $markup = ''; if ( $parent_block && ! $prev ) { // Candidate for first-child insertion. - $relative_position = 'first_child'; - $anchor_block_type = $parent_block['blockName']; - $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) - ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] - : array(); - - /** - * Filters the list of hooked block types for a given anchor block type and relative position. - * - * @since 6.4.0 - * - * @param string[] $hooked_block_types The list of hooked block types. - * @param string $relative_position The relative position of the hooked blocks. - * Can be one of 'before', 'after', 'first_child', or 'last_child'. - * @param string $anchor_block_type The anchor block type. - * @param WP_Block_Template|array $context The block template, template part, or pattern that the anchor block belongs to. - */ - $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); - foreach ( $hooked_block_types as $hooked_block_type ) { - $markup .= get_comment_delimited_block_content( $hooked_block_type, array(), '' ); - } + $markup .= call_user_func_array( + $callback, + array( &$parent_block, 'first_child', $hooked_blocks, $context ) + ); } - $relative_position = 'before'; - $anchor_block_type = $block['blockName']; - $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) - ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] - : array(); - - /** This filter is documented in wp-includes/blocks.php */ - $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); - foreach ( $hooked_block_types as $hooked_block_type ) { - $markup .= get_comment_delimited_block_content( $hooked_block_type, array(), '' ); - } + $markup .= call_user_func_array( + $callback, + array( &$block, 'before', $hooked_blocks, $context ) + ); return $markup; }; @@ -837,14 +1069,19 @@ function make_before_block_visitor( $hooked_blocks, $context ) { * This function is meant for internal use only. * * @since 6.4.0 + * @since 6.5.0 Added $callback argument. * @access private * - * @param array $hooked_blocks An array of blocks hooked to another block. - * @param WP_Block_Template|array $context A block template, template part, or pattern that the blocks belong to. + * @param array $hooked_blocks An array of blocks hooked to another block. + * @param WP_Block_Template|WP_Post|array $context A block template, template part, `wp_navigation` post object, + * or pattern that the blocks belong to. + * @param callable $callback A function that will be called for each block to generate + * the markup for a given list of blocks that are hooked to it. + * Default: 'insert_hooked_blocks'. * @return callable A function that returns the serialized markup for the given block, * including the markup for any hooked blocks after it. */ -function make_after_block_visitor( $hooked_blocks, $context ) { +function make_after_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) { /** * Injects hooked blocks after the given block, and returns the serialized markup. * @@ -856,34 +1093,18 @@ function make_after_block_visitor( $hooked_blocks, $context ) { * @param array $next The next sibling block of the given block. Default null. * @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it. */ - return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context ) { - $markup = ''; - - $relative_position = 'after'; - $anchor_block_type = $block['blockName']; - $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) - ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] - : array(); - - /** This filter is documented in wp-includes/blocks.php */ - $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); - foreach ( $hooked_block_types as $hooked_block_type ) { - $markup .= get_comment_delimited_block_content( $hooked_block_type, array(), '' ); - } + return function ( &$block, &$parent_block = null, $next = null ) use ( $hooked_blocks, $context, $callback ) { + $markup = call_user_func_array( + $callback, + array( &$block, 'after', $hooked_blocks, $context ) + ); if ( $parent_block && ! $next ) { // Candidate for last-child insertion. - $relative_position = 'last_child'; - $anchor_block_type = $parent_block['blockName']; - $hooked_block_types = isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) - ? $hooked_blocks[ $anchor_block_type ][ $relative_position ] - : array(); - - /** This filter is documented in wp-includes/blocks.php */ - $hooked_block_types = apply_filters( 'hooked_block_types', $hooked_block_types, $relative_position, $anchor_block_type, $context ); - foreach ( $hooked_block_types as $hooked_block_type ) { - $markup .= get_comment_delimited_block_content( $hooked_block_type, array(), '' ); - } + $markup .= call_user_func_array( + $callback, + array( &$parent_block, 'last_child', $hooked_blocks, $context ) + ); } return $markup; @@ -1201,8 +1422,8 @@ function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols /** * Callback used for regular expression replacement in filter_block_content(). * - * @private * @since 6.2.1 + * @access private * * @param array $matches Array of preg_replace_callback matches. * @return string Replacement string. @@ -1576,6 +1797,7 @@ function block_version( $content ) { * @param array $style_properties Array containing the properties of the style name, label, * style_handle (name of the stylesheet to be enqueued), * inline_style (string containing the CSS to be added). + * See WP_Block_Styles_Registry::register(). * @return bool True if the block style was registered with success and false otherwise. */ function register_block_style( $block_name, $style_properties ) { @@ -1965,16 +2187,17 @@ function get_comments_pagination_arrow( $block, $pagination_type = 'next' ) { /** * Strips all HTML from the content of footnotes, and sanitizes the ID. + * * This function expects slashed data on the footnotes content. * * @access private * @since 6.3.2 * - * @param string $footnotes JSON encoded string of an array containing the content and ID of each footnote. - * @return string Filtered content without any HTML on the footnote content and with the sanitized id. + * @param string $footnotes JSON-encoded string of an array containing the content and ID of each footnote. + * @return string Filtered content without any HTML on the footnote content and with the sanitized ID. */ function _wp_filter_post_meta_footnotes( $footnotes ) { - $footnotes_decoded = json_decode( $footnotes, true ); + $footnotes_decoded = json_decode( $footnotes, true ); if ( ! is_array( $footnotes_decoded ) ) { return ''; } @@ -1991,7 +2214,7 @@ function _wp_filter_post_meta_footnotes( $footnotes ) { } /** - * Adds the filters to filter footnotes meta field. + * Adds the filters for footnotes meta field. * * @access private * @since 6.3.2 @@ -2001,7 +2224,7 @@ function _wp_footnotes_kses_init_filters() { } /** - * Removes the filters that filter footnotes meta field. + * Removes the filters for footnotes meta field. * * @access private * @since 6.3.2 @@ -2011,7 +2234,7 @@ function _wp_footnotes_remove_filters() { } /** - * Registers the filter of footnotes meta field if the user does not have unfiltered_html capability. + * Registers the filter of footnotes meta field if the user does not have `unfiltered_html` capability. * * @access private * @since 6.3.2 @@ -2024,12 +2247,12 @@ function _wp_footnotes_kses_init() { } /** - * Initializes footnotes meta field filters when imported data should be filtered. + * Initializes the filters for footnotes meta field when imported data should be filtered. * - * This filter is the last being executed on force_filtered_html_on_import. - * If the input of the filter is true it means we are in an import situation and should - * enable kses, independently of the user capabilities. - * So in that case we call _wp_footnotes_kses_init_filters; + * This filter is the last one being executed on {@see 'force_filtered_html_on_import'}. + * If the input of the filter is true, it means we are in an import situation and should + * enable kses, independently of the user capabilities. So in that case we call + * _wp_footnotes_kses_init_filters(). * * @access private * @since 6.3.2 @@ -2038,7 +2261,7 @@ function _wp_footnotes_kses_init() { * @return string Input argument of the filter. */ function _wp_footnotes_force_filtered_html_on_import_filter( $arg ) { - // force_filtered_html_on_import is true we need to init the global styles kses filters. + // If `force_filtered_html_on_import` is true, we need to init the global styles kses filters. if ( $arg ) { _wp_footnotes_kses_init_filters(); } |