diff --git a/lib/class-wp-block-templates-registry.php b/lib/class-wp-block-templates-registry.php index 81548dcf35359..96aa00615da01 100644 --- a/lib/class-wp-block-templates-registry.php +++ b/lib/class-wp-block-templates-registry.php @@ -17,7 +17,10 @@ final class WP_Block_Templates_Registry { * Registered block templates, as `$name => $instance` pairs. * * @since 6.6.0 - * @var WP_Block_Type[] + * @var array $registered_block_templates { + * @type WP_Block_Template[] $wp_template Registered block templates. + * @type WP_Block_Template[] $wp_template_part Registered block template parts. + * } */ private $registered_block_templates = array( 'wp_template' => array(), @@ -83,7 +86,7 @@ public function register( $template_name, $template_type, $args = array() ) { if ( ! preg_match( $name_matcher, $template_name ) ) { _doing_it_wrong( __METHOD__, - __( 'Block template names must contain a namespace prefix. Example: my-plugin/my-custom-template', 'gutenberg' ), + __( 'Block template names must contain a namespace prefix. Example: my-plugin//my-custom-template', 'gutenberg' ), '6.6.0' ); return false; @@ -101,25 +104,25 @@ public function register( $template_name, $template_type, $args = array() ) { if ( ! $template ) { $theme_name = get_stylesheet(); - $slug = array_key_exists( 'slug', $args ) ? $args['slug'] : explode( '//', $template_name )[1]; + $slug = isset( $args['slug'] ) ? $args['slug'] : explode( '//', $template_name )[1]; $template = new WP_Block_Template(); $template->id = $theme_name . '//' . $slug; - $template->theme = $theme_name; // @todo If not attached to the theme, this should be the plugin URI. - $template->plugin = array_key_exists( 'plugin', $args ) ? $args['plugin'] : ''; + $template->theme = $theme_name; + $template->plugin = isset( $args['plugin'] ) ? $args['plugin'] : ''; $template->author = null; - $template->content = array_key_exists( 'path', $args ) ? file_get_contents( $args['path'] ) : ''; + $template->content = isset( $args['path'] ) ? file_get_contents( $args['path'] ) : ''; $template->source = 'plugin'; $template->slug = $slug; $template->type = $template_type; - $template->title = array_key_exists( 'title', $args ) ? $args['title'] : ''; - $template->description = array_key_exists( 'description', $args ) ? $args['description'] : ''; + $template->title = isset( $args['title'] ) ? $args['title'] : ''; + $template->description = isset( $args['description'] ) ? $args['description'] : ''; $template->status = 'publish'; $template->has_theme_file = true; $template->origin = 'plugin'; $template->is_custom = true; - $template->post_types = array_key_exists( 'post_types', $args ) ? $args['post_types'] : ''; - $template->area = 'wp_template_part' === $template_type && array_key_exists( 'area', $args ) ? $args['area'] : ''; + $template->post_types = 'wp_template' === $template_type && isset( $args['post_types'] ) ? $args['post_types'] : ''; + $template->area = 'wp_template_part' === $template_type && isset( $args['area'] ) ? $args['area'] : ''; } $this->registered_block_templates[ $template_type ][ $template_name ] = $template; @@ -127,30 +130,35 @@ public function register( $template_name, $template_type, $args = array() ) { return $template; } - public function get_by_slug( $template_type, $template_slug ) { - $all_templates = $this->get_all_registered( $template_type ); - - if ( ! $all_templates ) { - return null; - } - - foreach ( $all_templates as $template ) { - if ( $template->slug === $template_slug ) { - return $template; - } + /** + * Retrieves all registered block templates by type. + * + * @since 6.6.0 + * + * @param string $template_type Template type, either `wp_template` or `wp_template_part`. + * @return WP_Block_Template[]|false Associative array of `$block_template_name => $block_template` pairs. + */ + public function get_all_registered( $template_type ) { + if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) { + _doing_it_wrong( + __METHOD__, + __( 'Only valid block template types are `wp_template` and `wp_template_part`.', 'gutenberg' ), + '6.6.0' + ); + return false; } - return null; + return $this->registered_block_templates[ $template_type ]; } /** - * Retrieves a registered template. + * Retrieves a registered template by its type and name. * * @since 6.6.0 * * @param string $template_type Template type, either `wp_template` or `wp_template_part`. - * @param string $template_name Block type name including namespace. - * @return WP_Block_Type|null The registered block type, or null if it is not registered. + * @param string $template_name Block template name including namespace. + * @return WP_Block_Template|null|false The registered block template, or null if it is not registered. */ public function get_registered( $template_type, $template_name ) { if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) { @@ -170,24 +178,28 @@ public function get_registered( $template_type, $template_name ) { } /** - * Retrieves all registered block templates by type. + * Retrieves a registered template by its type and slug. * * @since 6.6.0 * * @param string $template_type Template type, either `wp_template` or `wp_template_part`. - * @return WP_Block_Template[] Associative array of `$block_type_name => $block_type` pairs. + * @param string $template_slug Slug of the template. + * @return WP_Block_Template|null The registered block template, or null if it is not registered. */ - public function get_all_registered( $template_type ) { - if ( 'wp_template' !== $template_type && 'wp_template_part' !== $template_type ) { - _doing_it_wrong( - __METHOD__, - __( 'Only valid block template types are `wp_template` and `wp_template_part`.', 'gutenberg' ), - '6.6.0' - ); - return false; + public function get_by_slug( $template_type, $template_slug ) { + $all_templates = $this->get_all_registered( $template_type ); + + if ( ! $all_templates ) { + return null; } - return $this->registered_block_templates[ $template_type ]; + foreach ( $all_templates as $template ) { + if ( $template->slug === $template_slug ) { + return $template; + } + } + + return null; } /** @@ -230,7 +242,7 @@ public function get_by_query( $template_type, $query = array() ) { unset( $all_templates[ $template_name ] ); } - if ( ! empty( $post_type ) && ! in_array( $post_type, $template->post_types, true ) ) { + if ( 'wp_template' === $template_type && ! empty( $post_type ) && ! in_array( $post_type, $template->post_types, true ) ) { unset( $all_templates[ $template_name ] ); } } @@ -244,7 +256,7 @@ public function get_by_query( $template_type, $query = array() ) { * @since 6.6.0 * * @param string $template_type Template type, either `wp_template` or `wp_template_part`. - * @param string $template_name Block type name including namespace. + * @param string $template_name Block template name including namespace. * @return bool True if the template is registered, false otherwise. */ public function is_registered( $template_type, $template_name ) { @@ -266,15 +278,10 @@ public function is_registered( $template_type, $template_name ) { * @since 6.6.0 * * @param string $template_type Template type, either `wp_template` or `wp_template_part`. - * @param string|WP_Block_Template $name Block template name including namespace, or alternatively - * a complete WP_Block_Template instance. + * @param string $name Block template name including namespace. * @return WP_Block_Template|false The unregistered block template on success, or false on failure. */ public function unregister( $template_type, $template_name ) { - if ( $template_name instanceof WP_Block_Type ) { - $template_name = $template_name->name; - } - if ( ! $this->is_registered( $template_type, $template_name ) ) { _doing_it_wrong( __METHOD__, diff --git a/lib/compat/wordpress-6.6/block-template-utils.php b/lib/compat/wordpress-6.6/block-template-utils.php index 4bf77764ffdaf..953f6bf20c077 100644 --- a/lib/compat/wordpress-6.6/block-template-utils.php +++ b/lib/compat/wordpress-6.6/block-template-utils.php @@ -228,14 +228,6 @@ function _gutenberg_get_block_templates_files( $template_type, $query = array() return array_values( $template_files ); } -function _gutenberg_add_template_details_from_registration( $template_type, $template_object_from_file ) { - $registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_type, $template_object_from_file->slug ); - if ( $registered_template ) { - $template_object_from_file->plugin = $registered_template->plugin; - } - return $template_object_from_file; -} - /** * Retrieves a list of unified template objects based on a query. * @@ -335,11 +327,10 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t continue; } - $query_result[] = _gutenberg_add_template_details_from_registration( $template_type, $template ); + $query_result[] = $template; } if ( ! isset( $query['wp_id'] ) ) { - /* * If the query has found some use templates, those have priority * over the theme-provided ones, so we skip querying and building them. @@ -347,27 +338,8 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t $query['slug__not_in'] = wp_list_pluck( $query_result, 'slug' ); $template_files = _gutenberg_get_block_templates_files( $template_type, $query ); foreach ( $template_files as $template_file ) { - $template_object_from_file = _build_block_template_result_from_file( $template_file, $template_type ); - - $query_result[] = _gutenberg_add_template_details_from_registration( $template_type, $template_object_from_file ); + $query_result[] = _build_block_template_result_from_file( $template_file, $template_type ); } - - /* - * Add templates registered in the template registry. Filtering out the ones which have a theme file. - */ - $registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $template_type, $query ); - $matching_registered_templates = array_filter( - $registered_templates, - function ( $registered_template ) use ( $template_files ) { - foreach ( $template_files as $template_file ) { - if ( $template_file['slug'] === $registered_template->slug ) { - return false; - } - } - return true; - } - ); - $query_result = array_merge( $query_result, $matching_registered_templates ); } /** @@ -388,82 +360,3 @@ function ( $registered_template ) use ( $template_files ) { */ return apply_filters( 'get_block_templates', $query_result, $query, $template_type ); } - -/** - * Retrieves a single unified template object using its id. - * - * @since 5.8.0 - * - * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). - * @param string $template_type Optional. Template type. Either 'wp_template' or 'wp_template_part'. - * Default 'wp_template'. - * @return WP_Block_Template|null Template. - */ -function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) { - /** - * Filters the block template object before the query takes place. - * - * Return a non-null value to bypass the WordPress queries. - * - * @since 5.9.0 - * - * @param WP_Block_Template|null $block_template Return block template object to short-circuit the default query, - * or null to allow WP to run its normal queries. - * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). - * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. - */ - $block_template = apply_filters( 'pre_get_block_template', null, $id, $template_type ); - if ( ! is_null( $block_template ) ) { - return $block_template; - } - - $parts = explode( '//', $id, 2 ); - if ( count( $parts ) < 2 ) { - return null; - } - list( $theme, $slug ) = $parts; - $wp_query_args = array( - 'post_name__in' => array( $slug ), - 'post_type' => $template_type, - 'post_status' => array( 'auto-draft', 'draft', 'publish', 'trash' ), - 'posts_per_page' => 1, - 'no_found_rows' => true, - 'tax_query' => array( - array( - 'taxonomy' => 'wp_theme', - 'field' => 'name', - 'terms' => $theme, - ), - ), - ); - $template_query = new WP_Query( $wp_query_args ); - $posts = $template_query->posts; - - if ( count( $posts ) > 0 ) { - $template = _build_block_template_result_from_post( $posts[0] ); - - if ( ! is_wp_error( $template ) ) { - return $template; - } - } - - $block_template = get_block_file_template( $id, $template_type ); - // @core-merge: This code will go into Core's 'get_block_template' function. - if ( ! $block_template ) { - $block_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_type, $slug ); - } - // @core-merge: End of the code that will go into Core. - - $block_template = _gutenberg_add_template_details_from_registration( $template_type, $block_template ); - - /** - * Filters the queried block template object after it's been fetched. - * - * @since 5.9.0 - * - * @param WP_Block_Template|null $block_template The found block template, or null if there isn't one. - * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). - * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. - */ - return apply_filters( 'get_block_template', $block_template, $id, $template_type ); -} diff --git a/lib/compat/wordpress-6.6/class-gutenberg-rest-posts-controller-6-6.php b/lib/compat/wordpress-6.6/class-gutenberg-rest-posts-controller-6-6.php deleted file mode 100644 index 29fa1245c0eed..0000000000000 --- a/lib/compat/wordpress-6.6/class-gutenberg-rest-posts-controller-6-6.php +++ /dev/null @@ -1,125 +0,0 @@ - $this->post_type ), 'wp_template' ); - - foreach ( $allowed_templates as $allowed_template ) { - if ( $request['template'] === $allowed_template->slug ) { - return true; - } - } - - if ( isset( $allowed_templates[ $template ] ) ) { - return true; - } - - $allowed_templates_slugs = array_map( - function ( $allowed_template ) { - return $allowed_template->slug; - }, - $allowed_templates - ); - - return new WP_Error( - 'rest_invalid_param', - /* translators: 1: Parameter, 2: List of valid values. */ - sprintf( __( '%1$s is not one of %2$s.' ), 'template', implode( ', ', array_keys( $allowed_templates_slugs ) ) ) - ); - } -} - -add_action( - 'init', - function () { - // @core-merge: We need to register the Post and Page post types again to assign them the - // correct `rest_controller_class`. When merging to core, updating `get_block_templates` - // would be enough. - register_post_type( - 'post', - array( - 'labels' => array( - 'name_admin_bar' => _x( 'Post', 'add new from admin bar' ), - ), - 'public' => true, - '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ - '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */ - 'capability_type' => 'post', - 'map_meta_cap' => true, - 'menu_position' => 5, - 'menu_icon' => 'dashicons-admin-post', - 'hierarchical' => false, - 'rewrite' => false, - 'query_var' => false, - 'delete_with_user' => true, - 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'excerpt', 'trackbacks', 'custom-fields', 'comments', 'revisions', 'post-formats' ), - 'show_in_rest' => true, - 'rest_base' => 'posts', - 'rest_controller_class' => 'Gutenberg_REST_Posts_Controller_6_6', - ) - ); - - register_post_type( - 'page', - array( - 'labels' => array( - 'name_admin_bar' => _x( 'Page', 'add new from admin bar' ), - ), - 'public' => true, - 'publicly_queryable' => false, - '_builtin' => true, /* internal use only. don't use this when registering your own post type. */ - '_edit_link' => 'post.php?post=%d', /* internal use only. don't use this when registering your own post type. */ - 'capability_type' => 'page', - 'map_meta_cap' => true, - 'menu_position' => 20, - 'menu_icon' => 'dashicons-admin-page', - 'hierarchical' => true, - 'rewrite' => false, - 'query_var' => false, - 'delete_with_user' => true, - 'supports' => array( 'title', 'editor', 'author', 'thumbnail', 'page-attributes', 'custom-fields', 'comments', 'revisions' ), - 'show_in_rest' => true, - 'rest_base' => 'pages', - 'rest_controller_class' => 'Gutenberg_REST_Posts_Controller_6_6', - ) - ); - } -); diff --git a/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php b/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php index f3b5c95d57874..0afbc07a88907 100644 --- a/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php +++ b/lib/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php @@ -127,15 +127,13 @@ public function get_template_fallback( $request ) { public function get_item( $request ) { if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { $template = get_block_file_template( $request['id'], $this->post_type ); - // Even if the source is 'theme', make sure the 'plugin' property is - // defined if the template was registered by a plugin. - $template = _gutenberg_add_template_details_from_registration( $this->post_type, $template ); - } elseif ( isset( $request['source'] ) && 'plugin' === $request['source'] ) { // @core-merge: Add a special case for plugin templates. + } elseif ( isset( $request['source'] ) && 'plugin' === $request['source'] ) { list( , $slug ) = explode( '//', $request['id'] ); $template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $this->post_type, $slug ); + // @core-merge: End of changes to merge in core. } else { - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); + $template = get_block_template( $request['id'], $this->post_type ); } if ( ! $template ) { @@ -146,293 +144,7 @@ public function get_item( $request ) { } /** - * Updates a single template. - * - * @since 5.8.0 - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. - */ - public function update_item( $request ) { - // @core-merge: Update instances of `get_block_template` to `gutenberg_get_block_template`. - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); - if ( ! $template ) { - return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); - } - - $post_before = get_post( $template->wp_id ); - - if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { - wp_delete_post( $template->wp_id, true ); - $request->set_param( 'context', 'edit' ); - - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); - $response = $this->prepare_item_for_response( $template, $request ); - - return rest_ensure_response( $response ); - } - - $changes = $this->prepare_item_for_database( $request ); - - if ( is_wp_error( $changes ) ) { - return $changes; - } - - if ( 'custom' === $template->source ) { - $update = true; - $result = wp_update_post( wp_slash( (array) $changes ), false ); - } else { - $update = false; - $post_before = null; - $result = wp_insert_post( wp_slash( (array) $changes ), false ); - } - - if ( is_wp_error( $result ) ) { - if ( 'db_update_error' === $result->get_error_code() ) { - $result->add_data( array( 'status' => 500 ) ); - } else { - $result->add_data( array( 'status' => 400 ) ); - } - return $result; - } - - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); - $fields_update = $this->update_additional_fields_for_object( $template, $request ); - if ( is_wp_error( $fields_update ) ) { - return $fields_update; - } - - $request->set_param( 'context', 'edit' ); - - $post = get_post( $template->wp_id ); - /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ - do_action( "rest_after_insert_{$this->post_type}", $post, $request, false ); - - wp_after_insert_post( $post, $update, $post_before ); - - $response = $this->prepare_item_for_response( $template, $request ); - - return rest_ensure_response( $response ); - } - - /** - * Creates a single template. - * - * @since 5.8.0 - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. - */ - public function create_item( $request ) { - // @core-merge: Update instances of `get_block_template` to `gutenberg_get_block_template` - // and `get_block_templates` to `gutenberg_get_block_templates`. - $prepared_post = $this->prepare_item_for_database( $request ); - - if ( is_wp_error( $prepared_post ) ) { - return $prepared_post; - } - - $prepared_post->post_name = $request['slug']; - $post_id = wp_insert_post( wp_slash( (array) $prepared_post ), true ); - if ( is_wp_error( $post_id ) ) { - if ( 'db_insert_error' === $post_id->get_error_code() ) { - $post_id->add_data( array( 'status' => 500 ) ); - } else { - $post_id->add_data( array( 'status' => 400 ) ); - } - - return $post_id; - } - $posts = gutenberg_get_block_templates( array( 'wp_id' => $post_id ), $this->post_type ); - if ( ! count( $posts ) ) { - return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ), array( 'status' => 400 ) ); - } - $id = $posts[0]->id; - $post = get_post( $post_id ); - $template = gutenberg_get_block_template( $id, $this->post_type ); - $fields_update = $this->update_additional_fields_for_object( $template, $request ); - if ( is_wp_error( $fields_update ) ) { - return $fields_update; - } - - /** This action is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ - do_action( "rest_after_insert_{$this->post_type}", $post, $request, true ); - - wp_after_insert_post( $post, false, null ); - - $response = $this->prepare_item_for_response( $template, $request ); - $response = rest_ensure_response( $response ); - - $response->set_status( 201 ); - $response->header( 'Location', rest_url( sprintf( '%s/%s/%s', $this->namespace, $this->rest_base, $template->id ) ) ); - - return $response; - } - - /** - * Deletes a single template. - * - * @since 5.8.0 - * - * @param WP_REST_Request $request Full details about the request. - * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. - */ - public function delete_item( $request ) { - // @core-merge: Update instances of `get_block_template` to `gutenberg_get_block_template`. - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); - if ( ! $template ) { - return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); - } - if ( 'custom' !== $template->source ) { - return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.' ), array( 'status' => 400 ) ); - } - - $id = $template->wp_id; - $force = (bool) $request['force']; - - $request->set_param( 'context', 'edit' ); - - // If we're forcing, then delete permanently. - if ( $force ) { - $previous = $this->prepare_item_for_response( $template, $request ); - $result = wp_delete_post( $id, true ); - $response = new WP_REST_Response(); - $response->set_data( - array( - 'deleted' => true, - 'previous' => $previous->get_data(), - ) - ); - } else { - // Otherwise, only trash if we haven't already. - if ( 'trash' === $template->status ) { - return new WP_Error( - 'rest_template_already_trashed', - __( 'The template has already been deleted.' ), - array( 'status' => 410 ) - ); - } - - /* - * (Note that internally this falls through to `wp_delete_post()` - * if the Trash is disabled.) - */ - $result = wp_trash_post( $id ); - $template->status = 'trash'; - $response = $this->prepare_item_for_response( $template, $request ); - } - - if ( ! $result ) { - return new WP_Error( - 'rest_cannot_delete', - __( 'The template cannot be deleted.' ), - array( 'status' => 500 ) - ); - } - - return $response; - } - - /** - * Prepares a single template for create or update. - * - * @since 5.8.0 - * - * @param WP_REST_Request $request Request object. - * @return stdClass|WP_Error Changes to pass to wp_update_post. - */ - protected function prepare_item_for_database( $request ) { - // @core-merge: Update instances of `get_block_template` to `gutenberg_get_block_template` - $template = $request['id'] ? gutenberg_get_block_template( $request['id'], $this->post_type ) : null; - $changes = new stdClass(); - if ( null === $template ) { - $changes->post_type = $this->post_type; - $changes->post_status = 'publish'; - $changes->tax_input = array( - 'wp_theme' => isset( $request['theme'] ) ? $request['theme'] : get_stylesheet(), - ); - } elseif ( 'custom' !== $template->source ) { - $changes->post_name = $template->slug; - $changes->post_type = $this->post_type; - $changes->post_status = 'publish'; - $changes->tax_input = array( - 'wp_theme' => $template->theme, - ); - $changes->meta_input = array( - 'origin' => $template->source, - ); - } else { - $changes->post_name = $template->slug; - $changes->ID = $template->wp_id; - $changes->post_status = 'publish'; - } - if ( isset( $request['content'] ) ) { - if ( is_string( $request['content'] ) ) { - $changes->post_content = $request['content']; - } elseif ( isset( $request['content']['raw'] ) ) { - $changes->post_content = $request['content']['raw']; - } - } elseif ( null !== $template && 'custom' !== $template->source ) { - $changes->post_content = $template->content; - } - if ( isset( $request['title'] ) ) { - if ( is_string( $request['title'] ) ) { - $changes->post_title = $request['title']; - } elseif ( ! empty( $request['title']['raw'] ) ) { - $changes->post_title = $request['title']['raw']; - } - } elseif ( null !== $template && 'custom' !== $template->source ) { - $changes->post_title = $template->title; - } - if ( isset( $request['description'] ) ) { - $changes->post_excerpt = $request['description']; - } elseif ( null !== $template && 'custom' !== $template->source ) { - $changes->post_excerpt = $template->description; - } - - if ( 'wp_template' === $this->post_type && isset( $request['is_wp_suggestion'] ) ) { - $changes->meta_input = wp_parse_args( - array( - 'is_wp_suggestion' => $request['is_wp_suggestion'], - ), - $changes->meta_input = array() - ); - } - - if ( 'wp_template_part' === $this->post_type ) { - if ( isset( $request['area'] ) ) { - $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] ); - } elseif ( null !== $template && 'custom' !== $template->source && $template->area ) { - $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $template->area ); - } elseif ( empty( $template->area ) ) { - $changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; - } - } - - if ( ! empty( $request['author'] ) ) { - $post_author = (int) $request['author']; - - if ( get_current_user_id() !== $post_author ) { - $user_obj = get_userdata( $post_author ); - - if ( ! $user_obj ) { - return new WP_Error( - 'rest_invalid_author', - __( 'Invalid author ID.' ), - array( 'status' => 400 ) - ); - } - } - - $changes->post_author = $post_author; - } - - /** This filter is documented in wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php */ - return apply_filters( "rest_pre_insert_{$this->post_type}", $changes, $request ); - } - - /** - * Fix wrong author in plugin templates. + * Prepare a single template output for response * * @param WP_Block_Template $item Template instance. * @param WP_REST_Request $request Request object. @@ -446,6 +158,7 @@ public function prepare_item_for_response( $item, $request ) { if ( 'plugin' !== $item->origin ) { return parent::prepare_item_for_response( $item, $request ); } + // @core-merge: Fix wrong author in plugin templates. $cloned_item = clone $item; // Set the origin as theme when calling the previous `prepare_item_for_response()` to prevent warnings when generating the author text. $cloned_item->origin = 'theme'; @@ -482,7 +195,7 @@ public function prepare_item_for_response( $item, $request ) { } /** - * Allow plugin authors where `has_theme_file` is false. + * Returns the source from where the template originally comes from. * * @param WP_Block_Template $template_object Template instance. * @return string Original source of the template one of theme, plugin, site, or user. @@ -528,7 +241,7 @@ private static function get_wp_templates_original_source_field( $template_object } /** - * Prioritize plugin name instead of theme name for plugin-registered templates. + * Returns a human readable text for the author of the template. * * @param WP_Block_Template $template_object Template instance. * @return string Human readable text for the author. @@ -541,9 +254,11 @@ private static function get_wp_templates_author_text_field( $template_object ) { return empty( $theme_name ) ? $template_object->theme : $theme_name; case 'plugin': $plugins = get_plugins(); + // @core-merge: Prioritize plugin name instead of theme name for plugin-registered templates. $plugin_name = isset( $template_object->plugin ) ? $template_object->plugin . '/' . $template_object->plugin : $template_object->theme; $plugin = $plugins[ plugin_basename( sanitize_text_field( $plugin_name . '.php' ) ) ]; return empty( $plugin['Name'] ) ? $template_object->theme : $plugin['Name']; + // @core-merge: End of changes to merge in core. case 'site': return get_bloginfo( 'name' ); case 'user': @@ -554,50 +269,4 @@ private static function get_wp_templates_author_text_field( $template_object ) { return $author->get( 'display_name' ); } } - - /** - * Prepares links for the request. - * - * @since 5.8.0 - * - * @param integer $id ID. - * @return array Links for the given post. - */ - protected function prepare_links( $id ) { - // @core-merge: Update instances of `get_block_template` to `gutenberg_get_block_template`. - $links = array( - 'self' => array( - 'href' => rest_url( sprintf( '/%s/%s/%s', $this->namespace, $this->rest_base, $id ) ), - ), - 'collection' => array( - 'href' => rest_url( rest_get_route_for_post_type_items( $this->post_type ) ), - ), - 'about' => array( - 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), - ), - ); - - if ( post_type_supports( $this->post_type, 'revisions' ) ) { - $template = gutenberg_get_block_template( $id, $this->post_type ); - if ( $template instanceof WP_Block_Template && ! empty( $template->wp_id ) ) { - $revisions = wp_get_latest_revision_id_and_total_count( $template->wp_id ); - $revisions_count = ! is_wp_error( $revisions ) ? $revisions['count'] : 0; - $revisions_base = sprintf( '/%s/%s/%s/revisions', $this->namespace, $this->rest_base, $id ); - - $links['version-history'] = array( - 'href' => rest_url( $revisions_base ), - 'count' => $revisions_count, - ); - - if ( $revisions_count > 0 ) { - $links['predecessor-version'] = array( - 'href' => rest_url( $revisions_base . '/' . $revisions['latest_id'] ), - 'id' => $revisions['latest_id'], - ); - } - } - } - - return $links; - } } diff --git a/lib/compat/wordpress-6.6/compat.php b/lib/compat/wordpress-6.6/compat.php index d81701a7ccfa9..4038f90b28678 100644 --- a/lib/compat/wordpress-6.6/compat.php +++ b/lib/compat/wordpress-6.6/compat.php @@ -32,57 +32,72 @@ function gutenberg_change_patterns_link_and_remove_template_parts_submenu_item() add_action( 'admin_init', 'gutenberg_change_patterns_link_and_remove_template_parts_submenu_item' ); /** - * @core-merge: Given that we can't modify `locate_block_template()` in `wp-includes` to call `gutenberg_get_block_templates()` instead of `get_block_templates()` we need to filter the results and return the correct template. + * Hooks into `get_block_templates` so templates from the registry are also returned, as long as there + * isn't a theme template with the same slug. * - * @global string $_wp_current_template_content - * @global int $_wp_current_template_id + * @param WP_Block_Template[] $query_result Array of found block templates. + * @param array $query { + * Arguments to retrieve templates. All arguments are optional. + * + * @type string[] $slug__in List of slugs to include. + * @type int $wp_id Post ID of customized template. + * @type string $area A 'wp_template_part_area' taxonomy value to filter by (for 'wp_template_part' template type only). + * @type string $post_type Post type to get the templates for. + * } + * @param string $template_type wp_template or wp_template_part. + * @return WP_Block_Template[] The same $query_result but might contain some additional templates from + * the registry. */ -$template_filters = array( - '404_template', - 'archive_template', - 'attachment_template', - 'author_template', - 'category_template', - 'date_template', - 'embed_template', - 'frontpage_template', - 'home_template', - 'index_template', - 'page_template', - 'paged_template', - 'privacypolicy_template', - 'search_template', - 'single_template', - 'singular_template', - 'tag_template', - 'taxonomy_template', -); -foreach ( $template_filters as $template_filter ) { - add_filter( - $template_filter, - function ( - $template, - $type, - $templates - ) { - if ( $template ) { - return $template; - } +function _gutenberg_add_block_templates_from_registry( $query_result, $query, $template_type ) { + if ( ! isset( $query['wp_id'] ) ) { + $template_files = _gutenberg_get_block_templates_files( $template_type, $query ); - global $_wp_current_template_content, $_wp_current_template_id; - foreach ( $templates as $template_slug ) { - $located_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( 'wp_template', $template_slug ); - if ( isset( $located_template ) ) { - $_wp_current_template_id = $located_template->id; - $_wp_current_template_content = $located_template->content; - - return ABSPATH . WPINC . '/template-canvas.php'; + /* + * Add templates registered in the template registry. Filtering out the ones which have a theme file. + */ + $registered_templates = WP_Block_Templates_Registry::get_instance()->get_by_query( $template_type, $query ); + $matching_registered_templates = array_filter( + $registered_templates, + function ( $registered_template ) use ( $template_files ) { + foreach ( $template_files as $template_file ) { + if ( $template_file['slug'] === $registered_template->slug ) { + return false; + } } + return true; } + ); + $query_result = array_merge( $query_result, $matching_registered_templates ); + } + + return $query_result; +} +add_filter( 'get_block_templates', '_gutenberg_add_block_templates_from_registry', 10, 3 ); + +/** + * Hooks into `get_block_file_template` so templates from the registry are also returned. + * + * @param WP_Block_Template|null $block_template The found block template, or null if there is none. + * @param string $id Template unique identifier (example: 'theme_slug//template_slug'). + * @param string $template_type Template type. Either 'wp_template' or 'wp_template_part'. + * @return WP_Block_Template|null The block template that was already found or from the registry. In case the template was already found, add the necessary details from the registry. + */ +function _gutenberg_add_block_file_templates_from_registry( $block_template, $id, $template_type ) { + if ( $block_template ) { + $registered_template = WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_type, $block_template->slug ); + if ( $registered_template ) { + $block_template->plugin = $registered_template->plugin; + } + return $block_template; + } + + $parts = explode( '//', $id, 2 ); + + if ( count( $parts ) < 2 ) { + return $block_template; + } - return $template; - }, - 10, - 3 - ); + list( , $slug ) = $parts; + return WP_Block_Templates_Registry::get_instance()->get_by_slug( $template_type, $slug ); } +add_filter( 'get_block_file_template', '_gutenberg_add_block_file_templates_from_registry', 10, 3 ); diff --git a/lib/load.php b/lib/load.php index 98c89e074aec5..0da7944e94792 100644 --- a/lib/load.php +++ b/lib/load.php @@ -48,7 +48,6 @@ function gutenberg_is_experiment_enabled( $name ) { // WordPress 6.6 compat. require __DIR__ . '/compat/wordpress-6.6/class-gutenberg-rest-global-styles-revisions-controller-6-6.php'; - require __DIR__ . '/compat/wordpress-6.6/class-gutenberg-rest-posts-controller-6-6.php'; require __DIR__ . '/compat/wordpress-6.6/class-gutenberg-rest-templates-controller-6-6.php'; require __DIR__ . '/compat/wordpress-6.6/rest-api.php';