wp/wp-includes/blocks.php
changeset 18 be944660c56a
parent 16 a86126ab1dd4
child 19 3d72ae0968f4
--- a/wp/wp-includes/blocks.php	Tue Dec 15 15:52:01 2020 +0100
+++ b/wp/wp-includes/blocks.php	Wed Sep 21 18:19:35 2022 +0200
@@ -8,40 +8,6 @@
  */
 
 /**
- * Registers 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. 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`.
- *     Any arguments may be defined, however the ones described below are supported by default.
- *     Default empty array.
- *
- *     @type callable $render_callback Callback used to render blocks of this block type.
- * }
- * @return WP_Block_Type|false The registered block type on success, or false on failure.
- */
-function register_block_type( $name, $args = array() ) {
-	return WP_Block_Type_Registry::get_instance()->register( $name, $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 );
-}
-
-/**
  * Removes the block asset's path prefix if provided.
  *
  * @since 5.5.0
@@ -71,6 +37,14 @@
  * @return string Generated asset name for the block's field.
  */
 function generate_block_asset_handle( $block_name, $field_name ) {
+	if ( 0 === strpos( $block_name, 'core/' ) ) {
+		$asset_handle = str_replace( 'core/', 'wp-block-', $block_name );
+		if ( 0 === strpos( $field_name, 'editor' ) ) {
+			$asset_handle .= '-editor';
+		}
+		return $asset_handle;
+	}
+
 	$field_mappings = array(
 		'editorScript' => 'editor-script',
 		'script'       => 'script',
@@ -91,8 +65,8 @@
  *
  * @param array  $metadata   Block metadata.
  * @param string $field_name Field name to pick from metadata.
- * @return string|bool Script handle provided directly or created through
- *                     script's registration, or false on failure.
+ * @return string|false Script handle provided directly or created through
+ *                      script's registration, or false on failure.
  */
 function register_block_script_handle( $metadata, $field_name ) {
 	if ( empty( $metadata[ $field_name ] ) ) {
@@ -110,13 +84,16 @@
 		substr_replace( $script_path, '.asset.php', - strlen( '.js' ) )
 	);
 	if ( ! file_exists( $script_asset_path ) ) {
-		$message = sprintf(
-			/* translators: %1: field name. %2: block name */
-			__( 'The asset file for the "%1$s" defined in "%2$s" block definition is missing.', 'default' ),
-			$field_name,
-			$metadata['name']
+		_doing_it_wrong(
+			__FUNCTION__,
+			sprintf(
+				/* translators: 1: Field name, 2: Block name. */
+				__( 'The asset file for the "%1$s" defined in "%2$s" block definition is missing.' ),
+				$field_name,
+				$metadata['name']
+			),
+			'5.5.0'
 		);
-		_doing_it_wrong( __FUNCTION__, $message, '5.5.0' );
 		return false;
 	}
 	$script_asset = require $script_asset_path;
@@ -126,7 +103,15 @@
 		$script_asset['dependencies'],
 		$script_asset['version']
 	);
-	return $result ? $script_handle : false;
+	if ( ! $result ) {
+		return false;
+	}
+
+	if ( ! empty( $metadata['textdomain'] ) ) {
+		wp_set_script_translations( $script_handle, $metadata['textdomain'] );
+	}
+
+	return $script_handle;
 }
 
 /**
@@ -136,46 +121,73 @@
  *
  * @since 5.5.0
  *
- * @param array  $metadata Block metadata.
+ * @param array  $metadata   Block metadata.
  * @param string $field_name Field name to pick from metadata.
- * @return string|boolean Style handle provided directly or created through
- *                        style's registration, or false on failure.
+ * @return string|false Style handle provided directly or created through
+ *                      style's registration, or false on failure.
  */
 function register_block_style_handle( $metadata, $field_name ) {
 	if ( empty( $metadata[ $field_name ] ) ) {
 		return false;
 	}
+	$is_core_block = isset( $metadata['file'] ) && 0 === strpos( $metadata['file'], ABSPATH . WPINC );
+	if ( $is_core_block && ! wp_should_load_separate_core_block_assets() ) {
+		return false;
+	}
+
+	// Check whether styles should have a ".min" suffix or not.
+	$suffix = SCRIPT_DEBUG ? '' : '.min';
+
 	$style_handle = $metadata[ $field_name ];
 	$style_path   = remove_block_asset_path_prefix( $metadata[ $field_name ] );
-	if ( $style_handle === $style_path ) {
+
+	if ( $style_handle === $style_path && ! $is_core_block ) {
 		return $style_handle;
 	}
 
-	$style_handle = generate_block_asset_handle( $metadata['name'], $field_name );
-	$block_dir    = dirname( $metadata['file'] );
-	$result       = wp_register_style(
+	$style_uri = plugins_url( $style_path, $metadata['file'] );
+	if ( $is_core_block ) {
+		$style_path = "style$suffix.css";
+		$style_uri  = includes_url( 'blocks/' . str_replace( 'core/', '', $metadata['name'] ) . "/style$suffix.css" );
+	}
+
+	$style_handle   = generate_block_asset_handle( $metadata['name'], $field_name );
+	$block_dir      = dirname( $metadata['file'] );
+	$style_file     = realpath( "$block_dir/$style_path" );
+	$has_style_file = false !== $style_file;
+	$version        = ! $is_core_block && isset( $metadata['version'] ) ? $metadata['version'] : false;
+	$style_uri      = $has_style_file ? $style_uri : false;
+	$result         = wp_register_style(
 		$style_handle,
-		plugins_url( $style_path, $metadata['file'] ),
+		$style_uri,
 		array(),
-		filemtime( realpath( "$block_dir/$style_path" ) )
+		$version
 	);
+	if ( file_exists( str_replace( '.css', '-rtl.css', $style_file ) ) ) {
+		wp_style_add_data( $style_handle, 'rtl', 'replace' );
+	}
+	if ( $has_style_file ) {
+		wp_style_add_data( $style_handle, 'path', $style_file );
+	}
+
+	$rtl_file = str_replace( "$suffix.css", "-rtl$suffix.css", $style_file );
+	if ( is_rtl() && file_exists( $rtl_file ) ) {
+		wp_style_add_data( $style_handle, 'path', $rtl_file );
+	}
+
 	return $result ? $style_handle : false;
 }
 
 /**
- * Registers a block type from metadata stored in the `block.json` file.
+ * Registers a block type from the metadata stored in the `block.json` file.
  *
  * @since 5.5.0
  *
  * @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.
- * @param array  $args {
- *     Optional. Array of block type arguments. Accepts any public property of `WP_Block_Type`.
- *     Any arguments may be defined, however the ones described below are supported by default.
- *     Default empty array.
- *
- *     @type callable $render_callback Callback used to render blocks of this block type.
- * }
+ * @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_from_metadata( $file_or_folder, $args = array() ) {
@@ -193,6 +205,27 @@
 	}
 	$metadata['file'] = $metadata_file;
 
+	/**
+	 * 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 );
+
+	// Add `style` and `editor_style` for core blocks if missing.
+	if ( ! empty( $metadata['name'] ) && 0 === strpos( $metadata['name'], 'core/' ) ) {
+		$block_name = str_replace( 'core/', '', $metadata['name'] );
+
+		if ( ! isset( $metadata['style'] ) ) {
+			$metadata['style'] = "wp-block-$block_name";
+		}
+		if ( ! isset( $metadata['editorStyle'] ) ) {
+			$metadata['editorStyle'] = "wp-block-{$block_name}-editor";
+		}
+	}
+
 	$settings          = array();
 	$property_mappings = array(
 		'title'           => 'title',
@@ -207,11 +240,53 @@
 		'supports'        => 'supports',
 		'styles'          => 'styles',
 		'example'         => 'example',
+		'apiVersion'      => 'api_version',
 	);
 
 	foreach ( $property_mappings as $key => $mapped_key ) {
 		if ( isset( $metadata[ $key ] ) ) {
-			$settings[ $mapped_key ] = $metadata[ $key ];
+			$value = $metadata[ $key ];
+			if ( empty( $metadata['textdomain'] ) ) {
+				$settings[ $mapped_key ] = $value;
+				continue;
+			}
+			$textdomain = $metadata['textdomain'];
+			switch ( $key ) {
+				case 'title':
+				case 'description':
+					// phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralContext,WordPress.WP.I18n.NonSingularStringLiteralDomain
+					$settings[ $mapped_key ] = translate_with_gettext_context( $value, sprintf( 'block %s', $key ), $textdomain );
+					break;
+				case 'keywords':
+					$settings[ $mapped_key ] = array();
+					if ( ! is_array( $value ) ) {
+						continue 2;
+					}
+
+					foreach ( $value as $keyword ) {
+						// phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
+						$settings[ $mapped_key ][] = translate_with_gettext_context( $keyword, 'block keyword', $textdomain );
+					}
+
+					break;
+				case 'styles':
+					$settings[ $mapped_key ] = array();
+					if ( ! is_array( $value ) ) {
+						continue 2;
+					}
+
+					foreach ( $value as $style ) {
+						if ( ! empty( $style['label'] ) ) {
+							// phpcs:ignore WordPress.WP.I18n.LowLevelTranslationFunction,WordPress.WP.I18n.NonSingularStringLiteralText,WordPress.WP.I18n.NonSingularStringLiteralDomain
+							$style['label'] = translate_with_gettext_context( $style['label'], 'block style label', $textdomain );
+						}
+						$settings[ $mapped_key ][] = $style;
+					}
+
+					break;
+				default:
+					$settings[ $mapped_key ] = $value;
+			}
 		}
 	}
 
@@ -243,16 +318,69 @@
 		);
 	}
 
-	return register_block_type(
-		$metadata['name'],
+	/**
+	 * 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.
+	 */
+	$settings = apply_filters(
+		'block_type_metadata_settings',
 		array_merge(
 			$settings,
 			$args
-		)
+		),
+		$metadata
+	);
+
+	return WP_Block_Type_Registry::get_instance()->register(
+		$metadata['name'],
+		$settings
 	);
 }
 
 /**
+ * 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
+ * @since 5.8.0 First param accepts a path to the `block.json` file.
+ *
+ * @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 );
+}
+
+/**
  * Determine whether a post or content string has blocks.
  *
  * This test optimizes for performance rather than strict accuracy, detecting
@@ -263,7 +391,8 @@
  *
  * @see parse_blocks()
  *
- * @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object. Defaults to global $post.
+ * @param int|string|WP_Post|null $post Optional. Post content, post ID, or post object.
+ *                                      Defaults to global $post.
  * @return bool Whether the post has blocks.
  */
 function has_blocks( $post = null ) {
@@ -281,15 +410,16 @@
  * Determine whether a $post or a string contains a specific block type.
  *
  * This test optimizes for performance rather than strict accuracy, detecting
- * the block type exists but not validating its structure. For strict accuracy,
- * you should use the block parser on post content.
+ * whether the block type exists but not validating its structure and not checking
+ * reusable blocks. For strict accuracy, you should use the block parser on post content.
  *
  * @since 5.0.0
  *
  * @see parse_blocks()
  *
- * @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.
+ * @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.
  * @return bool Whether the post content contains the specified block.
  */
 function has_block( $block_name, $post = null ) {
@@ -358,13 +488,17 @@
  * substitution for characters which might otherwise interfere with embedding
  * the result in an HTML comment.
  *
+ * 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.
+ *
  * @since 5.3.1
  *
  * @param array $block_attributes Attributes object.
  * @return string Serialized attributes.
  */
 function serialize_block_attributes( $block_attributes ) {
-	$encoded_attributes = json_encode( $block_attributes );
+	$encoded_attributes = wp_json_encode( $block_attributes, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
 	$encoded_attributes = preg_replace( '/--/', '\\u002d\\u002d', $encoded_attributes );
 	$encoded_attributes = preg_replace( '/</', '\\u003c', $encoded_attributes );
 	$encoded_attributes = preg_replace( '/>/', '\\u003e', $encoded_attributes );
@@ -397,12 +531,13 @@
  *
  * @since 5.3.1
  *
- * @param string $block_name       Block name.
- * @param array  $block_attributes Block attributes.
- * @param string $block_content    Block save content.
+ * @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.
  * @return string Comment-delimited block content.
  */
-function get_comment_delimited_block_content( $block_name = null, $block_attributes, $block_content ) {
+function get_comment_delimited_block_content( $block_name, $block_attributes, $block_content ) {
 	if ( is_null( $block_name ) ) {
 		return $block_content;
 	}
@@ -579,7 +714,23 @@
 		'core/verse',
 	);
 
-	$allowed_blocks = array_merge( $allowed_inner_blocks, array( 'core/columns' ) );
+	$allowed_wrapper_blocks = array(
+		'core/columns',
+		'core/column',
+		'core/group',
+	);
+
+	/**
+	 * Filters the list of blocks that can be used as wrapper blocks, allowing
+	 * excerpts to be generated from the `innerBlocks` of these wrappers.
+	 *
+	 * @since 5.8.0
+	 *
+	 * @param array $allowed_wrapper_blocks The list of allowed wrapper blocks.
+	 */
+	$allowed_wrapper_blocks = apply_filters( 'excerpt_allowed_wrapper_blocks', $allowed_wrapper_blocks );
+
+	$allowed_blocks = array_merge( $allowed_inner_blocks, $allowed_wrapper_blocks );
 
 	/**
 	 * Filters the list of blocks that can contribute to the excerpt.
@@ -598,8 +749,8 @@
 	foreach ( $blocks as $block ) {
 		if ( in_array( $block['blockName'], $allowed_blocks, true ) ) {
 			if ( ! empty( $block['innerBlocks'] ) ) {
-				if ( 'core/columns' === $block['blockName'] ) {
-					$output .= _excerpt_render_inner_columns_blocks( $block, $allowed_inner_blocks );
+				if ( in_array( $block['blockName'], $allowed_wrapper_blocks, true ) ) {
+					$output .= _excerpt_render_inner_blocks( $block, $allowed_blocks );
 					continue;
 				}
 
@@ -622,23 +773,28 @@
 }
 
 /**
- * Render inner blocks from the `core/columns` block for generating an excerpt.
+ * Render inner blocks from the allowed wrapper blocks
+ * for generating an excerpt.
  *
- * @since 5.2.0
+ * @since 5.8
  * @access private
  *
- * @param array $columns        The parsed columns block.
+ * @param array $parsed_block   The parsed block.
  * @param array $allowed_blocks The list of allowed inner blocks.
  * @return string The rendered inner blocks.
  */
-function _excerpt_render_inner_columns_blocks( $columns, $allowed_blocks ) {
+function _excerpt_render_inner_blocks( $parsed_block, $allowed_blocks ) {
 	$output = '';
 
-	foreach ( $columns['innerBlocks'] as $column ) {
-		foreach ( $column['innerBlocks'] as $inner_block ) {
-			if ( in_array( $inner_block['blockName'], $allowed_blocks, true ) && empty( $inner_block['innerBlocks'] ) ) {
-				$output .= render_block( $inner_block );
-			}
+	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 );
 		}
 	}
 
@@ -651,13 +807,12 @@
  * @since 5.0.0
  *
  * @global WP_Post  $post     The post to edit.
- * @global WP_Query $wp_query WordPress Query object.
  *
  * @param array $parsed_block A single parsed block object.
  * @return string String of rendered HTML.
  */
 function render_block( $parsed_block ) {
-	global $post, $wp_query;
+	global $post;
 
 	/**
 	 * Allows render_block() to be short-circuited, by returning a non-null value.
@@ -698,13 +853,6 @@
 		$context['postType'] = $post->post_type;
 	}
 
-	if ( $wp_query instanceof WP_Query && isset( $wp_query->tax_query->queried_terms['category'] ) ) {
-		$context['query'] = array( 'categoryIds' => array() );
-		foreach ( $wp_query->tax_query->queried_terms['category']['terms'] as $category_slug_or_id ) {
-			$context['query']['categoryIds'][] = 'slug' === $wp_query->tax_query->queried_terms['category']['field'] ? get_cat_ID( $category_slug_or_id ) : $category_slug_or_id;
-		}
-	}
-
 	/**
 	 * Filters the default context provided to a rendered block.
 	 *
@@ -811,7 +959,7 @@
  * @param array  $style_properties Array containing the properties of the style name,
  *                                 label, style (name of the stylesheet to be enqueued),
  *                                 inline_style (string containing the CSS to be added).
- * @return boolean True if the block style was registered with success and false otherwise.
+ * @return bool True if the block style was registered with success and false otherwise.
  */
 function register_block_style( $block_name, $style_properties ) {
 	return WP_Block_Styles_Registry::get_instance()->register( $block_name, $style_properties );
@@ -823,9 +971,171 @@
  * @since 5.3.0
  *
  * @param string $block_name       Block type name including namespace.
- * @param array  $block_style_name Block style name.
- * @return boolean True if the block style was unregistered with success and false otherwise.
+ * @param string $block_style_name Block style name.
+ * @return bool True if the block style was unregistered with success and false otherwise.
  */
 function unregister_block_style( $block_name, $block_style_name ) {
 	return WP_Block_Styles_Registry::get_instance()->unregister( $block_name, $block_style_name );
 }
+
+/**
+ * Checks whether the current block type supports the feature requested.
+ *
+ * @since 5.8.0
+ *
+ * @param WP_Block_Type $block_type Block type to check for support.
+ * @param string        $feature    Name of the feature to check support for.
+ * @param mixed         $default    Fallback value for feature support, defaults to false.
+ *
+ * @return boolean                  Whether or not the feature is supported.
+ */
+function block_has_support( $block_type, $feature, $default = false ) {
+	$block_support = $default;
+	if ( $block_type && property_exists( $block_type, 'supports' ) ) {
+		$block_support = _wp_array_get( $block_type->supports, $feature, $default );
+	}
+
+	return true === $block_support || is_array( $block_support );
+}
+
+/**
+ * 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.
+ */
+function wp_migrate_old_typography_shape( $metadata ) {
+	if ( ! isset( $metadata['supports'] ) ) {
+		return $metadata;
+	}
+
+	$typography_keys = array(
+		'__experimentalFontFamily',
+		'__experimentalFontStyle',
+		'__experimentalFontWeight',
+		'__experimentalLetterSpacing',
+		'__experimentalTextDecoration',
+		'__experimentalTextTransform',
+		'fontSize',
+		'lineHeight',
+	);
+
+	foreach ( $typography_keys as $typography_key ) {
+		$support_for_key = _wp_array_get( $metadata['supports'], array( $typography_key ), null );
+
+		if ( null !== $support_for_key ) {
+			_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'
+			);
+
+			_wp_array_set( $metadata['supports'], array( 'typography', $typography_key ), $support_for_key );
+			unset( $metadata['supports'][ $typography_key ] );
+		}
+	}
+
+	return $metadata;
+}
+
+/**
+ * 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
+ *
+ * @param WP_Block $block Block instance.
+ * @param int      $page  Current query's page.
+ *
+ * @return array Returns the constructed WP_Query arguments.
+ */
+function build_query_vars_from_query_block( $block, $page ) {
+	$query = array(
+		'post_type'    => 'post',
+		'order'        => 'DESC',
+		'orderby'      => 'date',
+		'post__not_in' => array(),
+	);
+
+	if ( isset( $block->context['query'] ) ) {
+		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;
+			}
+		}
+		if ( isset( $block->context['query']['sticky'] ) && ! empty( $block->context['query']['sticky'] ) ) {
+			$sticky = get_option( 'sticky_posts' );
+			if ( 'only' === $block->context['query']['sticky'] ) {
+				$query['post__in'] = $sticky;
+			} else {
+				$query['post__not_in'] = array_merge( $query['post__not_in'], $sticky );
+			}
+		}
+		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 );
+		}
+		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;
+		}
+		if ( ! empty( $block->context['query']['categoryIds'] ) ) {
+			$term_ids              = array_map( 'intval', $block->context['query']['categoryIds'] );
+			$term_ids              = array_filter( $term_ids );
+			$query['category__in'] = $term_ids;
+		}
+		if ( ! empty( $block->context['query']['tagIds'] ) ) {
+			$term_ids         = array_map( 'intval', $block->context['query']['tagIds'] );
+			$term_ids         = array_filter( $term_ids );
+			$query['tag__in'] = $term_ids;
+		}
+		if (
+			isset( $block->context['query']['order'] ) &&
+				in_array( strtoupper( $block->context['query']['order'] ), array( 'ASC', 'DESC' ), true )
+		) {
+			$query['order'] = strtoupper( $block->context['query']['order'] );
+		}
+		if ( isset( $block->context['query']['orderBy'] ) ) {
+			$query['orderby'] = $block->context['query']['orderBy'];
+		}
+		if (
+			isset( $block->context['query']['author'] ) &&
+			(int) $block->context['query']['author'] > 0
+		) {
+			$query['author'] = (int) $block->context['query']['author'];
+		}
+		if ( ! empty( $block->context['query']['search'] ) ) {
+			$query['s'] = $block->context['query']['search'];
+		}
+	}
+	return $query;
+}