2018-12-13 10:44:23 +01:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Functions related to registering and parsing blocks.
|
|
|
|
*
|
|
|
|
* @package WordPress
|
|
|
|
* @subpackage Blocks
|
|
|
|
* @since 5.0.0
|
|
|
|
*/
|
|
|
|
|
2020-06-23 17:45:11 +02:00
|
|
|
/**
|
|
|
|
* Removes the block asset's path prefix if provided.
|
|
|
|
*
|
|
|
|
* @since 5.5.0
|
|
|
|
*
|
|
|
|
* @param string $asset_handle_or_path Asset handle or prefixed path.
|
|
|
|
* @return string Path without the prefix or the original value.
|
|
|
|
*/
|
|
|
|
function remove_block_asset_path_prefix( $asset_handle_or_path ) {
|
|
|
|
$path_prefix = 'file:';
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( ! str_starts_with( $asset_handle_or_path, $path_prefix ) ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
return $asset_handle_or_path;
|
|
|
|
}
|
2022-02-11 13:14:04 +01:00
|
|
|
$path = substr(
|
2020-06-23 17:45:11 +02:00
|
|
|
$asset_handle_or_path,
|
|
|
|
strlen( $path_prefix )
|
|
|
|
);
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( str_starts_with( $path, './' ) ) {
|
2022-02-11 13:14:04 +01:00
|
|
|
$path = substr( $path, 2 );
|
|
|
|
}
|
|
|
|
return $path;
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Generates the name for an asset based on the name of the block
|
|
|
|
* and the field name provided.
|
|
|
|
*
|
|
|
|
* @since 5.5.0
|
2022-09-14 12:52:08 +02:00
|
|
|
* @since 6.1.0 Added `$index` parameter.
|
2024-02-08 11:41:13 +01:00
|
|
|
* @since 6.5.0 Added support for `viewScriptModule` field.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
|
|
|
* @param string $block_name Name of the block.
|
|
|
|
* @param string $field_name Name of the metadata field.
|
2022-09-14 12:52:08 +02:00
|
|
|
* @param int $index Optional. Index of the asset when multiple items passed.
|
|
|
|
* Default 0.
|
2020-06-23 17:45:11 +02:00
|
|
|
* @return string Generated asset name for the block's field.
|
|
|
|
*/
|
2022-09-14 12:52:08 +02:00
|
|
|
function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) {
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( str_starts_with( $block_name, 'core/' ) ) {
|
2020-12-21 12:39:08 +01:00
|
|
|
$asset_handle = str_replace( 'core/', 'wp-block-', $block_name );
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( str_starts_with( $field_name, 'editor' ) ) {
|
2020-12-21 12:39:08 +01:00
|
|
|
$asset_handle .= '-editor';
|
|
|
|
}
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( str_starts_with( $field_name, 'view' ) ) {
|
2021-07-28 12:06:59 +02:00
|
|
|
$asset_handle .= '-view';
|
|
|
|
}
|
2024-02-08 11:41:13 +01:00
|
|
|
if ( str_ends_with( strtolower( $field_name ), 'scriptmodule' ) ) {
|
|
|
|
$asset_handle .= '-script-module';
|
|
|
|
}
|
2022-09-14 12:52:08 +02:00
|
|
|
if ( $index > 0 ) {
|
|
|
|
$asset_handle .= '-' . ( $index + 1 );
|
|
|
|
}
|
2020-12-21 12:39:08 +01:00
|
|
|
return $asset_handle;
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:45:11 +02:00
|
|
|
$field_mappings = array(
|
2024-02-08 11:41:13 +01:00
|
|
|
'editorScript' => 'editor-script',
|
|
|
|
'editorStyle' => 'editor-style',
|
|
|
|
'script' => 'script',
|
|
|
|
'style' => 'style',
|
|
|
|
'viewScript' => 'view-script',
|
|
|
|
'viewScriptModule' => 'view-script-module',
|
|
|
|
'viewStyle' => 'view-style',
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
2022-09-14 12:52:08 +02:00
|
|
|
$asset_handle = str_replace( '/', '-', $block_name ) .
|
2020-06-23 17:45:11 +02:00
|
|
|
'-' . $field_mappings[ $field_name ];
|
2022-09-14 12:52:08 +02:00
|
|
|
if ( $index > 0 ) {
|
|
|
|
$asset_handle .= '-' . ( $index + 1 );
|
|
|
|
}
|
|
|
|
return $asset_handle;
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
/**
|
|
|
|
* Gets the URL to a block asset.
|
|
|
|
*
|
|
|
|
* @since 6.4.0
|
|
|
|
*
|
|
|
|
* @param string $path A normalized path to a block asset.
|
|
|
|
* @return string|false The URL to the block asset or false on failure.
|
|
|
|
*/
|
|
|
|
function get_block_asset_url( $path ) {
|
|
|
|
if ( empty( $path ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Path needs to be normalized to work in Windows env.
|
|
|
|
static $wpinc_path_norm = '';
|
|
|
|
if ( ! $wpinc_path_norm ) {
|
|
|
|
$wpinc_path_norm = wp_normalize_path( realpath( ABSPATH . WPINC ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( str_starts_with( $path, $wpinc_path_norm ) ) {
|
|
|
|
return includes_url( str_replace( $wpinc_path_norm, '', $path ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
static $template_paths_norm = array();
|
|
|
|
|
|
|
|
$template = get_template();
|
|
|
|
if ( ! isset( $template_paths_norm[ $template ] ) ) {
|
2024-02-21 10:38:12 +01:00
|
|
|
$template_paths_norm[ $template ] = wp_normalize_path( realpath( get_template_directory() ) );
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( str_starts_with( $path, trailingslashit( $template_paths_norm[ $template ] ) ) ) {
|
|
|
|
return get_theme_file_uri( str_replace( $template_paths_norm[ $template ], '', $path ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( is_child_theme() ) {
|
|
|
|
$stylesheet = get_stylesheet();
|
|
|
|
if ( ! isset( $template_paths_norm[ $stylesheet ] ) ) {
|
2024-02-21 10:38:12 +01:00
|
|
|
$template_paths_norm[ $stylesheet ] = wp_normalize_path( realpath( get_stylesheet_directory() ) );
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( str_starts_with( $path, trailingslashit( $template_paths_norm[ $stylesheet ] ) ) ) {
|
|
|
|
return get_theme_file_uri( str_replace( $template_paths_norm[ $stylesheet ], '', $path ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return plugins_url( basename( $path ), $path );
|
|
|
|
}
|
|
|
|
|
2024-02-08 11:41:13 +01:00
|
|
|
/**
|
|
|
|
* 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();
|
2024-02-21 12:20:10 +01:00
|
|
|
$block_version = isset( $metadata['version'] ) ? $metadata['version'] : false;
|
|
|
|
$module_version = isset( $module_asset['version'] ) ? $module_asset['version'] : $block_version;
|
2024-02-08 11:41:13 +01:00
|
|
|
|
|
|
|
wp_register_script_module(
|
|
|
|
$module_id,
|
|
|
|
$module_uri,
|
|
|
|
$module_dependencies,
|
2024-02-21 12:20:10 +01:00
|
|
|
$module_version
|
2024-02-08 11:41:13 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
return $module_id;
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:45:11 +02:00
|
|
|
/**
|
|
|
|
* Finds a script handle for the selected block metadata field. It detects
|
2024-02-08 09:18:10 +01:00
|
|
|
* when a path to file was provided and optionally finds a corresponding asset
|
|
|
|
* file with details necessary to register the script under automatically
|
2020-07-27 00:17:01 +02:00
|
|
|
* generated handle name. It returns unprocessed script handle otherwise.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
|
|
|
* @since 5.5.0
|
2022-09-14 12:52:08 +02:00
|
|
|
* @since 6.1.0 Added `$index` parameter.
|
2024-02-12 12:42:11 +01:00
|
|
|
* @since 6.5.0 The asset file is optional. Added script handle support in the asset file.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
|
|
|
* @param array $metadata Block metadata.
|
|
|
|
* @param string $field_name Field name to pick from metadata.
|
2022-09-14 12:52:08 +02:00
|
|
|
* @param int $index Optional. Index of the script to register when multiple items passed.
|
|
|
|
* Default 0.
|
2021-01-03 23:04:04 +01:00
|
|
|
* @return string|false Script handle provided directly or created through
|
|
|
|
* script's registration, or false on failure.
|
2020-06-23 17:45:11 +02:00
|
|
|
*/
|
2022-09-14 12:52:08 +02:00
|
|
|
function register_block_script_handle( $metadata, $field_name, $index = 0 ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
if ( empty( $metadata[ $field_name ] ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-09-14 12:52:08 +02:00
|
|
|
|
2024-02-12 12:42:11 +01:00
|
|
|
$script_handle_or_path = $metadata[ $field_name ];
|
|
|
|
if ( is_array( $script_handle_or_path ) ) {
|
|
|
|
if ( empty( $script_handle_or_path[ $index ] ) ) {
|
2022-09-14 12:52:08 +02:00
|
|
|
return false;
|
|
|
|
}
|
2024-02-12 12:42:11 +01:00
|
|
|
$script_handle_or_path = $script_handle_or_path[ $index ];
|
2022-09-14 12:52:08 +02:00
|
|
|
}
|
|
|
|
|
2024-02-12 12:42:11 +01:00
|
|
|
$script_path = remove_block_asset_path_prefix( $script_handle_or_path );
|
|
|
|
if ( $script_handle_or_path === $script_path ) {
|
|
|
|
return $script_handle_or_path;
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
$path = dirname( $metadata['file'] );
|
|
|
|
$script_asset_raw_path = $path . '/' . substr_replace( $script_path, '.asset.php', - strlen( '.js' ) );
|
2023-03-01 16:59:41 +01:00
|
|
|
$script_asset_path = wp_normalize_path(
|
|
|
|
realpath( $script_asset_raw_path )
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
2023-03-01 16:59:41 +01:00
|
|
|
|
2024-02-12 12:42:11 +01:00
|
|
|
// Asset file for blocks is optional. See https://core.trac.wordpress.org/ticket/60460.
|
2024-02-21 12:20:10 +01:00
|
|
|
$script_asset = ! empty( $script_asset_path ) ? require $script_asset_path : array();
|
2024-02-12 12:42:11 +01:00
|
|
|
$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;
|
|
|
|
}
|
2021-11-30 21:02:01 +01:00
|
|
|
|
2024-02-12 12:42:11 +01:00
|
|
|
$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();
|
Editor: Avoid Deferring Loading for Empty Block Script URI
In the context of register_block_script_handle, the get_block_asset_url function may return false when an empty string is provided as the input. This behavior is intended to prevent the generation of invalid URLs. However, when the script loading strategy is set to "defer" while passing false, it triggers a "doing it wrong" message.
This situation becomes problematic, especially for scenarios where the scripts haven't been built yet. In such cases, the realpath call returns an empty string because the file doesn't exist. To address this issue, we now perform a simple check to ensure that the script URI is not empty before applying the "defer" loading strategy. This adjustment prevents unnecessary deferral of loading for scripts with empty URIs.
Follow on from [56683] and [56033].
Props kebbet, mukesh27, swissspidy, westonruter, spacedmonkey.
Fixes #59475
Built from https://develop.svn.wordpress.org/trunk@56744
git-svn-id: http://core.svn.wordpress.org/trunk@56256 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-29 15:15:25 +02:00
|
|
|
if ( 'viewScript' === $field_name && $script_uri ) {
|
2023-08-17 18:39:18 +02:00
|
|
|
$script_args['strategy'] = 'defer';
|
|
|
|
}
|
|
|
|
|
2024-02-12 12:42:11 +01:00
|
|
|
$result = wp_register_script(
|
2020-06-23 17:45:11 +02:00
|
|
|
$script_handle,
|
2021-07-28 12:06:59 +02:00
|
|
|
$script_uri,
|
|
|
|
$script_dependencies,
|
2024-02-12 12:42:11 +01:00
|
|
|
$script_version,
|
2023-08-17 18:39:18 +02:00
|
|
|
$script_args
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
2021-01-19 12:06:14 +01:00
|
|
|
if ( ! $result ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-10-05 18:53:00 +02:00
|
|
|
if ( ! empty( $metadata['textdomain'] ) && in_array( 'wp-i18n', $script_dependencies, true ) ) {
|
2021-01-19 12:06:14 +01:00
|
|
|
wp_set_script_translations( $script_handle, $metadata['textdomain'] );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $script_handle;
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds a style handle for the block metadata field. It detects when a path
|
|
|
|
* to file was provided and registers the style under automatically
|
|
|
|
* generated handle name. It returns unprocessed style handle otherwise.
|
|
|
|
*
|
|
|
|
* @since 5.5.0
|
2022-09-14 12:52:08 +02:00
|
|
|
* @since 6.1.0 Added `$index` parameter.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
2021-03-13 12:15:04 +01:00
|
|
|
* @param array $metadata Block metadata.
|
2020-06-23 17:45:11 +02:00
|
|
|
* @param string $field_name Field name to pick from metadata.
|
2022-09-14 12:52:08 +02:00
|
|
|
* @param int $index Optional. Index of the style to register when multiple items passed.
|
|
|
|
* Default 0.
|
2021-01-03 23:04:04 +01:00
|
|
|
* @return string|false Style handle provided directly or created through
|
|
|
|
* style's registration, or false on failure.
|
2020-06-23 17:45:11 +02:00
|
|
|
*/
|
2022-09-14 12:52:08 +02:00
|
|
|
function register_block_style_handle( $metadata, $field_name, $index = 0 ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
if ( empty( $metadata[ $field_name ] ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
2022-09-14 12:52:08 +02:00
|
|
|
|
2023-06-26 23:17:22 +02:00
|
|
|
$style_handle = $metadata[ $field_name ];
|
|
|
|
if ( is_array( $style_handle ) ) {
|
|
|
|
if ( empty( $style_handle[ $index ] ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
$style_handle = $style_handle[ $index ];
|
|
|
|
}
|
|
|
|
|
|
|
|
$style_handle_name = generate_block_asset_handle( $metadata['name'], $field_name, $index );
|
|
|
|
// If the style handle is already registered, skip re-registering.
|
|
|
|
if ( wp_style_is( $style_handle_name, 'registered' ) ) {
|
|
|
|
return $style_handle_name;
|
|
|
|
}
|
|
|
|
|
Blocks: Avoid extra calls to `realpath()` in block scripts and styles registration.
This affects:
* `register_block_script_handle()`
* `register_block_style_handle()`
Both functions set a variable with this code:
{{{
$wpinc_path_norm = wp_normalize_path( realpath( ABSPATH . WPINC ) );
}}}
That value never changes during page load, so we can save it to a static variable. By doing so, we can avoid ~200 calls to `realpath()` and `wp_normalize_path()`, or even more if third-party plugins register scripts or styles.
Follow-up to [52291], [52939], [54290], [54291], [54309], [54327].
Props aristath, mukesh27, SergeyBiryukov.
Fixes #56758.
Built from https://develop.svn.wordpress.org/trunk@54415
git-svn-id: http://core.svn.wordpress.org/trunk@53974 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-10-07 17:46:12 +02:00
|
|
|
static $wpinc_path_norm = '';
|
|
|
|
if ( ! $wpinc_path_norm ) {
|
|
|
|
$wpinc_path_norm = wp_normalize_path( realpath( ABSPATH . WPINC ) );
|
|
|
|
}
|
Blocks: Remove extra `get_theme_file_path()` calls in `register_block_style_handle()`.
The `register_block_style_handle()` function runs ~200 times on each page load. Each time it runs, we call `get_theme_file_path()` and then run it through `wp_normalize_path()`.
`get_theme_file_path()` calls a few other functions: `get_stylesheet_directory()`, `get_stylesheet()`, `get_option()`, and there's a bunch of filters that run on each iteration of that, without ever changing.
By caching the value in a static variable, we can avoid ~200 calls on many functions and filters, improving performance.
Follow-up to [53091], [54290], [54291], [54309].
Props aristath, mukesh27.
Fixes #56666.
Built from https://develop.svn.wordpress.org/trunk@54327
git-svn-id: http://core.svn.wordpress.org/trunk@53886 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-27 17:11:14 +02:00
|
|
|
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
$is_core_block = isset( $metadata['file'] ) && str_starts_with( $metadata['file'], $wpinc_path_norm );
|
2022-09-14 12:52:08 +02:00
|
|
|
// Skip registering individual styles for each core block when a bundled version provided.
|
2021-05-17 16:28:04 +02:00
|
|
|
if ( $is_core_block && ! wp_should_load_separate_core_block_assets() ) {
|
2021-05-11 11:43:08 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-09-14 12:52:08 +02:00
|
|
|
$style_path = remove_block_asset_path_prefix( $style_handle );
|
|
|
|
$is_style_handle = $style_handle === $style_path;
|
|
|
|
// Allow only passing style handles for core blocks.
|
|
|
|
if ( $is_core_block && ! $is_style_handle ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// Return the style handle unless it's the first item for every core block that requires special treatment.
|
|
|
|
if ( $is_style_handle && ! ( $is_core_block && 0 === $index ) ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
return $style_handle;
|
|
|
|
}
|
|
|
|
|
2022-09-14 12:52:08 +02:00
|
|
|
// Check whether styles should have a ".min" suffix or not.
|
2022-09-27 09:40:11 +02:00
|
|
|
$suffix = SCRIPT_DEBUG ? '' : '.min';
|
2021-05-11 11:43:08 +02:00
|
|
|
if ( $is_core_block ) {
|
2023-06-23 21:01:24 +02:00
|
|
|
$style_path = ( 'editorStyle' === $field_name ) ? "editor{$suffix}.css" : "style{$suffix}.css";
|
2021-05-11 11:43:08 +02:00
|
|
|
}
|
Blocks: Remove extra `get_theme_file_path()` calls in `register_block_style_handle()`.
The `register_block_style_handle()` function runs ~200 times on each page load. Each time it runs, we call `get_theme_file_path()` and then run it through `wp_normalize_path()`.
`get_theme_file_path()` calls a few other functions: `get_stylesheet_directory()`, `get_stylesheet()`, `get_option()`, and there's a bunch of filters that run on each iteration of that, without ever changing.
By caching the value in a static variable, we can avoid ~200 calls on many functions and filters, improving performance.
Follow-up to [53091], [54290], [54291], [54309].
Props aristath, mukesh27.
Fixes #56666.
Built from https://develop.svn.wordpress.org/trunk@54327
git-svn-id: http://core.svn.wordpress.org/trunk@53886 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-27 17:11:14 +02:00
|
|
|
|
2022-04-07 13:59:05 +02:00
|
|
|
$style_path_norm = wp_normalize_path( realpath( dirname( $metadata['file'] ) . '/' . $style_path ) );
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
$style_uri = get_block_asset_url( $style_path_norm );
|
2022-04-07 13:59:05 +02:00
|
|
|
|
2023-06-26 23:17:22 +02:00
|
|
|
$version = ! $is_core_block && isset( $metadata['version'] ) ? $metadata['version'] : false;
|
|
|
|
$result = wp_register_style(
|
|
|
|
$style_handle_name,
|
2021-05-11 11:43:08 +02:00
|
|
|
$style_uri,
|
2020-06-23 17:45:11 +02:00
|
|
|
array(),
|
2021-05-11 11:43:08 +02:00
|
|
|
$version
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
2022-09-27 09:40:11 +02:00
|
|
|
if ( ! $result ) {
|
|
|
|
return false;
|
2021-01-19 12:50:08 +01:00
|
|
|
}
|
2022-09-27 09:40:11 +02:00
|
|
|
|
Editor: Introduce get_block_asset_url Utility Function.
This commit introduces a valuable utility function, get_block_asset_url, designed to simplify the retrieval of block asset URLs, such as those for CSS and JavaScript files. This utility eliminates redundancy in both register_block_script_handle and register_block_style_handle. Additionally, `get_block_asset_url` incorporates an early exit mechanism to optimize performance.
This update includes comprehensive unit tests, covering various scenarios, including asset registration from core (wp-includes), themes, child themes, plugins, and mu-plugins.
Props spacedmonkey, joemcgill, flixos90, gziolo.
Fixes #58525.
Built from https://develop.svn.wordpress.org/trunk@56683
git-svn-id: http://core.svn.wordpress.org/trunk@56195 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 19:49:19 +02:00
|
|
|
if ( $style_uri ) {
|
2023-06-26 23:17:22 +02:00
|
|
|
wp_style_add_data( $style_handle_name, 'path', $style_path_norm );
|
2021-05-11 11:43:08 +02:00
|
|
|
|
2023-03-14 17:00:19 +01:00
|
|
|
if ( $is_core_block ) {
|
|
|
|
$rtl_file = str_replace( "{$suffix}.css", "-rtl{$suffix}.css", $style_path_norm );
|
|
|
|
} else {
|
2023-03-14 17:26:18 +01:00
|
|
|
$rtl_file = str_replace( '.css', '-rtl.css', $style_path_norm );
|
2023-03-14 17:00:19 +01:00
|
|
|
}
|
Editor: Correctly load RTL stylesheets in `register_block_style_handle()`.
When setting an RTL language under Settings → General, some RTL stylesheets were not loaded, with LTR stylesheets being loaded instead, meaning that some blocks were not displayed correctly.
This commit ensures that all appropriate RTL stylesheets are loaded when selecting an RTL language.
Additionally, this commit improves performance by only running a `file_exists()` check for an RTL stylesheet if `is_rtl()` returns true, i.e. an RTL locale is selected.
Follow-up to [49982], [50836].
Props zoonini, sabernhardt, maahrokh, ankit-k-gupta, aristath, poena, SergeyBiryukov.
See #56325.
Built from https://develop.svn.wordpress.org/trunk@54330
git-svn-id: http://core.svn.wordpress.org/trunk@53889 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-27 17:43:09 +02:00
|
|
|
|
2022-09-27 09:40:11 +02:00
|
|
|
if ( is_rtl() && file_exists( $rtl_file ) ) {
|
2023-06-26 23:17:22 +02:00
|
|
|
wp_style_add_data( $style_handle_name, 'rtl', 'replace' );
|
|
|
|
wp_style_add_data( $style_handle_name, 'suffix', $suffix );
|
|
|
|
wp_style_add_data( $style_handle_name, 'path', $rtl_file );
|
2022-09-27 09:40:11 +02:00
|
|
|
}
|
2021-05-11 11:43:08 +02:00
|
|
|
}
|
2021-01-19 12:50:08 +01:00
|
|
|
|
2023-06-26 23:17:22 +02:00
|
|
|
return $style_handle_name;
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
2021-08-11 11:08:01 +02:00
|
|
|
/**
|
|
|
|
* Gets i18n schema for block's metadata read from `block.json` file.
|
|
|
|
*
|
|
|
|
* @since 5.9.0
|
|
|
|
*
|
2022-02-24 09:27:09 +01:00
|
|
|
* @return object The schema for block's metadata.
|
2021-08-11 11:08:01 +02:00
|
|
|
*/
|
|
|
|
function get_block_metadata_i18n_schema() {
|
|
|
|
static $i18n_block_schema;
|
|
|
|
|
|
|
|
if ( ! isset( $i18n_block_schema ) ) {
|
|
|
|
$i18n_block_schema = wp_json_file_decode( __DIR__ . '/block-i18n.json' );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $i18n_block_schema;
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:45:11 +02:00
|
|
|
/**
|
2021-05-19 15:52:00 +02:00
|
|
|
* Registers a block type from the metadata stored in the `block.json` file.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
|
|
|
* @since 5.5.0
|
2021-08-11 11:08:01 +02:00
|
|
|
* @since 5.7.0 Added support for `textdomain` field and i18n handling for all translatable fields.
|
|
|
|
* @since 5.9.0 Added support for `variations` and `viewScript` fields.
|
2022-09-12 15:14:13 +02:00
|
|
|
* @since 6.1.0 Added support for `render` field.
|
2023-04-21 12:43:25 +02:00
|
|
|
* @since 6.3.0 Added `selectors` field.
|
2023-09-14 15:25:18 +02:00
|
|
|
* @since 6.4.0 Added support for `blockHooks` field.
|
2024-02-08 11:41:13 +01:00
|
|
|
* @since 6.5.0 Added support for `allowedBlocks`, `viewScriptModule`, and `viewStyle` fields.
|
2024-07-24 16:11:08 +02:00
|
|
|
* @since 6.7.0 Allow PHP filename as `variations` argument.
|
2020-06-23 17:45:11 +02:00
|
|
|
*
|
|
|
|
* @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.
|
2021-11-04 17:03:57 +01:00
|
|
|
* If providing the path to a JSON file, the filename must end with `block.json`.
|
2021-02-23 20:18:02 +01:00
|
|
|
* @param array $args Optional. Array of block type arguments. Accepts any public property
|
|
|
|
* of `WP_Block_Type`. See WP_Block_Type::__construct() for information
|
|
|
|
* on accepted arguments. Default empty array.
|
2020-06-23 17:45:11 +02:00
|
|
|
* @return WP_Block_Type|false The registered block type on success, or false on failure.
|
|
|
|
*/
|
|
|
|
function register_block_type_from_metadata( $file_or_folder, $args = array() ) {
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
/*
|
|
|
|
* Get an array of metadata from a PHP file.
|
|
|
|
* This improves performance for core blocks as it's only necessary to read a single PHP file
|
|
|
|
* instead of reading a JSON file per-block, and then decoding from JSON to PHP.
|
|
|
|
* Using a static variable ensures that the metadata is only read once per request.
|
|
|
|
*/
|
|
|
|
static $core_blocks_meta;
|
|
|
|
if ( ! $core_blocks_meta ) {
|
2023-06-26 23:17:22 +02:00
|
|
|
$core_blocks_meta = require ABSPATH . WPINC . '/blocks/blocks-json.php';
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$metadata_file = ( ! str_ends_with( $file_or_folder, 'block.json' ) ) ?
|
|
|
|
trailingslashit( $file_or_folder ) . 'block.json' :
|
2020-06-23 17:45:11 +02:00
|
|
|
$file_or_folder;
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
|
2023-06-13 13:46:27 +02:00
|
|
|
$is_core_block = str_starts_with( $file_or_folder, ABSPATH . WPINC );
|
2023-10-28 03:02:26 +02:00
|
|
|
// 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'] ) ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
// Try to get metadata from the static cache for core blocks.
|
2023-10-28 03:02:26 +02:00
|
|
|
$metadata = array();
|
2023-06-13 13:46:27 +02:00
|
|
|
if ( $is_core_block ) {
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
$core_block_name = str_replace( ABSPATH . WPINC . '/blocks/', '', $file_or_folder );
|
|
|
|
if ( ! empty( $core_blocks_meta[ $core_block_name ] ) ) {
|
|
|
|
$metadata = $core_blocks_meta[ $core_block_name ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If metadata is not found in the static cache, read it from the file.
|
2023-10-28 03:02:26 +02:00
|
|
|
if ( $metadata_file_exists && empty( $metadata ) ) {
|
Editor: Improve block loading PHP performance.
This commit improves PHP performance for core blocks by reading a single PHP file with block metadata, instead of reading a JSON file per-block and then decoding from JSON to PHP.
Includes:
* Adding a new Grunt task to convert `block.json` files to `block-json.php`.
* Using the new `block-json.php` file in the `register_block_type_from_metadata()` function.
Follow-up to [48141].
Props aristath, gziolo, johnbillion, presstoke, mukesh27, hellofromTonya, petitphp, adamsilverstein, costdev, desrosj, SergeyBiryukov.
Fixes #55005.
Built from https://develop.svn.wordpress.org/trunk@54276
git-svn-id: http://core.svn.wordpress.org/trunk@53835 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2022-09-21 15:57:21 +02:00
|
|
|
$metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) );
|
|
|
|
}
|
|
|
|
|
2023-10-28 03:02:26 +02:00
|
|
|
if ( ! is_array( $metadata ) || ( empty( $metadata['name'] ) && empty( $args['name'] ) ) ) {
|
2020-06-23 17:45:11 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-28 03:02:26 +02:00
|
|
|
|
|
|
|
$metadata['file'] = $metadata_file_exists ? wp_normalize_path( realpath( $metadata_file ) ) : null;
|
2020-06-23 17:45:11 +02:00
|
|
|
|
2021-01-08 17:45:07 +01:00
|
|
|
/**
|
|
|
|
* Filters the metadata provided for registering a block type.
|
|
|
|
*
|
|
|
|
* @since 5.7.0
|
|
|
|
*
|
|
|
|
* @param array $metadata Metadata for registering a block type.
|
|
|
|
*/
|
|
|
|
$metadata = apply_filters( 'block_type_metadata', $metadata );
|
|
|
|
|
2021-06-30 19:20:58 +02:00
|
|
|
// Add `style` and `editor_style` for core blocks if missing.
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( ! empty( $metadata['name'] ) && str_starts_with( $metadata['name'], 'core/' ) ) {
|
2021-06-08 19:36:58 +02:00
|
|
|
$block_name = str_replace( 'core/', '', $metadata['name'] );
|
|
|
|
|
|
|
|
if ( ! isset( $metadata['style'] ) ) {
|
|
|
|
$metadata['style'] = "wp-block-$block_name";
|
|
|
|
}
|
Script Loader: Fix performance issues in `wp_common_block_scripts_and_styles`.
In [52069] the function `wp_common_block_scripts_and_styles` was changed load individual theme stylesheets, if the current theme supports block styles and loading separate core block assets. To do this, the function calls many expensive file operation functions, such as `glob`, `file_exists` and `file_get_contents`. This is wasteful, as these functions are loaded on every page request, even request that do not include blocks, like REST API calls. In [56044] all core block styles are registered in a single place. In `register_core_block_style_handles` calls `glob` to get all css styles in block directories. While registering style and editor styles, also register block theme styles, under a new style handle. Example `wp-block-avatar-theme`. If the current theme supports block styles, also request the block to enqueue the theme style on the front end. As these new stylesheets have a path attribute set, the function `wp_maybe_inline_styles` will automatically inline the styles for you.
Props spacedmonkey, flixos90, oandregal, costdev, audrasjb, mukesh27.
Fixes #58560.
Built from https://develop.svn.wordpress.org/trunk@56064
git-svn-id: http://core.svn.wordpress.org/trunk@55576 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-06-27 13:28:28 +02:00
|
|
|
if ( current_theme_supports( 'wp-block-styles' ) && wp_should_load_separate_core_block_assets() ) {
|
|
|
|
$metadata['style'] = (array) $metadata['style'];
|
|
|
|
$metadata['style'][] = "wp-block-{$block_name}-theme";
|
|
|
|
}
|
2021-06-29 02:08:57 +02:00
|
|
|
if ( ! isset( $metadata['editorStyle'] ) ) {
|
|
|
|
$metadata['editorStyle'] = "wp-block-{$block_name}-editor";
|
2021-06-08 19:36:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-23 17:45:11 +02:00
|
|
|
$settings = array();
|
|
|
|
$property_mappings = array(
|
2021-08-11 11:08:01 +02:00
|
|
|
'apiVersion' => 'api_version',
|
2023-10-28 03:02:26 +02:00
|
|
|
'name' => 'name',
|
2020-06-23 17:45:11 +02:00
|
|
|
'title' => 'title',
|
|
|
|
'category' => 'category',
|
|
|
|
'parent' => 'parent',
|
2022-07-19 15:24:12 +02:00
|
|
|
'ancestor' => 'ancestor',
|
2020-06-23 17:45:11 +02:00
|
|
|
'icon' => 'icon',
|
|
|
|
'description' => 'description',
|
|
|
|
'keywords' => 'keywords',
|
|
|
|
'attributes' => 'attributes',
|
|
|
|
'providesContext' => 'provides_context',
|
|
|
|
'usesContext' => 'uses_context',
|
2023-04-21 12:43:25 +02:00
|
|
|
'selectors' => 'selectors',
|
2020-06-23 17:45:11 +02:00
|
|
|
'supports' => 'supports',
|
|
|
|
'styles' => 'styles',
|
2021-08-11 11:08:01 +02:00
|
|
|
'variations' => 'variations',
|
2020-06-23 17:45:11 +02:00
|
|
|
'example' => 'example',
|
2024-02-02 14:01:21 +01:00
|
|
|
'allowedBlocks' => 'allowed_blocks',
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
2021-08-11 11:08:01 +02:00
|
|
|
$textdomain = ! empty( $metadata['textdomain'] ) ? $metadata['textdomain'] : null;
|
|
|
|
$i18n_schema = get_block_metadata_i18n_schema();
|
2020-06-23 17:45:11 +02:00
|
|
|
|
|
|
|
foreach ( $property_mappings as $key => $mapped_key ) {
|
|
|
|
if ( isset( $metadata[ $key ] ) ) {
|
2021-08-11 11:08:01 +02:00
|
|
|
$settings[ $mapped_key ] = $metadata[ $key ];
|
2023-10-28 03:02:26 +02:00
|
|
|
if ( $metadata_file_exists && $textdomain && isset( $i18n_schema->$key ) ) {
|
2021-08-11 11:08:01 +02:00
|
|
|
$settings[ $mapped_key ] = translate_settings_using_i18n_schema( $i18n_schema->$key, $settings[ $key ], $textdomain );
|
2021-01-19 12:06:14 +01:00
|
|
|
}
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-28 03:02:26 +02:00
|
|
|
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();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-07-24 16:11:08 +02:00
|
|
|
// If `variations` is a string, it's the name of a PHP file that
|
|
|
|
// generates the variations.
|
|
|
|
if ( ! empty( $metadata['variations'] ) && is_string( $metadata['variations'] ) ) {
|
|
|
|
$variations_path = wp_normalize_path(
|
|
|
|
realpath(
|
|
|
|
dirname( $metadata['file'] ) . '/' .
|
|
|
|
remove_block_asset_path_prefix( $metadata['variations'] )
|
|
|
|
)
|
|
|
|
);
|
|
|
|
if ( $variations_path ) {
|
|
|
|
/**
|
|
|
|
* Generates the list of block variations.
|
|
|
|
*
|
|
|
|
* @since 6.7.0
|
|
|
|
*
|
|
|
|
* @return string Returns the list of block variations.
|
|
|
|
*/
|
|
|
|
$settings['variation_callback'] = static function () use ( $variations_path ) {
|
|
|
|
$variations = require $variations_path;
|
|
|
|
return $variations;
|
|
|
|
};
|
|
|
|
// The block instance's `variations` field is only allowed to be an array
|
|
|
|
// (of known block variations). We unset it so that the block instance will
|
|
|
|
// provide a getter that returns the result of the `variation_callback` instead.
|
|
|
|
unset( $settings['variations'] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-28 03:02:26 +02:00
|
|
|
$settings = array_merge( $settings, $args );
|
|
|
|
|
2022-09-14 12:52:08 +02:00
|
|
|
$script_fields = array(
|
|
|
|
'editorScript' => 'editor_script_handles',
|
|
|
|
'script' => 'script_handles',
|
|
|
|
'viewScript' => 'view_script_handles',
|
|
|
|
);
|
|
|
|
foreach ( $script_fields as $metadata_field_name => $settings_field_name ) {
|
2023-10-28 03:02:26 +02:00
|
|
|
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
|
|
|
|
$metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ];
|
|
|
|
}
|
2022-09-14 12:52:08 +02:00
|
|
|
if ( ! empty( $metadata[ $metadata_field_name ] ) ) {
|
|
|
|
$scripts = $metadata[ $metadata_field_name ];
|
|
|
|
$processed_scripts = array();
|
|
|
|
if ( is_array( $scripts ) ) {
|
|
|
|
for ( $index = 0; $index < count( $scripts ); $index++ ) {
|
|
|
|
$result = register_block_script_handle(
|
|
|
|
$metadata,
|
|
|
|
$metadata_field_name,
|
|
|
|
$index
|
|
|
|
);
|
|
|
|
if ( $result ) {
|
|
|
|
$processed_scripts[] = $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$result = register_block_script_handle(
|
|
|
|
$metadata,
|
|
|
|
$metadata_field_name
|
|
|
|
);
|
|
|
|
if ( $result ) {
|
|
|
|
$processed_scripts[] = $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$settings[ $settings_field_name ] = $processed_scripts;
|
|
|
|
}
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
2024-02-08 11:41:13 +01:00
|
|
|
$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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-14 12:52:08 +02:00
|
|
|
$style_fields = array(
|
|
|
|
'editorStyle' => 'editor_style_handles',
|
|
|
|
'style' => 'style_handles',
|
2024-01-31 10:11:17 +01:00
|
|
|
'viewStyle' => 'view_style_handles',
|
2022-09-14 12:52:08 +02:00
|
|
|
);
|
|
|
|
foreach ( $style_fields as $metadata_field_name => $settings_field_name ) {
|
2023-10-28 03:02:26 +02:00
|
|
|
if ( ! empty( $settings[ $metadata_field_name ] ) ) {
|
|
|
|
$metadata[ $metadata_field_name ] = $settings[ $metadata_field_name ];
|
|
|
|
}
|
2022-09-14 12:52:08 +02:00
|
|
|
if ( ! empty( $metadata[ $metadata_field_name ] ) ) {
|
|
|
|
$styles = $metadata[ $metadata_field_name ];
|
|
|
|
$processed_styles = array();
|
|
|
|
if ( is_array( $styles ) ) {
|
|
|
|
for ( $index = 0; $index < count( $styles ); $index++ ) {
|
|
|
|
$result = register_block_style_handle(
|
|
|
|
$metadata,
|
|
|
|
$metadata_field_name,
|
|
|
|
$index
|
|
|
|
);
|
|
|
|
if ( $result ) {
|
|
|
|
$processed_styles[] = $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
$result = register_block_style_handle(
|
|
|
|
$metadata,
|
|
|
|
$metadata_field_name
|
|
|
|
);
|
|
|
|
if ( $result ) {
|
|
|
|
$processed_styles[] = $result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$settings[ $settings_field_name ] = $processed_styles;
|
|
|
|
}
|
2020-06-23 17:45:11 +02:00
|
|
|
}
|
|
|
|
|
2023-09-14 15:25:18 +02:00
|
|
|
if ( ! empty( $metadata['blockHooks'] ) ) {
|
|
|
|
/**
|
|
|
|
* Map camelCased position string (from block.json) to snake_cased block type position.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
$position_mappings = array(
|
|
|
|
'before' => 'before',
|
|
|
|
'after' => 'after',
|
|
|
|
'firstChild' => 'first_child',
|
|
|
|
'lastChild' => 'last_child',
|
|
|
|
);
|
|
|
|
|
|
|
|
$settings['block_hooks'] = array();
|
|
|
|
foreach ( $metadata['blockHooks'] as $anchor_block_name => $position ) {
|
|
|
|
// Avoid infinite recursion (hooking to itself).
|
|
|
|
if ( $metadata['name'] === $anchor_block_name ) {
|
|
|
|
_doing_it_wrong(
|
|
|
|
__METHOD__,
|
2023-09-15 09:51:19 +02:00
|
|
|
__( 'Cannot hook block to itself.' ),
|
2023-09-14 15:25:18 +02:00
|
|
|
'6.4.0'
|
|
|
|
);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! isset( $position_mappings[ $position ] ) ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$settings['block_hooks'][ $anchor_block_name ] = $position_mappings[ $position ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-08 17:45:07 +01:00
|
|
|
/**
|
|
|
|
* Filters the settings determined from the block type metadata.
|
|
|
|
*
|
|
|
|
* @since 5.7.0
|
|
|
|
*
|
|
|
|
* @param array $settings Array of determined settings for registering a block type.
|
|
|
|
* @param array $metadata Metadata provided for registering a block type.
|
|
|
|
*/
|
2023-10-28 03:02:26 +02:00
|
|
|
$settings = apply_filters( 'block_type_metadata_settings', $settings, $metadata );
|
|
|
|
|
|
|
|
$metadata['name'] = ! empty( $settings['name'] ) ? $settings['name'] : $metadata['name'];
|
2021-01-08 17:45:07 +01:00
|
|
|
|
2021-05-19 15:52:00 +02:00
|
|
|
return WP_Block_Type_Registry::get_instance()->register(
|
2021-01-08 17:45:07 +01:00
|
|
|
$metadata['name'],
|
|
|
|
$settings
|
2020-06-23 17:45:11 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-05-19 15:52:00 +02:00
|
|
|
/**
|
|
|
|
* Registers a block type. The recommended way is to register a block type using
|
|
|
|
* the metadata stored in the `block.json` file.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
2021-07-22 18:54:58 +02:00
|
|
|
* @since 5.8.0 First parameter now accepts a path to the `block.json` file.
|
2021-05-19 15:52:00 +02:00
|
|
|
*
|
|
|
|
* @param string|WP_Block_Type $block_type Block type name including namespace, or alternatively
|
|
|
|
* a path to the JSON file with metadata definition for the block,
|
|
|
|
* or a path to the folder where the `block.json` file is located,
|
|
|
|
* or a complete WP_Block_Type instance.
|
|
|
|
* In case a WP_Block_Type is provided, the $args parameter will be ignored.
|
|
|
|
* @param array $args Optional. Array of block type arguments. Accepts any public property
|
|
|
|
* of `WP_Block_Type`. See WP_Block_Type::__construct() for information
|
|
|
|
* on accepted arguments. Default empty array.
|
|
|
|
*
|
|
|
|
* @return WP_Block_Type|false The registered block type on success, or false on failure.
|
|
|
|
*/
|
|
|
|
function register_block_type( $block_type, $args = array() ) {
|
|
|
|
if ( is_string( $block_type ) && file_exists( $block_type ) ) {
|
|
|
|
return register_block_type_from_metadata( $block_type, $args );
|
|
|
|
}
|
|
|
|
|
|
|
|
return WP_Block_Type_Registry::get_instance()->register( $block_type, $args );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregisters a block type.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
|
|
|
* @param string|WP_Block_Type $name Block type name including namespace, or alternatively
|
|
|
|
* a complete WP_Block_Type instance.
|
|
|
|
* @return WP_Block_Type|false The unregistered block type on success, or false on failure.
|
|
|
|
*/
|
|
|
|
function unregister_block_type( $name ) {
|
|
|
|
return WP_Block_Type_Registry::get_instance()->unregister( $name );
|
|
|
|
}
|
|
|
|
|
2018-12-13 10:44:23 +01:00
|
|
|
/**
|
2022-04-20 16:09:11 +02:00
|
|
|
* Determines whether a post or content string has blocks.
|
2018-12-13 10:44:23 +01:00
|
|
|
*
|
|
|
|
* This test optimizes for performance rather than strict accuracy, detecting
|
|
|
|
* the pattern of a block but not validating its structure. For strict accuracy,
|
|
|
|
* you should use the block parser on post content.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
2020-06-16 23:07:14 +02:00
|
|
|
*
|
2018-12-13 10:44:23 +01:00
|
|
|
* @see parse_blocks()
|
|
|
|
*
|
2021-05-29 20:43:00 +02:00
|
|
|
* @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object.
|
|
|
|
* Defaults to global $post.
|
2018-12-13 10:44:23 +01:00
|
|
|
* @return bool Whether the post has blocks.
|
|
|
|
*/
|
|
|
|
function has_blocks( $post = null ) {
|
|
|
|
if ( ! is_string( $post ) ) {
|
|
|
|
$wp_post = get_post( $post );
|
2022-08-08 10:22:12 +02:00
|
|
|
|
|
|
|
if ( ! $wp_post instanceof WP_Post ) {
|
|
|
|
return false;
|
2018-12-13 10:44:23 +01:00
|
|
|
}
|
2022-08-08 10:22:12 +02:00
|
|
|
|
|
|
|
$post = $wp_post->post_content;
|
2018-12-13 10:44:23 +01:00
|
|
|
}
|
|
|
|
|
Code Modernization: Replace usage of `strpos()` with `str_contains()`.
`str_contains()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) contains the given substring (needle).
WordPress core includes a polyfill for `str_contains()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `false !== strpos( ... )` with `str_contains()` in core files, making the code more readable and consistent, as well as better aligned with modern development practices.
Follow-up to [52039], [52040], [52326], [55703], [55710], [55987].
Props Soean, spacedmonkey, costdev, dingo_d, azaozz, mikeschroder, flixos90, peterwilsoncc, SergeyBiryukov.
Fixes #58206.
Built from https://develop.svn.wordpress.org/trunk@55988
git-svn-id: http://core.svn.wordpress.org/trunk@55500 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-06-22 16:36:26 +02:00
|
|
|
return str_contains( (string) $post, '<!-- wp:' );
|
2018-12-13 10:44:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-04-20 16:09:11 +02:00
|
|
|
* Determines whether a $post or a string contains a specific block type.
|
2018-12-13 10:44:23 +01:00
|
|
|
*
|
|
|
|
* This test optimizes for performance rather than strict accuracy, detecting
|
2021-05-29 20:43:00 +02:00
|
|
|
* whether the block type exists but not validating its structure and not checking
|
2023-10-31 13:58:23 +01:00
|
|
|
* synced patterns (formerly called reusable blocks). For strict accuracy,
|
|
|
|
* you should use the block parser on post content.
|
2018-12-13 10:44:23 +01:00
|
|
|
*
|
|
|
|
* @since 5.0.0
|
2020-06-16 23:07:14 +02:00
|
|
|
*
|
2018-12-13 10:44:23 +01:00
|
|
|
* @see parse_blocks()
|
|
|
|
*
|
2021-05-29 20:43:00 +02:00
|
|
|
* @param string $block_name Full block type to look for.
|
|
|
|
* @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object.
|
|
|
|
* Defaults to global $post.
|
2018-12-13 10:44:23 +01:00
|
|
|
* @return bool Whether the post content contains the specified block.
|
|
|
|
*/
|
2019-12-12 19:02:03 +01:00
|
|
|
function has_block( $block_name, $post = null ) {
|
2018-12-13 10:44:23 +01:00
|
|
|
if ( ! has_blocks( $post ) ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! is_string( $post ) ) {
|
|
|
|
$wp_post = get_post( $post );
|
|
|
|
if ( $wp_post instanceof WP_Post ) {
|
|
|
|
$post = $wp_post->post_content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-12 19:02:03 +01:00
|
|
|
/*
|
|
|
|
* Normalize block name to include namespace, if provided as non-namespaced.
|
|
|
|
* This matches behavior for WordPress 5.0.0 - 5.3.0 in matching blocks by
|
|
|
|
* their serialized names.
|
|
|
|
*/
|
Code Modernization: Replace usage of `strpos()` with `str_contains()`.
`str_contains()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) contains the given substring (needle).
WordPress core includes a polyfill for `str_contains()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `false !== strpos( ... )` with `str_contains()` in core files, making the code more readable and consistent, as well as better aligned with modern development practices.
Follow-up to [52039], [52040], [52326], [55703], [55710], [55987].
Props Soean, spacedmonkey, costdev, dingo_d, azaozz, mikeschroder, flixos90, peterwilsoncc, SergeyBiryukov.
Fixes #58206.
Built from https://develop.svn.wordpress.org/trunk@55988
git-svn-id: http://core.svn.wordpress.org/trunk@55500 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-06-22 16:36:26 +02:00
|
|
|
if ( ! str_contains( $block_name, '/' ) ) {
|
2019-12-12 19:02:03 +01:00
|
|
|
$block_name = 'core/' . $block_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Test for existence of block by its fully qualified name.
|
Code Modernization: Replace usage of `strpos()` with `str_contains()`.
`str_contains()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) contains the given substring (needle).
WordPress core includes a polyfill for `str_contains()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `false !== strpos( ... )` with `str_contains()` in core files, making the code more readable and consistent, as well as better aligned with modern development practices.
Follow-up to [52039], [52040], [52326], [55703], [55710], [55987].
Props Soean, spacedmonkey, costdev, dingo_d, azaozz, mikeschroder, flixos90, peterwilsoncc, SergeyBiryukov.
Fixes #58206.
Built from https://develop.svn.wordpress.org/trunk@55988
git-svn-id: http://core.svn.wordpress.org/trunk@55500 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-06-22 16:36:26 +02:00
|
|
|
$has_block = str_contains( $post, '<!-- wp:' . $block_name . ' ' );
|
2019-12-12 19:02:03 +01:00
|
|
|
|
|
|
|
if ( ! $has_block ) {
|
|
|
|
/*
|
|
|
|
* If the given block name would serialize to a different name, test for
|
|
|
|
* existence by the serialized form.
|
|
|
|
*/
|
|
|
|
$serialized_block_name = strip_core_block_namespace( $block_name );
|
|
|
|
if ( $serialized_block_name !== $block_name ) {
|
Code Modernization: Replace usage of `strpos()` with `str_contains()`.
`str_contains()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) contains the given substring (needle).
WordPress core includes a polyfill for `str_contains()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `false !== strpos( ... )` with `str_contains()` in core files, making the code more readable and consistent, as well as better aligned with modern development practices.
Follow-up to [52039], [52040], [52326], [55703], [55710], [55987].
Props Soean, spacedmonkey, costdev, dingo_d, azaozz, mikeschroder, flixos90, peterwilsoncc, SergeyBiryukov.
Fixes #58206.
Built from https://develop.svn.wordpress.org/trunk@55988
git-svn-id: http://core.svn.wordpress.org/trunk@55500 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-06-22 16:36:26 +02:00
|
|
|
$has_block = str_contains( $post, '<!-- wp:' . $serialized_block_name . ' ' );
|
2019-12-12 19:02:03 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $has_block;
|
2018-12-13 10:44:23 +01:00
|
|
|
}
|
2018-12-13 10:54:25 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an array of the names of all registered dynamic block types.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2019-11-05 22:30:03 +01:00
|
|
|
* @return string[] Array of dynamic block names.
|
2018-12-13 10:54:25 +01:00
|
|
|
*/
|
|
|
|
function get_dynamic_block_names() {
|
|
|
|
$dynamic_block_names = array();
|
|
|
|
|
|
|
|
$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
|
|
|
|
foreach ( $block_types as $block_type ) {
|
|
|
|
if ( $block_type->is_dynamic() ) {
|
|
|
|
$dynamic_block_names[] = $block_type->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $dynamic_block_names;
|
|
|
|
}
|
2018-12-13 18:40:39 +01:00
|
|
|
|
2023-09-18 14:43:13 +02:00
|
|
|
/**
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
* Retrieves block types hooked into the given block, grouped by anchor block type and the relative position.
|
2023-09-18 14:43:13 +02:00
|
|
|
*
|
|
|
|
* @since 6.4.0
|
|
|
|
*
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
* @return array[] Array of block types grouped by anchor block type and the relative position.
|
2023-09-18 14:43:13 +02:00
|
|
|
*/
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
function get_hooked_blocks() {
|
2023-09-25 13:48:17 +02:00
|
|
|
$block_types = WP_Block_Type_Registry::get_instance()->get_all_registered();
|
2023-09-18 14:43:13 +02:00
|
|
|
$hooked_blocks = array();
|
|
|
|
foreach ( $block_types as $block_type ) {
|
2023-09-25 13:48:17 +02:00
|
|
|
if ( ! ( $block_type instanceof WP_Block_Type ) || ! is_array( $block_type->block_hooks ) ) {
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-09-26 13:49:21 +02:00
|
|
|
foreach ( $block_type->block_hooks as $anchor_block_type => $relative_position ) {
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
if ( ! isset( $hooked_blocks[ $anchor_block_type ] ) ) {
|
|
|
|
$hooked_blocks[ $anchor_block_type ] = array();
|
2023-09-25 10:44:22 +02:00
|
|
|
}
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
if ( ! isset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
|
|
|
|
$hooked_blocks[ $anchor_block_type ][ $relative_position ] = array();
|
2023-09-18 14:43:13 +02:00
|
|
|
}
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
$hooked_blocks[ $anchor_block_type ][ $relative_position ][] = $block_type->name;
|
2023-09-18 14:43:13 +02:00
|
|
|
}
|
|
|
|
}
|
Blocks: Call `get_hooked_blocks` only once per template/part/pattern.
Prior to this changeset, `get_hooked_blocks` was called four times ''for every parsed block'' in each template, template part, and pattern. With this changeset applied, `get_hooked_blocks` is called only once per template, template part, or pattern.
Additionally, `get_hooked_blocks` is called only once when returning the list of all registered patterns. (The latter modification brings the implementation closer to its state prior to Block Hooks.)
Finally, when there are no registered hooked blocks or `hooked_block_types` filters, parsing, hooked block insertion, and re-serializing is skipped altogether.
Props gziolo, flixos90, joemcgill, dmsnell, spacedmonkey, hellofromtonya.
Fixes #59383.
Built from https://develop.svn.wordpress.org/trunk@56805
git-svn-id: http://core.svn.wordpress.org/trunk@56317 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-09 18:40:24 +02:00
|
|
|
|
2023-09-18 14:43:13 +02:00
|
|
|
return $hooked_blocks;
|
|
|
|
}
|
|
|
|
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
/**
|
|
|
|
* Returns the markup for blocks hooked to the given anchor block in a specific relative position.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
* @access private
|
|
|
|
*
|
2024-05-23 20:35:14 +02:00
|
|
|
* @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|WP_Post|array $context The block template, template part, or pattern that the anchor block belongs to.
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
* @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
|
|
|
|
*
|
2024-02-07 11:56:08 +01:00
|
|
|
* @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.
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
*/
|
|
|
|
$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(),
|
|
|
|
);
|
|
|
|
|
2024-02-20 10:27:06 +01:00
|
|
|
/**
|
|
|
|
* Filters the parsed block array for a given hooked block.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
2024-02-20 16:22:08 +01:00
|
|
|
* @param array|null $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block.
|
2024-02-20 10:27:06 +01:00
|
|
|
* @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 );
|
|
|
|
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
/**
|
|
|
|
* Filters the parsed block array for a given hooked block.
|
|
|
|
*
|
2024-01-25 15:20:17 +01:00
|
|
|
* The dynamic portion of the hook name, `$hooked_block_type`, refers to the block type name of the specific hooked block.
|
|
|
|
*
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
* @since 6.5.0
|
|
|
|
*
|
2024-02-20 16:22:08 +01:00
|
|
|
* @param array|null $parsed_hooked_block The parsed block array for the given hooked block type, or null to suppress the block.
|
2024-02-20 10:27:06 +01:00
|
|
|
* @param string $hooked_block_type The hooked block type name.
|
2024-02-07 11:56:08 +01:00
|
|
|
* @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.
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
*/
|
2024-02-20 10:27:06 +01:00
|
|
|
$parsed_hooked_block = apply_filters( "hooked_block_{$hooked_block_type}", $parsed_hooked_block, $hooked_block_type, $relative_position, $parsed_anchor_block, $context );
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
|
2024-02-20 16:22:08 +01:00
|
|
|
if ( null === $parsed_hooked_block ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-02-20 10:27:06 +01:00
|
|
|
// 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.
|
2024-02-13 16:12:09 +01:00
|
|
|
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 );
|
|
|
|
}
|
Block Hooks: Introduce a new `hooked_block_{$block_type}` filter.
Add a new `hooked_block_{$block_type}` filter that allows modifying a hooked block (in parsed block format) prior to insertion, while providing read access to its anchor block (in the same format).
This allows block authors to e.g. set a hooked block's attributes, or its inner blocks; the filter can peruse information about the anchor block when doing so. As such, this filter provides a solution to both #59572 and #60126.
The new filter is designed to strike a good balance and separation of concerns with regard to the existing [https://developer.wordpress.org/reference/hooks/hooked_block_types/ `hooked_block_types` filter], which allows addition or removal of a block to the list of hooked blocks for a given anchor block -- all of which are identified only by their block ''types''. This new filter, on the other hand, only applies to ''one'' hooked block at a time, and allows modifying the entire (parsed) hooked block; it also gives (read) access to the parsed anchor block.
Props gziolo, tomjcafferkey, andrewserong, isabel_brison, timbroddin, yansern.
Fixes #59572, #60126.
Built from https://develop.svn.wordpress.org/trunk@57354
git-svn-id: http://core.svn.wordpress.org/trunk@56860 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-25 14:48:18 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return $markup;
|
2023-12-04 21:26:22 +01:00
|
|
|
}
|
|
|
|
|
2024-02-13 16:12:09 +01:00
|
|
|
/**
|
|
|
|
* 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
|
|
|
|
*
|
2024-05-23 20:35:14 +02:00
|
|
|
* @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|WP_Post|array $context The block template, template part, or pattern that the anchor block belongs to.
|
|
|
|
* @return string Empty string.
|
2024-02-13 16:12:09 +01:00
|
|
|
*/
|
|
|
|
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 '';
|
|
|
|
}
|
|
|
|
|
2024-02-20 16:22:08 +01:00
|
|
|
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 ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-13 16:12:09 +01:00
|
|
|
$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 '';
|
|
|
|
}
|
|
|
|
|
2024-05-23 20:35:14 +02:00
|
|
|
/**
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* Runs the hooked blocks algorithm on the given content.
|
2024-05-23 20:35:14 +02:00
|
|
|
*
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* @since 6.6.0
|
2024-09-27 11:20:18 +02:00
|
|
|
* @since 6.7.0 Injects the `theme` attribute into Template Part blocks, even if no hooked blocks are registered.
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* @access private
|
|
|
|
*
|
2024-06-06 16:36:12 +02:00
|
|
|
* @param string $content Serialized content.
|
|
|
|
* @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'.
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* @return string The serialized markup.
|
|
|
|
*/
|
|
|
|
function apply_block_hooks_to_content( $content, $context, $callback = 'insert_hooked_blocks' ) {
|
|
|
|
$hooked_blocks = get_hooked_blocks();
|
2024-09-27 11:20:18 +02:00
|
|
|
|
|
|
|
$before_block_visitor = '_inject_theme_attribute_in_template_part_block';
|
|
|
|
$after_block_visitor = null;
|
|
|
|
if ( ! empty( $hooked_blocks ) || has_filter( 'hooked_block_types' ) ) {
|
|
|
|
$before_block_visitor = make_before_block_visitor( $hooked_blocks, $context, $callback );
|
|
|
|
$after_block_visitor = make_after_block_visitor( $hooked_blocks, $context, $callback );
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
}
|
|
|
|
|
Block Hooks: Respect `"multiple": false` in hooked blocks.
If a prospective hooked block has its `multiple` block-supports field set to `false` (thus allowing only one instance of the block to be present), ensure that:
1. Only one instance of the block will be inserted if it's not yet present in the current context.
2. The block will not be inserted at all if an instance of it is already present in the current context.
As always in Block Hooks parlance, "context" denotes the containing template, template part, pattern, or navigation post that a hooked block is supposed to be inserted into.
The markup of a webpage that uses a Block Theme typically comprises a number of such contexts -- one template and any number of template parts, patterns, and navigation posts. Note that the limitation imposed by this changeset only applies on a per-context basis, so it's still possible that the resulting page contains more than one instance of a hooked block with `"multiple": false` set, as each context could contribute up to one such instance.
Props bernhard-reiter, jonsurrell, gziolo.
Fixes #61902.
Built from https://develop.svn.wordpress.org/trunk@59124
git-svn-id: http://core.svn.wordpress.org/trunk@58520 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-09-30 14:23:17 +02:00
|
|
|
$block_allows_multiple_instances = array();
|
|
|
|
/*
|
|
|
|
* Remove hooked blocks from `$hooked_block_types` if they have `multiple` set to false and
|
|
|
|
* are already present in `$content`.
|
|
|
|
*/
|
|
|
|
foreach ( $hooked_blocks as $anchor_block_type => $relative_positions ) {
|
|
|
|
foreach ( $relative_positions as $relative_position => $hooked_block_types ) {
|
|
|
|
foreach ( $hooked_block_types as $index => $hooked_block_type ) {
|
|
|
|
$hooked_block_type_definition =
|
|
|
|
WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );
|
|
|
|
|
|
|
|
$block_allows_multiple_instances[ $hooked_block_type ] =
|
|
|
|
block_has_support( $hooked_block_type_definition, 'multiple', true );
|
|
|
|
|
|
|
|
if (
|
|
|
|
! $block_allows_multiple_instances[ $hooked_block_type ] &&
|
|
|
|
has_block( $hooked_block_type, $content )
|
|
|
|
) {
|
|
|
|
unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ][ $index ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( empty( $hooked_blocks[ $anchor_block_type ][ $relative_position ] ) ) {
|
|
|
|
unset( $hooked_blocks[ $anchor_block_type ][ $relative_position ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( empty( $hooked_blocks[ $anchor_block_type ] ) ) {
|
|
|
|
unset( $hooked_blocks[ $anchor_block_type ] );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We also need to cover the case where the hooked block is not present in
|
|
|
|
* `$content` at first and we're allowed to insert it once -- but not again.
|
|
|
|
*/
|
|
|
|
$suppress_single_instance_blocks = static function ( $hooked_block_types ) use ( &$block_allows_multiple_instances, $content ) {
|
|
|
|
static $single_instance_blocks_present_in_content = array();
|
|
|
|
foreach ( $hooked_block_types as $index => $hooked_block_type ) {
|
|
|
|
if ( ! isset( $block_allows_multiple_instances[ $hooked_block_type ] ) ) {
|
|
|
|
$hooked_block_type_definition =
|
|
|
|
WP_Block_Type_Registry::get_instance()->get_registered( $hooked_block_type );
|
|
|
|
|
|
|
|
$block_allows_multiple_instances[ $hooked_block_type ] =
|
|
|
|
block_has_support( $hooked_block_type_definition, 'multiple', true );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( $block_allows_multiple_instances[ $hooked_block_type ] ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The block doesn't allow multiple instances, so we need to check if it's already present.
|
|
|
|
if (
|
|
|
|
in_array( $hooked_block_type, $single_instance_blocks_present_in_content, true ) ||
|
|
|
|
has_block( $hooked_block_type, $content )
|
|
|
|
) {
|
|
|
|
unset( $hooked_block_types[ $index ] );
|
|
|
|
} else {
|
|
|
|
// We can insert the block once, but need to remember not to insert it again.
|
|
|
|
$single_instance_blocks_present_in_content[] = $hooked_block_type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $hooked_block_types;
|
|
|
|
};
|
|
|
|
add_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );
|
|
|
|
$content = traverse_and_serialize_blocks(
|
|
|
|
parse_blocks( $content ),
|
|
|
|
$before_block_visitor,
|
|
|
|
$after_block_visitor
|
|
|
|
);
|
|
|
|
remove_filter( 'hooked_block_types', $suppress_single_instance_blocks, PHP_INT_MAX );
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
|
Block Hooks: Respect `"multiple": false` in hooked blocks.
If a prospective hooked block has its `multiple` block-supports field set to `false` (thus allowing only one instance of the block to be present), ensure that:
1. Only one instance of the block will be inserted if it's not yet present in the current context.
2. The block will not be inserted at all if an instance of it is already present in the current context.
As always in Block Hooks parlance, "context" denotes the containing template, template part, pattern, or navigation post that a hooked block is supposed to be inserted into.
The markup of a webpage that uses a Block Theme typically comprises a number of such contexts -- one template and any number of template parts, patterns, and navigation posts. Note that the limitation imposed by this changeset only applies on a per-context basis, so it's still possible that the resulting page contains more than one instance of a hooked block with `"multiple": false` set, as each context could contribute up to one such instance.
Props bernhard-reiter, jonsurrell, gziolo.
Fixes #61902.
Built from https://develop.svn.wordpress.org/trunk@59124
git-svn-id: http://core.svn.wordpress.org/trunk@58520 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-09-30 14:23:17 +02:00
|
|
|
return $content;
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the inner blocks.
|
2024-05-23 20:35:14 +02:00
|
|
|
*
|
|
|
|
* @since 6.6.0
|
|
|
|
* @access private
|
|
|
|
*
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* @param string $serialized_block The serialized markup of a block and its inner blocks.
|
|
|
|
* @return string The serialized markup of the inner blocks.
|
|
|
|
*/
|
|
|
|
function remove_serialized_parent_block( $serialized_block ) {
|
|
|
|
$start = strpos( $serialized_block, '-->' ) + strlen( '-->' );
|
|
|
|
$end = strrpos( $serialized_block, '<!--' );
|
|
|
|
return substr( $serialized_block, $start, $end - $start );
|
|
|
|
}
|
|
|
|
|
2024-07-02 12:03:15 +02:00
|
|
|
/**
|
|
|
|
* Accepts the serialized markup of a block and its inner blocks, and returns serialized markup of the wrapper block.
|
|
|
|
*
|
|
|
|
* @since 6.7.0
|
|
|
|
* @access private
|
|
|
|
*
|
|
|
|
* @see remove_serialized_parent_block()
|
|
|
|
*
|
|
|
|
* @param string $serialized_block The serialized markup of a block and its inner blocks.
|
|
|
|
* @return string The serialized markup of the wrapper block.
|
|
|
|
*/
|
|
|
|
function extract_serialized_parent_block( $serialized_block ) {
|
|
|
|
$start = strpos( $serialized_block, '-->' ) + strlen( '-->' );
|
|
|
|
$end = strrpos( $serialized_block, '<!--' );
|
|
|
|
return substr( $serialized_block, 0, $start ) . substr( $serialized_block, $end );
|
|
|
|
}
|
|
|
|
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
/**
|
|
|
|
* Updates the wp_postmeta with the list of ignored hooked blocks where the inner blocks are stored as post content.
|
|
|
|
* Currently only supports `wp_navigation` post types.
|
|
|
|
*
|
|
|
|
* @since 6.6.0
|
|
|
|
* @access private
|
|
|
|
*
|
|
|
|
* @param stdClass $post Post object.
|
|
|
|
* @return stdClass The updated post object.
|
|
|
|
*/
|
|
|
|
function update_ignored_hooked_blocks_postmeta( $post ) {
|
|
|
|
/*
|
|
|
|
* In this scenario the user has likely tried to create a navigation via the REST API.
|
|
|
|
* In which case we won't have a post ID to work with and store meta against.
|
|
|
|
*/
|
|
|
|
if ( empty( $post->ID ) ) {
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:38:12 +02:00
|
|
|
/*
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* Skip meta generation when consumers intentionally update specific Navigation fields
|
|
|
|
* and omit the content update.
|
|
|
|
*/
|
|
|
|
if ( ! isset( $post->post_content ) ) {
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:38:12 +02:00
|
|
|
/*
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* Skip meta generation when the post content is not a navigation block.
|
|
|
|
*/
|
|
|
|
if ( ! isset( $post->post_type ) || 'wp_navigation' !== $post->post_type ) {
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
|
|
|
$attributes = array();
|
|
|
|
|
|
|
|
$ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
|
|
|
|
if ( ! empty( $ignored_hooked_blocks ) ) {
|
|
|
|
$ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true );
|
|
|
|
$attributes['metadata'] = array(
|
|
|
|
'ignoredHookedBlocks' => $ignored_hooked_blocks,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$markup = get_comment_delimited_block_content(
|
|
|
|
'core/navigation',
|
|
|
|
$attributes,
|
|
|
|
$post->post_content
|
|
|
|
);
|
|
|
|
|
2024-06-26 10:54:13 +02:00
|
|
|
$existing_post = get_post( $post->ID );
|
|
|
|
// Merge the existing post object with the updated post object to pass to the block hooks algorithm for context.
|
|
|
|
$context = (object) array_merge( (array) $existing_post, (array) $post );
|
|
|
|
$serialized_block = apply_block_hooks_to_content( $markup, $context, 'set_ignored_hooked_blocks_metadata' );
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
$root_block = parse_blocks( $serialized_block )[0];
|
|
|
|
|
|
|
|
$ignored_hooked_blocks = isset( $root_block['attrs']['metadata']['ignoredHookedBlocks'] )
|
|
|
|
? $root_block['attrs']['metadata']['ignoredHookedBlocks']
|
|
|
|
: array();
|
|
|
|
|
|
|
|
if ( ! empty( $ignored_hooked_blocks ) ) {
|
|
|
|
$existing_ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
|
|
|
|
if ( ! empty( $existing_ignored_hooked_blocks ) ) {
|
|
|
|
$existing_ignored_hooked_blocks = json_decode( $existing_ignored_hooked_blocks, true );
|
|
|
|
$ignored_hooked_blocks = array_unique( array_merge( $ignored_hooked_blocks, $existing_ignored_hooked_blocks ) );
|
|
|
|
}
|
2024-06-26 10:54:13 +02:00
|
|
|
|
|
|
|
if ( ! isset( $post->meta_input ) ) {
|
|
|
|
$post->meta_input = array();
|
|
|
|
}
|
|
|
|
$post->meta_input['_wp_ignored_hooked_blocks'] = json_encode( $ignored_hooked_blocks );
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
$post->post_content = remove_serialized_parent_block( $serialized_block );
|
|
|
|
return $post;
|
|
|
|
}
|
|
|
|
|
2024-06-06 14:38:12 +02:00
|
|
|
/**
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
* Returns the markup for blocks hooked to the given anchor block in a specific relative position and then
|
|
|
|
* adds a list of hooked block types to an anchor block's ignored hooked block types.
|
|
|
|
*
|
|
|
|
* This function is meant for internal use only.
|
|
|
|
*
|
2024-06-06 14:38:12 +02:00
|
|
|
* @since 6.6.0
|
|
|
|
* @access private
|
|
|
|
*
|
2024-05-23 20:35:14 +02:00
|
|
|
* @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|WP_Post|array $context The block template, template part, or pattern that the anchor block belongs to.
|
|
|
|
* @return string
|
|
|
|
*/
|
|
|
|
function insert_hooked_blocks_and_set_ignored_hooked_blocks_metadata( &$parsed_anchor_block, $relative_position, $hooked_blocks, $context ) {
|
Block Hooks: Move ignoredHookedBlocks metadata injection logic.
As of [57790], the Templates endpoint uses the `rest_pre_insert_*` filter to inject the `ignoredHookedBlocks` metadata attribute into anchor blocks, prior to persisting a template or template part to the database. The same principle was implemented for the Navigation endpoint (where additionally, first and last child blocks added at the top level are store in the `wp_navigation` post object's post meta). The required logic was added to the Navigation block's code, i.e. inside the Gutenberg code repository, and then synchronized to Core.
In order to harmonize the code between the two endpoints, this changeset introduces a new `update_ignored_hooked_blocks_postmeta` function, which is based on the Navigation block's `block_core_navigation_update_ignore_hooked_blocks_meta`, alongside a few helper functions, and hooks it to the `rest_pre_insert_wp_navigation` filter hook. (The Navigation block has been prepared in [58275] to add an additional conditional to check for the new `update_ignored_hooked_blocks_postmeta` filter so there won't be any collisions.)
Eventually, this will allow to deprecate `block_core_navigation_update_ignore_hooked_blocks_meta` (and some related functions), and remove the relevant code from the Navigation block. It also paves the way for some other future changes, such as inserting a hooked block as a Template Part block's first or last child (#60854).
Props tomjcafferkey, bernhard-reiter.
Fixes #60759.
Built from https://develop.svn.wordpress.org/trunk@58291
git-svn-id: http://core.svn.wordpress.org/trunk@57751 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-03 14:05:15 +02:00
|
|
|
$markup = insert_hooked_blocks( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
|
2024-05-23 20:35:14 +02:00
|
|
|
$markup .= set_ignored_hooked_blocks_metadata( $parsed_anchor_block, $relative_position, $hooked_blocks, $context );
|
|
|
|
|
|
|
|
return $markup;
|
|
|
|
}
|
|
|
|
|
2024-06-03 14:37:14 +02:00
|
|
|
/**
|
|
|
|
* Hooks into the REST API response for the core/navigation block and adds the first and last inner blocks.
|
|
|
|
*
|
|
|
|
* @since 6.6.0
|
|
|
|
*
|
|
|
|
* @param WP_REST_Response $response The response object.
|
|
|
|
* @param WP_Post $post Post object.
|
|
|
|
* @return WP_REST_Response The response object.
|
|
|
|
*/
|
|
|
|
function insert_hooked_blocks_into_rest_response( $response, $post ) {
|
|
|
|
if ( ! isset( $response->data['content']['raw'] ) || ! isset( $response->data['content']['rendered'] ) ) {
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
Coding Standards: Apply changes after running `composer format`.
This applies several formatting related changes made while running `composer format`.
Follow up to [55720], [58171], [58271], [58282], [58283], [58292], [58299], [58303], [58332].
See #51857, #60719, #60895, #61021, #61118, #61228, #61276, #61324.
Built from https://develop.svn.wordpress.org/trunk@58408
git-svn-id: http://core.svn.wordpress.org/trunk@57857 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-13 17:06:07 +02:00
|
|
|
$attributes = array();
|
2024-06-03 14:37:14 +02:00
|
|
|
$ignored_hooked_blocks = get_post_meta( $post->ID, '_wp_ignored_hooked_blocks', true );
|
|
|
|
if ( ! empty( $ignored_hooked_blocks ) ) {
|
|
|
|
$ignored_hooked_blocks = json_decode( $ignored_hooked_blocks, true );
|
|
|
|
$attributes['metadata'] = array(
|
|
|
|
'ignoredHookedBlocks' => $ignored_hooked_blocks,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
$content = get_comment_delimited_block_content(
|
|
|
|
'core/navigation',
|
|
|
|
$attributes,
|
|
|
|
$response->data['content']['raw']
|
|
|
|
);
|
|
|
|
|
|
|
|
$content = apply_block_hooks_to_content( $content, $post );
|
|
|
|
|
|
|
|
// Remove mock Navigation block wrapper.
|
|
|
|
$content = remove_serialized_parent_block( $content );
|
|
|
|
|
|
|
|
$response->data['content']['raw'] = $content;
|
|
|
|
|
|
|
|
/** This filter is documented in wp-includes/post-template.php */
|
|
|
|
$response->data['content']['rendered'] = apply_filters( 'the_content', $content );
|
|
|
|
|
|
|
|
return $response;
|
|
|
|
}
|
|
|
|
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
/**
|
|
|
|
* 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)`,
|
|
|
|
* where it will inject the `theme` attribute into all Template Part blocks, and prepend the markup for
|
|
|
|
* any blocks hooked `before` the given block and as its parent's `first_child`, respectively.
|
|
|
|
*
|
2023-11-06 14:37:24 +01:00
|
|
|
* This function is meant for internal use only.
|
|
|
|
*
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @since 6.4.0
|
2024-02-13 16:12:09 +01:00
|
|
|
* @since 6.5.0 Added $callback argument.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @access private
|
|
|
|
*
|
2024-02-07 11:56:08 +01:00
|
|
|
* @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.
|
2024-02-13 16:12:09 +01:00
|
|
|
* @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'.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @return callable A function that returns the serialized markup for the given block,
|
|
|
|
* including the markup for any hooked blocks before it.
|
|
|
|
*/
|
2024-02-13 16:12:09 +01:00
|
|
|
function make_before_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) {
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
/**
|
|
|
|
* Injects hooked blocks before the given block, injects the `theme` attribute into Template Part blocks, and returns the serialized markup.
|
|
|
|
*
|
|
|
|
* If the current block is a Template Part block, inject the `theme` attribute.
|
|
|
|
* Furthermore, prepend the markup for any blocks hooked `before` the given block and as its parent's
|
|
|
|
* `first_child`, respectively, to the serialized markup for the given block.
|
|
|
|
*
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
* @param array $block The block to inject the theme attribute into, and hooked blocks before. Passed by reference.
|
|
|
|
* @param array $parent_block The parent block of the given block. Passed by reference. Default null.
|
|
|
|
* @param array $prev The previous sibling block of the given block. Default null.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @return string The serialized markup for the given block, with the markup for any hooked blocks prepended to it.
|
|
|
|
*/
|
2024-02-13 16:12:09 +01:00
|
|
|
return function ( &$block, &$parent_block = null, $prev = null ) use ( $hooked_blocks, $context, $callback ) {
|
Patterns, Templates: Inject `theme` attr into Template Part blocks.
It was found that Template Part blocks were broken in the Site Editor, showing the `Template part has been deleted or is unavailable` message, due to a missing `theme` attribute.
This bug seems to have been introduced by [56896], whose goal was to only inject that attribute into the markup returned by the templates and patterns REST API endpoints but not on the frontend, in order to improve performance. It has been demonstrated locally that reverting that changeset fixes the bug.
Reverts [56896].
Props mmcalister, swisspidy, thelovelist, hellofromTonya, pbiron, Pauthake015, richtabor, nicolefurlan, huzaifaalmesbah, annezazu, kafleg, aegkr, sunitarai, shresthaaman, andraganescu, onemaggie, gziolo.
Fixes #59629.
Built from https://develop.svn.wordpress.org/trunk@56960
git-svn-id: http://core.svn.wordpress.org/trunk@56471 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-17 17:48:23 +02:00
|
|
|
_inject_theme_attribute_in_template_part_block( $block );
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
|
|
|
|
$markup = '';
|
|
|
|
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
if ( $parent_block && ! $prev ) {
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
// Candidate for first-child insertion.
|
2024-02-13 16:12:09 +01:00
|
|
|
$markup .= call_user_func_array(
|
|
|
|
$callback,
|
|
|
|
array( &$parent_block, 'first_child', $hooked_blocks, $context )
|
|
|
|
);
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
}
|
|
|
|
|
2024-02-13 16:12:09 +01:00
|
|
|
$markup .= call_user_func_array(
|
|
|
|
$callback,
|
|
|
|
array( &$block, 'before', $hooked_blocks, $context )
|
|
|
|
);
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
|
|
|
|
return $markup;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a function that injects the hooked blocks after a given block.
|
|
|
|
*
|
|
|
|
* The returned function can be used as `$post_callback` argument to `traverse_and_serialize_block(s)`,
|
|
|
|
* where it will append the markup for any blocks hooked `after` the given block and as its parent's
|
|
|
|
* `last_child`, respectively.
|
|
|
|
*
|
2023-11-06 14:37:24 +01:00
|
|
|
* This function is meant for internal use only.
|
|
|
|
*
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @since 6.4.0
|
2024-02-13 16:12:09 +01:00
|
|
|
* @since 6.5.0 Added $callback argument.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @access private
|
|
|
|
*
|
2024-02-07 11:56:08 +01:00
|
|
|
* @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.
|
2024-02-13 16:12:09 +01:00
|
|
|
* @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'.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @return callable A function that returns the serialized markup for the given block,
|
|
|
|
* including the markup for any hooked blocks after it.
|
|
|
|
*/
|
2024-02-13 16:12:09 +01:00
|
|
|
function make_after_block_visitor( $hooked_blocks, $context, $callback = 'insert_hooked_blocks' ) {
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
/**
|
|
|
|
* Injects hooked blocks after the given block, and returns the serialized markup.
|
|
|
|
*
|
|
|
|
* Append the markup for any blocks hooked `after` the given block and as its parent's
|
|
|
|
* `last_child`, respectively, to the serialized markup for the given block.
|
|
|
|
*
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
* @param array $block The block to inject the hooked blocks after. Passed by reference.
|
|
|
|
* @param array $parent_block The parent block of the given block. Passed by reference. Default null.
|
|
|
|
* @param array $next The next sibling block of the given block. Default null.
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
* @return string The serialized markup for the given block, with the markup for any hooked blocks appended to it.
|
|
|
|
*/
|
2024-02-13 16:12:09 +01:00
|
|
|
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 )
|
|
|
|
);
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
if ( $parent_block && ! $next ) {
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
// Candidate for last-child insertion.
|
2024-02-13 16:12:09 +01:00
|
|
|
$markup .= call_user_func_array(
|
|
|
|
$callback,
|
|
|
|
array( &$parent_block, 'last_child', $hooked_blocks, $context )
|
|
|
|
);
|
Blocks: Implement automatic block insertion into Block Hooks.
Block Hooks allow a third-party block to specify a position relative to a given block into which it will then be automatically inserted (e.g. a "Like" button block can ask to be inserted after the Post Content block, or an eCommerce shopping cart block can ask to be inserted after the Navigation block).
The underlying idea is to provide an extensibility mechanism for Block Themes, in analogy to WordPress' [https://developer.wordpress.org/plugins/hooks/ Hooks] concept that has allowed extending Classic Themes through filters and actions.
The two core tenets for Block Hooks are:
1. Insertion into the frontend should happen right after a plugin containing a hooked block is activated (i.e. the user isn't required to insert the block manually in the editor first); similarly, disabling the plugin should remove the hooked block from the frontend.
2. The user has the ultimate power to customize that automatic insertion: The hooked block is also visible in the editor, and the user's decision to persist, dismiss (i.e. remove), customize, or move it will be respected (and reflected on the frontend).
To account for both tenets, the **tradeoff** was made to limit automatic block insertion to unmodified templates (and template parts, respectively). The reason for this is that the simplest way of storing the information whether a block has been persisted to (or dismissed from) a given template (or part) is right in the template markup.
To accommodate for that tradeoff, [https://github.com/WordPress/gutenberg/pull/52969 UI controls (toggles)] are being added to increase visibility of hooked blocks, and to allow for their later insertion into templates (or parts) that already have been modified by the user.
For hooked blocks to appear both in the frontend and in the editor (see tenet number 2), they need to be inserted into both the frontend markup and the REST API (templates and patterns endpoints) equally. As a consequence, this means that automatic insertion couldn't (only) be implemented at block ''render'' stage, as for the editor, the ''serialized'' (but ''unrendered'') markup needs to be modified.
Furthermore, hooked blocks also have to be inserted into block patterns. Since practically no filters exist for the patterns registry, this has to be done in the registry's `get_registered` and `get_all_registered` methods.
Props gziolo.
Fixes #59313.
Built from https://develop.svn.wordpress.org/trunk@56649
git-svn-id: http://core.svn.wordpress.org/trunk@56161 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-21 18:18:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return $markup;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2019-12-12 19:02:03 +01:00
|
|
|
/**
|
|
|
|
* Given an array of attributes, returns a string in the serialized attributes
|
|
|
|
* format prepared for post content.
|
|
|
|
*
|
|
|
|
* The serialized result is a JSON-encoded string, with unicode escape sequence
|
|
|
|
* substitution for characters which might otherwise interfere with embedding
|
|
|
|
* the result in an HTML comment.
|
|
|
|
*
|
2021-08-26 21:10:58 +02:00
|
|
|
* This function must produce output that remains in sync with the output of
|
|
|
|
* the serializeAttributes JavaScript function in the block editor in order
|
|
|
|
* to ensure consistent operation between PHP and JavaScript.
|
|
|
|
*
|
2019-12-12 19:02:03 +01:00
|
|
|
* @since 5.3.1
|
|
|
|
*
|
2020-07-23 02:48:06 +02:00
|
|
|
* @param array $block_attributes Attributes object.
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return string Serialized attributes.
|
|
|
|
*/
|
|
|
|
function serialize_block_attributes( $block_attributes ) {
|
2021-08-26 21:10:58 +02:00
|
|
|
$encoded_attributes = wp_json_encode( $block_attributes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
|
2019-12-12 19:02:03 +01:00
|
|
|
$encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes );
|
|
|
|
$encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes );
|
|
|
|
$encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes );
|
|
|
|
$encoded_attributes = preg_replace( '/&/', '\\u0026', $encoded_attributes );
|
|
|
|
// Regex: /\\"/
|
|
|
|
$encoded_attributes = preg_replace( '/\\\\"/', '\\u0022', $encoded_attributes );
|
|
|
|
|
|
|
|
return $encoded_attributes;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the block name to use for serialization. This will remove the default
|
|
|
|
* "core/" namespace from a block name.
|
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
2022-10-16 17:46:15 +02:00
|
|
|
* @param string|null $block_name Optional. Original block name. Null if the block name is unknown,
|
|
|
|
* e.g. Classic blocks have their name set to null. Default null.
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return string Block name to use for serialization.
|
|
|
|
*/
|
|
|
|
function strip_core_block_namespace( $block_name = null ) {
|
Code Modernization: Replace usage of `strpos()` with `str_starts_with()`.
`str_starts_with()` was introduced in PHP 8.0 to perform a case-sensitive check indicating if the string to search in (haystack) begins with the given substring (needle).
WordPress core includes a polyfill for `str_starts_with()` on PHP < 8.0 as of WordPress 5.9.
This commit replaces `0 === strpos( ... )` with `str_starts_with()` in core files, making the code more readable and consistent, as well as improving performance.
While `strpos()` is slightly faster than the polyfill on PHP < 8.0, `str_starts_with()` is noticeably faster on PHP 8.0+, as it is optimized to avoid unnecessarily searching along the whole haystack if it does not find the needle.
Follow-up to [52039], [52040], [52326].
Props spacedmonkey, costdev, sabernhardt, mukesh27, desrosj, jorbin, TobiasBg, ayeshrajans, lgadzhev, SergeyBiryukov.
Fixes #58012.
Built from https://develop.svn.wordpress.org/trunk@55703
git-svn-id: http://core.svn.wordpress.org/trunk@55215 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-05-02 17:45:22 +02:00
|
|
|
if ( is_string( $block_name ) && str_starts_with( $block_name, 'core/' ) ) {
|
2019-12-12 19:02:03 +01:00
|
|
|
return substr( $block_name, 5 );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $block_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the content of a block, including comment delimiters.
|
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
2020-08-15 15:40:03 +02:00
|
|
|
* @param string|null $block_name Block name. Null if the block name is unknown,
|
|
|
|
* e.g. Classic blocks have their name set to null.
|
|
|
|
* @param array $block_attributes Block attributes.
|
|
|
|
* @param string $block_content Block save content.
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return string Comment-delimited block content.
|
|
|
|
*/
|
2020-08-15 15:40:03 +02:00
|
|
|
function get_comment_delimited_block_content( $block_name, $block_attributes, $block_content ) {
|
2019-12-12 19:02:03 +01:00
|
|
|
if ( is_null( $block_name ) ) {
|
|
|
|
return $block_content;
|
|
|
|
}
|
|
|
|
|
|
|
|
$serialized_block_name = strip_core_block_namespace( $block_name );
|
|
|
|
$serialized_attributes = empty( $block_attributes ) ? '' : serialize_block_attributes( $block_attributes ) . ' ';
|
|
|
|
|
|
|
|
if ( empty( $block_content ) ) {
|
|
|
|
return sprintf( '<!-- wp:%s %s/-->', $serialized_block_name, $serialized_attributes );
|
|
|
|
}
|
|
|
|
|
|
|
|
return sprintf(
|
|
|
|
'<!-- wp:%s %s-->%s<!-- /wp:%s -->',
|
|
|
|
$serialized_block_name,
|
|
|
|
$serialized_attributes,
|
|
|
|
$block_content,
|
|
|
|
$serialized_block_name
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the content of a block, including comment delimiters, serializing all
|
|
|
|
* attributes from the given parsed block.
|
|
|
|
*
|
|
|
|
* This should be used when preparing a block to be saved to post content.
|
|
|
|
* Prefer `render_block` when preparing a block for display. Unlike
|
|
|
|
* `render_block`, this does not evaluate a block's `render_callback`, and will
|
|
|
|
* instead preserve the markup as parsed.
|
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array $block {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of a single parsed block object. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return string String of rendered HTML.
|
|
|
|
*/
|
2023-09-19 14:50:19 +02:00
|
|
|
function serialize_block( $block ) {
|
2019-12-12 19:02:03 +01:00
|
|
|
$block_content = '';
|
|
|
|
|
|
|
|
$index = 0;
|
|
|
|
foreach ( $block['innerContent'] as $chunk ) {
|
2023-09-19 14:50:19 +02:00
|
|
|
$block_content .= is_string( $chunk ) ? $chunk : serialize_block( $block['innerBlocks'][ $index++ ] );
|
2019-12-12 19:02:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! is_array( $block['attrs'] ) ) {
|
|
|
|
$block['attrs'] = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_comment_delimited_block_content(
|
|
|
|
$block['blockName'],
|
|
|
|
$block['attrs'],
|
|
|
|
$block_content
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-09-15 15:29:13 +02:00
|
|
|
* Returns a joined string of the aggregate serialization of the given
|
|
|
|
* parsed blocks.
|
2019-12-12 19:02:03 +01:00
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array[] $blocks {
|
|
|
|
* Array of block structures.
|
|
|
|
*
|
|
|
|
* @type array ...$0 {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of a single parsed block object. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
|
|
|
* }
|
2023-09-19 14:50:19 +02:00
|
|
|
* @return string String of rendered HTML.
|
|
|
|
*/
|
|
|
|
function serialize_blocks( $blocks ) {
|
|
|
|
return implode( '', array_map( 'serialize_block', $blocks ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-09-21 10:34:18 +02:00
|
|
|
* Traverses a parsed block tree and applies callbacks before and after serializing it.
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
2023-09-21 10:34:18 +02:00
|
|
|
* Recursively traverses the block and its inner blocks and applies the two callbacks provided as
|
|
|
|
* arguments, the first one before serializing the block, and the second one after serializing it.
|
|
|
|
* If either callback returns a string value, it will be prepended and appended to the serialized
|
|
|
|
* block markup, respectively.
|
|
|
|
*
|
|
|
|
* The callbacks will receive a reference to the current block as their first argument, so that they
|
|
|
|
* can also modify it, and the current block's parent block as second argument. Finally, the
|
|
|
|
* `$pre_callback` receives the previous block, whereas the `$post_callback` receives
|
|
|
|
* the next block as third argument.
|
|
|
|
*
|
|
|
|
* Serialized blocks are returned including comment delimiters, and with all attributes serialized.
|
|
|
|
*
|
|
|
|
* This function should be used when there is a need to modify the saved block, or to inject markup
|
|
|
|
* into the return value. Prefer `serialize_block` when preparing a block to be saved to post content.
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
2023-11-06 14:37:24 +01:00
|
|
|
* This function is meant for internal use only.
|
|
|
|
*
|
2023-09-19 14:50:19 +02:00
|
|
|
* @since 6.4.0
|
2023-11-06 14:37:24 +01:00
|
|
|
* @access private
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
|
|
|
* @see serialize_block()
|
|
|
|
*
|
2024-09-11 14:08:19 +02:00
|
|
|
* @param array $block An associative array of a single parsed block object. See WP_Block_Parser_Block.
|
2023-09-21 10:34:18 +02:00
|
|
|
* @param callable $pre_callback Callback to run on each block in the tree before it is traversed and serialized.
|
|
|
|
* It is called with the following arguments: &$block, $parent_block, $previous_block.
|
|
|
|
* Its string return value will be prepended to the serialized block markup.
|
|
|
|
* @param callable $post_callback Callback to run on each block in the tree after it is traversed and serialized.
|
|
|
|
* It is called with the following arguments: &$block, $parent_block, $next_block.
|
|
|
|
* Its string return value will be appended to the serialized block markup.
|
|
|
|
* @return string Serialized block markup.
|
2019-12-12 19:02:03 +01:00
|
|
|
*/
|
2023-09-21 10:34:18 +02:00
|
|
|
function traverse_and_serialize_block( $block, $pre_callback = null, $post_callback = null ) {
|
2023-09-19 14:50:19 +02:00
|
|
|
$block_content = '';
|
|
|
|
$block_index = 0;
|
|
|
|
|
2023-09-21 10:34:18 +02:00
|
|
|
foreach ( $block['innerContent'] as $chunk ) {
|
2023-09-19 14:50:19 +02:00
|
|
|
if ( is_string( $chunk ) ) {
|
|
|
|
$block_content .= $chunk;
|
|
|
|
} else {
|
2023-09-21 10:34:18 +02:00
|
|
|
$inner_block = $block['innerBlocks'][ $block_index ];
|
|
|
|
|
|
|
|
if ( is_callable( $pre_callback ) ) {
|
|
|
|
$prev = 0 === $block_index
|
|
|
|
? null
|
|
|
|
: $block['innerBlocks'][ $block_index - 1 ];
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2023-09-21 10:34:18 +02:00
|
|
|
$block_content .= call_user_func_array(
|
|
|
|
$pre_callback,
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
array( &$inner_block, &$block, $prev )
|
2023-09-21 10:34:18 +02:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( is_callable( $post_callback ) ) {
|
|
|
|
$next = count( $block['innerBlocks'] ) - 1 === $block_index
|
|
|
|
? null
|
|
|
|
: $block['innerBlocks'][ $block_index + 1 ];
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2023-10-18 21:32:23 +02:00
|
|
|
$post_markup = call_user_func_array(
|
2023-09-21 10:34:18 +02:00
|
|
|
$post_callback,
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
array( &$inner_block, &$block, $next )
|
2023-09-21 10:34:18 +02:00
|
|
|
);
|
|
|
|
}
|
2023-10-18 21:32:23 +02:00
|
|
|
|
|
|
|
$block_content .= traverse_and_serialize_block( $inner_block, $pre_callback, $post_callback );
|
|
|
|
$block_content .= isset( $post_markup ) ? $post_markup : '';
|
|
|
|
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
++$block_index;
|
2023-09-19 14:50:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! is_array( $block['attrs'] ) ) {
|
|
|
|
$block['attrs'] = array();
|
|
|
|
}
|
|
|
|
|
|
|
|
return get_comment_delimited_block_content(
|
|
|
|
$block['blockName'],
|
|
|
|
$block['attrs'],
|
|
|
|
$block_content
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-06-03 20:32:14 +02:00
|
|
|
/**
|
|
|
|
* Replaces patterns in a block tree with their content.
|
|
|
|
*
|
|
|
|
* @since 6.6.0
|
|
|
|
*
|
|
|
|
* @param array $blocks An array blocks.
|
|
|
|
*
|
|
|
|
* @return array An array of blocks with patterns replaced by their content.
|
|
|
|
*/
|
|
|
|
function resolve_pattern_blocks( $blocks ) {
|
|
|
|
static $inner_content;
|
|
|
|
// Keep track of seen references to avoid infinite loops.
|
|
|
|
static $seen_refs = array();
|
|
|
|
$i = 0;
|
|
|
|
while ( $i < count( $blocks ) ) {
|
|
|
|
if ( 'core/pattern' === $blocks[ $i ]['blockName'] ) {
|
|
|
|
$attrs = $blocks[ $i ]['attrs'];
|
|
|
|
|
|
|
|
if ( empty( $attrs['slug'] ) ) {
|
|
|
|
++$i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$slug = $attrs['slug'];
|
|
|
|
|
|
|
|
if ( isset( $seen_refs[ $slug ] ) ) {
|
|
|
|
// Skip recursive patterns.
|
|
|
|
array_splice( $blocks, $i, 1 );
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$registry = WP_Block_Patterns_Registry::get_instance();
|
|
|
|
$pattern = $registry->get_registered( $slug );
|
|
|
|
|
|
|
|
// Skip unknown patterns.
|
|
|
|
if ( ! $pattern ) {
|
|
|
|
++$i;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$blocks_to_insert = parse_blocks( $pattern['content'] );
|
|
|
|
$seen_refs[ $slug ] = true;
|
|
|
|
$prev_inner_content = $inner_content;
|
|
|
|
$inner_content = null;
|
|
|
|
$blocks_to_insert = resolve_pattern_blocks( $blocks_to_insert );
|
|
|
|
$inner_content = $prev_inner_content;
|
|
|
|
unset( $seen_refs[ $slug ] );
|
|
|
|
array_splice( $blocks, $i, 1, $blocks_to_insert );
|
|
|
|
|
|
|
|
// If we have inner content, we need to insert nulls in the
|
|
|
|
// inner content array, otherwise serialize_blocks will skip
|
|
|
|
// blocks.
|
|
|
|
if ( $inner_content ) {
|
|
|
|
$null_indices = array_keys( $inner_content, null, true );
|
|
|
|
$content_index = $null_indices[ $i ];
|
|
|
|
$nulls = array_fill( 0, count( $blocks_to_insert ), null );
|
|
|
|
array_splice( $inner_content, $content_index, 1, $nulls );
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip inserted blocks.
|
|
|
|
$i += count( $blocks_to_insert );
|
|
|
|
} else {
|
|
|
|
if ( ! empty( $blocks[ $i ]['innerBlocks'] ) ) {
|
Coding Standards: Apply changes after running `composer format`.
This applies several formatting related changes made while running `composer format`.
Follow up to [55720], [58171], [58271], [58282], [58283], [58292], [58299], [58303], [58332].
See #51857, #60719, #60895, #61021, #61118, #61228, #61276, #61324.
Built from https://develop.svn.wordpress.org/trunk@58408
git-svn-id: http://core.svn.wordpress.org/trunk@57857 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-13 17:06:07 +02:00
|
|
|
$prev_inner_content = $inner_content;
|
|
|
|
$inner_content = $blocks[ $i ]['innerContent'];
|
|
|
|
$blocks[ $i ]['innerBlocks'] = resolve_pattern_blocks(
|
2024-06-03 20:32:14 +02:00
|
|
|
$blocks[ $i ]['innerBlocks']
|
|
|
|
);
|
|
|
|
$blocks[ $i ]['innerContent'] = $inner_content;
|
Coding Standards: Apply changes after running `composer format`.
This applies several formatting related changes made while running `composer format`.
Follow up to [55720], [58171], [58271], [58282], [58283], [58292], [58299], [58303], [58332].
See #51857, #60719, #60895, #61021, #61118, #61228, #61276, #61324.
Built from https://develop.svn.wordpress.org/trunk@58408
git-svn-id: http://core.svn.wordpress.org/trunk@57857 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-06-13 17:06:07 +02:00
|
|
|
$inner_content = $prev_inner_content;
|
2024-06-03 20:32:14 +02:00
|
|
|
}
|
|
|
|
++$i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return $blocks;
|
|
|
|
}
|
|
|
|
|
2023-09-19 14:50:19 +02:00
|
|
|
/**
|
2023-09-21 10:34:18 +02:00
|
|
|
* Given an array of parsed block trees, applies callbacks before and after serializing them and
|
|
|
|
* returns their concatenated output.
|
|
|
|
*
|
|
|
|
* Recursively traverses the blocks and their inner blocks and applies the two callbacks provided as
|
|
|
|
* arguments, the first one before serializing a block, and the second one after serializing.
|
|
|
|
* If either callback returns a string value, it will be prepended and appended to the serialized
|
|
|
|
* block markup, respectively.
|
|
|
|
*
|
|
|
|
* The callbacks will receive a reference to the current block as their first argument, so that they
|
|
|
|
* can also modify it, and the current block's parent block as second argument. Finally, the
|
|
|
|
* `$pre_callback` receives the previous block, whereas the `$post_callback` receives
|
|
|
|
* the next block as third argument.
|
|
|
|
*
|
|
|
|
* Serialized blocks are returned including comment delimiters, and with all attributes serialized.
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
2023-09-21 10:34:18 +02:00
|
|
|
* This function should be used when there is a need to modify the saved blocks, or to inject markup
|
|
|
|
* into the return value. Prefer `serialize_blocks` when preparing blocks to be saved to post content.
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
2023-11-06 14:37:24 +01:00
|
|
|
* This function is meant for internal use only.
|
|
|
|
*
|
2023-09-19 14:50:19 +02:00
|
|
|
* @since 6.4.0
|
2023-11-06 14:37:24 +01:00
|
|
|
* @access private
|
2023-09-19 14:50:19 +02:00
|
|
|
*
|
|
|
|
* @see serialize_blocks()
|
|
|
|
*
|
2023-09-21 10:34:18 +02:00
|
|
|
* @param array[] $blocks An array of parsed blocks. See WP_Block_Parser_Block.
|
|
|
|
* @param callable $pre_callback Callback to run on each block in the tree before it is traversed and serialized.
|
|
|
|
* It is called with the following arguments: &$block, $parent_block, $previous_block.
|
|
|
|
* Its string return value will be prepended to the serialized block markup.
|
|
|
|
* @param callable $post_callback Callback to run on each block in the tree after it is traversed and serialized.
|
|
|
|
* It is called with the following arguments: &$block, $parent_block, $next_block.
|
|
|
|
* Its string return value will be appended to the serialized block markup.
|
|
|
|
* @return string Serialized block markup.
|
2023-09-19 14:50:19 +02:00
|
|
|
*/
|
2023-09-21 10:34:18 +02:00
|
|
|
function traverse_and_serialize_blocks( $blocks, $pre_callback = null, $post_callback = null ) {
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
$result = '';
|
|
|
|
$parent_block = null; // At the top level, there is no parent block to pass to the callbacks; yet the callbacks expect a reference.
|
|
|
|
|
2024-09-21 16:41:17 +02:00
|
|
|
$pre_callback_is_callable = is_callable( $pre_callback );
|
|
|
|
$post_callback_is_callable = is_callable( $post_callback );
|
|
|
|
|
2023-09-21 10:34:18 +02:00
|
|
|
foreach ( $blocks as $index => $block ) {
|
2024-09-21 16:41:17 +02:00
|
|
|
if ( $pre_callback_is_callable ) {
|
2023-09-21 10:34:18 +02:00
|
|
|
$prev = 0 === $index
|
|
|
|
? null
|
|
|
|
: $blocks[ $index - 1 ];
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2023-09-21 10:34:18 +02:00
|
|
|
$result .= call_user_func_array(
|
|
|
|
$pre_callback,
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
array( &$block, &$parent_block, $prev )
|
2023-09-21 10:34:18 +02:00
|
|
|
);
|
|
|
|
}
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2024-09-21 16:41:17 +02:00
|
|
|
if ( $post_callback_is_callable ) {
|
2023-09-21 10:34:18 +02:00
|
|
|
$next = count( $blocks ) - 1 === $index
|
|
|
|
? null
|
|
|
|
: $blocks[ $index + 1 ];
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2023-10-18 21:32:23 +02:00
|
|
|
$post_markup = call_user_func_array(
|
2023-09-21 10:34:18 +02:00
|
|
|
$post_callback,
|
Block Hooks: Allow traversal callbacks to modify parent block.
The callbacks returned by `make_before_block_visitor` and `make_after_block_visitor`, respectively, (which are passed as arguments to `traverse_and_serialize_block(s)`) currently accept three arguments, all of which are block arrays (i.e. with properties `blockName`, `attrs`, etc.):
- A ''reference'' to the block they're currently visiting, `&$block`;
- the block's `$parent_block`; and
- the `$prev`ious block (for `make_before_block_visitor`), or the `$next` block (for `make_after_block_visitor`), respectively.
Those arguments are passed to the "block visitor" callbacks by `traverse_and_serialize_block(s)` during traversal. The block that the callback is currently visiting is passed ''by reference'' to allow modifying it, which is e.g. used to inject the `theme` attribute into Template Part blocks.
One major limitation of Block Hooks is that they currently only work with templates, parts, and patterns that ''don't have any user modifications'' (i.e. that come straight from the corresponding theme files, rather than from the database). For WordPress 6.5, it is planned to change that to make Block Hooks work for templates, parts, and patterns that ''do'' have user modifications: #59646.
This will be implemented by storing an attribute on the "anchor" block. While working on that feature, it was found that the aforementioned callbacks will need to modify not only the currently visited `$block`, but also the `$parent_block` -- i.e. that the latter argument needs to be passed by reference as well. This is consistent with the requirement of adding an attribute to an anchor block, as it's not only the currently visited block that can serve as an anchor block (in the case of `before` or `after` sibling insertion), but also its parent (for `first_child` and `last_child` insertion).
If the `$parent_block` argument were to be changed to become a reference in a later WordPress version, this could be considered a backwards-compatibility breaking change. For this reason, this change is instead proposed for 6.4 already, which is the cycle during which the relevant functions were first introduced. This should have no impact on existing code, since nothing currently relies on `$parent_block` remaining unmodified by the respective callback, nor is anything currently modifying that argument.
Props hellofromTonya.
Fixes #59776.
Built from https://develop.svn.wordpress.org/trunk@57038
git-svn-id: http://core.svn.wordpress.org/trunk@56549 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-10-31 20:25:19 +01:00
|
|
|
array( &$block, &$parent_block, $next )
|
2023-09-21 10:34:18 +02:00
|
|
|
);
|
|
|
|
}
|
2023-10-18 21:32:23 +02:00
|
|
|
|
|
|
|
$result .= traverse_and_serialize_block( $block, $pre_callback, $post_callback );
|
|
|
|
$result .= isset( $post_markup ) ? $post_markup : '';
|
2023-09-17 04:10:17 +02:00
|
|
|
}
|
Coding Standards: Fix a few newly introduced WPCS issues.
Follow-up to [56570], [56573], [56589], [56604], [56612], [56620], [56629], [56631], [56638], [56642], [56644], [56649].
Props jrf.
See #59161, #58831.
Built from https://develop.svn.wordpress.org/trunk@56680
git-svn-id: http://core.svn.wordpress.org/trunk@56192 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-25 17:36:18 +02:00
|
|
|
|
2023-09-12 15:02:19 +02:00
|
|
|
return $result;
|
2019-12-12 19:02:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-09-15 15:29:13 +02:00
|
|
|
* Filters and sanitizes block content to remove non-allowable HTML
|
|
|
|
* from parsed block attribute values.
|
2019-12-12 19:02:03 +01:00
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
|
|
|
* @param string $text Text that may contain block content.
|
2022-10-16 17:46:15 +02:00
|
|
|
* @param array[]|string $allowed_html Optional. An array of allowed HTML elements and attributes,
|
2022-09-15 15:29:13 +02:00
|
|
|
* or a context name such as 'post'. See wp_kses_allowed_html()
|
2022-10-16 17:46:15 +02:00
|
|
|
* for the list of accepted context names. Default 'post'.
|
2022-09-15 15:29:13 +02:00
|
|
|
* @param string[] $allowed_protocols Optional. Array of allowed URL protocols.
|
|
|
|
* Defaults to the result of wp_allowed_protocols().
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return string The filtered and sanitized content result.
|
|
|
|
*/
|
|
|
|
function filter_block_content( $text, $allowed_html = 'post', $allowed_protocols = array() ) {
|
|
|
|
$result = '';
|
|
|
|
|
2023-06-25 12:50:24 +02:00
|
|
|
if ( str_contains( $text, '<!--' ) && str_contains( $text, '--->' ) ) {
|
2023-05-16 16:23:19 +02:00
|
|
|
$text = preg_replace_callback( '%<!--(.*?)--->%', '_filter_block_content_callback', $text );
|
|
|
|
}
|
|
|
|
|
2019-12-12 19:02:03 +01:00
|
|
|
$blocks = parse_blocks( $text );
|
|
|
|
foreach ( $blocks as $block ) {
|
|
|
|
$block = filter_block_kses( $block, $allowed_html, $allowed_protocols );
|
|
|
|
$result .= serialize_block( $block );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
2023-05-16 16:23:19 +02:00
|
|
|
/**
|
|
|
|
* Callback used for regular expression replacement in filter_block_content().
|
|
|
|
*
|
|
|
|
* @since 6.2.1
|
2023-11-06 10:27:23 +01:00
|
|
|
* @access private
|
2023-05-16 16:23:19 +02:00
|
|
|
*
|
|
|
|
* @param array $matches Array of preg_replace_callback matches.
|
|
|
|
* @return string Replacement string.
|
|
|
|
*/
|
|
|
|
function _filter_block_content_callback( $matches ) {
|
|
|
|
return '<!--' . rtrim( $matches[1], '-' ) . '-->';
|
|
|
|
}
|
|
|
|
|
2019-12-12 19:02:03 +01:00
|
|
|
/**
|
2022-09-15 15:29:13 +02:00
|
|
|
* Filters and sanitizes a parsed block to remove non-allowable HTML
|
|
|
|
* from block attribute values.
|
2019-12-12 19:02:03 +01:00
|
|
|
*
|
|
|
|
* @since 5.3.1
|
|
|
|
*
|
|
|
|
* @param WP_Block_Parser_Block $block The parsed block object.
|
2022-09-15 15:29:13 +02:00
|
|
|
* @param array[]|string $allowed_html An array of allowed HTML elements and attributes,
|
|
|
|
* or a context name such as 'post'. See wp_kses_allowed_html()
|
|
|
|
* for the list of accepted context names.
|
|
|
|
* @param string[] $allowed_protocols Optional. Array of allowed URL protocols.
|
|
|
|
* Defaults to the result of wp_allowed_protocols().
|
2019-12-12 19:02:03 +01:00
|
|
|
* @return array The filtered and sanitized block object result.
|
|
|
|
*/
|
|
|
|
function filter_block_kses( $block, $allowed_html, $allowed_protocols = array() ) {
|
2024-06-24 16:42:09 +02:00
|
|
|
$block['attrs'] = filter_block_kses_value( $block['attrs'], $allowed_html, $allowed_protocols, $block );
|
2019-12-12 19:02:03 +01:00
|
|
|
|
|
|
|
if ( is_array( $block['innerBlocks'] ) ) {
|
|
|
|
foreach ( $block['innerBlocks'] as $i => $inner_block ) {
|
|
|
|
$block['innerBlocks'][ $i ] = filter_block_kses( $inner_block, $allowed_html, $allowed_protocols );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $block;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-09-15 15:29:13 +02:00
|
|
|
* Filters and sanitizes a parsed block attribute value to remove
|
|
|
|
* non-allowable HTML.
|
2019-12-12 19:02:03 +01:00
|
|
|
*
|
|
|
|
* @since 5.3.1
|
2024-06-24 16:42:09 +02:00
|
|
|
* @since 6.5.5 Added the `$block_context` parameter.
|
2019-12-12 19:02:03 +01:00
|
|
|
*
|
2020-03-01 11:38:07 +01:00
|
|
|
* @param string[]|string $value The attribute value to filter.
|
2022-09-15 15:29:13 +02:00
|
|
|
* @param array[]|string $allowed_html An array of allowed HTML elements and attributes,
|
|
|
|
* or a context name such as 'post'. See wp_kses_allowed_html()
|
|
|
|
* for the list of accepted context names.
|
|
|
|
* @param string[] $allowed_protocols Optional. Array of allowed URL protocols.
|
|
|
|
* Defaults to the result of wp_allowed_protocols().
|
2024-06-24 16:42:09 +02:00
|
|
|
* @param array $block_context Optional. The block the attribute belongs to, in parsed block array format.
|
2020-03-01 11:38:07 +01:00
|
|
|
* @return string[]|string The filtered and sanitized result.
|
2019-12-12 19:02:03 +01:00
|
|
|
*/
|
2024-06-24 16:42:09 +02:00
|
|
|
function filter_block_kses_value( $value, $allowed_html, $allowed_protocols = array(), $block_context = null ) {
|
2019-12-12 19:02:03 +01:00
|
|
|
if ( is_array( $value ) ) {
|
|
|
|
foreach ( $value as $key => $inner_value ) {
|
2024-06-24 16:42:09 +02:00
|
|
|
$filtered_key = filter_block_kses_value( $key, $allowed_html, $allowed_protocols, $block_context );
|
|
|
|
$filtered_value = filter_block_kses_value( $inner_value, $allowed_html, $allowed_protocols, $block_context );
|
2019-12-12 19:02:03 +01:00
|
|
|
|
2024-06-24 16:42:09 +02:00
|
|
|
if ( isset( $block_context['blockName'] ) && 'core/template-part' === $block_context['blockName'] ) {
|
|
|
|
$filtered_value = filter_block_core_template_part_attributes( $filtered_value, $filtered_key, $allowed_html );
|
|
|
|
}
|
2019-12-12 19:02:03 +01:00
|
|
|
if ( $filtered_key !== $key ) {
|
|
|
|
unset( $value[ $key ] );
|
|
|
|
}
|
|
|
|
|
|
|
|
$value[ $filtered_key ] = $filtered_value;
|
|
|
|
}
|
|
|
|
} elseif ( is_string( $value ) ) {
|
|
|
|
return wp_kses( $value, $allowed_html, $allowed_protocols );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $value;
|
|
|
|
}
|
|
|
|
|
2024-06-24 16:42:09 +02:00
|
|
|
/**
|
|
|
|
* Sanitizes the value of the Template Part block's `tagName` attribute.
|
|
|
|
*
|
|
|
|
* @since 6.5.5
|
|
|
|
*
|
2024-06-25 14:45:18 +02:00
|
|
|
* @param string $attribute_value The attribute value to filter.
|
|
|
|
* @param string $attribute_name The attribute name.
|
|
|
|
* @param array[]|string $allowed_html An array of allowed HTML elements and attributes,
|
|
|
|
* or a context name such as 'post'. See wp_kses_allowed_html()
|
|
|
|
* for the list of accepted context names.
|
2024-06-24 16:42:09 +02:00
|
|
|
* @return string The sanitized attribute value.
|
|
|
|
*/
|
|
|
|
function filter_block_core_template_part_attributes( $attribute_value, $attribute_name, $allowed_html ) {
|
|
|
|
if ( empty( $attribute_value ) || 'tagName' !== $attribute_name ) {
|
|
|
|
return $attribute_value;
|
|
|
|
}
|
|
|
|
if ( ! is_array( $allowed_html ) ) {
|
|
|
|
$allowed_html = wp_kses_allowed_html( $allowed_html );
|
|
|
|
}
|
|
|
|
return isset( $allowed_html[ $attribute_value ] ) ? $attribute_value : '';
|
|
|
|
}
|
|
|
|
|
2018-12-13 23:22:38 +01:00
|
|
|
/**
|
2018-12-17 05:52:00 +01:00
|
|
|
* Parses blocks out of a content string, and renders those appropriate for the excerpt.
|
|
|
|
*
|
|
|
|
* As the excerpt should be a small string of text relevant to the full post content,
|
|
|
|
* this function renders the blocks that are most likely to contain such text.
|
2018-12-13 23:22:38 +01:00
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2018-12-17 05:52:00 +01:00
|
|
|
* @param string $content The content to parse.
|
|
|
|
* @return string The parsed and filtered content.
|
2018-12-13 23:22:38 +01:00
|
|
|
*/
|
2018-12-17 05:52:00 +01:00
|
|
|
function excerpt_remove_blocks( $content ) {
|
2023-09-12 21:20:21 +02:00
|
|
|
if ( ! has_blocks( $content ) ) {
|
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
2019-04-24 23:39:53 +02:00
|
|
|
$allowed_inner_blocks = array(
|
2018-12-17 05:52:00 +01:00
|
|
|
// Classic blocks have their blockName set to null.
|
|
|
|
null,
|
|
|
|
'core/freeform',
|
|
|
|
'core/heading',
|
|
|
|
'core/html',
|
|
|
|
'core/list',
|
|
|
|
'core/media-text',
|
|
|
|
'core/paragraph',
|
|
|
|
'core/preformatted',
|
|
|
|
'core/pullquote',
|
|
|
|
'core/quote',
|
|
|
|
'core/table',
|
|
|
|
'core/verse',
|
|
|
|
);
|
2019-04-24 23:39:53 +02:00
|
|
|
|
2021-07-06 17:32:57 +02:00
|
|
|
$allowed_wrapper_blocks = array(
|
|
|
|
'core/columns',
|
|
|
|
'core/column',
|
|
|
|
'core/group',
|
|
|
|
);
|
|
|
|
|
2021-07-07 21:10:57 +02:00
|
|
|
/**
|
|
|
|
* Filters the list of blocks that can be used as wrapper blocks, allowing
|
2021-07-08 00:39:57 +02:00
|
|
|
* excerpts to be generated from the `innerBlocks` of these wrappers.
|
2021-07-07 21:10:57 +02:00
|
|
|
*
|
|
|
|
* @since 5.8.0
|
|
|
|
*
|
2021-07-22 18:54:58 +02:00
|
|
|
* @param string[] $allowed_wrapper_blocks The list of names of allowed wrapper blocks.
|
2021-07-07 21:10:57 +02:00
|
|
|
*/
|
|
|
|
$allowed_wrapper_blocks = apply_filters( 'excerpt_allowed_wrapper_blocks', $allowed_wrapper_blocks );
|
|
|
|
|
2021-07-06 17:32:57 +02:00
|
|
|
$allowed_blocks = array_merge( $allowed_inner_blocks, $allowed_wrapper_blocks );
|
2019-04-24 23:39:53 +02:00
|
|
|
|
2018-12-17 05:52:00 +01:00
|
|
|
/**
|
|
|
|
* Filters the list of blocks that can contribute to the excerpt.
|
|
|
|
*
|
|
|
|
* If a dynamic block is added to this list, it must not generate another
|
|
|
|
* excerpt, as this will cause an infinite loop to occur.
|
|
|
|
*
|
2019-05-03 18:54:52 +02:00
|
|
|
* @since 5.0.0
|
2018-12-17 05:52:00 +01:00
|
|
|
*
|
2021-07-22 18:54:58 +02:00
|
|
|
* @param string[] $allowed_blocks The list of names of allowed blocks.
|
2018-12-17 05:52:00 +01:00
|
|
|
*/
|
|
|
|
$allowed_blocks = apply_filters( 'excerpt_allowed_blocks', $allowed_blocks );
|
|
|
|
$blocks = parse_blocks( $content );
|
|
|
|
$output = '';
|
2019-04-24 23:39:53 +02:00
|
|
|
|
2018-12-17 05:52:00 +01:00
|
|
|
foreach ( $blocks as $block ) {
|
|
|
|
if ( in_array( $block['blockName'], $allowed_blocks, true ) ) {
|
2019-04-24 23:39:53 +02:00
|
|
|
if ( ! empty( $block['innerBlocks'] ) ) {
|
2021-07-06 17:32:57 +02:00
|
|
|
if ( in_array( $block['blockName'], $allowed_wrapper_blocks, true ) ) {
|
|
|
|
$output .= _excerpt_render_inner_blocks( $block, $allowed_blocks );
|
2019-04-24 23:39:53 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Skip the block if it has disallowed or nested inner blocks.
|
|
|
|
foreach ( $block['innerBlocks'] as $inner_block ) {
|
|
|
|
if (
|
|
|
|
! in_array( $inner_block['blockName'], $allowed_inner_blocks, true ) ||
|
|
|
|
! empty( $inner_block['innerBlocks'] )
|
|
|
|
) {
|
|
|
|
continue 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-17 05:52:00 +01:00
|
|
|
$output .= render_block( $block );
|
|
|
|
}
|
|
|
|
}
|
2019-04-24 23:39:53 +02:00
|
|
|
|
|
|
|
return $output;
|
|
|
|
}
|
|
|
|
|
2023-07-17 03:47:26 +02:00
|
|
|
/**
|
|
|
|
* Parses footnotes markup out of a content string,
|
|
|
|
* and renders those appropriate for the excerpt.
|
|
|
|
*
|
|
|
|
* @since 6.3.0
|
|
|
|
*
|
|
|
|
* @param string $content The content to parse.
|
|
|
|
* @return string The parsed and filtered content.
|
|
|
|
*/
|
|
|
|
function excerpt_remove_footnotes( $content ) {
|
|
|
|
if ( ! str_contains( $content, 'data-fn=' ) ) {
|
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
|
|
|
return preg_replace(
|
|
|
|
'_<sup data-fn="[^"]+" class="[^"]+">\s*<a href="[^"]+" id="[^"]+">\d+</a>\s*</sup>_',
|
|
|
|
'',
|
|
|
|
$content
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2019-04-24 23:39:53 +02:00
|
|
|
/**
|
2022-08-08 10:33:09 +02:00
|
|
|
* Renders inner blocks from the allowed wrapper blocks
|
2021-07-06 17:32:57 +02:00
|
|
|
* for generating an excerpt.
|
2019-04-24 23:39:53 +02:00
|
|
|
*
|
2021-07-22 18:54:58 +02:00
|
|
|
* @since 5.8.0
|
2019-04-24 23:39:53 +02:00
|
|
|
* @access private
|
|
|
|
*
|
2021-07-06 17:32:57 +02:00
|
|
|
* @param array $parsed_block The parsed block.
|
2019-04-24 23:39:53 +02:00
|
|
|
* @param array $allowed_blocks The list of allowed inner blocks.
|
|
|
|
* @return string The rendered inner blocks.
|
|
|
|
*/
|
2021-07-06 17:32:57 +02:00
|
|
|
function _excerpt_render_inner_blocks( $parsed_block, $allowed_blocks ) {
|
2019-04-24 23:39:53 +02:00
|
|
|
$output = '';
|
|
|
|
|
2021-07-06 17:32:57 +02:00
|
|
|
foreach ( $parsed_block['innerBlocks'] as $inner_block ) {
|
|
|
|
if ( ! in_array( $inner_block['blockName'], $allowed_blocks, true ) ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( empty( $inner_block['innerBlocks'] ) ) {
|
|
|
|
$output .= render_block( $inner_block );
|
|
|
|
} else {
|
|
|
|
$output .= _excerpt_render_inner_blocks( $inner_block, $allowed_blocks );
|
2019-04-24 23:39:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $output;
|
2018-12-13 23:22:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-12-17 05:52:00 +01:00
|
|
|
* Renders a single block into a HTML string.
|
2018-12-13 23:22:38 +01:00
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2022-08-08 10:33:09 +02:00
|
|
|
* @global WP_Post $post The post to edit.
|
2018-12-17 05:52:00 +01:00
|
|
|
*
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array $parsed_block {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of the block being rendered. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
2018-12-17 05:52:00 +01:00
|
|
|
* @return string String of rendered HTML.
|
2018-12-13 23:22:38 +01:00
|
|
|
*/
|
2020-06-30 13:04:04 +02:00
|
|
|
function render_block( $parsed_block ) {
|
2021-05-21 17:57:56 +02:00
|
|
|
global $post;
|
2021-10-06 20:49:01 +02:00
|
|
|
$parent_block = null;
|
2018-12-13 23:22:38 +01:00
|
|
|
|
2019-01-11 00:16:50 +01:00
|
|
|
/**
|
2020-11-25 02:20:09 +01:00
|
|
|
* Allows render_block() to be short-circuited, by returning a non-null value.
|
2019-01-11 00:16:50 +01:00
|
|
|
*
|
|
|
|
* @since 5.1.0
|
2021-10-07 15:15:59 +02:00
|
|
|
* @since 5.9.0 The `$parent_block` parameter was added.
|
2019-01-11 00:16:50 +01:00
|
|
|
*
|
2021-10-06 20:49:01 +02:00
|
|
|
* @param string|null $pre_render The pre-rendered content. Default null.
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array $parsed_block {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of the block being rendered. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
2021-10-06 20:49:01 +02:00
|
|
|
* @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
|
2019-01-11 00:16:50 +01:00
|
|
|
*/
|
2021-10-06 20:49:01 +02:00
|
|
|
$pre_render = apply_filters( 'pre_render_block', null, $parsed_block, $parent_block );
|
2019-01-11 00:31:50 +01:00
|
|
|
if ( ! is_null( $pre_render ) ) {
|
2019-01-11 00:16:50 +01:00
|
|
|
return $pre_render;
|
|
|
|
}
|
|
|
|
|
2020-11-25 02:20:09 +01:00
|
|
|
$source_block = $parsed_block;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Filters the block being rendered in render_block(), before it's processed.
|
|
|
|
*
|
|
|
|
* @since 5.1.0
|
2021-10-07 15:15:59 +02:00
|
|
|
* @since 5.9.0 The `$parent_block` parameter was added.
|
2020-11-25 02:20:09 +01:00
|
|
|
*
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array $parsed_block {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of the block being rendered. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
|
|
|
* @param array $source_block {
|
|
|
|
* An un-modified copy of `$parsed_block`, as it appeared in the source content.
|
|
|
|
* See WP_Block_Parser_Block.
|
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
2021-10-06 20:49:01 +02:00
|
|
|
* @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
|
2020-11-25 02:20:09 +01:00
|
|
|
*/
|
2021-10-06 20:49:01 +02:00
|
|
|
$parsed_block = apply_filters( 'render_block_data', $parsed_block, $source_block, $parent_block );
|
2020-11-25 02:20:09 +01:00
|
|
|
|
2020-06-30 13:04:04 +02:00
|
|
|
$context = array();
|
2018-12-17 05:52:00 +01:00
|
|
|
|
2020-07-01 08:08:06 +02:00
|
|
|
if ( $post instanceof WP_Post ) {
|
2020-06-30 13:04:04 +02:00
|
|
|
$context['postId'] = $post->ID;
|
2018-12-13 23:22:38 +01:00
|
|
|
|
2020-06-30 13:04:04 +02:00
|
|
|
/*
|
2020-06-30 13:16:00 +02:00
|
|
|
* The `postType` context is largely unnecessary server-side, since the ID
|
|
|
|
* is usually sufficient on its own. That being said, since a block's
|
|
|
|
* manifest is expected to be shared between the server and the client,
|
|
|
|
* it should be included to consistently fulfill the expectation.
|
|
|
|
*/
|
2020-06-30 13:04:04 +02:00
|
|
|
$context['postType'] = $post->post_type;
|
|
|
|
}
|
|
|
|
|
2020-11-25 02:20:09 +01:00
|
|
|
/**
|
|
|
|
* Filters the default context provided to a rendered block.
|
|
|
|
*
|
|
|
|
* @since 5.5.0
|
2021-10-07 15:15:59 +02:00
|
|
|
* @since 5.9.0 The `$parent_block` parameter was added.
|
2020-11-25 02:20:09 +01:00
|
|
|
*
|
2021-10-06 20:49:01 +02:00
|
|
|
* @param array $context Default context.
|
2024-05-02 21:54:13 +02:00
|
|
|
* @param array $parsed_block {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of the block being rendered. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
2021-10-06 20:49:01 +02:00
|
|
|
* @param WP_Block|null $parent_block If this is a nested block, a reference to the parent block.
|
2020-11-25 02:20:09 +01:00
|
|
|
*/
|
2021-10-06 20:49:01 +02:00
|
|
|
$context = apply_filters( 'render_block_context', $context, $parsed_block, $parent_block );
|
2020-11-25 02:20:09 +01:00
|
|
|
|
2020-06-30 13:04:04 +02:00
|
|
|
$block = new WP_Block( $parsed_block, $context );
|
|
|
|
|
|
|
|
return $block->render();
|
2018-12-13 23:22:38 +01:00
|
|
|
}
|
|
|
|
|
2018-12-13 18:40:39 +01:00
|
|
|
/**
|
|
|
|
* Parses blocks out of a content string.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2018-12-17 05:52:00 +01:00
|
|
|
* @param string $content Post content.
|
2024-05-02 21:54:13 +02:00
|
|
|
* @return array[] {
|
|
|
|
* Array of block structures.
|
|
|
|
*
|
|
|
|
* @type array ...$0 {
|
2024-09-11 14:08:19 +02:00
|
|
|
* An associative array of a single parsed block object. See WP_Block_Parser_Block.
|
2024-05-02 21:54:13 +02:00
|
|
|
*
|
|
|
|
* @type string $blockName Name of block.
|
|
|
|
* @type array $attrs Attributes from block comment delimiters.
|
|
|
|
* @type array[] $innerBlocks List of inner blocks. An array of arrays that
|
|
|
|
* have the same structure as this one.
|
|
|
|
* @type string $innerHTML HTML from inside block comment delimiters.
|
|
|
|
* @type array $innerContent List of string fragments and null markers where
|
|
|
|
* inner blocks were found.
|
|
|
|
* }
|
|
|
|
* }
|
2018-12-13 18:40:39 +01:00
|
|
|
*/
|
|
|
|
function parse_blocks( $content ) {
|
|
|
|
/**
|
2022-08-08 10:33:09 +02:00
|
|
|
* Filter to allow plugins to replace the server-side block parser.
|
2018-12-13 18:40:39 +01:00
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2018-12-13 23:22:38 +01:00
|
|
|
* @param string $parser_class Name of block parser class.
|
2018-12-13 18:40:39 +01:00
|
|
|
*/
|
|
|
|
$parser_class = apply_filters( 'block_parser_class', 'WP_Block_Parser' );
|
|
|
|
|
|
|
|
$parser = new $parser_class();
|
|
|
|
return $parser->parse( $content );
|
|
|
|
}
|
2018-12-13 23:22:38 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses dynamic blocks out of `post_content` and re-renders them.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
2019-05-24 03:05:52 +02:00
|
|
|
* @param string $content Post content.
|
2018-12-13 23:22:38 +01:00
|
|
|
* @return string Updated post content.
|
|
|
|
*/
|
|
|
|
function do_blocks( $content ) {
|
|
|
|
$blocks = parse_blocks( $content );
|
2018-12-17 05:52:00 +01:00
|
|
|
$output = '';
|
|
|
|
|
|
|
|
foreach ( $blocks as $block ) {
|
|
|
|
$output .= render_block( $block );
|
|
|
|
}
|
|
|
|
|
2019-04-08 08:54:54 +02:00
|
|
|
// If there are blocks in this content, we shouldn't run wpautop() on it later.
|
|
|
|
$priority = has_filter( 'the_content', 'wpautop' );
|
|
|
|
if ( false !== $priority && doing_filter( 'the_content' ) && has_blocks( $content ) ) {
|
|
|
|
remove_filter( 'the_content', 'wpautop', $priority );
|
|
|
|
add_filter( 'the_content', '_restore_wpautop_hook', $priority + 1 );
|
|
|
|
}
|
|
|
|
|
2018-12-17 05:52:00 +01:00
|
|
|
return $output;
|
2018-12-13 23:22:38 +01:00
|
|
|
}
|
|
|
|
|
2018-12-17 04:06:12 +01:00
|
|
|
/**
|
2019-04-11 19:27:52 +02:00
|
|
|
* If do_blocks() needs to remove wpautop() from the `the_content` filter, this re-adds it afterwards,
|
2018-12-17 04:06:12 +01:00
|
|
|
* for subsequent `the_content` usage.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
2022-04-12 11:26:16 +02:00
|
|
|
* @access private
|
2018-12-17 04:06:12 +01:00
|
|
|
*
|
|
|
|
* @param string $content The post content running through this filter.
|
|
|
|
* @return string The unmodified content.
|
|
|
|
*/
|
|
|
|
function _restore_wpautop_hook( $content ) {
|
2018-12-17 04:19:38 +01:00
|
|
|
$current_priority = has_filter( 'the_content', '_restore_wpautop_hook' );
|
2018-12-17 04:06:12 +01:00
|
|
|
|
|
|
|
add_filter( 'the_content', 'wpautop', $current_priority - 1 );
|
|
|
|
remove_filter( 'the_content', '_restore_wpautop_hook', $current_priority );
|
|
|
|
|
|
|
|
return $content;
|
|
|
|
}
|
|
|
|
|
2018-12-14 01:55:37 +01:00
|
|
|
/**
|
|
|
|
* Returns the current version of the block format that the content string is using.
|
|
|
|
*
|
|
|
|
* If the string doesn't contain blocks, it returns 0.
|
|
|
|
*
|
|
|
|
* @since 5.0.0
|
|
|
|
*
|
|
|
|
* @param string $content Content to test.
|
2018-12-17 19:07:51 +01:00
|
|
|
* @return int The block format version is 1 if the content contains one or more blocks, 0 otherwise.
|
2018-12-14 01:55:37 +01:00
|
|
|
*/
|
|
|
|
function block_version( $content ) {
|
|
|
|
return has_blocks( $content ) ? 1 : 0;
|
|
|
|
}
|
2019-09-14 20:21:54 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Registers a new block style.
|
|
|
|
*
|
|
|
|
* @since 5.3.0
|
2024-05-30 10:54:07 +02:00
|
|
|
* @since 6.6.0 Added support for registering styles for multiple block types.
|
2019-09-14 20:21:54 +02:00
|
|
|
*
|
2022-08-14 00:38:09 +02:00
|
|
|
* @link https://developer.wordpress.org/block-editor/reference-guides/block-api/block-styles/
|
|
|
|
*
|
2024-05-30 10:54:07 +02:00
|
|
|
* @param string|string[] $block_name Block type name including namespace or array of namespaced block type names.
|
|
|
|
* @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),
|
|
|
|
* style_data (theme.json-like array to generate CSS from).
|
|
|
|
* See WP_Block_Styles_Registry::register().
|
2020-10-10 22:02:05 +02:00
|
|
|
* @return bool True if the block style was registered with success and false otherwise.
|
2019-09-14 20:21:54 +02:00
|
|
|
*/
|
|
|
|
function register_block_style( $block_name, $style_properties ) {
|
|
|
|
return WP_Block_Styles_Registry::get_instance()->register( $block_name, $style_properties );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Unregisters a block style.
|
|
|
|
*
|
|
|
|
* @since 5.3.0
|
|
|
|
*
|
|
|
|
* @param string $block_name Block type name including namespace.
|
2021-03-12 21:05:08 +01:00
|
|
|
* @param string $block_style_name Block style name.
|
2020-10-10 22:02:05 +02:00
|
|
|
* @return bool True if the block style was unregistered with success and false otherwise.
|
2019-09-14 20:21:54 +02:00
|
|
|
*/
|
|
|
|
function unregister_block_style( $block_name, $block_style_name ) {
|
|
|
|
return WP_Block_Styles_Registry::get_instance()->unregister( $block_name, $block_style_name );
|
|
|
|
}
|
2021-04-15 17:19:43 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Checks whether the current block type supports the feature requested.
|
|
|
|
*
|
|
|
|
* @since 5.8.0
|
2023-08-10 18:48:19 +02:00
|
|
|
* @since 6.4.0 The `$feature` parameter now supports a string.
|
2021-04-15 17:19:43 +02:00
|
|
|
*
|
Code Modernization: Rename parameters that use reserved keywords in `wp-includes/blocks.php`.
While using reserved PHP keywords as parameter name labels is allowed, in the context of function calls using named parameters in PHP 8.0+, this will easily lead to confusion. To avoid that, it is recommended not to use reserved keywords as function parameter names.
This commit renames the `$default` parameter to `$default_value` in `block_has_support()`.
Follow-up to [52946], [52996], [52997], [52998], [53003], [53014], [53029], [53039], [53116], [53117], [53137], [53174], [53184], [53185], [53192], [53193], [53198], [53203], [53207], [53215], [53216], [53220], [53230], [53232], [53236], [53239], [53240], [53242], [53243], [53245], [53246], [53257], [53269], [53270], [53271], [53272], [53273], [53274], [53275], [53276], [53277], [53281], [53283], [53284], [53285], [53287], [53364], [53365], [54927], [54929], [54930], [54931], [54932], [54933], [54938], [54943], [54944], [54945], [54946], [54947], [54948], [54950], [54951], [54952], [54956], [54959], [54960], [54961], [54962], [54964], [54965], [54969], [54970], [54971], [54972], [54996], [55000], [55011], [55013], [55014], [55015], [55016], [55017], [55020], [55021], [55023], [55027], [55028], [55034], [55036], [55037], [55038], [55039], [55049], [55050], [55060], [55062], [55064], [55065], [55076], [55077], [55078], [55081], [55090], [55100], [55104], [55112], [55115], [55116], [55117], [55119], [55120].
Props jrf, aristath, poena, justinahinon, SergeyBiryukov.
See #56788.
Built from https://develop.svn.wordpress.org/trunk@55126
git-svn-id: http://core.svn.wordpress.org/trunk@54659 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-01-24 15:42:17 +01:00
|
|
|
* @param WP_Block_Type $block_type Block type to check for support.
|
2023-08-10 18:48:19 +02:00
|
|
|
* @param string|array $feature Feature slug, or path to a specific feature to check support for.
|
Code Modernization: Rename parameters that use reserved keywords in `wp-includes/blocks.php`.
While using reserved PHP keywords as parameter name labels is allowed, in the context of function calls using named parameters in PHP 8.0+, this will easily lead to confusion. To avoid that, it is recommended not to use reserved keywords as function parameter names.
This commit renames the `$default` parameter to `$default_value` in `block_has_support()`.
Follow-up to [52946], [52996], [52997], [52998], [53003], [53014], [53029], [53039], [53116], [53117], [53137], [53174], [53184], [53185], [53192], [53193], [53198], [53203], [53207], [53215], [53216], [53220], [53230], [53232], [53236], [53239], [53240], [53242], [53243], [53245], [53246], [53257], [53269], [53270], [53271], [53272], [53273], [53274], [53275], [53276], [53277], [53281], [53283], [53284], [53285], [53287], [53364], [53365], [54927], [54929], [54930], [54931], [54932], [54933], [54938], [54943], [54944], [54945], [54946], [54947], [54948], [54950], [54951], [54952], [54956], [54959], [54960], [54961], [54962], [54964], [54965], [54969], [54970], [54971], [54972], [54996], [55000], [55011], [55013], [55014], [55015], [55016], [55017], [55020], [55021], [55023], [55027], [55028], [55034], [55036], [55037], [55038], [55039], [55049], [55050], [55060], [55062], [55064], [55065], [55076], [55077], [55078], [55081], [55090], [55100], [55104], [55112], [55115], [55116], [55117], [55119], [55120].
Props jrf, aristath, poena, justinahinon, SergeyBiryukov.
See #56788.
Built from https://develop.svn.wordpress.org/trunk@55126
git-svn-id: http://core.svn.wordpress.org/trunk@54659 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-01-24 15:42:17 +01:00
|
|
|
* @param mixed $default_value Optional. Fallback value for feature support. Default false.
|
2021-07-01 23:02:57 +02:00
|
|
|
* @return bool Whether the feature is supported.
|
2021-04-15 17:19:43 +02:00
|
|
|
*/
|
Code Modernization: Rename parameters that use reserved keywords in `wp-includes/blocks.php`.
While using reserved PHP keywords as parameter name labels is allowed, in the context of function calls using named parameters in PHP 8.0+, this will easily lead to confusion. To avoid that, it is recommended not to use reserved keywords as function parameter names.
This commit renames the `$default` parameter to `$default_value` in `block_has_support()`.
Follow-up to [52946], [52996], [52997], [52998], [53003], [53014], [53029], [53039], [53116], [53117], [53137], [53174], [53184], [53185], [53192], [53193], [53198], [53203], [53207], [53215], [53216], [53220], [53230], [53232], [53236], [53239], [53240], [53242], [53243], [53245], [53246], [53257], [53269], [53270], [53271], [53272], [53273], [53274], [53275], [53276], [53277], [53281], [53283], [53284], [53285], [53287], [53364], [53365], [54927], [54929], [54930], [54931], [54932], [54933], [54938], [54943], [54944], [54945], [54946], [54947], [54948], [54950], [54951], [54952], [54956], [54959], [54960], [54961], [54962], [54964], [54965], [54969], [54970], [54971], [54972], [54996], [55000], [55011], [55013], [55014], [55015], [55016], [55017], [55020], [55021], [55023], [55027], [55028], [55034], [55036], [55037], [55038], [55039], [55049], [55050], [55060], [55062], [55064], [55065], [55076], [55077], [55078], [55081], [55090], [55100], [55104], [55112], [55115], [55116], [55117], [55119], [55120].
Props jrf, aristath, poena, justinahinon, SergeyBiryukov.
See #56788.
Built from https://develop.svn.wordpress.org/trunk@55126
git-svn-id: http://core.svn.wordpress.org/trunk@54659 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-01-24 15:42:17 +01:00
|
|
|
function block_has_support( $block_type, $feature, $default_value = false ) {
|
|
|
|
$block_support = $default_value;
|
2023-09-25 14:17:23 +02:00
|
|
|
if ( $block_type instanceof WP_Block_Type ) {
|
2023-08-10 18:48:19 +02:00
|
|
|
if ( is_array( $feature ) && count( $feature ) === 1 ) {
|
|
|
|
$feature = $feature[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( is_array( $feature ) ) {
|
|
|
|
$block_support = _wp_array_get( $block_type->supports, $feature, $default_value );
|
|
|
|
} elseif ( isset( $block_type->supports[ $feature ] ) ) {
|
|
|
|
$block_support = $block_type->supports[ $feature ];
|
|
|
|
}
|
2021-04-15 17:19:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return true === $block_support || is_array( $block_support );
|
|
|
|
}
|
2021-05-19 17:09:27 +02:00
|
|
|
|
2021-06-15 18:04:58 +02:00
|
|
|
/**
|
|
|
|
* Converts typography keys declared under `supports.*` to `supports.typography.*`.
|
|
|
|
*
|
|
|
|
* Displays a `_doing_it_wrong()` notice when a block using the older format is detected.
|
|
|
|
*
|
|
|
|
* @since 5.8.0
|
|
|
|
*
|
|
|
|
* @param array $metadata Metadata for registering a block type.
|
|
|
|
* @return array Filtered metadata for registering a block type.
|
|
|
|
*/
|
2021-06-08 10:09:53 +02:00
|
|
|
function wp_migrate_old_typography_shape( $metadata ) {
|
2021-06-15 23:37:58 +02:00
|
|
|
if ( ! isset( $metadata['supports'] ) ) {
|
|
|
|
return $metadata;
|
|
|
|
}
|
|
|
|
|
2021-06-08 10:09:53 +02:00
|
|
|
$typography_keys = array(
|
|
|
|
'__experimentalFontFamily',
|
|
|
|
'__experimentalFontStyle',
|
|
|
|
'__experimentalFontWeight',
|
|
|
|
'__experimentalLetterSpacing',
|
|
|
|
'__experimentalTextDecoration',
|
|
|
|
'__experimentalTextTransform',
|
|
|
|
'fontSize',
|
|
|
|
'lineHeight',
|
|
|
|
);
|
2021-06-15 23:37:58 +02:00
|
|
|
|
2021-06-08 10:09:53 +02:00
|
|
|
foreach ( $typography_keys as $typography_key ) {
|
Editor: Reduce the use of the `_wp_array_get()` function to improve performance.
`_wp_array_get()` is an expensive function, and it's called thousands of times on each page view on the front end. While the function performance was slightly improved in #58376, it is still called more times than it should be.
This commit aims to further optimize its usage:
* In many cases, `_wp_array_get()` can be replaced with a much simpler and faster `isset()` check.
* The `isset()` function is capable of checking nested arrays, so `isset( $foo['a']['b']['c'] )` will return false even if `$foo['a']` is unset, without throwing any errors or warnings.
* When `_wp_array_get()` cannot be directly replaced with `isset()`, it would be good practice to wrap it in an `isset()` function so that `_wp_array_get()` only runs when it needs to.
Original PR from Gutenberg repository:
* [https://github.com/WordPress/gutenberg/pull/51116 #51116 Performance improvement: Reduce the use of the _wp_array_get() function]
Follow-up to [55851], [56382].
Props aristath, jrf, spacedmonkey, mukesh27, swissspidy, hellofromTonya.
Fixes #59405.
Built from https://develop.svn.wordpress.org/trunk@56709
git-svn-id: http://core.svn.wordpress.org/trunk@56221 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2023-09-26 15:47:20 +02:00
|
|
|
$support_for_key = isset( $metadata['supports'][ $typography_key ] ) ? $metadata['supports'][ $typography_key ] : null;
|
2021-06-15 23:37:58 +02:00
|
|
|
|
2021-06-08 10:09:53 +02:00
|
|
|
if ( null !== $support_for_key ) {
|
2021-06-15 16:02:59 +02:00
|
|
|
_doing_it_wrong(
|
|
|
|
'register_block_type_from_metadata()',
|
|
|
|
sprintf(
|
|
|
|
/* translators: 1: Block type, 2: Typography supports key, e.g: fontSize, lineHeight, etc. 3: block.json, 4: Old metadata key, 5: New metadata key. */
|
|
|
|
__( 'Block "%1$s" is declaring %2$s support in %3$s file under %4$s. %2$s support is now declared under %5$s.' ),
|
|
|
|
$metadata['name'],
|
|
|
|
"<code>$typography_key</code>",
|
|
|
|
'<code>block.json</code>',
|
|
|
|
"<code>supports.$typography_key</code>",
|
|
|
|
"<code>supports.typography.$typography_key</code>"
|
|
|
|
),
|
|
|
|
'5.8.0'
|
2021-06-08 10:09:53 +02:00
|
|
|
);
|
2021-06-15 23:37:58 +02:00
|
|
|
|
2021-06-15 01:44:58 +02:00
|
|
|
_wp_array_set( $metadata['supports'], array( 'typography', $typography_key ), $support_for_key );
|
2021-06-08 10:09:53 +02:00
|
|
|
unset( $metadata['supports'][ $typography_key ] );
|
|
|
|
}
|
|
|
|
}
|
2021-06-15 23:37:58 +02:00
|
|
|
|
2021-06-08 10:09:53 +02:00
|
|
|
return $metadata;
|
|
|
|
}
|
|
|
|
|
2021-05-19 17:09:27 +02:00
|
|
|
/**
|
|
|
|
* Helper function that constructs a WP_Query args array from
|
|
|
|
* a `Query` block properties.
|
|
|
|
*
|
|
|
|
* It's used in Query Loop, Query Pagination Numbers and Query Pagination Next blocks.
|
|
|
|
*
|
|
|
|
* @since 5.8.0
|
2022-09-15 13:41:10 +02:00
|
|
|
* @since 6.1.0 Added `query_loop_block_query_vars` filter and `parents` support in query.
|
2024-09-30 03:19:16 +02:00
|
|
|
* @since 6.7.0 Added support for the `format` property in query.
|
2021-05-19 17:09:27 +02:00
|
|
|
*
|
|
|
|
* @param WP_Block $block Block instance.
|
|
|
|
* @param int $page Current query's page.
|
|
|
|
*
|
|
|
|
* @return array Returns the constructed WP_Query arguments.
|
|
|
|
*/
|
2021-05-21 12:14:23 +02:00
|
|
|
function build_query_vars_from_query_block( $block, $page ) {
|
2021-05-19 17:09:27 +02:00
|
|
|
$query = array(
|
|
|
|
'post_type' => 'post',
|
|
|
|
'order' => 'DESC',
|
|
|
|
'orderby' => 'date',
|
|
|
|
'post__not_in' => array(),
|
2024-09-30 03:19:16 +02:00
|
|
|
'tax_query' => array(),
|
2021-05-19 17:09:27 +02:00
|
|
|
);
|
|
|
|
|
|
|
|
if ( isset( $block->context['query'] ) ) {
|
2021-07-07 01:57:21 +02:00
|
|
|
if ( ! empty( $block->context['query']['postType'] ) ) {
|
|
|
|
$post_type_param = $block->context['query']['postType'];
|
|
|
|
if ( is_post_type_viewable( $post_type_param ) ) {
|
|
|
|
$query['post_type'] = $post_type_param;
|
|
|
|
}
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
|
|
|
if ( isset( $block->context['query']['sticky'] ) && ! empty( $block->context['query']['sticky'] ) ) {
|
|
|
|
$sticky = get_option( 'sticky_posts' );
|
|
|
|
if ( 'only' === $block->context['query']['sticky'] ) {
|
2023-03-01 17:15:18 +01:00
|
|
|
/*
|
|
|
|
* Passing an empty array to post__in will return have_posts() as true (and all posts will be returned).
|
|
|
|
* Logic should be used before hand to determine if WP_Query should be used in the event that the array
|
|
|
|
* being passed to post__in is empty.
|
|
|
|
*
|
|
|
|
* @see https://core.trac.wordpress.org/ticket/28099
|
|
|
|
*/
|
|
|
|
$query['post__in'] = ! empty( $sticky ) ? $sticky : array( 0 );
|
|
|
|
$query['ignore_sticky_posts'] = 1;
|
2021-05-19 17:09:27 +02:00
|
|
|
} else {
|
|
|
|
$query['post__not_in'] = array_merge( $query['post__not_in'], $sticky );
|
|
|
|
}
|
|
|
|
}
|
2021-07-07 01:57:21 +02:00
|
|
|
if ( ! empty( $block->context['query']['exclude'] ) ) {
|
|
|
|
$excluded_post_ids = array_map( 'intval', $block->context['query']['exclude'] );
|
|
|
|
$excluded_post_ids = array_filter( $excluded_post_ids );
|
|
|
|
$query['post__not_in'] = array_merge( $query['post__not_in'], $excluded_post_ids );
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2021-07-07 01:57:21 +02:00
|
|
|
if (
|
|
|
|
isset( $block->context['query']['perPage'] ) &&
|
|
|
|
is_numeric( $block->context['query']['perPage'] )
|
|
|
|
) {
|
|
|
|
$per_page = absint( $block->context['query']['perPage'] );
|
|
|
|
$offset = 0;
|
|
|
|
|
|
|
|
if (
|
|
|
|
isset( $block->context['query']['offset'] ) &&
|
|
|
|
is_numeric( $block->context['query']['offset'] )
|
|
|
|
) {
|
|
|
|
$offset = absint( $block->context['query']['offset'] );
|
|
|
|
}
|
|
|
|
|
|
|
|
$query['offset'] = ( $per_page * ( $page - 1 ) ) + $offset;
|
|
|
|
$query['posts_per_page'] = $per_page;
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2022-04-12 11:26:16 +02:00
|
|
|
// Migrate `categoryIds` and `tagIds` to `tax_query` for backwards compatibility.
|
|
|
|
if ( ! empty( $block->context['query']['categoryIds'] ) || ! empty( $block->context['query']['tagIds'] ) ) {
|
2024-09-30 03:19:16 +02:00
|
|
|
$tax_query_back_compat = array();
|
2022-04-12 11:26:16 +02:00
|
|
|
if ( ! empty( $block->context['query']['categoryIds'] ) ) {
|
2024-09-30 03:19:16 +02:00
|
|
|
$tax_query_back_compat[] = array(
|
2022-04-12 11:26:16 +02:00
|
|
|
'taxonomy' => 'category',
|
|
|
|
'terms' => array_filter( array_map( 'intval', $block->context['query']['categoryIds'] ) ),
|
|
|
|
'include_children' => false,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
if ( ! empty( $block->context['query']['tagIds'] ) ) {
|
2024-09-30 03:19:16 +02:00
|
|
|
$tax_query_back_compat[] = array(
|
2022-04-12 11:26:16 +02:00
|
|
|
'taxonomy' => 'post_tag',
|
|
|
|
'terms' => array_filter( array_map( 'intval', $block->context['query']['tagIds'] ) ),
|
|
|
|
'include_children' => false,
|
|
|
|
);
|
|
|
|
}
|
2024-09-30 03:19:16 +02:00
|
|
|
$query['tax_query'] = array_merge( $query['tax_query'], $tax_query_back_compat );
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2022-04-12 11:26:16 +02:00
|
|
|
if ( ! empty( $block->context['query']['taxQuery'] ) ) {
|
2024-09-30 03:19:16 +02:00
|
|
|
$tax_query = array();
|
2022-04-12 11:26:16 +02:00
|
|
|
foreach ( $block->context['query']['taxQuery'] as $taxonomy => $terms ) {
|
|
|
|
if ( is_taxonomy_viewable( $taxonomy ) && ! empty( $terms ) ) {
|
2024-09-30 03:19:16 +02:00
|
|
|
$tax_query[] = array(
|
2022-04-12 11:26:16 +02:00
|
|
|
'taxonomy' => $taxonomy,
|
|
|
|
'terms' => array_filter( array_map( 'intval', $terms ) ),
|
|
|
|
'include_children' => false,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2024-09-30 03:19:16 +02:00
|
|
|
$query['tax_query'] = array_merge( $query['tax_query'], $tax_query );
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2024-09-30 03:19:16 +02:00
|
|
|
if ( ! empty( $block->context['query']['format'] ) && is_array( $block->context['query']['format'] ) ) {
|
|
|
|
$formats = $block->context['query']['format'];
|
|
|
|
/*
|
|
|
|
* Validate that the format is either `standard` or a supported post format.
|
|
|
|
* - First, add `standard` to the array of valid formats.
|
|
|
|
* - Then, remove any invalid formats.
|
|
|
|
*/
|
|
|
|
$valid_formats = array_merge( array( 'standard' ), get_post_format_slugs() );
|
|
|
|
$formats = array_intersect( $formats, $valid_formats );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The relation needs to be set to `OR` since the request can contain
|
|
|
|
* two separate conditions. The user may be querying for items that have
|
|
|
|
* either the `standard` format or a specific format.
|
|
|
|
*/
|
|
|
|
$formats_query = array( 'relation' => 'OR' );
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The default post format, `standard`, is not stored in the database.
|
|
|
|
* If `standard` is part of the request, the query needs to exclude all post items that
|
|
|
|
* have a format assigned.
|
|
|
|
*/
|
|
|
|
if ( in_array( 'standard', $formats, true ) ) {
|
|
|
|
$formats_query[] = array(
|
|
|
|
'taxonomy' => 'post_format',
|
|
|
|
'field' => 'slug',
|
|
|
|
'operator' => 'NOT EXISTS',
|
|
|
|
);
|
|
|
|
// Remove the `standard` format, since it cannot be queried.
|
|
|
|
unset( $formats[ array_search( 'standard', $formats, true ) ] );
|
|
|
|
}
|
|
|
|
// Add any remaining formats to the formats query.
|
|
|
|
if ( ! empty( $formats ) ) {
|
|
|
|
// Add the `post-format-` prefix.
|
|
|
|
$terms = array_map(
|
|
|
|
static function ( $format ) {
|
|
|
|
return "post-format-$format";
|
|
|
|
},
|
|
|
|
$formats
|
|
|
|
);
|
|
|
|
$formats_query[] = array(
|
|
|
|
'taxonomy' => 'post_format',
|
|
|
|
'field' => 'slug',
|
|
|
|
'terms' => $terms,
|
|
|
|
'operator' => 'IN',
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Add `$formats_query` to `$query`, as long as it contains more than one key:
|
|
|
|
* If `$formats_query` only contains the initial `relation` key, there are no valid formats to query,
|
|
|
|
* and the query should not be modified.
|
|
|
|
*/
|
|
|
|
if ( count( $formats_query ) > 1 ) {
|
|
|
|
// Enable filtering by both post formats and other taxonomies by combining them with `AND`.
|
|
|
|
if ( empty( $query['tax_query'] ) ) {
|
|
|
|
$query['tax_query'] = $formats_query;
|
|
|
|
} else {
|
|
|
|
$query['tax_query'] = array(
|
|
|
|
'relation' => 'AND',
|
|
|
|
$query['tax_query'],
|
|
|
|
$formats_query,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-07-07 01:57:21 +02:00
|
|
|
if (
|
|
|
|
isset( $block->context['query']['order'] ) &&
|
|
|
|
in_array( strtoupper( $block->context['query']['order'] ), array( 'ASC', 'DESC' ), true )
|
|
|
|
) {
|
2021-05-19 17:09:27 +02:00
|
|
|
$query['order'] = strtoupper( $block->context['query']['order'] );
|
|
|
|
}
|
|
|
|
if ( isset( $block->context['query']['orderBy'] ) ) {
|
|
|
|
$query['orderby'] = $block->context['query']['orderBy'];
|
|
|
|
}
|
2021-07-07 01:57:21 +02:00
|
|
|
if (
|
2023-06-29 15:30:33 +02:00
|
|
|
isset( $block->context['query']['author'] )
|
2021-07-07 01:57:21 +02:00
|
|
|
) {
|
2023-06-29 15:30:33 +02:00
|
|
|
if ( is_array( $block->context['query']['author'] ) ) {
|
|
|
|
$query['author__in'] = array_filter( array_map( 'intval', $block->context['query']['author'] ) );
|
|
|
|
} elseif ( is_string( $block->context['query']['author'] ) ) {
|
|
|
|
$query['author__in'] = array_filter( array_map( 'intval', explode( ',', $block->context['query']['author'] ) ) );
|
|
|
|
} elseif ( is_int( $block->context['query']['author'] ) && $block->context['query']['author'] > 0 ) {
|
|
|
|
$query['author'] = $block->context['query']['author'];
|
|
|
|
}
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2021-07-07 01:57:21 +02:00
|
|
|
if ( ! empty( $block->context['query']['search'] ) ) {
|
2021-05-19 17:09:27 +02:00
|
|
|
$query['s'] = $block->context['query']['search'];
|
|
|
|
}
|
2022-09-15 13:41:10 +02:00
|
|
|
if ( ! empty( $block->context['query']['parents'] ) && is_post_type_hierarchical( $query['post_type'] ) ) {
|
|
|
|
$query['post_parent__in'] = array_filter( array_map( 'intval', $block->context['query']['parents'] ) );
|
|
|
|
}
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2022-09-15 13:41:10 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Filters the arguments which will be passed to `WP_Query` for the Query Loop Block.
|
|
|
|
*
|
|
|
|
* Anything to this filter should be compatible with the `WP_Query` API to form
|
|
|
|
* the query context which will be passed down to the Query Loop Block's children.
|
|
|
|
* This can help, for example, to include additional settings or meta queries not
|
|
|
|
* directly supported by the core Query Loop Block, and extend its capabilities.
|
|
|
|
*
|
|
|
|
* Please note that this will only influence the query that will be rendered on the
|
|
|
|
* front-end. The editor preview is not affected by this filter. Also, worth noting
|
|
|
|
* that the editor preview uses the REST API, so, ideally, one should aim to provide
|
|
|
|
* attributes which are also compatible with the REST API, in order to be able to
|
|
|
|
* implement identical queries on both sides.
|
|
|
|
*
|
|
|
|
* @since 6.1.0
|
|
|
|
*
|
|
|
|
* @param array $query Array containing parameters for `WP_Query` as parsed by the block context.
|
|
|
|
* @param WP_Block $block Block instance.
|
|
|
|
* @param int $page Current query's page.
|
|
|
|
*/
|
|
|
|
return apply_filters( 'query_loop_block_query_vars', $query, $block, $page );
|
2021-05-19 17:09:27 +02:00
|
|
|
}
|
2021-11-08 23:31:58 +01:00
|
|
|
|
|
|
|
/**
|
2022-04-28 11:59:13 +02:00
|
|
|
* Helper function that returns the proper pagination arrow HTML for
|
2021-11-08 23:31:58 +01:00
|
|
|
* `QueryPaginationNext` and `QueryPaginationPrevious` blocks based
|
|
|
|
* on the provided `paginationArrow` from `QueryPagination` context.
|
|
|
|
*
|
|
|
|
* It's used in QueryPaginationNext and QueryPaginationPrevious blocks.
|
|
|
|
*
|
2021-11-09 00:10:59 +01:00
|
|
|
* @since 5.9.0
|
|
|
|
*
|
2021-11-08 23:31:58 +01:00
|
|
|
* @param WP_Block $block Block instance.
|
2022-08-08 10:33:09 +02:00
|
|
|
* @param bool $is_next Flag for handling `next/previous` blocks.
|
2022-04-28 11:59:13 +02:00
|
|
|
* @return string|null The pagination arrow HTML or null if there is none.
|
2021-11-08 23:31:58 +01:00
|
|
|
*/
|
|
|
|
function get_query_pagination_arrow( $block, $is_next ) {
|
|
|
|
$arrow_map = array(
|
|
|
|
'none' => '',
|
|
|
|
'arrow' => array(
|
|
|
|
'next' => '→',
|
|
|
|
'previous' => '←',
|
|
|
|
),
|
|
|
|
'chevron' => array(
|
|
|
|
'next' => '»',
|
|
|
|
'previous' => '«',
|
|
|
|
),
|
|
|
|
);
|
|
|
|
if ( ! empty( $block->context['paginationArrow'] ) && array_key_exists( $block->context['paginationArrow'], $arrow_map ) && ! empty( $arrow_map[ $block->context['paginationArrow'] ] ) ) {
|
|
|
|
$pagination_type = $is_next ? 'next' : 'previous';
|
|
|
|
$arrow_attribute = $block->context['paginationArrow'];
|
|
|
|
$arrow = $arrow_map[ $block->context['paginationArrow'] ][ $pagination_type ];
|
|
|
|
$arrow_classes = "wp-block-query-pagination-$pagination_type-arrow is-arrow-$arrow_attribute";
|
2022-09-13 01:34:12 +02:00
|
|
|
return "<span class='$arrow_classes' aria-hidden='true'>$arrow</span>";
|
2021-11-08 23:31:58 +01:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2021-11-09 03:17:17 +01:00
|
|
|
|
2022-04-11 17:22:09 +02:00
|
|
|
/**
|
|
|
|
* Helper function that constructs a comment query vars array from the passed
|
|
|
|
* block properties.
|
|
|
|
*
|
|
|
|
* It's used with the Comment Query Loop inner blocks.
|
|
|
|
*
|
|
|
|
* @since 6.0.0
|
|
|
|
*
|
|
|
|
* @param WP_Block $block Block instance.
|
|
|
|
* @return array Returns the comment query parameters to use with the
|
2022-04-28 11:59:13 +02:00
|
|
|
* WP_Comment_Query constructor.
|
2022-04-11 17:22:09 +02:00
|
|
|
*/
|
|
|
|
function build_comment_query_vars_from_block( $block ) {
|
|
|
|
|
|
|
|
$comment_args = array(
|
2022-04-28 03:18:13 +02:00
|
|
|
'orderby' => 'comment_date_gmt',
|
|
|
|
'order' => 'ASC',
|
|
|
|
'status' => 'approve',
|
|
|
|
'no_found_rows' => false,
|
2022-04-11 17:22:09 +02:00
|
|
|
);
|
|
|
|
|
2022-04-28 03:18:13 +02:00
|
|
|
if ( is_user_logged_in() ) {
|
|
|
|
$comment_args['include_unapproved'] = array( get_current_user_id() );
|
|
|
|
} else {
|
|
|
|
$unapproved_email = wp_get_unapproved_comment_author_email();
|
|
|
|
|
|
|
|
if ( $unapproved_email ) {
|
|
|
|
$comment_args['include_unapproved'] = array( $unapproved_email );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-11 17:22:09 +02:00
|
|
|
if ( ! empty( $block->context['postId'] ) ) {
|
|
|
|
$comment_args['post_id'] = (int) $block->context['postId'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( get_option( 'thread_comments' ) ) {
|
|
|
|
$comment_args['hierarchical'] = 'threaded';
|
|
|
|
} else {
|
|
|
|
$comment_args['hierarchical'] = false;
|
|
|
|
}
|
|
|
|
|
2022-04-11 18:35:10 +02:00
|
|
|
if ( get_option( 'page_comments' ) === '1' || get_option( 'page_comments' ) === true ) {
|
|
|
|
$per_page = get_option( 'comments_per_page' );
|
|
|
|
$default_page = get_option( 'default_comments_page' );
|
|
|
|
if ( $per_page > 0 ) {
|
|
|
|
$comment_args['number'] = $per_page;
|
|
|
|
|
|
|
|
$page = (int) get_query_var( 'cpage' );
|
|
|
|
if ( $page ) {
|
|
|
|
$comment_args['paged'] = $page;
|
|
|
|
} elseif ( 'oldest' === $default_page ) {
|
|
|
|
$comment_args['paged'] = 1;
|
|
|
|
} elseif ( 'newest' === $default_page ) {
|
2022-05-03 16:33:12 +02:00
|
|
|
$max_num_pages = (int) ( new WP_Comment_Query( $comment_args ) )->max_num_pages;
|
|
|
|
if ( 0 !== $max_num_pages ) {
|
|
|
|
$comment_args['paged'] = $max_num_pages;
|
|
|
|
}
|
2022-04-11 18:35:10 +02:00
|
|
|
}
|
2022-04-11 17:22:09 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $comment_args;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2022-04-28 11:59:13 +02:00
|
|
|
* Helper function that returns the proper pagination arrow HTML for
|
2022-04-11 17:22:09 +02:00
|
|
|
* `CommentsPaginationNext` and `CommentsPaginationPrevious` blocks based on the
|
|
|
|
* provided `paginationArrow` from `CommentsPagination` context.
|
|
|
|
*
|
|
|
|
* It's used in CommentsPaginationNext and CommentsPaginationPrevious blocks.
|
|
|
|
*
|
|
|
|
* @since 6.0.0
|
|
|
|
*
|
|
|
|
* @param WP_Block $block Block instance.
|
2022-10-16 17:46:15 +02:00
|
|
|
* @param string $pagination_type Optional. Type of the arrow we will be rendering.
|
|
|
|
* Accepts 'next' or 'previous'. Default 'next'.
|
2022-04-28 11:59:13 +02:00
|
|
|
* @return string|null The pagination arrow HTML or null if there is none.
|
2022-04-11 17:22:09 +02:00
|
|
|
*/
|
|
|
|
function get_comments_pagination_arrow( $block, $pagination_type = 'next' ) {
|
|
|
|
$arrow_map = array(
|
|
|
|
'none' => '',
|
|
|
|
'arrow' => array(
|
|
|
|
'next' => '→',
|
|
|
|
'previous' => '←',
|
|
|
|
),
|
|
|
|
'chevron' => array(
|
|
|
|
'next' => '»',
|
|
|
|
'previous' => '«',
|
|
|
|
),
|
|
|
|
);
|
|
|
|
if ( ! empty( $block->context['comments/paginationArrow'] ) && ! empty( $arrow_map[ $block->context['comments/paginationArrow'] ][ $pagination_type ] ) ) {
|
|
|
|
$arrow_attribute = $block->context['comments/paginationArrow'];
|
|
|
|
$arrow = $arrow_map[ $block->context['comments/paginationArrow'] ][ $pagination_type ];
|
|
|
|
$arrow_classes = "wp-block-comments-pagination-$pagination_type-arrow is-arrow-$arrow_attribute";
|
2022-09-13 01:34:12 +02:00
|
|
|
return "<span class='$arrow_classes' aria-hidden='true'>$arrow</span>";
|
2022-04-11 17:22:09 +02:00
|
|
|
}
|
|
|
|
return null;
|
|
|
|
}
|
2023-10-12 14:58:23 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Strips all HTML from the content of footnotes, and sanitizes the ID.
|
2023-11-17 14:29:26 +01:00
|
|
|
*
|
2023-10-12 14:58:23 +02:00
|
|
|
* This function expects slashed data on the footnotes content.
|
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @since 6.3.2
|
|
|
|
*
|
2023-11-17 14:29:26 +01:00
|
|
|
* @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.
|
2023-10-12 14:58:23 +02:00
|
|
|
*/
|
|
|
|
function _wp_filter_post_meta_footnotes( $footnotes ) {
|
2023-11-02 01:04:24 +01:00
|
|
|
$footnotes_decoded = json_decode( $footnotes, true );
|
2023-10-12 14:58:23 +02:00
|
|
|
if ( ! is_array( $footnotes_decoded ) ) {
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
$footnotes_sanitized = array();
|
|
|
|
foreach ( $footnotes_decoded as $footnote ) {
|
|
|
|
if ( ! empty( $footnote['content'] ) && ! empty( $footnote['id'] ) ) {
|
|
|
|
$footnotes_sanitized[] = array(
|
|
|
|
'id' => sanitize_key( $footnote['id'] ),
|
|
|
|
'content' => wp_unslash( wp_filter_post_kses( wp_slash( $footnote['content'] ) ) ),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return wp_json_encode( $footnotes_sanitized );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-11-17 14:29:26 +01:00
|
|
|
* Adds the filters for footnotes meta field.
|
2023-10-12 14:58:23 +02:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @since 6.3.2
|
|
|
|
*/
|
|
|
|
function _wp_footnotes_kses_init_filters() {
|
|
|
|
add_filter( 'sanitize_post_meta_footnotes', '_wp_filter_post_meta_footnotes' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-11-17 14:29:26 +01:00
|
|
|
* Removes the filters for footnotes meta field.
|
2023-10-12 14:58:23 +02:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @since 6.3.2
|
|
|
|
*/
|
|
|
|
function _wp_footnotes_remove_filters() {
|
|
|
|
remove_filter( 'sanitize_post_meta_footnotes', '_wp_filter_post_meta_footnotes' );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-11-17 14:29:26 +01:00
|
|
|
* Registers the filter of footnotes meta field if the user does not have `unfiltered_html` capability.
|
2023-10-12 14:58:23 +02:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @since 6.3.2
|
|
|
|
*/
|
|
|
|
function _wp_footnotes_kses_init() {
|
|
|
|
_wp_footnotes_remove_filters();
|
|
|
|
if ( ! current_user_can( 'unfiltered_html' ) ) {
|
|
|
|
_wp_footnotes_kses_init_filters();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2023-11-17 14:29:26 +01:00
|
|
|
* Initializes the filters for footnotes meta field when imported data should be filtered.
|
2023-10-12 14:58:23 +02:00
|
|
|
*
|
2023-11-17 14:29:26 +01:00
|
|
|
* 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().
|
2023-10-12 14:58:23 +02:00
|
|
|
*
|
|
|
|
* @access private
|
|
|
|
* @since 6.3.2
|
|
|
|
*
|
|
|
|
* @param string $arg Input argument of the filter.
|
|
|
|
* @return string Input argument of the filter.
|
|
|
|
*/
|
|
|
|
function _wp_footnotes_force_filtered_html_on_import_filter( $arg ) {
|
2023-11-17 14:29:26 +01:00
|
|
|
// If `force_filtered_html_on_import` is true, we need to init the global styles kses filters.
|
2023-10-12 14:58:23 +02:00
|
|
|
if ( $arg ) {
|
|
|
|
_wp_footnotes_kses_init_filters();
|
|
|
|
}
|
|
|
|
return $arg;
|
|
|
|
}
|