From fcb806822a5a608bd84111bfcce1cf2395e01412 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Wed, 19 May 2021 21:14:50 +0200 Subject: [PATCH 01/57] Add block templates based theme fixtures from GB --- .../block-templates-child/block-templates/page-1.html | 3 +++ .../data/themedir1/block-templates-child/page-home.php | 3 +++ tests/phpunit/data/themedir1/block-templates-child/style.css | 4 ++++ .../data/themedir1/block-templates/block-templates/index.html | 3 +++ .../themedir1/block-templates/block-templates/page-home.html | 3 +++ .../data/themedir1/block-templates/block-templates/page.html | 3 +++ tests/phpunit/data/themedir1/block-templates/page-1.php | 3 +++ tests/phpunit/data/themedir1/block-templates/style.css | 3 +++ 8 files changed, 25 insertions(+) create mode 100644 tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html create mode 100644 tests/phpunit/data/themedir1/block-templates-child/page-home.php create mode 100644 tests/phpunit/data/themedir1/block-templates-child/style.css create mode 100644 tests/phpunit/data/themedir1/block-templates/block-templates/index.html create mode 100644 tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html create mode 100644 tests/phpunit/data/themedir1/block-templates/block-templates/page.html create mode 100644 tests/phpunit/data/themedir1/block-templates/page-1.php create mode 100644 tests/phpunit/data/themedir1/block-templates/style.css diff --git a/tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html b/tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html new file mode 100644 index 0000000000000..c3e788b393ee8 --- /dev/null +++ b/tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html @@ -0,0 +1,3 @@ + +

Page (ID 1) Template

+ \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-templates-child/page-home.php b/tests/phpunit/data/themedir1/block-templates-child/page-home.php new file mode 100644 index 0000000000000..86efe80db6afb --- /dev/null +++ b/tests/phpunit/data/themedir1/block-templates-child/page-home.php @@ -0,0 +1,3 @@ + +

Index Template

+ \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html b/tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html new file mode 100644 index 0000000000000..6be0c70fb29c8 --- /dev/null +++ b/tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html @@ -0,0 +1,3 @@ + +

Page (Home) Template

+ \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-templates/block-templates/page.html b/tests/phpunit/data/themedir1/block-templates/block-templates/page.html new file mode 100644 index 0000000000000..61c493e1bd8e8 --- /dev/null +++ b/tests/phpunit/data/themedir1/block-templates/block-templates/page.html @@ -0,0 +1,3 @@ + +

Page Template

+ \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-templates/page-1.php b/tests/phpunit/data/themedir1/block-templates/page-1.php new file mode 100644 index 0000000000000..eafbb1b6e854b --- /dev/null +++ b/tests/phpunit/data/themedir1/block-templates/page-1.php @@ -0,0 +1,3 @@ + Date: Wed, 19 May 2021 21:15:50 +0200 Subject: [PATCH 02/57] Update names --- tests/phpunit/data/themedir1/block-templates-child/style.css | 4 ++-- tests/phpunit/data/themedir1/block-templates/style.css | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/phpunit/data/themedir1/block-templates-child/style.css b/tests/phpunit/data/themedir1/block-templates-child/style.css index 5d96a4e09ba00..166e3104c8376 100644 --- a/tests/phpunit/data/themedir1/block-templates-child/style.css +++ b/tests/phpunit/data/themedir1/block-templates-child/style.css @@ -1,4 +1,4 @@ /* -Theme Name: Test Theme Child -Template: test-theme +Theme Name: Block Templates Theme Child +Template: block-templates */ diff --git a/tests/phpunit/data/themedir1/block-templates/style.css b/tests/phpunit/data/themedir1/block-templates/style.css index cca8a45747e0c..a6b5798ba64d1 100644 --- a/tests/phpunit/data/themedir1/block-templates/style.css +++ b/tests/phpunit/data/themedir1/block-templates/style.css @@ -1,3 +1,3 @@ /* -Theme Name: Test Theme +Theme Name: Block Templates Theme */ From 0a529e393af9e856c191a7b3c14223d20dbaef92 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 20 May 2021 16:09:34 +0200 Subject: [PATCH 03/57] Add class-wp-rest-templates-controller.php --- .../class-wp-rest-templates-controller.php | 584 ++++++++++++++++++ 1 file changed, 584 insertions(+) create mode 100644 src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php new file mode 100644 index 0000000000000..e6b3a90efd3d3 --- /dev/null +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -0,0 +1,584 @@ +post_type = $post_type; + $this->namespace = 'wp/v2'; + $obj = get_post_type_object( $post_type ); + $this->rest_base = ! empty( $obj->rest_base ) ? $obj->rest_base : $obj->name; + } + + /** + * Registers the controllers routes. + * + * @return void + */ + public function register_routes() { + // Lists all templates. + register_rest_route( + $this->namespace, + '/' . $this->rest_base, + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_items' ), + 'permission_callback' => array( $this, 'get_items_permissions_check' ), + 'args' => $this->get_collection_params(), + ), + array( + 'methods' => WP_REST_Server::CREATABLE, + 'callback' => array( $this, 'create_item' ), + 'permission_callback' => array( $this, 'create_item_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + + // Lists/updates a single template based on the given id. + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/(?P[\/\w-]+)', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_item' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'id' => array( + 'description' => __( 'The id of a template', 'gutenberg' ), + 'type' => 'string', + ), + ), + ), + array( + 'methods' => WP_REST_Server::EDITABLE, + 'callback' => array( $this, 'update_item' ), + 'permission_callback' => array( $this, 'update_item_permissions_check' ), + 'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ), + ), + array( + 'methods' => WP_REST_Server::DELETABLE, + 'callback' => array( $this, 'delete_item' ), + 'permission_callback' => array( $this, 'delete_item_permissions_check' ), + 'args' => array( + 'force' => array( + 'type' => 'boolean', + 'default' => false, + 'description' => __( 'Whether to bypass Trash and force deletion.', 'gutenberg' ), + ), + ), + ), + 'schema' => array( $this, 'get_public_item_schema' ), + ) + ); + } + + /** + * Checks if the user has permissions to make the request. + * + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + protected function permissions_check() { + // Verify if the current user has edit_theme_options capability. + // This capability is required to edit/view/delete templates. + if ( ! current_user_can( 'edit_theme_options' ) ) { + return new WP_Error( + 'rest_cannot_manage_templates', + __( 'Sorry, you are not allowed to access the templates on this site.', 'gutenberg' ), + array( + 'status' => rest_authorization_required_code(), + ) + ); + } + + return true; + } + + /** + * Checks if a given request has access to read templates. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access, WP_Error object otherwise. + */ + public function get_items_permissions_check( $request ) { + return $this->permissions_check( $request ); + } + + /** + * Returns a list of templates. + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response + */ + public function get_items( $request ) { + $query = array(); + if ( isset( $request['wp_id'] ) ) { + $query['wp_id'] = $request['wp_id']; + } + if ( isset( $request['area'] ) ) { + $query['area'] = $request['area']; + } + $templates = array(); + foreach ( gutenberg_get_block_templates( $query, $this->post_type ) as $template ) { + $data = $this->prepare_item_for_response( $template, $request ); + $templates[] = $this->prepare_response_for_collection( $data ); + } + + return rest_ensure_response( $templates ); + } + + /** + * Checks if a given request has access to read a single template. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. + */ + public function get_item_permissions_check( $request ) { + return $this->permissions_check( $request ); + } + + /** + * Returns the given template + * + * @param WP_REST_Request $request The request instance. + * + * @return WP_REST_Response|WP_Error + */ + public function get_item( $request ) { + if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { + $template = gutenberg_get_block_file_template( $request['id'], $this->post_type ); + } else { + $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.', 'gutenberg' ), array( 'status' => 404 ) ); + } + + return $this->prepare_item_for_response( $template, $request ); + } + + /** + * Checks if a given request has access to write a single template. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. + */ + public function update_item_permissions_check( $request ) { + return $this->permissions_check( $request ); + } + + /** + * Updates a single template. + * + * @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 ) { + $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.', 'gutenberg' ), array( 'status' => 404 ) ); + } + + if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { + wp_delete_post( $template->wp_id, true ); + return $this->prepare_item_for_response( gutenberg_get_block_file_template( $request['id'], $this->post_type ), $request ); + } + + $changes = $this->prepare_item_for_database( $request ); + + if ( 'custom' === $template->source ) { + $result = wp_update_post( wp_slash( (array) $changes ), true ); + } else { + $result = wp_insert_post( wp_slash( (array) $changes ), true ); + } + if ( is_wp_error( $result ) ) { + 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; + } + + return $this->prepare_item_for_response( + gutenberg_get_block_template( $request['id'], $this->post_type ), + $request + ); + } + + /** + * Checks if a given request has access to create a template. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. + */ + public function create_item_permissions_check( $request ) { + return $this->permissions_check( $request ); + } + + /** + * Creates a single template. + * + * @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 ) { + $changes = $this->prepare_item_for_database( $request ); + $changes->post_name = $request['slug']; + $result = wp_insert_post( wp_slash( (array) $changes ), true ); + if ( is_wp_error( $result ) ) { + return $result; + } + $posts = gutenberg_get_block_templates( array( 'wp_id' => $result ), $this->post_type ); + if ( ! count( $posts ) ) { + return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.', 'gutenberg' ) ); + } + $id = $posts[0]->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; + } + + return $this->prepare_item_for_response( + gutenberg_get_block_template( $id, $this->post_type ), + $request + ); + } + + /** + * Checks if a given request has access to delete a single template. + * + * @param WP_REST_Request $request Full details about the request. + * @return true|WP_Error True if the request has delete access for the item, WP_Error object otherwise. + */ + public function delete_item_permissions_check( $request ) { + return $this->permissions_check( $request ); + } + + /** + * Deletes a single template. + * + * @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 ) { + $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.', 'gutenberg' ), array( 'status' => 404 ) ); + } + if ( 'custom' !== $template->source ) { + return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.', 'gutenberg' ), array( 'status' => 400 ) ); + } + + $id = $template->wp_id; + $force = (bool) $request['force']; + + // If we're forcing, then delete permanently. + if ( $force ) { + $previous = $this->prepare_item_for_response( $template, $request ); + wp_delete_post( $id, true ); + $response = new WP_REST_Response(); + $response->set_data( + array( + 'deleted' => true, + 'previous' => $previous->get_data(), + ) + ); + + return $response; + } + + // 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.', 'gutenberg' ), + array( 'status' => 410 ) + ); + } + + wp_trash_post( $id ); + $template->status = 'trash'; + return $this->prepare_item_for_response( $template, $request ); + } + + /** + * Prepares a single template for create or update. + * + * @param WP_REST_Request $request Request object. + * @return stdClass Changes to pass to wp_update_post. + */ + protected function prepare_item_for_database( $request ) { + $template = $request['id'] ? gutenberg_get_block_template( $request['id'], $this->post_type ) : null; + $changes = new stdClass(); + $changes->post_name = $template->slug; + if ( null === $template ) { + $changes->post_type = $this->post_type; + $changes->post_status = 'publish'; + $changes->tax_input = array( + 'wp_theme' => isset( $request['theme'] ) ? $request['content'] : wp_get_theme()->get_stylesheet(), + ); + } elseif ( 'custom' !== $template->source ) { + $changes->post_type = $this->post_type; + $changes->post_status = 'publish'; + $changes->tax_input = array( + 'wp_theme' => $template->theme, + ); + } else { + $changes->ID = $template->wp_id; + $changes->post_status = 'publish'; + } + if ( isset( $request['content'] ) ) { + $changes->post_content = $request['content']; + } elseif ( null !== $template && 'custom' !== $template->source ) { + $changes->post_content = $template->content; + } + if ( isset( $request['title'] ) ) { + $changes->post_title = $request['title']; + } 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_part' === $this->post_type ) { + if ( isset( $request['area'] ) ) { + $changes->tax_input['wp_template_part_area'] = gutenberg_filter_template_part_area( $request['area'] ); + } elseif ( null !== $template && 'custom' !== $template->source && $template->area ) { + $changes->tax_input['wp_template_part_area'] = gutenberg_filter_template_part_area( $template->area ); + } elseif ( ! $template->area ) { + $changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; + } + } + + return $changes; + } + + /** + * Prepare a single template output for response + * + * @param WP_Block_Template $template Template instance. + * @param WP_REST_Request $request Request object. + * + * @return WP_REST_Response $data + */ + public function prepare_item_for_response( $template, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable + $result = array( + 'id' => $template->id, + 'theme' => $template->theme, + 'content' => array( 'raw' => $template->content ), + 'slug' => $template->slug, + 'source' => $template->source, + 'type' => $template->type, + 'description' => $template->description, + 'title' => array( + 'raw' => $template->title, + 'rendered' => $template->title, + ), + 'status' => $template->status, + 'wp_id' => $template->wp_id, + 'has_theme_file' => $template->has_theme_file, + ); + + if ( 'wp_template_part' === $template->type ) { + $result['area'] = $template->area; + } + + $result = $this->add_additional_fields_to_object( $result, $request ); + + $response = rest_ensure_response( $result ); + $links = $this->prepare_links( $template->id ); + $response->add_links( $links ); + if ( ! empty( $links['self']['href'] ) ) { + $actions = $this->get_available_actions(); + $self = $links['self']['href']; + foreach ( $actions as $rel ) { + $response->add_link( $rel, $self ); + } + } + + return $response; + } + + + /** + * Prepares links for the request. + * + * @param integer $id ID. + * @return array Links for the given post. + */ + protected function prepare_links( $id ) { + $base = sprintf( '%s/%s', $this->namespace, $this->rest_base ); + + $links = array( + 'self' => array( + 'href' => rest_url( trailingslashit( $base ) . $id ), + ), + 'collection' => array( + 'href' => rest_url( $base ), + ), + 'about' => array( + 'href' => rest_url( 'wp/v2/types/' . $this->post_type ), + ), + ); + + return $links; + } + + /** + * Get the link relations available for the post and current user. + * + * @return array List of link relations. + */ + protected function get_available_actions() { + $rels = array(); + + $post_type = get_post_type_object( $this->post_type ); + + if ( current_user_can( $post_type->cap->publish_posts ) ) { + $rels[] = 'https://api.w.org/action-publish'; + } + + if ( current_user_can( 'unfiltered_html' ) ) { + $rels[] = 'https://api.w.org/action-unfiltered-html'; + } + + return $rels; + } + + /** + * Retrieves the query params for the posts collection. + * + * @return array Collection parameters. + */ + public function get_collection_params() { + return array( + 'context' => $this->get_context_param(), + 'wp_id' => array( + 'description' => __( 'Limit to the specified post id.', 'gutenberg' ), + 'type' => 'integer', + ), + ); + } + + /** + * Retrieves the block type' schema, conforming to JSON Schema. + * + * @return array Item schema data. + */ + public function get_item_schema() { + if ( $this->schema ) { + return $this->add_additional_fields_schema( $this->schema ); + } + + $schema = array( + '$schema' => 'http://json-schema.org/draft-04/schema#', + 'title' => $this->post_type, + 'type' => 'object', + 'properties' => array( + 'id' => array( + 'description' => __( 'ID of template.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + 'slug' => array( + 'description' => __( 'Unique slug identifying the template.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + 'required' => true, + 'minLength' => 1, + 'pattern' => '[a-zA-Z_\-]+', + ), + 'theme' => array( + 'description' => __( 'Theme identifier for the template.', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + ), + 'source' => array( + 'description' => __( 'Source of template', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + 'content' => array( + 'description' => __( 'Content of template.', 'gutenberg' ), + 'type' => array( 'object', 'string' ), + 'default' => '', + 'context' => array( 'embed', 'view', 'edit' ), + ), + 'title' => array( + 'description' => __( 'Title of template.', 'gutenberg' ), + 'type' => array( 'object', 'string' ), + 'default' => '', + 'context' => array( 'embed', 'view', 'edit' ), + ), + 'description' => array( + 'description' => __( 'Description of template.', 'gutenberg' ), + 'type' => 'string', + 'default' => '', + 'context' => array( 'embed', 'view', 'edit' ), + ), + 'status' => array( + 'description' => __( 'Status of template.', 'gutenberg' ), + 'type' => 'string', + 'default' => 'publish', + 'context' => array( 'embed', 'view', 'edit' ), + ), + 'wp_id' => array( + 'description' => __( 'Post ID.', 'gutenberg' ), + 'type' => 'integer', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + 'has_theme_file' => array( + 'description' => __( 'Theme file exists.', 'gutenberg' ), + 'type' => 'bool', + 'context' => array( 'embed', 'view', 'edit' ), + 'readonly' => true, + ), + ), + ); + + if ( 'wp_template_part' === $this->post_type ) { + $schema['properties']['area'] = array( + 'description' => __( 'Where the template part is intended for use (header, footer, etc.)', 'gutenberg' ), + 'type' => 'string', + 'context' => array( 'embed', 'view', 'edit' ), + ); + } + + $this->schema = $schema; + + return $this->add_additional_fields_schema( $this->schema ); + } +} From 808babb293b594ec17786b97640850561eda3b4b Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 20 May 2021 18:48:49 +0200 Subject: [PATCH 04/57] Add templates controller test --- .../rest-api/rest-templates-controller.php | 283 ++++++++++++++++++ 1 file changed, 283 insertions(+) create mode 100644 tests/phpunit/tests/rest-api/rest-templates-controller.php diff --git a/tests/phpunit/tests/rest-api/rest-templates-controller.php b/tests/phpunit/tests/rest-api/rest-templates-controller.php new file mode 100644 index 0000000000000..cf5931a68a0a8 --- /dev/null +++ b/tests/phpunit/tests/rest-api/rest-templates-controller.php @@ -0,0 +1,283 @@ +user->create( + array( + 'role' => 'administrator', + ) + ); + } + + public function test_register_routes() { + $routes = rest_get_server()->get_routes(); + $this->assertArrayHasKey( '/wp/v2/templates', $routes ); + $this->assertArrayHasKey( '/wp/v2/templates/(?P[\/\w-]+)', $routes ); + + $this->assertArrayHasKey( '/wp/v2/template-parts', $routes ); + $this->assertArrayHasKey( '/wp/v2/template-parts/(?P[\/\w-]+)', $routes ); + } + + public function test_context_param() { + // TODO: Implement test_context_param() method. + } + + public function test_get_items() { + function find_and_normalize_template_by_id( $templates, $id ) { + foreach ( $templates as $template ) { + if ( $template['id'] === $id ) { + unset( $template['content'] ); + unset( $template['_links'] ); + return $template; + } + } + + return null; + } + + wp_set_current_user( 0 ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_cannot_manage_templates', $response, 401 ); + + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertEquals( + array( + 'id' => 'tt1-blocks//index', + 'theme' => 'tt1-blocks', + 'slug' => 'index', + 'title' => array( + 'raw' => 'Index', + 'rendered' => 'Index', + ), + 'description' => 'The default template used when no other template is available. This is a required template in WordPress.', + 'status' => 'publish', + 'source' => 'theme', + 'type' => 'wp_template', + 'wp_id' => null, + 'has_theme_file' => true, + ), + find_and_normalize_template_by_id( $data, 'tt1-blocks//index' ) + ); + + // Test template parts. + $request = new WP_REST_Request( 'GET', '/wp/v2/template-parts' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + + $this->assertEquals( + array( + 'id' => 'tt1-blocks//header', + 'theme' => 'tt1-blocks', + 'slug' => 'header', + 'title' => array( + 'raw' => 'header', + 'rendered' => 'header', + ), + 'description' => '', + 'status' => 'publish', + 'source' => 'theme', + 'type' => 'wp_template_part', + 'wp_id' => null, + 'area' => WP_TEMPLATE_PART_AREA_HEADER, + 'has_theme_file' => true, + ), + find_and_normalize_template_by_id( $data, 'tt1-blocks//header' ) + ); + } + + public function test_get_item() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/tt1-blocks//index' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['content'] ); + unset( $data['_links'] ); + + $this->assertEquals( + array( + 'id' => 'tt1-blocks//index', + 'theme' => 'tt1-blocks', + 'slug' => 'index', + 'title' => array( + 'raw' => 'Index', + 'rendered' => 'Index', + ), + 'description' => 'The default template used when no other template is available. This is a required template in WordPress.', + 'status' => 'publish', + 'source' => 'theme', + 'type' => 'wp_template', + 'wp_id' => null, + 'has_theme_file' => true, + ), + $data + ); + + // Test template parts. + $request = new WP_REST_Request( 'GET', '/wp/v2/template-parts/tt1-blocks//header' ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['content'] ); + unset( $data['_links'] ); + $this->assertEquals( + array( + 'id' => 'tt1-blocks//header', + 'theme' => 'tt1-blocks', + 'slug' => 'header', + 'title' => array( + 'raw' => 'header', + 'rendered' => 'header', + ), + 'description' => '', + 'status' => 'publish', + 'source' => 'theme', + 'type' => 'wp_template_part', + 'wp_id' => null, + 'area' => WP_TEMPLATE_PART_AREA_HEADER, + 'has_theme_file' => true, + ), + $data + ); + } + + public function test_create_item() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'POST', '/wp/v2/templates' ); + $request->set_body_params( + array( + 'slug' => 'my_custom_template', + 'title' => 'My Template', + 'description' => 'Just a description', + 'content' => 'Content', + ) + ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['_links'] ); + unset( $data['wp_id'] ); + + $this->assertEquals( + array( + 'id' => 'tt1-blocks//my_custom_template', + 'theme' => 'tt1-blocks', + 'slug' => 'my_custom_template', + 'title' => array( + 'raw' => 'My Template', + 'rendered' => 'My Template', + ), + 'description' => 'Just a description', + 'status' => 'publish', + 'source' => 'custom', + 'type' => 'wp_template', + 'content' => array( + 'raw' => 'Content', + ), + 'has_theme_file' => false, + ), + $data + ); + + // Test template parts. + $request = new WP_REST_Request( 'POST', '/wp/v2/template-parts' ); + $request->set_body_params( + array( + 'slug' => 'my_custom_template_part', + 'title' => 'My Template Part', + 'description' => 'Just a description of a template part', + 'content' => 'Content', + 'area' => 'header', + ) + ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + unset( $data['_links'] ); + unset( $data['wp_id'] ); + + $this->assertEquals( + array( + 'id' => 'tt1-blocks//my_custom_template_part', + 'theme' => 'tt1-blocks', + 'slug' => 'my_custom_template_part', + 'title' => array( + 'raw' => 'My Template Part', + 'rendered' => 'My Template Part', + ), + 'description' => 'Just a description of a template part', + 'status' => 'publish', + 'source' => 'custom', + 'type' => 'wp_template_part', + 'content' => array( + 'raw' => 'Content', + ), + 'area' => 'header', + 'has_theme_file' => false, + ), + $data + ); + } + + public function test_update_item() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'PUT', '/wp/v2/templates/tt1-blocks//index' ); + $request->set_body_params( + array( + 'title' => 'My new Index Title', + ) + ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertEquals( 'My new Index Title', $data['title']['raw'] ); + $this->assertEquals( 'custom', $data['source'] ); + + // Test template parts. + $request = new WP_REST_Request( 'PUT', '/wp/v2/template-parts/tt1-blocks//header' ); + $request->set_body_params( + array( + 'area' => 'something unsupported', + ) + ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $this->assertEquals( WP_TEMPLATE_PART_AREA_UNCATEGORIZED, $data['area'] ); + $this->assertEquals( 'custom', $data['source'] ); + } + + public function test_delete_item() { + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/justrandom//template' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_template_not_found', $response, 404 ); + + wp_set_current_user( self::$admin_id ); + $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/tt1-blocks//single' ); + $response = rest_get_server()->dispatch( $request ); + $this->assertErrorResponse( 'rest_invalid_template', $response, 400 ); + } + + public function test_prepare_item() { + // TODO: Implement test_prepare_item() method. + } + + public function test_get_item_schema() { + // TODO: Implement test_get_item_schema() method. + } +} From c7889f19d3f94c2e2ccd90d9f2d4c0f45745d708 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Thu, 20 May 2021 20:03:33 +0200 Subject: [PATCH 05/57] Add class-wp-block-template.php --- src/wp-includes/class-wp-block-template.php | 90 +++++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 src/wp-includes/class-wp-block-template.php diff --git a/src/wp-includes/class-wp-block-template.php b/src/wp-includes/class-wp-block-template.php new file mode 100644 index 0000000000000..d8c9d5c54a2b9 --- /dev/null +++ b/src/wp-includes/class-wp-block-template.php @@ -0,0 +1,90 @@ + Date: Fri, 21 May 2021 13:37:46 +0200 Subject: [PATCH 06/57] Register wp_template post type --- src/wp-includes/post.php | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 81d152f6387e2..36103ede9e066 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -310,6 +310,53 @@ function create_initial_post_types() { ) ); + if ( gutenberg_supports_block_templates() ) { + register_post_type( + 'wp_template', + array( + 'labels' => array( + 'name' => __( 'Templates', 'gutenberg' ), + 'singular_name' => __( 'Template', 'gutenberg' ), + 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), + 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), + 'add_new_item' => __( 'Add New Template', 'gutenberg' ), + 'new_item' => __( 'New Template', 'gutenberg' ), + 'edit_item' => __( 'Edit Template', 'gutenberg' ), + 'view_item' => __( 'View Template', 'gutenberg' ), + 'all_items' => __( 'All Templates', 'gutenberg' ), + 'search_items' => __( 'Search Templates', 'gutenberg' ), + 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), + 'not_found' => __( 'No templates found.', 'gutenberg' ), + 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), + 'archives' => __( 'Template archives', 'gutenberg' ), + 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), + 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), + 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), + 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), + 'items_list' => __( 'Templates list', 'gutenberg' ), + ), + 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), + 'public' => false, + 'has_archive' => false, + 'show_ui' => true, + 'show_in_menu' => 'themes.php', + 'show_in_admin_bar' => false, + 'show_in_rest' => true, + 'rest_base' => 'templates', + 'rest_controller_class' => 'WP_REST_Templates_Controller', + 'capability_type' => array( 'template', 'templates' ), + 'map_meta_cap' => true, + 'supports' => array( + 'title', + 'slug', + 'excerpt', + 'editor', + 'revisions', + ), + ) + ); + } + register_post_status( 'publish', array( From dac31895d1b2472458d40ba32d2faa3e1d75cb4b Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 14:07:22 +0200 Subject: [PATCH 07/57] Register wp_theme taxonomy --- src/wp-includes/taxonomy.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 7d7785407cd7a..98cf3a9b31fd0 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -172,6 +172,27 @@ function create_initial_taxonomies() { 'show_in_nav_menus' => current_theme_supports( 'post-formats' ), ) ); + + if ( ! gutenberg_supports_block_templates() && ! WP_Theme_JSON_Resolver::theme_has_support() ) { + register_taxonomy( + 'wp_theme', + array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), + array( + 'public' => false, + 'hierarchical' => false, + 'labels' => array( + 'name' => __( 'Themes', 'gutenberg' ), + 'singular_name' => __( 'Theme', 'gutenberg' ), + ), + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => false, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => false, + ) + ); + } } /** From 26712c74bec56aa4e3284f551456f9d3afd245ed Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 14:33:37 +0200 Subject: [PATCH 08/57] Add src/wp-admin/includes/templates-utils.php --- src/wp-admin/includes/templates-utils.php | 113 ++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/wp-admin/includes/templates-utils.php diff --git a/src/wp-admin/includes/templates-utils.php b/src/wp-admin/includes/templates-utils.php new file mode 100644 index 0000000000000..bc270a738d967 --- /dev/null +++ b/src/wp-admin/includes/templates-utils.php @@ -0,0 +1,113 @@ +post_name ); + return; + } + + if ( 'description' === $column_name && has_excerpt( $post_id ) ) { + the_excerpt( $post_id ); + return; + } + + if ( 'status' === $column_name ) { + $post_status = get_post_status( $post_id ); + // The auto-draft status doesn't have localized labels. + if ( 'auto-draft' === $post_status ) { + echo esc_html_x( 'Auto-Draft', 'Post status', 'gutenberg' ); + return; + } + $post_status_object = get_post_status_object( $post_status ); + echo esc_html( $post_status_object->label ); + return; + } + + if ( 'theme' === $column_name ) { + $terms = get_the_terms( $post_id, 'wp_theme' ); + if ( empty( $terms ) || is_wp_error( $terms ) ) { + return; + } + $themes = array(); + foreach ( $terms as $term ) { + $themes[] = esc_html( wp_get_theme( $term->slug ) ); + } + echo implode( '
', $themes ); + return; + } +} + +/** + * Adds the auto-draft view to the templates and template parts admin lists. + * + * @param array $views The edit views to filter. + */ +function gutenberg_filter_templates_edit_views( $views ) { + $post_type = get_current_screen()->post_type; + $url = add_query_arg( + array( + 'post_type' => $post_type, + 'post_status' => 'auto-draft', + ), + 'edit.php' + ); + $is_auto_draft_view = isset( $_REQUEST['post_status'] ) && 'auto-draft' === $_REQUEST['post_status']; + $class_html = $is_auto_draft_view ? ' class="current"' : ''; + $aria_current = $is_auto_draft_view ? ' aria-current="page"' : ''; + $post_count = wp_count_posts( $post_type, 'readable' ); + $label = sprintf( + // The auto-draft status doesn't have localized labels. + translate_nooped_plural( + /* translators: %s: Number of auto-draft posts. */ + _nx_noop( + 'Auto-Draft (%s)', + 'Auto-Drafts (%s)', + 'Post status', + 'gutenberg' + ), + $post_count->{'auto-draft'} + ), + number_format_i18n( $post_count->{'auto-draft'} ) + ); + + $auto_draft_view = sprintf( + '%s', + esc_url( $url ), + $class_html, + $aria_current, + $label + ); + + array_splice( $views, 1, 0, array( 'auto-draft' => $auto_draft_view ) ); + + return $views; +} From f991abe1047392e76bf70957f01f6e6ca035f208 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 14:46:04 +0200 Subject: [PATCH 09/57] Add src/wp-admin/theme-templates.php --- src/wp-admin/theme-templates.php | 266 +++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 src/wp-admin/theme-templates.php diff --git a/src/wp-admin/theme-templates.php b/src/wp-admin/theme-templates.php new file mode 100644 index 0000000000000..3b15473692680 --- /dev/null +++ b/src/wp-admin/theme-templates.php @@ -0,0 +1,266 @@ + __( 'Templates', 'gutenberg' ), + 'singular_name' => __( 'Template', 'gutenberg' ), + 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), + 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), + 'add_new_item' => __( 'Add New Template', 'gutenberg' ), + 'new_item' => __( 'New Template', 'gutenberg' ), + 'edit_item' => __( 'Edit Template', 'gutenberg' ), + 'view_item' => __( 'View Template', 'gutenberg' ), + 'all_items' => __( 'All Templates', 'gutenberg' ), + 'search_items' => __( 'Search Templates', 'gutenberg' ), + 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), + 'not_found' => __( 'No templates found.', 'gutenberg' ), + 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), + 'archives' => __( 'Template archives', 'gutenberg' ), + 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), + 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), + 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), + 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), + 'items_list' => __( 'Templates list', 'gutenberg' ), + ); + + $args = array( + 'labels' => $labels, + 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), + 'public' => false, + 'has_archive' => false, + 'show_ui' => true, + 'show_in_menu' => 'themes.php', + 'show_in_admin_bar' => false, + 'show_in_rest' => true, + 'rest_base' => 'templates', + 'rest_controller_class' => 'WP_REST_Templates_Controller', + 'capability_type' => array( 'template', 'templates' ), + 'map_meta_cap' => true, + 'supports' => array( + 'title', + 'slug', + 'excerpt', + 'editor', + 'revisions', + ), + ); + + register_post_type( 'wp_template', $args ); +} +add_action( 'init', 'gutenberg_register_template_post_type' ); + +/** + * Registers block editor 'wp_theme' taxonomy. + */ +function gutenberg_register_wp_theme_taxonomy() { + if ( ! gutenberg_supports_block_templates() && ! WP_Theme_JSON_Resolver::theme_has_support() ) { + return; + } + + register_taxonomy( + 'wp_theme', + array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), + array( + 'public' => false, + 'hierarchical' => false, + 'labels' => array( + 'name' => __( 'Themes', 'gutenberg' ), + 'singular_name' => __( 'Theme', 'gutenberg' ), + ), + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => false, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => false, + ) + ); +} +add_action( 'init', 'gutenberg_register_wp_theme_taxonomy' ); + +/** + * Filters the capabilities of a user to conditionally grant them capabilities for managing 'wp_template' posts. + * + * Any user who can 'edit_theme_options' will have access. + * + * @param array $allcaps A user's capabilities. + * @return array Filtered $allcaps. + */ +function gutenberg_grant_template_caps( array $allcaps ) { + if ( isset( $allcaps['edit_theme_options'] ) ) { + $allcaps['edit_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_others_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_published_templates'] = $allcaps['edit_theme_options']; + $allcaps['edit_private_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_others_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_published_templates'] = $allcaps['edit_theme_options']; + $allcaps['delete_private_templates'] = $allcaps['edit_theme_options']; + $allcaps['publish_templates'] = $allcaps['edit_theme_options']; + $allcaps['read_private_templates'] = $allcaps['edit_theme_options']; + } + + return $allcaps; +} +add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); + +/** + * Fixes the label of the 'wp_template' admin menu entry. + */ +function gutenberg_fix_template_admin_menu_entry() { + if ( ! gutenberg_supports_block_templates() ) { + return; + } + global $submenu; + if ( ! isset( $submenu['themes.php'] ) ) { + return; + } + $post_type = get_post_type_object( 'wp_template' ); + if ( ! $post_type ) { + return; + } + foreach ( $submenu['themes.php'] as $key => $submenu_entry ) { + if ( $post_type->labels->all_items === $submenu['themes.php'][ $key ][0] ) { + $submenu['themes.php'][ $key ][0] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride + break; + } + } +} +add_action( 'admin_menu', 'gutenberg_fix_template_admin_menu_entry' ); + +// Customize the `wp_template` admin list. +add_filter( 'manage_wp_template_posts_columns', 'gutenberg_templates_lists_custom_columns' ); +add_action( 'manage_wp_template_posts_custom_column', 'gutenberg_render_templates_lists_custom_column', 10, 2 ); +add_filter( 'views_edit-wp_template', 'gutenberg_filter_templates_edit_views' ); + +/** + * Sets a custom slug when creating auto-draft templates. + * This is only needed for auto-drafts created by the regular WP editor. + * If this page is to be removed, this won't be necessary. + * + * @param int $post_id Post ID. + */ +function set_unique_slug_on_create_template( $post_id ) { + $post = get_post( $post_id ); + if ( 'auto-draft' !== $post->post_status ) { + return; + } + + if ( ! $post->post_name ) { + wp_update_post( + array( + 'ID' => $post_id, + 'post_name' => 'custom_slug_' . uniqid(), + ) + ); + } + + $terms = get_the_terms( $post_id, 'wp_theme' ); + if ( ! $terms || ! count( $terms ) ) { + wp_set_post_terms( $post_id, wp_get_theme()->get_stylesheet(), 'wp_theme' ); + } +} +add_action( 'save_post_wp_template', 'set_unique_slug_on_create_template' ); + +/** + * Print the skip-link script & styles. + * + * @return void + */ +function gutenberg_the_skip_link() { + + // Early exit if not an FSE theme. + if ( ! gutenberg_supports_block_templates() ) { + return; + } + ?> + + + + + + Date: Fri, 21 May 2021 14:47:35 +0200 Subject: [PATCH 10/57] Remove post type and taxonomy registration from theme-templates.php --- src/wp-admin/theme-templates.php | 85 -------------------------------- 1 file changed, 85 deletions(-) diff --git a/src/wp-admin/theme-templates.php b/src/wp-admin/theme-templates.php index 3b15473692680..06f0b74028b9c 100644 --- a/src/wp-admin/theme-templates.php +++ b/src/wp-admin/theme-templates.php @@ -5,91 +5,6 @@ * @package gutenberg */ -/** - * Registers block editor 'wp_template' post type. - */ -function gutenberg_register_template_post_type() { - if ( ! gutenberg_supports_block_templates() ) { - return; - } - - $labels = array( - 'name' => __( 'Templates', 'gutenberg' ), - 'singular_name' => __( 'Template', 'gutenberg' ), - 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), - 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), - 'add_new_item' => __( 'Add New Template', 'gutenberg' ), - 'new_item' => __( 'New Template', 'gutenberg' ), - 'edit_item' => __( 'Edit Template', 'gutenberg' ), - 'view_item' => __( 'View Template', 'gutenberg' ), - 'all_items' => __( 'All Templates', 'gutenberg' ), - 'search_items' => __( 'Search Templates', 'gutenberg' ), - 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), - 'not_found' => __( 'No templates found.', 'gutenberg' ), - 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), - 'archives' => __( 'Template archives', 'gutenberg' ), - 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), - 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), - 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), - 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), - 'items_list' => __( 'Templates list', 'gutenberg' ), - ); - - $args = array( - 'labels' => $labels, - 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), - 'public' => false, - 'has_archive' => false, - 'show_ui' => true, - 'show_in_menu' => 'themes.php', - 'show_in_admin_bar' => false, - 'show_in_rest' => true, - 'rest_base' => 'templates', - 'rest_controller_class' => 'WP_REST_Templates_Controller', - 'capability_type' => array( 'template', 'templates' ), - 'map_meta_cap' => true, - 'supports' => array( - 'title', - 'slug', - 'excerpt', - 'editor', - 'revisions', - ), - ); - - register_post_type( 'wp_template', $args ); -} -add_action( 'init', 'gutenberg_register_template_post_type' ); - -/** - * Registers block editor 'wp_theme' taxonomy. - */ -function gutenberg_register_wp_theme_taxonomy() { - if ( ! gutenberg_supports_block_templates() && ! WP_Theme_JSON_Resolver::theme_has_support() ) { - return; - } - - register_taxonomy( - 'wp_theme', - array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), - array( - 'public' => false, - 'hierarchical' => false, - 'labels' => array( - 'name' => __( 'Themes', 'gutenberg' ), - 'singular_name' => __( 'Theme', 'gutenberg' ), - ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => false, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => false, - ) - ); -} -add_action( 'init', 'gutenberg_register_wp_theme_taxonomy' ); - /** * Filters the capabilities of a user to conditionally grant them capabilities for managing 'wp_template' posts. * From ba9f4ead711f302796c033e8e801d0c8a2567c91 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 16:52:55 +0200 Subject: [PATCH 11/57] Add wp_template caps to src/wp-includes/post.php --- src/wp-admin/theme-templates.php | 26 -------------------------- src/wp-includes/post.php | 11 +++++++++++ 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/src/wp-admin/theme-templates.php b/src/wp-admin/theme-templates.php index 06f0b74028b9c..52b0802ddca89 100644 --- a/src/wp-admin/theme-templates.php +++ b/src/wp-admin/theme-templates.php @@ -5,32 +5,6 @@ * @package gutenberg */ -/** - * Filters the capabilities of a user to conditionally grant them capabilities for managing 'wp_template' posts. - * - * Any user who can 'edit_theme_options' will have access. - * - * @param array $allcaps A user's capabilities. - * @return array Filtered $allcaps. - */ -function gutenberg_grant_template_caps( array $allcaps ) { - if ( isset( $allcaps['edit_theme_options'] ) ) { - $allcaps['edit_templates'] = $allcaps['edit_theme_options']; - $allcaps['edit_others_templates'] = $allcaps['edit_theme_options']; - $allcaps['edit_published_templates'] = $allcaps['edit_theme_options']; - $allcaps['edit_private_templates'] = $allcaps['edit_theme_options']; - $allcaps['delete_templates'] = $allcaps['edit_theme_options']; - $allcaps['delete_others_templates'] = $allcaps['edit_theme_options']; - $allcaps['delete_published_templates'] = $allcaps['edit_theme_options']; - $allcaps['delete_private_templates'] = $allcaps['edit_theme_options']; - $allcaps['publish_templates'] = $allcaps['edit_theme_options']; - $allcaps['read_private_templates'] = $allcaps['edit_theme_options']; - } - - return $allcaps; -} -add_filter( 'user_has_cap', 'gutenberg_grant_template_caps' ); - /** * Fixes the label of the 'wp_template' admin menu entry. */ diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 36103ede9e066..40afd28a5e610 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -345,6 +345,17 @@ function create_initial_post_types() { 'rest_base' => 'templates', 'rest_controller_class' => 'WP_REST_Templates_Controller', 'capability_type' => array( 'template', 'templates' ), + 'capabilities' => array( + 'edit_posts' => 'edit_theme_options', + 'edit_others_posts' => 'edit_theme_options', + 'edit_published_posts' => 'edit_theme_options', + 'edit_private_posts' => 'edit_theme_options', + 'delete_posts' => 'edit_theme_options', + 'delete_others_posts' => 'edit_theme_options', + 'delete_published_posts' => 'edit_theme_options', + 'delete_private_posts' => 'edit_theme_options', + 'read_private_posts' => 'edit_theme_options', + ), 'map_meta_cap' => true, 'supports' => array( 'title', From daeba9042191a8de25ae9c72711b039066ea29d7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 18:43:03 +0200 Subject: [PATCH 12/57] Add src/wp-includes/block-templates.php --- src/wp-includes/block-templates.php | 496 ++++++++++++++++++++++++++++ 1 file changed, 496 insertions(+) create mode 100644 src/wp-includes/block-templates.php diff --git a/src/wp-includes/block-templates.php b/src/wp-includes/block-templates.php new file mode 100644 index 0000000000000..e2d157e2540db --- /dev/null +++ b/src/wp-includes/block-templates.php @@ -0,0 +1,496 @@ + $file ) { + $path_list[] = $path; + } + } + return $path_list; +} + +/** + * Retrieves the template file from the theme for a given slug. + * + * @access private + * @internal + * + * @param array $template_type wp_template or wp_template_part. + * @param string $slug template slug. + * + * @return array Template. + */ +function _gutenberg_get_template_file( $template_type, $slug ) { + $template_base_paths = array( + 'wp_template' => 'block-templates', + 'wp_template_part' => 'block-template-parts', + ); + $themes = array( + get_stylesheet() => get_stylesheet_directory(), + get_template() => get_template_directory(), + ); + foreach ( $themes as $theme_slug => $theme_dir ) { + $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; + if ( file_exists( $file_path ) ) { + $new_template_item = array( + 'slug' => $slug, + 'path' => $file_path, + 'theme' => $theme_slug, + 'type' => $template_type, + ); + + if ( 'wp_template_part' === $template_type ) { + return _gutenberg_add_template_part_area_info( $new_template_item ); + } + return $new_template_item; + } + } + + return null; +} + +/** + * Retrieves the template files from the theme. + * + * @access private + * @internal + * + * @param array $template_type wp_template or wp_template_part. + * + * @return array Template. + */ +function _gutenberg_get_template_files( $template_type ) { + $template_base_paths = array( + 'wp_template' => 'block-templates', + 'wp_template_part' => 'block-template-parts', + ); + $themes = array( + get_stylesheet() => get_stylesheet_directory(), + get_template() => get_template_directory(), + ); + + $template_files = array(); + foreach ( $themes as $theme_slug => $theme_dir ) { + $theme_template_files = _gutenberg_get_template_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] ); + foreach ( $theme_template_files as $template_file ) { + $template_base_path = $template_base_paths[ $template_type ]; + $template_slug = substr( + $template_file, + // Starting position of slug. + strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ), + // Subtract ending '.html'. + -5 + ); + $new_template_item = array( + 'slug' => $template_slug, + 'path' => $template_file, + 'theme' => $theme_slug, + 'type' => $template_type, + ); + + if ( 'wp_template_part' === $template_type ) { + $template_files[] = _gutenberg_add_template_part_area_info( $new_template_item ); + } else { + $template_files[] = $new_template_item; + } + } + } + + return $template_files; +} + +/** + * Attempts to add the template part's area information to the input template. + * + * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). + * + * @return array Template. + */ +function _gutenberg_add_template_part_area_info( $template_info ) { + if ( WP_Theme_JSON_Resolver::theme_has_support() ) { + $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_template_parts(); + } + + if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { + $template_info['area'] = gutenberg_filter_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); + } else { + $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; + } + + return $template_info; +} + +/** + * Returns an array containing the references of + * the passed blocks and their inner blocks. + * + * @param array $blocks array of blocks. + * + * @return array block references to the passed blocks and their inner blocks. + */ +function _flatten_blocks( &$blocks ) { + $all_blocks = array(); + $queue = array(); + foreach ( $blocks as &$block ) { + $queue[] = &$block; + } + + while ( count( $queue ) > 0 ) { + $block = &$queue[0]; + array_shift( $queue ); + $all_blocks[] = &$block; + + if ( ! empty( $block['innerBlocks'] ) ) { + foreach ( $block['innerBlocks'] as &$inner_block ) { + $queue[] = &$inner_block; + } + } + } + + return $all_blocks; +} + +/** + * Parses wp_template content and injects the current theme's + * stylesheet as a theme attribute into each wp_template_part + * + * @param string $template_content serialized wp_template content. + * + * @return string Updated wp_template content. + */ +function _inject_theme_attribute_in_content( $template_content ) { + $has_updated_content = false; + $new_content = ''; + $template_blocks = parse_blocks( $template_content ); + + $blocks = _flatten_blocks( $template_blocks ); + foreach ( $blocks as &$block ) { + if ( + 'core/template-part' === $block['blockName'] && + ! isset( $block['attrs']['theme'] ) + ) { + $block['attrs']['theme'] = wp_get_theme()->get_stylesheet(); + $has_updated_content = true; + } + } + + if ( $has_updated_content ) { + foreach ( $template_blocks as &$block ) { + $new_content .= serialize_block( $block ); + } + + return $new_content; + } + + return $template_content; +} + +/** + * Build a unified template object based on a theme file. + * + * @param array $template_file Theme file. + * @param array $template_type wp_template or wp_template_part. + * + * @return WP_Block_Template Template. + */ +function _gutenberg_build_template_result_from_file( $template_file, $template_type ) { + $default_template_types = gutenberg_get_default_template_types(); + $template_content = file_get_contents( $template_file['path'] ); + $theme = wp_get_theme()->get_stylesheet(); + + $template = new WP_Block_Template(); + $template->id = $theme . '//' . $template_file['slug']; + $template->theme = $theme; + $template->content = _inject_theme_attribute_in_content( $template_content ); + $template->slug = $template_file['slug']; + $template->source = 'theme'; + $template->type = $template_type; + $template->title = $template_file['slug']; + $template->status = 'publish'; + $template->has_theme_file = true; + + if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) { + $template->description = $default_template_types[ $template_file['slug'] ]['description']; + $template->title = $default_template_types[ $template_file['slug'] ]['title']; + } + + if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) { + $template->area = $template_file['area']; + } + + return $template; +} + +/** + * Build a unified template object based a post Object. + * + * @param WP_Post $post Template post. + * + * @return WP_Block_Template|WP_Error Template. + */ +function _gutenberg_build_template_result_from_post( $post ) { + $terms = get_the_terms( $post, 'wp_theme' ); + + if ( is_wp_error( $terms ) ) { + return $terms; + } + + if ( ! $terms ) { + return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'gutenberg' ) ); + } + + $theme = $terms[0]->name; + $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && + null !== _gutenberg_get_template_file( $post->post_type, $post->post_name ); + + $template = new WP_Block_Template(); + $template->wp_id = $post->ID; + $template->id = $theme . '//' . $post->post_name; + $template->theme = $theme; + $template->content = $post->post_content; + $template->slug = $post->post_name; + $template->source = 'custom'; + $template->type = $post->post_type; + $template->description = $post->post_excerpt; + $template->title = $post->post_title; + $template->status = $post->post_status; + $template->has_theme_file = $has_theme_file; + + if ( 'wp_template_part' === $post->post_type ) { + $type_terms = get_the_terms( $post, 'wp_template_part_area' ); + if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { + $template->area = $type_terms[0]->name; + } + } + + return $template; +} + +/** + * Retrieves a list of unified template objects based on a query. + * + * @param array $query { + * Optional. Arguments to retrieve templates. + * + * @type array $slug__in List of slugs to include. + * @type int $wp_id Post ID of customized template. + * } + * @param array $template_type wp_template or wp_template_part. + * + * @return array Templates. + */ +function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_template' ) { + $wp_query_args = array( + 'post_status' => array( 'auto-draft', 'draft', 'publish' ), + 'post_type' => $template_type, + 'posts_per_page' => -1, + 'no_found_rows' => true, + 'tax_query' => array( + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => wp_get_theme()->get_stylesheet(), + ), + ), + ); + + if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) { + $wp_query_args['tax_query'][] = array( + 'taxonomy' => 'wp_template_part_area', + 'field' => 'name', + 'terms' => $query['area'], + ); + $wp_query_args['tax_query']['relation'] = 'AND'; + } + + if ( isset( $query['slug__in'] ) ) { + $wp_query_args['post_name__in'] = $query['slug__in']; + } + + // This is only needed for the regular templates/template parts CPT listing and editor. + if ( isset( $query['wp_id'] ) ) { + $wp_query_args['p'] = $query['wp_id']; + } else { + $wp_query_args['post_status'] = 'publish'; + } + + $template_query = new WP_Query( $wp_query_args ); + $query_result = array(); + foreach ( $template_query->get_posts() as $post ) { + $template = _gutenberg_build_template_result_from_post( $post ); + + if ( ! is_wp_error( $template ) ) { + $query_result[] = $template; + } + } + + if ( ! isset( $query['wp_id'] ) ) { + $template_files = _gutenberg_get_template_files( $template_type ); + foreach ( $template_files as $template_file ) { + $is_not_custom = false === array_search( + wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'], + array_column( $query_result, 'id' ), + true + ); + $fits_slug_query = + ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true ); + $fits_area_query = + ! isset( $query['area'] ) || $template_file['area'] === $query['area']; + $should_include = $is_not_custom && $fits_slug_query && $fits_area_query; + if ( $should_include ) { + $query_result[] = _gutenberg_build_template_result_from_file( $template_file, $template_type ); + } + } + } + + return $query_result; +} + +/** + * Retrieves a single unified template object using its id. + * + * @param string $id Template unique identifier (example: theme_slug//template_slug). + * @param array $template_type wp_template or wp_template_part. + * + * @return WP_Block_Template|null Template. + */ +function gutenberg_get_block_template( $id, $template_type = 'wp_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->get_posts(); + + if ( count( $posts ) > 0 ) { + $template = _gutenberg_build_template_result_from_post( $posts[0] ); + + if ( ! is_wp_error( $template ) ) { + return $template; + } + } + + return gutenberg_get_block_file_template( $id, $template_type ); +} + +/** + * Retrieves a single unified template object using its id. + * Retrieves the file template. + * + * @param string $id Template unique identifier (example: theme_slug//template_slug). + * @param array $template_type wp_template or wp_template_part. + * + * @return WP_Block_Template|null File template. + */ +function gutenberg_get_block_file_template( $id, $template_type = 'wp_template' ) { + $parts = explode( '//', $id, 2 ); + if ( count( $parts ) < 2 ) { + return null; + } + list( $theme, $slug ) = $parts; + + if ( wp_get_theme()->get_stylesheet() === $theme ) { + $template_file = _gutenberg_get_template_file( $template_type, $slug ); + if ( null !== $template_file ) { + return _gutenberg_build_template_result_from_file( $template_file, $template_type ); + } + } + + return null; +} + +/** + * Generates a unique slug for templates or template parts. + * + * @param string $override_slug The filtered value of the slug (starts as `null` from apply_filter). + * @param string $slug The original/un-filtered slug (post_name). + * @param int $post_ID Post ID. + * @param string $post_status No uniqueness checks are made if the post is still draft or pending. + * @param string $post_type Post type. + * @return string The original, desired slug. + */ +function gutenberg_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { + if ( 'wp_template' !== $post_type && 'wp_template_part' !== $post_type ) { + return $override_slug; + } + + if ( ! $override_slug ) { + $override_slug = $slug; + } + + // Template slugs must be unique within the same theme. + // TODO - Figure out how to update this to work for a multi-theme + // environment. Unfortunately using `get_the_terms` for the 'wp-theme' + // term does not work in the case of new entities since is too early in + // the process to have been saved to the entity. So for now we use the + // currently activated theme for creation. + $theme = wp_get_theme()->get_stylesheet(); + $terms = get_the_terms( $post_ID, 'wp_theme' ); + if ( $terms && ! is_wp_error( $terms ) ) { + $theme = $terms[0]->name; + } + + $check_query_args = array( + 'post_name__in' => array( $override_slug ), + 'post_type' => $post_type, + 'posts_per_page' => 1, + 'no_found_rows' => true, + 'post__not_in' => array( $post_ID ), + 'tax_query' => array( + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => $theme, + ), + ), + ); + $check_query = new WP_Query( $check_query_args ); + $posts = $check_query->get_posts(); + + if ( count( $posts ) > 0 ) { + $suffix = 2; + do { + $query_args = $check_query_args; + $alt_post_name = _truncate_post_slug( $override_slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; + $query_args['post_name__in'] = array( $alt_post_name ); + $query = new WP_Query( $query_args ); + $suffix++; + } while ( count( $query->get_posts() ) > 0 ); + $override_slug = $alt_post_name; + } + + return $override_slug; +} +add_filter( 'pre_wp_unique_post_slug', 'gutenberg_filter_wp_template_unique_post_slug', 10, 5 ); From fc621507aed918764f819dde1ddbe608e01fb7e2 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 18:44:59 +0200 Subject: [PATCH 13/57] Add src/wp-includes/default-template-types.php --- src/wp-includes/default-template-types.php | 124 +++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/wp-includes/default-template-types.php diff --git a/src/wp-includes/default-template-types.php b/src/wp-includes/default-template-types.php new file mode 100644 index 0000000000000..1a9c2b023dbe8 --- /dev/null +++ b/src/wp-includes/default-template-types.php @@ -0,0 +1,124 @@ + array( + 'title' => _x( 'Index', 'Template name', 'gutenberg' ), + 'description' => __( 'The default template used when no other template is available. This is a required template in WordPress.', 'gutenberg' ), + ), + 'home' => array( + 'title' => _x( 'Home', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used for the main page that displays blog posts. This is the front page by default in WordPress. If a static front page is set, this is the template used for the page that contains the latest blog posts.', 'gutenberg' ), + ), + 'front-page' => array( + 'title' => _x( 'Front Page', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used to render the front page of the site, whether it displays blog posts or a static page. The front page template takes precedence over the "Home" template.', 'gutenberg' ), + ), + 'singular' => array( + 'title' => _x( 'Singular', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used for displaying single views of the content. This template is a fallback for the Single, Post, and Page templates, which take precedence when they exist.', 'gutenberg' ), + ), + 'single' => array( + 'title' => _x( 'Single Post', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used to display a single blog post.', 'gutenberg' ), + ), + 'page' => array( + 'title' => _x( 'Page', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used to display individual pages.', 'gutenberg' ), + ), + 'archive' => array( + 'title' => _x( 'Archive', 'Template name', 'gutenberg' ), + 'description' => __( 'The archive template displays multiple entries at once. It is used as a fallback for the Category, Author, and Date templates, which take precedence when they are available.', 'gutenberg' ), + ), + 'author' => array( + 'title' => _x( 'Author', 'Template name', 'gutenberg' ), + 'description' => __( 'Archive template used to display a list of posts from a single author.', 'gutenberg' ), + ), + 'category' => array( + 'title' => _x( 'Category', 'Template name', 'gutenberg' ), + 'description' => __( 'Archive template used to display a list of posts from the same category.', 'gutenberg' ), + ), + 'taxonomy' => array( + 'title' => _x( 'Taxonomy', 'Template name', 'gutenberg' ), + 'description' => __( 'Archive template used to display a list of posts from the same taxonomy.', 'gutenberg' ), + ), + 'date' => array( + 'title' => _x( 'Date', 'Template name', 'gutenberg' ), + 'description' => __( 'Archive template used to display a list of posts from a specific date.', 'gutenberg' ), + ), + 'tag' => array( + 'title' => _x( 'Tag', 'Template name', 'gutenberg' ), + 'description' => __( 'Archive template used to display a list of posts with a given tag.', 'gutenberg' ), + ), + 'attachment' => array( + 'title' => __( 'Media', 'gutenberg' ), + 'description' => __( 'Template used to display individual media items or attachments.', 'gutenberg' ), + ), + 'search' => array( + 'title' => _x( 'Search', 'Template name', 'gutenberg' ), + 'description' => __( 'Template used to display search results.', 'gutenberg' ), + ), + 'privacy-policy' => array( + 'title' => __( 'Privacy Policy', 'gutenberg' ), + 'description' => '', + ), + '404' => array( + 'title' => _x( '404', 'Template name', 'gutenberg' ), + 'description' => __( 'Template shown when no content is found.', 'gutenberg' ), + ), + ); + + /** + * Filters the list of template types. + * + * @param array $default_template_types An array of template types, formatted as [ slug => [ title, description ] ]. + * + * @since 5.x.x + */ + return apply_filters( 'default_template_types', $default_template_types ); +} + +/** + * Converts the default template types array from associative to indexed, + * to be used in JS, where numeric keys (e.g. '404') always appear before alphabetical + * ones, regardless of the actual order of the array. + * + * From slug-keyed associative array: + * `[ 'index' => [ 'title' => 'Index', 'description' => 'Index template' ] ]` + * + * ...to indexed array with slug as property: + * `[ [ 'slug' => 'index', 'title' => 'Index', 'description' => 'Index template' ] ]` + * + * @return array The default template types as an indexed array. + */ +function gutenberg_get_indexed_default_template_types() { + $indexed_template_types = array(); + $default_template_types = gutenberg_get_default_template_types(); + foreach ( $default_template_types as $slug => $template_type ) { + $template_type['slug'] = (string) $slug; + $indexed_template_types[] = $template_type; + } + return $indexed_template_types; +} + +/** + * Return a list of all overrideable default template type slugs. + * + * @see get_query_template + * + * @return string[] List of all overrideable default template type slugs. + */ +function gutenberg_get_template_type_slugs() { + return array_keys( gutenberg_get_default_template_types() ); +} From ab6fa3827f7da0027f3073575d8b521bb4837561 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 18:50:34 +0200 Subject: [PATCH 14/57] Add tests/phpunit/tests/block-templates.php --- tests/phpunit/tests/block-templates.php | 309 ++++++++++++++++++++++++ 1 file changed, 309 insertions(+) create mode 100644 tests/phpunit/tests/block-templates.php diff --git a/tests/phpunit/tests/block-templates.php b/tests/phpunit/tests/block-templates.php new file mode 100644 index 0000000000000..1d747426665b7 --- /dev/null +++ b/tests/phpunit/tests/block-templates.php @@ -0,0 +1,309 @@ + 'wp_template', + 'post_name' => 'my_template', + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + 'this-theme-should-not-resolve', + ), + ), + ); + self::$post = self::factory()->post->create_and_get( $args ); + wp_set_post_terms( self::$post->ID, 'this-theme-should-not-resolve', 'wp_theme' ); + + // Set up template post. + $args = array( + 'post_type' => 'wp_template', + 'post_name' => 'my_template', + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + get_stylesheet(), + ), + ), + ); + self::$post = self::factory()->post->create_and_get( $args ); + wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' ); + + // Set up template part post. + $template_part_args = array( + 'post_type' => 'wp_template_part', + 'post_name' => 'my_template_part', + 'post_title' => 'My Template Part', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template part', + 'tax_input' => array( + 'wp_theme' => array( + get_stylesheet(), + ), + 'wp_template_part_area' => array( + WP_TEMPLATE_PART_AREA_HEADER, + ), + ), + ); + self::$template_part_post = self::factory()->post->create_and_get( $template_part_args ); + wp_set_post_terms( self::$template_part_post->ID, WP_TEMPLATE_PART_AREA_HEADER, 'wp_template_part_area' ); + wp_set_post_terms( self::$template_part_post->ID, get_stylesheet(), 'wp_theme' ); + } + + public static function wpTearDownAfterClass() { + wp_delete_post( self::$post->ID ); + } + + function test_gutenberg_build_template_result_from_file() { + $template = _gutenberg_build_template_result_from_file( + array( + 'slug' => 'single', + 'path' => __DIR__ . '/fixtures/template.html', + ), + 'wp_template' + ); + + $this->assertEquals( get_stylesheet() . '//single', $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'single', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'theme', $template->source ); + $this->assertEquals( 'Single Post', $template->title ); + $this->assertEquals( 'Template used to display a single blog post.', $template->description ); + $this->assertEquals( 'wp_template', $template->type ); + + // Test template parts. + $template_part = _gutenberg_build_template_result_from_file( + array( + 'slug' => 'header', + 'path' => __DIR__ . '/fixtures/template.html', + 'area' => WP_TEMPLATE_PART_AREA_HEADER, + ), + 'wp_template_part' + ); + $this->assertEquals( get_stylesheet() . '//header', $template_part->id ); + $this->assertEquals( get_stylesheet(), $template_part->theme ); + $this->assertEquals( 'header', $template_part->slug ); + $this->assertEquals( 'publish', $template_part->status ); + $this->assertEquals( 'theme', $template_part->source ); + $this->assertEquals( 'header', $template_part->title ); + $this->assertEquals( '', $template_part->description ); + $this->assertEquals( 'wp_template_part', $template_part->type ); + $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template_part->area ); + } + + function test_gutenberg_build_template_result_from_post() { + $template = _gutenberg_build_template_result_from_post( + self::$post, + 'wp_template' + ); + + $this->assertNotWPError( $template ); + $this->assertEquals( get_stylesheet() . '//my_template', $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'my_template', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'custom', $template->source ); + $this->assertEquals( 'My Template', $template->title ); + $this->assertEquals( 'Description of my template', $template->description ); + $this->assertEquals( 'wp_template', $template->type ); + + // Test template parts. + $template_part = _gutenberg_build_template_result_from_post( + self::$template_part_post, + 'wp_template_part' + ); + $this->assertNotWPError( $template_part ); + $this->assertEquals( get_stylesheet() . '//my_template_part', $template_part->id ); + $this->assertEquals( get_stylesheet(), $template_part->theme ); + $this->assertEquals( 'my_template_part', $template_part->slug ); + $this->assertEquals( 'publish', $template_part->status ); + $this->assertEquals( 'custom', $template_part->source ); + $this->assertEquals( 'My Template Part', $template_part->title ); + $this->assertEquals( 'Description of my template part', $template_part->description ); + $this->assertEquals( 'wp_template_part', $template_part->type ); + $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template_part->area ); + } + + function test_inject_theme_attribute_in_content() { + $theme = get_stylesheet(); + $content_without_theme_attribute = ''; + $template_content = _inject_theme_attribute_in_content( + $content_without_theme_attribute, + $theme + ); + $expected = sprintf( + '', + get_stylesheet() + ); + $this->assertEquals( $expected, $template_content ); + + $content_without_theme_attribute_nested = ''; + $template_content = _inject_theme_attribute_in_content( + $content_without_theme_attribute_nested, + $theme + ); + $expected = sprintf( + '', + get_stylesheet() + ); + $this->assertEquals( $expected, $template_content ); + + // Does not inject theme when there is an existing theme attribute. + $content_with_existing_theme_attribute = ''; + $template_content = _inject_theme_attribute_in_content( + $content_with_existing_theme_attribute, + $theme + ); + $this->assertEquals( $content_with_existing_theme_attribute, $template_content ); + + // Does not inject theme when there is no template part. + $content_with_no_template_part = ''; + $template_content = _inject_theme_attribute_in_content( + $content_with_no_template_part, + $theme + ); + $this->assertEquals( $content_with_no_template_part, $template_content ); + } + + /** + * Should retrieve the template from the theme files. + */ + function test_gutenberg_get_block_template_from_file() { + $id = get_stylesheet() . '//' . 'index'; + $template = gutenberg_get_block_template( $id, 'wp_template' ); + $this->assertEquals( $id, $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'index', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'theme', $template->source ); + $this->assertEquals( 'wp_template', $template->type ); + + // Test template parts. + $id = get_stylesheet() . '//' . 'header'; + $template = gutenberg_get_block_template( $id, 'wp_template_part' ); + $this->assertEquals( $id, $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'header', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'theme', $template->source ); + $this->assertEquals( 'wp_template_part', $template->type ); + $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template->area ); + } + + /** + * Should retrieve the template from the CPT. + */ + function test_gutenberg_get_block_template_from_post() { + $id = get_stylesheet() . '//' . 'my_template'; + $template = gutenberg_get_block_template( $id, 'wp_template' ); + $this->assertEquals( $id, $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'my_template', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'custom', $template->source ); + $this->assertEquals( 'wp_template', $template->type ); + + // Test template parts. + $id = get_stylesheet() . '//' . 'my_template_part'; + $template = gutenberg_get_block_template( $id, 'wp_template_part' ); + $this->assertEquals( $id, $template->id ); + $this->assertEquals( get_stylesheet(), $template->theme ); + $this->assertEquals( 'my_template_part', $template->slug ); + $this->assertEquals( 'publish', $template->status ); + $this->assertEquals( 'custom', $template->source ); + $this->assertEquals( 'wp_template_part', $template->type ); + $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template->area ); + } + + /** + * Should retrieve block templates (file and CPT) + */ + function test_gutenberg_get_block_templates() { + function get_template_ids( $templates ) { + return array_map( + function( $template ) { + return $template->id; + }, + $templates + ); + } + + // All results. + $templates = gutenberg_get_block_templates( array(), 'wp_template' ); + $template_ids = get_template_ids( $templates ); + + // Avoid testing the entire array because the theme might add/remove templates. + $this->assertContains( get_stylesheet() . '//' . 'my_template', $template_ids ); + $this->assertContains( get_stylesheet() . '//' . 'index', $template_ids ); + + // Filter by slug. + $templates = gutenberg_get_block_templates( array( 'slug__in' => array( 'my_template' ) ), 'wp_template' ); + $template_ids = get_template_ids( $templates ); + $this->assertEquals( array( get_stylesheet() . '//' . 'my_template' ), $template_ids ); + + // Filter by CPT ID. + $templates = gutenberg_get_block_templates( array( 'wp_id' => self::$post->ID ), 'wp_template' ); + $template_ids = get_template_ids( $templates ); + $this->assertEquals( array( get_stylesheet() . '//' . 'my_template' ), $template_ids ); + + // Filter template part by area. + $templates = gutenberg_get_block_templates( array( 'area' => WP_TEMPLATE_PART_AREA_HEADER ), 'wp_template_part' ); + $template_ids = get_template_ids( $templates ); + $this->assertEquals( + array( + get_stylesheet() . '//' . 'my_template_part', + get_stylesheet() . '//' . 'header', + ), + $template_ids + ); + } + + /** + * Should flatten nested blocks + */ + function test_flatten_blocks() { + $content_template_part_inside_group = ''; + $blocks = parse_blocks( $content_template_part_inside_group ); + $actual = _flatten_blocks( $blocks ); + $expected = array( $blocks[0], $blocks[0]['innerBlocks'][0] ); + $this->assertEquals( $expected, $actual ); + + $content_template_part_inside_group_inside_group = ''; + $blocks = parse_blocks( $content_template_part_inside_group_inside_group ); + $actual = _flatten_blocks( $blocks ); + $expected = array( $blocks[0], $blocks[0]['innerBlocks'][0], $blocks[0]['innerBlocks'][0]['innerBlocks'][0] ); + $this->assertEquals( $expected, $actual ); + + $content_without_inner_blocks = ''; + $blocks = parse_blocks( $content_without_inner_blocks ); + $actual = _flatten_blocks( $blocks ); + $expected = array( $blocks[0] ); + $this->assertEquals( $expected, $actual ); + } +} From c6a71b282612d27c3e8c8cdef2f559de938a802b Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 22:04:34 +0200 Subject: [PATCH 15/57] Move gutenberg_is_fse_theme and gutenberg_supports_block_templates to wp-includes/theme.php --- src/wp-includes/theme.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 458b8e6b3a403..32c7ab4ccd3f5 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -3232,6 +3232,24 @@ function get_registered_theme_feature( $feature ) { return isset( $_wp_registered_theme_features[ $feature ] ) ? $_wp_registered_theme_features[ $feature ] : null; } +/** + * Returns whether the current theme is an FSE theme or not. + * + * @return boolean Whether the current theme is an FSE theme or not. + */ +function gutenberg_is_fse_theme() { + return is_readable( get_stylesheet_directory() . '/block-templates/index.html' ); +} + +/** + * Returns whether the current theme is FSE-enabled or not. + * + * @return boolean Whether the current theme is FSE-enabled or not. + */ +function gutenberg_supports_block_templates() { + return gutenberg_is_fse_theme() || current_theme_supports( 'block-templates' ); +} + /** * Checks an attachment being deleted to see if it's a header or background image. * From 832e464b62bebcba5aaa91f250a91604e9a87035 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 22:33:33 +0200 Subject: [PATCH 16/57] Add custom block template support --- src/wp-includes/class-wp-theme.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index b365f457151eb..8e6da9850644d 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1182,6 +1182,7 @@ public function get_files( $type = null, $depth = 0, $search_parent = false ) { * Returns the theme's post templates. * * @since 4.7.0 + * @since 5.8.0 Include block templates. * * @return string[] Array of page templates, keyed by filename and post type, * with the value of the translated header name. @@ -1219,6 +1220,14 @@ public function get_post_templates() { } } + if ( gutenberg_supports_block_templates() ) { + $block_templates = gutenberg_get_block_templates( array(), 'wp_template' ); + foreach ( $block_templates as $block_template ) { + // TODO: Allow using block templates for custom post types (rather than just pages). + $post_templates['page'][ $block_template->slug ] = $block_template->title; + } + } + $this->cache_add( 'post_templates', $post_templates ); } From e9c64a44baa0b131062e67ee26ef856a1abb412c Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 22:58:26 +0200 Subject: [PATCH 17/57] Ugh, forgot to negate --- src/wp-includes/taxonomy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 98cf3a9b31fd0..d6d9ac5ffda14 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -173,7 +173,7 @@ function create_initial_taxonomies() { ) ); - if ( ! gutenberg_supports_block_templates() && ! WP_Theme_JSON_Resolver::theme_has_support() ) { + if ( gutenberg_supports_block_templates() || WP_Theme_JSON_Resolver::theme_has_support() ) { register_taxonomy( 'wp_theme', array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), From cc4393e5f8e082f041bb481c7ce2756ee3bd4d4f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:01:34 +0200 Subject: [PATCH 18/57] Uncomment theme.json specific criterion --- src/wp-includes/taxonomy.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index d6d9ac5ffda14..047d0637269b2 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -173,7 +173,8 @@ function create_initial_taxonomies() { ) ); - if ( gutenberg_supports_block_templates() || WP_Theme_JSON_Resolver::theme_has_support() ) { + // FIXME: Uncomment once theme.json support lands + if ( gutenberg_supports_block_templates() /* || WP_Theme_JSON_Resolver::theme_has_support() */ ) { register_taxonomy( 'wp_theme', array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), From 41db3dc0b87ca74e2cc45b88abbcdf805a02e7d6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:04:31 +0200 Subject: [PATCH 19/57] Remove now-obsolete test setup methods --- tests/phpunit/tests/rest-api/rest-templates-controller.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/phpunit/tests/rest-api/rest-templates-controller.php b/tests/phpunit/tests/rest-api/rest-templates-controller.php index cf5931a68a0a8..e2d26ee4067bd 100644 --- a/tests/phpunit/tests/rest-api/rest-templates-controller.php +++ b/tests/phpunit/tests/rest-api/rest-templates-controller.php @@ -13,10 +13,6 @@ class WP_REST_Template_Controller_Test extends WP_Test_REST_Controller_Testcase */ public static function wpSetupBeforeClass( $factory ) { switch_theme( 'tt1-blocks' ); - gutenberg_register_template_post_type(); - gutenberg_register_template_part_post_type(); - gutenberg_register_wp_theme_taxonomy(); - gutenberg_register_wp_template_part_area_taxonomy(); self::$admin_id = $factory->user->create( array( 'role' => 'administrator', From 31c1ce60e93b3ab38b755649908d00bea679d80f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:43:11 +0200 Subject: [PATCH 20/57] Add src/wp-includes/block-template.php --- src/wp-includes/block-template.php | 267 +++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/wp-includes/block-template.php diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php new file mode 100644 index 0000000000000..002a7b48f3a61 --- /dev/null +++ b/src/wp-includes/block-template.php @@ -0,0 +1,267 @@ + get_front_page_template. + $template_hierarchy_filter = str_replace( '-', '', $template_type ) . '_template_hierarchy'; // front-page -> frontpage_template_hierarchy. + + $result = array(); + $template_hierarchy_filter_function = function( $templates ) use ( &$result ) { + $result = $templates; + return $templates; + }; + + add_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20, 1 ); + call_user_func( $get_template_function ); // This invokes template_hierarchy_filter. + remove_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20 ); + + return $result; +} + +/** + * Filters into the "{$type}_template" hooks to redirect them to the Full Site Editing template canvas. + * + * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. + * + * @param string $template Path to the template. See locate_template(). + * @param string $type Sanitized filename without extension. + * @param array $templates A list of template candidates, in descending order of priority. + * @return string The path to the Full Site Editing template canvas file. + */ +function gutenberg_override_query_template( $template, $type, array $templates ) { + global $_wp_current_template_content; + + if ( $template ) { + // locate_template() has found a PHP template at the path specified by $template. + // That means that we have a fallback candidate if we cannot find a block template + // with higher specificity. + // Thus, before looking for matching block themes, we shorten our list of candidate + // templates accordingly. + + // Locate the index of $template (without the theme directory path) in $templates. + $relative_template_path = str_replace( + array( get_stylesheet_directory() . '/', get_template_directory() . '/' ), + '', + $template + ); + $index = array_search( $relative_template_path, $templates, true ); + + // If the template hiearchy algorithm has successfully located a PHP template file, + // we will only consider block templates with higher or equal specificity. + $templates = array_slice( $templates, 0, $index + 1 ); + } + + $block_template = gutenberg_resolve_template( $type, $templates ); + + if ( $block_template ) { + if ( empty( $block_template->content ) && is_user_logged_in() ) { + $_wp_current_template_content = + sprintf( + /* translators: %s: Template title */ + __( 'Empty template: %s', 'gutenberg' ), + $block_template->title + ); + } elseif ( ! empty( $block_template->content ) ) { + $_wp_current_template_content = $block_template->content; + } + if ( isset( $_GET['_wp-find-template'] ) ) { + wp_send_json_success( $block_template ); + } + } else { + if ( $template ) { + return $template; + } + + if ( 'index' === $type ) { + if ( isset( $_GET['_wp-find-template'] ) ) { + wp_send_json_error( array( 'message' => __( 'No matching template found.', 'gutenberg' ) ) ); + } + } else { + return false; // So that the template loader keeps looking for templates. + } + } + + // Add hooks for template canvas. + // Add viewport meta tag. + add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 ); + + // Render title tag with content, regardless of whether theme has title-tag support. + remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering... + add_action( 'wp_head', 'gutenberg_render_title_tag', 1 ); // ...and make it unconditional. + + // This file will be included instead of the theme's template file. + return gutenberg_dir_path() . 'lib/template-canvas.php'; +} + +/** + * Return the correct 'wp_template' to render for the request template type. + * + * Accepts an optional $template_hierarchy argument as a hint. + * + * @param string $template_type The current template type. + * @param string[] $template_hierarchy (optional) The current template hierarchy, ordered by priority. + * @return null|array { + * @type WP_Post|null template_post A template post object, or null if none could be found. + * @type int[] A list of template parts IDs for the template. + * } + */ +function gutenberg_resolve_template( $template_type, $template_hierarchy ) { + if ( ! $template_type ) { + return null; + } + + if ( empty( $template_hierarchy ) ) { + $template_hierarchy = array( $template_type ); + } + + $slugs = array_map( + 'gutenberg_strip_php_suffix', + $template_hierarchy + ); + + // Find all potential templates 'wp_template' post matching the hierarchy. + $query = array( + 'theme' => wp_get_theme()->get_stylesheet(), + 'slug__in' => $slugs, + ); + $templates = gutenberg_get_block_templates( $query ); + + // Order these templates per slug priority. + // Build map of template slugs to their priority in the current hierarchy. + $slug_priorities = array_flip( $slugs ); + + usort( + $templates, + function ( $template_a, $template_b ) use ( $slug_priorities ) { + return $slug_priorities[ $template_a->slug ] - $slug_priorities[ $template_b->slug ]; + } + ); + + return count( $templates ) ? $templates[0] : null; +} + +/** + * Displays title tag with content, regardless of whether theme has title-tag support. + * + * @see _wp_render_title_tag() + */ +function gutenberg_render_title_tag() { + echo '' . wp_get_document_title() . '' . "\n"; +} + +/** + * Returns the markup for the current template. + */ +function gutenberg_get_the_template_html() { + global $_wp_current_template_content; + global $wp_embed; + + if ( ! $_wp_current_template_content ) { + if ( is_user_logged_in() ) { + return '

' . esc_html__( 'No matching template found', 'gutenberg' ) . '

'; + } + return; + } + + $content = $wp_embed->run_shortcode( $_wp_current_template_content ); + $content = $wp_embed->autoembed( $content ); + $content = do_blocks( $content ); + $content = wptexturize( $content ); + if ( function_exists( 'wp_filter_content_tags' ) ) { + $content = wp_filter_content_tags( $content ); + } else { + $content = wp_make_content_images_responsive( $content ); + } + $content = str_replace( ']]>', ']]>', $content ); + + // Wrap block template in .wp-site-blocks to allow for specific descendant styles + // (e.g. `.wp-site-blocks > *`). + return '
' . $content . '
'; +} + +/** + * Renders the markup for the current template. + */ +function gutenberg_render_the_template() { + echo gutenberg_get_the_template_html(); // phpcs:ignore WordPress.Security.EscapeOutput +} + +/** + * Renders a 'viewport' meta tag. + * + * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. + */ +function gutenberg_viewport_meta_tag() { + echo '' . "\n"; +} + +/** + * Strips .php suffix from template file names. + * + * @access private + * + * @param string $template_file Template file name. + * @return string Template file name without extension. + */ +function gutenberg_strip_php_suffix( $template_file ) { + return preg_replace( '/\.(php|html)$/', '', $template_file ); +} + +/** + * Removes post details from block context when rendering a block template. + * + * @param array $context Default context. + * + * @return array Filtered context. + */ +function gutenberg_template_render_without_post_block_context( $context ) { + /* + * When loading a template or template part directly and not through a page + * that resolves it, the top-level post ID and type context get set to that + * of the template part. Templates are just the structure of a site, and + * they should not be available as post context because blocks like Post + * Content would recurse infinitely. + */ + if ( isset( $context['postType'] ) && + ( 'wp_template' === $context['postType'] || 'wp_template_part' === $context['postType'] ) ) { + unset( $context['postId'] ); + unset( $context['postType'] ); + } + + return $context; +} +add_filter( 'render_block_context', 'gutenberg_template_render_without_post_block_context' ); From 15d49d69351982e77550e36a21c4deb4c55a7703 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:51:17 +0200 Subject: [PATCH 21/57] FSE: Remove now-obsolete get_template_hierarchy() See https://github.com/WordPress/gutenberg/pull/32116 --- src/wp-includes/block-template.php | 29 ----------------------------- 1 file changed, 29 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 002a7b48f3a61..69b586bca1b26 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -23,35 +23,6 @@ function gutenberg_add_template_loader_filters() { add_action( 'wp_loaded', 'gutenberg_add_template_loader_filters' ); -/** - * Get the template hierarchy for a given template type. - * - * Internally, this filters into the "{$type}_template_hierarchy" hook to record the type-specific template hierarchy. - * - * @param string $template_type A template type. - * @return string[] A list of template candidates, in descending order of priority. - */ -function get_template_hierarchy( $template_type ) { - if ( ! in_array( $template_type, gutenberg_get_template_type_slugs(), true ) ) { - return array(); - } - - $get_template_function = 'get_' . str_replace( '-', '_', $template_type ) . '_template'; // front-page -> get_front_page_template. - $template_hierarchy_filter = str_replace( '-', '', $template_type ) . '_template_hierarchy'; // front-page -> frontpage_template_hierarchy. - - $result = array(); - $template_hierarchy_filter_function = function( $templates ) use ( &$result ) { - $result = $templates; - return $templates; - }; - - add_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20, 1 ); - call_user_func( $get_template_function ); // This invokes template_hierarchy_filter. - remove_filter( $template_hierarchy_filter, $template_hierarchy_filter_function, 20 ); - - return $result; -} - /** * Filters into the "{$type}_template" hooks to redirect them to the Full Site Editing template canvas. * From 0f3d1575948f0b63aaf6a32035901694586039b7 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:54:49 +0200 Subject: [PATCH 22/57] Call block template loader directly, rather than adding filters --- src/wp-includes/block-template.php | 24 +++--------------------- src/wp-includes/template.php | 2 ++ 2 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 69b586bca1b26..fe3d903b57c14 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -6,34 +6,16 @@ */ /** - * Adds necessary filters to use 'wp_template' posts instead of theme template files. - */ -function gutenberg_add_template_loader_filters() { - if ( ! gutenberg_supports_block_templates() ) { - return; - } - - foreach ( gutenberg_get_template_type_slugs() as $template_type ) { - if ( 'embed' === $template_type ) { // Skip 'embed' for now because it is not a regular template type. - continue; - } - add_filter( str_replace( '-', '', $template_type ) . '_template', 'gutenberg_override_query_template', 20, 3 ); - } -} - -add_action( 'wp_loaded', 'gutenberg_add_template_loader_filters' ); - -/** - * Filters into the "{$type}_template" hooks to redirect them to the Full Site Editing template canvas. + * Find a block template with equal or higher specificity than a given PHP template file. * * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. * * @param string $template Path to the template. See locate_template(). * @param string $type Sanitized filename without extension. * @param array $templates A list of template candidates, in descending order of priority. - * @return string The path to the Full Site Editing template canvas file. + * @return string The path to the Full Site Editing template canvas file, or the fallback PHP template. */ -function gutenberg_override_query_template( $template, $type, array $templates ) { +function locate_block_template( $template, $type, array $templates ) { global $_wp_current_template_content; if ( $template ) { diff --git a/src/wp-includes/template.php b/src/wp-includes/template.php index b5b5619af564a..891e77748dd72 100644 --- a/src/wp-includes/template.php +++ b/src/wp-includes/template.php @@ -63,6 +63,8 @@ function get_query_template( $type, $templates = array() ) { $template = locate_template( $templates ); + $template = locate_block_template( $template, $type, $templates ); + /** * Filters the path of the queried template by type. * From d5d3277f24aa978888b8508a5a0aea2441e45e93 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:56:23 +0200 Subject: [PATCH 23/57] Add src/template-canvas.php --- src/wp-includes/block-template.php | 2 +- src/wp-includes/template-canvas.php | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/wp-includes/template-canvas.php diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index fe3d903b57c14..834fc1c03f481 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -77,7 +77,7 @@ function locate_block_template( $template, $type, array $templates ) { add_action( 'wp_head', 'gutenberg_render_title_tag', 1 ); // ...and make it unconditional. // This file will be included instead of the theme's template file. - return gutenberg_dir_path() . 'lib/template-canvas.php'; + return __DIR__ . 'template-canvas.php'; } /** diff --git a/src/wp-includes/template-canvas.php b/src/wp-includes/template-canvas.php new file mode 100644 index 0000000000000..4d29113dbf8e0 --- /dev/null +++ b/src/wp-includes/template-canvas.php @@ -0,0 +1,28 @@ + so that blocks can add scripts and styles in wp_head(). + */ +$template_html = gutenberg_get_the_template_html(); +?> + +> + + + + + +> + + + + + + + From a543e5762d71f9222970d988a1afa56288855153 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Fri, 21 May 2021 23:58:51 +0200 Subject: [PATCH 24/57] Add tests/phpunit/tests/block-template.php --- tests/phpunit/tests/block-template.php | 205 +++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 tests/phpunit/tests/block-template.php diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php new file mode 100644 index 0000000000000..5532c97015403 --- /dev/null +++ b/tests/phpunit/tests/block-template.php @@ -0,0 +1,205 @@ + 'wp_template', + 'post_name' => 'wp-custom-template-my-block-template', + 'post_title' => 'My Custom Block Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my block template', + 'tax_input' => array( + 'wp_theme' => array( + get_stylesheet(), + ), + ), + ); + self::$post = self::factory()->post->create_and_get( $args ); + wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' ); + } + + public static function wpTearDownAfterClass() { + wp_delete_post( self::$post->ID ); + remove_filter( 'stylesheet_directory', array( __CLASS__, 'change_theme_directory' ) ); + remove_filter( 'template_directory', array( __CLASS__, 'change_theme_directory' ) ); + } + + public function tearDown() { + global $_wp_current_template_content; + unset( $_wp_current_template_content ); + } + + function test_gutenberg_page_home_block_template_takes_precedence_over_less_specific_block_templates() { + global $_wp_current_template_content; + $type = 'page'; + $templates = array( + 'page-home.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page-home.php', $type, $templates ); + $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-home.html', $_wp_current_template_content ); + } + + function test_gutenberg_page_block_template_takes_precedence() { + global $_wp_current_template_content; + $type = 'page'; + $templates = array( + 'page-slug-doesnt-exist.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page.php', $type, $templates ); + $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page.html', $_wp_current_template_content ); + } + + function test_gutenberg_block_template_takes_precedence_over_equally_specific_php_template() { + global $_wp_current_template_content; + $type = 'index'; + $templates = array( + 'index.php', + ); + $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/index.php', $type, $templates ); + $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/index.html', $_wp_current_template_content ); + } + + /** + * In a hybrid theme, a PHP template of higher specificity will take precedence over a block template + * with lower specificity. + * + * Covers https://github.com/WordPress/gutenberg/pull/29026. + */ + function test_gutenberg_more_specific_php_template_takes_precedence_over_less_specific_block_template() { + $page_id_template = 'page-1.php'; + $page_id_template_path = get_stylesheet_directory() . '/' . $page_id_template; + $type = 'page'; + $templates = array( + 'page-slug-doesnt-exist.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( $page_id_template_path, $type, $templates ); + $this->assertEquals( $page_id_template_path, $resolved_template_path ); + } + + /** + * If a theme is a child of a block-based parent theme but has php templates for some of its pages, + * a php template of the child will take precedence over the parent's block template if they have + * otherwise equal specificity. + * + * Covers https://github.com/WordPress/gutenberg/pull/31123. + */ + function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { + switch_theme( 'test-theme-child' ); + + $page_slug_template = 'page-home.php'; + $page_slug_template_path = get_stylesheet_directory() . '/' . $page_slug_template; + $type = 'page'; + $templates = array( + 'page-home.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( $page_slug_template_path, $type, $templates ); + $this->assertEquals( $page_slug_template_path, $resolved_template_path ); + + switch_theme( 'test-theme' ); + } + + function test_gutenberg_child_theme_block_template_takes_precedence_over_equally_specific_parent_theme_php_template() { + global $_wp_current_template_content; + + switch_theme( 'test-theme-child' ); + + $page_template = 'page-1.php'; + $parent_theme_page_template_path = get_template_directory() . '/' . $page_template; + $type = 'page'; + $templates = array( + 'page-slug-doesnt-exist.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( $parent_theme_page_template_path, $type, $templates ); + $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content ); + + switch_theme( 'test-theme' ); + } + + /** + * Regression: https://github.com/WordPress/gutenberg/issues/31399. + */ + function test_gutenberg_custom_page_php_template_takes_precedence_over_all_other_templates() { + $custom_page_template = 'templates/full-width.php'; + $custom_page_template_path = get_stylesheet_directory() . '/' . $custom_page_template; + $type = 'page'; + $templates = array( + $custom_page_template, + 'page-slug.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( $custom_page_template_path, $type, $templates ); + $this->assertEquals( $custom_page_template_path, $resolved_template_path ); + } + + /** + * Covers: https://github.com/WordPress/gutenberg/pull/30438. + */ + function test_gutenberg_custom_page_block_template_takes_precedence_over_all_other_templates() { + global $_wp_current_template_content; + + $custom_page_block_template = 'wp-custom-template-my-block-template'; + $page_template_path = get_stylesheet_directory() . '/' . 'page.php'; + $type = 'page'; + $templates = array( + $custom_page_block_template, + 'page-slug.php', + 'page-1.php', + 'page.php', + ); + $resolved_template_path = gutenberg_override_query_template( $page_template_path, $type, $templates ); + $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $this->assertEquals( self::$post->post_content, $_wp_current_template_content ); + } + + /** + * Regression: https://github.com/WordPress/gutenberg/issues/31652. + */ + function test_gutenberg_template_remains_unchanged_if_templates_array_is_empty() { + $resolved_template_path = gutenberg_override_query_template( '', 'search', array() ); + $this->assertEquals( '', $resolved_template_path ); + } + + static function change_theme_directory( $theme_dir, $theme ) { + return __DIR__ . '/fixtures/themes/' . $theme; + } +} From 19ed2590a84dd8d7e0c16d1c71d664ce76fd5204 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:20:28 +0200 Subject: [PATCH 25/57] Fix block-template tests --- tests/phpunit/tests/block-template.php | 55 +++++++++++--------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index 5532c97015403..66cc76f541a6b 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -1,6 +1,6 @@ assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/page-home.php', $type, $templates ); + $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-home.html', $_wp_current_template_content ); } @@ -75,8 +66,8 @@ function test_gutenberg_page_block_template_takes_precedence() { 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/page.php', $type, $templates ); - $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/page.php', $type, $templates ); + $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page.html', $_wp_current_template_content ); } @@ -86,8 +77,8 @@ function test_gutenberg_block_template_takes_precedence_over_equally_specific_ph $templates = array( 'index.php', ); - $resolved_template_path = gutenberg_override_query_template( get_stylesheet_directory() . '/index.php', $type, $templates ); - $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/index.php', $type, $templates ); + $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/index.html', $_wp_current_template_content ); } @@ -106,7 +97,7 @@ function test_gutenberg_more_specific_php_template_takes_precedence_over_less_sp 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( $page_id_template_path, $type, $templates ); + $resolved_template_path = locate_block_template( $page_id_template_path, $type, $templates ); $this->assertEquals( $page_id_template_path, $resolved_template_path ); } @@ -118,7 +109,7 @@ function test_gutenberg_more_specific_php_template_takes_precedence_over_less_sp * Covers https://github.com/WordPress/gutenberg/pull/31123. */ function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { - switch_theme( 'test-theme-child' ); + switch_theme( 'block-templates-child' ); $page_slug_template = 'page-home.php'; $page_slug_template_path = get_stylesheet_directory() . '/' . $page_slug_template; @@ -128,16 +119,16 @@ function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_s 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( $page_slug_template_path, $type, $templates ); + $resolved_template_path = locate_block_template( $page_slug_template_path, $type, $templates ); $this->assertEquals( $page_slug_template_path, $resolved_template_path ); - switch_theme( 'test-theme' ); + switch_theme( 'block-templates' ); } function test_gutenberg_child_theme_block_template_takes_precedence_over_equally_specific_parent_theme_php_template() { global $_wp_current_template_content; - switch_theme( 'test-theme-child' ); + switch_theme( 'block-templates-child' ); $page_template = 'page-1.php'; $parent_theme_page_template_path = get_template_directory() . '/' . $page_template; @@ -147,11 +138,11 @@ function test_gutenberg_child_theme_block_template_takes_precedence_over_equally 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( $parent_theme_page_template_path, $type, $templates ); - $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $resolved_template_path = locate_block_template( $parent_theme_page_template_path, $type, $templates ); + $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content ); - switch_theme( 'test-theme' ); + switch_theme( 'block-templates' ); } /** @@ -167,7 +158,7 @@ function test_gutenberg_custom_page_php_template_takes_precedence_over_all_other 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( $custom_page_template_path, $type, $templates ); + $resolved_template_path = locate_block_template( $custom_page_template_path, $type, $templates ); $this->assertEquals( $custom_page_template_path, $resolved_template_path ); } @@ -186,8 +177,8 @@ function test_gutenberg_custom_page_block_template_takes_precedence_over_all_oth 'page-1.php', 'page.php', ); - $resolved_template_path = gutenberg_override_query_template( $page_template_path, $type, $templates ); - $this->assertEquals( gutenberg_dir_path() . 'lib/template-canvas.php', $resolved_template_path ); + $resolved_template_path = locate_block_template( $page_template_path, $type, $templates ); + $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertEquals( self::$post->post_content, $_wp_current_template_content ); } @@ -195,7 +186,7 @@ function test_gutenberg_custom_page_block_template_takes_precedence_over_all_oth * Regression: https://github.com/WordPress/gutenberg/issues/31652. */ function test_gutenberg_template_remains_unchanged_if_templates_array_is_empty() { - $resolved_template_path = gutenberg_override_query_template( '', 'search', array() ); + $resolved_template_path = locate_block_template( '', 'search', array() ); $this->assertEquals( '', $resolved_template_path ); } From aa44958ceb01109e23af2d553c81d709469a40fb Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:20:47 +0200 Subject: [PATCH 26/57] Fix block-template implementation --- src/wp-includes/block-template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 834fc1c03f481..109eb38a96241 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -77,7 +77,7 @@ function locate_block_template( $template, $type, array $templates ) { add_action( 'wp_head', 'gutenberg_render_title_tag', 1 ); // ...and make it unconditional. // This file will be included instead of the theme's template file. - return __DIR__ . 'template-canvas.php'; + return ABSPATH . WPINC . '/template-canvas.php'; } /** From 5b8f95667de04c943570ebb822bd5ed6bc7380ef Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:20:55 +0200 Subject: [PATCH 27/57] Load stuff --- src/wp-settings.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/wp-settings.php b/src/wp-settings.php index 770fa9ff3dcec..e1b494c515af6 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -170,6 +170,10 @@ require ABSPATH . WPINC . '/class-wp-date-query.php'; require ABSPATH . WPINC . '/theme.php'; require ABSPATH . WPINC . '/class-wp-theme.php'; +require ABSPATH . WPINC . '/default-template-types.php'; +require ABSPATH . WPINC . '/class-wp-block-template.php'; +require ABSPATH . WPINC . '/block-templates.php'; +require ABSPATH . WPINC . '/block-template.php'; require ABSPATH . WPINC . '/template.php'; require ABSPATH . WPINC . '/https-detection.php'; require ABSPATH . WPINC . '/https-migration.php'; From 9a4052d5415a1a667a2ded7cf7277d82b179f9b6 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:26:15 +0200 Subject: [PATCH 28/57] Rename block-templates.php to block-template-loader.php to avoid confusion with block-template.php --- .../{block-templates.php => block-template-loader.php} | 0 src/wp-settings.php | 2 +- .../{block-templates.php => block-template-loader.php} | 6 +++--- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/wp-includes/{block-templates.php => block-template-loader.php} (100%) rename tests/phpunit/tests/{block-templates.php => block-template-loader.php} (98%) diff --git a/src/wp-includes/block-templates.php b/src/wp-includes/block-template-loader.php similarity index 100% rename from src/wp-includes/block-templates.php rename to src/wp-includes/block-template-loader.php diff --git a/src/wp-settings.php b/src/wp-settings.php index e1b494c515af6..bfd691e1bbdc5 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -172,7 +172,7 @@ require ABSPATH . WPINC . '/class-wp-theme.php'; require ABSPATH . WPINC . '/default-template-types.php'; require ABSPATH . WPINC . '/class-wp-block-template.php'; -require ABSPATH . WPINC . '/block-templates.php'; +require ABSPATH . WPINC . '/block-template-loader.php'; require ABSPATH . WPINC . '/block-template.php'; require ABSPATH . WPINC . '/template.php'; require ABSPATH . WPINC . '/https-detection.php'; diff --git a/tests/phpunit/tests/block-templates.php b/tests/phpunit/tests/block-template-loader.php similarity index 98% rename from tests/phpunit/tests/block-templates.php rename to tests/phpunit/tests/block-template-loader.php index 1d747426665b7..ce25d2c85c189 100644 --- a/tests/phpunit/tests/block-templates.php +++ b/tests/phpunit/tests/block-template-loader.php @@ -1,15 +1,15 @@ Date: Sat, 22 May 2021 00:28:23 +0200 Subject: [PATCH 29/57] Block Template Loader Test: Remove now-obsolete setup steps --- tests/phpunit/tests/block-template-loader.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/phpunit/tests/block-template-loader.php b/tests/phpunit/tests/block-template-loader.php index ce25d2c85c189..34b35fe3d4fe1 100644 --- a/tests/phpunit/tests/block-template-loader.php +++ b/tests/phpunit/tests/block-template-loader.php @@ -15,10 +15,6 @@ class Block_Template_Loader_Test extends WP_UnitTestCase { public static function wpSetUpBeforeClass() { switch_theme( 'tt1-blocks' ); - gutenberg_register_template_post_type(); - gutenberg_register_template_part_post_type(); - gutenberg_register_wp_theme_taxonomy(); - gutenberg_register_wp_template_part_area_taxonomy(); // Set up a template post corresponding to a different theme. // We do this to ensure resolution and slug creation works as expected, From c283b491a7f81be08a1ccca269498295973c410f Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:37:08 +0200 Subject: [PATCH 30/57] Minor fix to block-template-loader.php test --- tests/phpunit/tests/block-template-loader.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/phpunit/tests/block-template-loader.php b/tests/phpunit/tests/block-template-loader.php index 34b35fe3d4fe1..5ccfdf0286414 100644 --- a/tests/phpunit/tests/block-template-loader.php +++ b/tests/phpunit/tests/block-template-loader.php @@ -14,7 +14,7 @@ class Block_Template_Loader_Test extends WP_UnitTestCase { private static $template_part_post; public static function wpSetUpBeforeClass() { - switch_theme( 'tt1-blocks' ); + switch_theme( 'block-templates' ); // Set up a template post corresponding to a different theme. // We do this to ensure resolution and slug creation works as expected, @@ -79,7 +79,7 @@ function test_gutenberg_build_template_result_from_file() { $template = _gutenberg_build_template_result_from_file( array( 'slug' => 'single', - 'path' => __DIR__ . '/fixtures/template.html', + 'path' => get_stylesheet_directory() . '/block-templates/index.html', ), 'wp_template' ); From ff8a5e4e51e778934a87b9c6e2c44da134e585f5 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:38:11 +0200 Subject: [PATCH 31/57] Rename test block template themes --- .../block-templates/page-1.html | 0 .../page-home.php | 0 .../themedir1/block-template-theme-child/style.css | 4 ++++ .../block-templates/index.html | 0 .../block-templates/page-home.html | 0 .../block-templates/page.html | 0 .../page-1.php | 0 .../data/themedir1/block-template-theme/style.css | 3 +++ .../data/themedir1/block-templates-child/style.css | 4 ---- tests/phpunit/data/themedir1/block-templates/style.css | 3 --- tests/phpunit/tests/block-template-loader.php | 2 +- tests/phpunit/tests/block-template.php | 10 +++++----- 12 files changed, 13 insertions(+), 13 deletions(-) rename tests/phpunit/data/themedir1/{block-templates-child => block-template-theme-child}/block-templates/page-1.html (100%) rename tests/phpunit/data/themedir1/{block-templates-child => block-template-theme-child}/page-home.php (100%) create mode 100644 tests/phpunit/data/themedir1/block-template-theme-child/style.css rename tests/phpunit/data/themedir1/{block-templates => block-template-theme}/block-templates/index.html (100%) rename tests/phpunit/data/themedir1/{block-templates => block-template-theme}/block-templates/page-home.html (100%) rename tests/phpunit/data/themedir1/{block-templates => block-template-theme}/block-templates/page.html (100%) rename tests/phpunit/data/themedir1/{block-templates => block-template-theme}/page-1.php (100%) create mode 100644 tests/phpunit/data/themedir1/block-template-theme/style.css delete mode 100644 tests/phpunit/data/themedir1/block-templates-child/style.css delete mode 100644 tests/phpunit/data/themedir1/block-templates/style.css diff --git a/tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html b/tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html similarity index 100% rename from tests/phpunit/data/themedir1/block-templates-child/block-templates/page-1.html rename to tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html diff --git a/tests/phpunit/data/themedir1/block-templates-child/page-home.php b/tests/phpunit/data/themedir1/block-template-theme-child/page-home.php similarity index 100% rename from tests/phpunit/data/themedir1/block-templates-child/page-home.php rename to tests/phpunit/data/themedir1/block-template-theme-child/page-home.php diff --git a/tests/phpunit/data/themedir1/block-template-theme-child/style.css b/tests/phpunit/data/themedir1/block-template-theme-child/style.css new file mode 100644 index 0000000000000..7796984c0420c --- /dev/null +++ b/tests/phpunit/data/themedir1/block-template-theme-child/style.css @@ -0,0 +1,4 @@ +/* +Theme Name: Block Template Theme Child +Template: block-template-theme +*/ diff --git a/tests/phpunit/data/themedir1/block-templates/block-templates/index.html b/tests/phpunit/data/themedir1/block-template-theme/block-templates/index.html similarity index 100% rename from tests/phpunit/data/themedir1/block-templates/block-templates/index.html rename to tests/phpunit/data/themedir1/block-template-theme/block-templates/index.html diff --git a/tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html b/tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html similarity index 100% rename from tests/phpunit/data/themedir1/block-templates/block-templates/page-home.html rename to tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html diff --git a/tests/phpunit/data/themedir1/block-templates/block-templates/page.html b/tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html similarity index 100% rename from tests/phpunit/data/themedir1/block-templates/block-templates/page.html rename to tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html diff --git a/tests/phpunit/data/themedir1/block-templates/page-1.php b/tests/phpunit/data/themedir1/block-template-theme/page-1.php similarity index 100% rename from tests/phpunit/data/themedir1/block-templates/page-1.php rename to tests/phpunit/data/themedir1/block-template-theme/page-1.php diff --git a/tests/phpunit/data/themedir1/block-template-theme/style.css b/tests/phpunit/data/themedir1/block-template-theme/style.css new file mode 100644 index 0000000000000..3e275b17ab612 --- /dev/null +++ b/tests/phpunit/data/themedir1/block-template-theme/style.css @@ -0,0 +1,3 @@ +/* +Theme Name: Block Template Theme +*/ diff --git a/tests/phpunit/data/themedir1/block-templates-child/style.css b/tests/phpunit/data/themedir1/block-templates-child/style.css deleted file mode 100644 index 166e3104c8376..0000000000000 --- a/tests/phpunit/data/themedir1/block-templates-child/style.css +++ /dev/null @@ -1,4 +0,0 @@ -/* -Theme Name: Block Templates Theme Child -Template: block-templates -*/ diff --git a/tests/phpunit/data/themedir1/block-templates/style.css b/tests/phpunit/data/themedir1/block-templates/style.css deleted file mode 100644 index a6b5798ba64d1..0000000000000 --- a/tests/phpunit/data/themedir1/block-templates/style.css +++ /dev/null @@ -1,3 +0,0 @@ -/* -Theme Name: Block Templates Theme -*/ diff --git a/tests/phpunit/tests/block-template-loader.php b/tests/phpunit/tests/block-template-loader.php index 5ccfdf0286414..022d58d54fad1 100644 --- a/tests/phpunit/tests/block-template-loader.php +++ b/tests/phpunit/tests/block-template-loader.php @@ -14,7 +14,7 @@ class Block_Template_Loader_Test extends WP_UnitTestCase { private static $template_part_post; public static function wpSetUpBeforeClass() { - switch_theme( 'block-templates' ); + switch_theme( 'block-template-theme' ); // Set up a template post corresponding to a different theme. // We do this to ensure resolution and slug creation works as expected, diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index 66cc76f541a6b..bfb54e4144bd7 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -15,7 +15,7 @@ class Block_Template_Test extends WP_UnitTestCase { private static $template_canvas_path = ABSPATH . WPINC . '/template-canvas.php'; public static function wpSetUpBeforeClass() { - switch_theme( 'block-templates' ); + switch_theme( 'block-template-theme' ); // Set up custom template post. $args = array( @@ -109,7 +109,7 @@ function test_gutenberg_more_specific_php_template_takes_precedence_over_less_sp * Covers https://github.com/WordPress/gutenberg/pull/31123. */ function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { - switch_theme( 'block-templates-child' ); + switch_theme( 'block-template-theme-child' ); $page_slug_template = 'page-home.php'; $page_slug_template_path = get_stylesheet_directory() . '/' . $page_slug_template; @@ -122,13 +122,13 @@ function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_s $resolved_template_path = locate_block_template( $page_slug_template_path, $type, $templates ); $this->assertEquals( $page_slug_template_path, $resolved_template_path ); - switch_theme( 'block-templates' ); + switch_theme( 'block-template-theme' ); } function test_gutenberg_child_theme_block_template_takes_precedence_over_equally_specific_parent_theme_php_template() { global $_wp_current_template_content; - switch_theme( 'block-templates-child' ); + switch_theme( 'block-template-theme-child' ); $page_template = 'page-1.php'; $parent_theme_page_template_path = get_template_directory() . '/' . $page_template; @@ -142,7 +142,7 @@ function test_gutenberg_child_theme_block_template_takes_precedence_over_equally $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content ); - switch_theme( 'block-templates' ); + switch_theme( 'block-template-theme' ); } /** From ba9c8d69b08c1f1178f20d19edd715d0e466a0a3 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Sat, 22 May 2021 00:56:24 +0200 Subject: [PATCH 32/57] Load templates endpoint --- src/wp-settings.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-settings.php b/src/wp-settings.php index bfd691e1bbdc5..0af60bb89ff84 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -272,6 +272,7 @@ require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-sidebars-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-widget-types-controller.php'; require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-widgets-controller.php'; +require ABSPATH . WPINC . '/rest-api/endpoints/class-wp-rest-templates-controller.php'; require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-meta-fields.php'; require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-comment-meta-fields.php'; require ABSPATH . WPINC . '/rest-api/fields/class-wp-rest-post-meta-fields.php'; From 633e5c0417a8fa0bfe073bd9657eceac991f2d0c Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 08:53:17 +0100 Subject: [PATCH 33/57] Some cleaning --- src/wp-admin/includes/templates-utils.php | 113 ------------------ src/wp-includes/post.php | 5 +- .../theme-templates.php | 37 +----- src/wp-includes/theme.php | 11 +- src/wp-settings.php | 1 + 5 files changed, 8 insertions(+), 159 deletions(-) delete mode 100644 src/wp-admin/includes/templates-utils.php rename src/{wp-admin => wp-includes}/theme-templates.php (71%) diff --git a/src/wp-admin/includes/templates-utils.php b/src/wp-admin/includes/templates-utils.php deleted file mode 100644 index bc270a738d967..0000000000000 --- a/src/wp-admin/includes/templates-utils.php +++ /dev/null @@ -1,113 +0,0 @@ -post_name ); - return; - } - - if ( 'description' === $column_name && has_excerpt( $post_id ) ) { - the_excerpt( $post_id ); - return; - } - - if ( 'status' === $column_name ) { - $post_status = get_post_status( $post_id ); - // The auto-draft status doesn't have localized labels. - if ( 'auto-draft' === $post_status ) { - echo esc_html_x( 'Auto-Draft', 'Post status', 'gutenberg' ); - return; - } - $post_status_object = get_post_status_object( $post_status ); - echo esc_html( $post_status_object->label ); - return; - } - - if ( 'theme' === $column_name ) { - $terms = get_the_terms( $post_id, 'wp_theme' ); - if ( empty( $terms ) || is_wp_error( $terms ) ) { - return; - } - $themes = array(); - foreach ( $terms as $term ) { - $themes[] = esc_html( wp_get_theme( $term->slug ) ); - } - echo implode( '
', $themes ); - return; - } -} - -/** - * Adds the auto-draft view to the templates and template parts admin lists. - * - * @param array $views The edit views to filter. - */ -function gutenberg_filter_templates_edit_views( $views ) { - $post_type = get_current_screen()->post_type; - $url = add_query_arg( - array( - 'post_type' => $post_type, - 'post_status' => 'auto-draft', - ), - 'edit.php' - ); - $is_auto_draft_view = isset( $_REQUEST['post_status'] ) && 'auto-draft' === $_REQUEST['post_status']; - $class_html = $is_auto_draft_view ? ' class="current"' : ''; - $aria_current = $is_auto_draft_view ? ' aria-current="page"' : ''; - $post_count = wp_count_posts( $post_type, 'readable' ); - $label = sprintf( - // The auto-draft status doesn't have localized labels. - translate_nooped_plural( - /* translators: %s: Number of auto-draft posts. */ - _nx_noop( - 'Auto-Draft (%s)', - 'Auto-Drafts (%s)', - 'Post status', - 'gutenberg' - ), - $post_count->{'auto-draft'} - ), - number_format_i18n( $post_count->{'auto-draft'} ) - ); - - $auto_draft_view = sprintf( - '%s', - esc_url( $url ), - $class_html, - $aria_current, - $label - ); - - array_splice( $views, 1, 0, array( 'auto-draft' => $auto_draft_view ) ); - - return $views; -} diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 40afd28a5e610..0f77bc7506dfd 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -338,10 +338,11 @@ function create_initial_post_types() { 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), 'public' => false, 'has_archive' => false, - 'show_ui' => true, - 'show_in_menu' => 'themes.php', + 'show_ui' => false, + 'show_in_menu' => false, 'show_in_admin_bar' => false, 'show_in_rest' => true, + 'rewrite' => false, 'rest_base' => 'templates', 'rest_controller_class' => 'WP_REST_Templates_Controller', 'capability_type' => array( 'template', 'templates' ), diff --git a/src/wp-admin/theme-templates.php b/src/wp-includes/theme-templates.php similarity index 71% rename from src/wp-admin/theme-templates.php rename to src/wp-includes/theme-templates.php index 52b0802ddca89..a9ae7bd6e1d20 100644 --- a/src/wp-admin/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -1,38 +1,4 @@ $submenu_entry ) { - if ( $post_type->labels->all_items === $submenu['themes.php'][ $key ][0] ) { - $submenu['themes.php'][ $key ][0] = $post_type->labels->menu_name; // phpcs:ignore WordPress.WP.GlobalVariablesOverride - break; - } - } -} -add_action( 'admin_menu', 'gutenberg_fix_template_admin_menu_entry' ); - -// Customize the `wp_template` admin list. -add_filter( 'manage_wp_template_posts_columns', 'gutenberg_templates_lists_custom_columns' ); -add_action( 'manage_wp_template_posts_custom_column', 'gutenberg_render_templates_lists_custom_column', 10, 2 ); -add_filter( 'views_edit-wp_template', 'gutenberg_filter_templates_edit_views' ); /** * Sets a custom slug when creating auto-draft templates. @@ -153,3 +119,6 @@ function gutenberg_the_skip_link() { Date: Mon, 24 May 2021 09:01:07 +0100 Subject: [PATCH 34/57] Add editor setting to enable template mode --- src/wp-admin/edit-form-blocks.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 848157de961e2..00fa94b7800a2 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -212,6 +212,7 @@ 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), '__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(), '__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), + 'supportsTemplateMode' => gutenberg_supports_block_templates(), // Whether or not to load the 'postcustom' meta box is stored as a user meta // field so that we're not always loading its assets. From cf3cbd95ed13b030c4805c0b57035b79e4b2cba5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ella=20van=C2=A0Durpe?= Date: Mon, 24 May 2021 12:51:31 +0300 Subject: [PATCH 35/57] Add iframe assets --- src/wp-includes/default-filters.php | 4 ++ src/wp-includes/script-loader.php | 57 +++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index d828a9fd17e52..cf679247d959c 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -555,6 +555,10 @@ add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in . add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer. +add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'wp_add_iframed_editor_assets_html' ); +add_action( 'admin_footer-post.php', 'wp_add_iframed_editor_assets_html' ); +add_action( 'admin_footer-post-new.php', 'wp_add_iframed_editor_assets_html' ); + // Taxonomy. add_action( 'init', 'create_initial_taxonomies', 0 ); // Highest priority. add_action( 'change_locale', 'create_initial_taxonomies' ); diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 0f28ef4030d08..91f965c84f01a 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2637,3 +2637,60 @@ function( $a, $b ) { } } } + +function wp_add_iframed_editor_assets_html() { + $script_handles = array(); + $style_handles = array( + 'wp-block-editor', + 'wp-block-library', + 'wp-block-library-theme', + 'wp-edit-blocks', + ); + + $block_registry = WP_Block_Type_Registry::get_instance(); + + foreach ( $block_registry->get_all_registered() as $block_type ) { + if ( ! empty( $block_type->style ) ) { + $style_handles[] = $block_type->style; + } + + if ( ! empty( $block_type->editor_style ) ) { + $style_handles[] = $block_type->editor_style; + } + + if ( ! empty( $block_type->script ) ) { + $script_handles[] = $block_type->script; + } + } + + $style_handles = array_unique( $style_handles ); + $done = wp_styles()->done; + + ob_start(); + + wp_styles()->done = array(); + wp_styles()->do_items( $style_handles ); + wp_styles()->done = $done; + + $styles = ob_get_clean(); + + $script_handles = array_unique( $script_handles ); + $done = wp_scripts()->done; + + ob_start(); + + wp_scripts()->done = array(); + wp_scripts()->do_items( $script_handles ); + wp_scripts()->done = $done; + + $scripts = ob_get_clean(); + + $editor_assets = wp_json_encode( + array( + 'styles' => $styles, + 'scripts' => $scripts, + ) + ); + + echo ""; +} From ae960b0489c98eba1e5dea177912a2467f1f2b59 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 11:54:22 +0100 Subject: [PATCH 36/57] Assign block templates to all post types --- src/wp-includes/class-wp-theme.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 8e6da9850644d..5a619197268ae 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1222,9 +1222,10 @@ public function get_post_templates() { if ( gutenberg_supports_block_templates() ) { $block_templates = gutenberg_get_block_templates( array(), 'wp_template' ); - foreach ( $block_templates as $block_template ) { - // TODO: Allow using block templates for custom post types (rather than just pages). - $post_templates['page'][ $block_template->slug ] = $block_template->title; + foreach ( get_post_types( array( 'public' => true ) ) as $type ) { + foreach ( $block_templates as $block_template ) { + $post_templates[ $type ][ $block_template->slug ] = $block_template->title; + } } } From fef992de5caa6073aafac94b74b1f81c14df26e2 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 12:11:08 +0100 Subject: [PATCH 37/57] Remove template part related logic --- src/wp-includes/block-template-loader.php | 114 ++------------- src/wp-includes/block-template.php | 12 +- .../class-wp-rest-templates-controller.php | 8 -- tests/phpunit/tests/block-template-loader.php | 130 ------------------ .../rest-api/rest-templates-controller.php | 101 -------------- 5 files changed, 18 insertions(+), 347 deletions(-) diff --git a/src/wp-includes/block-template-loader.php b/src/wp-includes/block-template-loader.php index e2d157e2540db..16b6834cf1734 100644 --- a/src/wp-includes/block-template-loader.php +++ b/src/wp-includes/block-template-loader.php @@ -1,18 +1,18 @@ 'block-templates', - 'wp_template_part' => 'block-template-parts', ); $themes = array( get_stylesheet() => get_stylesheet_directory(), @@ -56,9 +55,6 @@ function _gutenberg_get_template_file( $template_type, $slug ) { 'type' => $template_type, ); - if ( 'wp_template_part' === $template_type ) { - return _gutenberg_add_template_part_area_info( $new_template_item ); - } return $new_template_item; } } @@ -72,14 +68,13 @@ function _gutenberg_get_template_file( $template_type, $slug ) { * @access private * @internal * - * @param array $template_type wp_template or wp_template_part. + * @param array $template_type wp_template. * * @return array Template. */ function _gutenberg_get_template_files( $template_type ) { $template_base_paths = array( 'wp_template' => 'block-templates', - 'wp_template_part' => 'block-template-parts', ); $themes = array( get_stylesheet() => get_stylesheet_directory(), @@ -105,38 +100,12 @@ function _gutenberg_get_template_files( $template_type ) { 'type' => $template_type, ); - if ( 'wp_template_part' === $template_type ) { - $template_files[] = _gutenberg_add_template_part_area_info( $new_template_item ); - } else { - $template_files[] = $new_template_item; - } - } + $template_files[] = $new_template_item; } return $template_files; } -/** - * Attempts to add the template part's area information to the input template. - * - * @param array $template_info Template to add information to (requires 'type' and 'slug' fields). - * - * @return array Template. - */ -function _gutenberg_add_template_part_area_info( $template_info ) { - if ( WP_Theme_JSON_Resolver::theme_has_support() ) { - $theme_data = WP_Theme_JSON_Resolver::get_theme_data()->get_template_parts(); - } - - if ( isset( $theme_data[ $template_info['slug'] ]['area'] ) ) { - $template_info['area'] = gutenberg_filter_template_part_area( $theme_data[ $template_info['slug'] ]['area'] ); - } else { - $template_info['area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; - } - - return $template_info; -} - /** * Returns an array containing the references of * the passed blocks and their inner blocks. @@ -167,46 +136,11 @@ function _flatten_blocks( &$blocks ) { return $all_blocks; } -/** - * Parses wp_template content and injects the current theme's - * stylesheet as a theme attribute into each wp_template_part - * - * @param string $template_content serialized wp_template content. - * - * @return string Updated wp_template content. - */ -function _inject_theme_attribute_in_content( $template_content ) { - $has_updated_content = false; - $new_content = ''; - $template_blocks = parse_blocks( $template_content ); - - $blocks = _flatten_blocks( $template_blocks ); - foreach ( $blocks as &$block ) { - if ( - 'core/template-part' === $block['blockName'] && - ! isset( $block['attrs']['theme'] ) - ) { - $block['attrs']['theme'] = wp_get_theme()->get_stylesheet(); - $has_updated_content = true; - } - } - - if ( $has_updated_content ) { - foreach ( $template_blocks as &$block ) { - $new_content .= serialize_block( $block ); - } - - return $new_content; - } - - return $template_content; -} - /** * Build a unified template object based on a theme file. * * @param array $template_file Theme file. - * @param array $template_type wp_template or wp_template_part. + * @param array $template_type wp_template. * * @return WP_Block_Template Template. */ @@ -218,7 +152,7 @@ function _gutenberg_build_template_result_from_file( $template_file, $template_t $template = new WP_Block_Template(); $template->id = $theme . '//' . $template_file['slug']; $template->theme = $theme; - $template->content = _inject_theme_attribute_in_content( $template_content ); + $template->content = $template_content; $template->slug = $template_file['slug']; $template->source = 'theme'; $template->type = $template_type; @@ -231,10 +165,6 @@ function _gutenberg_build_template_result_from_file( $template_file, $template_t $template->title = $default_template_types[ $template_file['slug'] ]['title']; } - if ( 'wp_template_part' === $template_type && isset( $template_file['area'] ) ) { - $template->area = $template_file['area']; - } - return $template; } @@ -273,13 +203,6 @@ function _gutenberg_build_template_result_from_post( $post ) { $template->status = $post->post_status; $template->has_theme_file = $has_theme_file; - if ( 'wp_template_part' === $post->post_type ) { - $type_terms = get_the_terms( $post, 'wp_template_part_area' ); - if ( ! is_wp_error( $type_terms ) && false !== $type_terms ) { - $template->area = $type_terms[0]->name; - } - } - return $template; } @@ -292,7 +215,7 @@ function _gutenberg_build_template_result_from_post( $post ) { * @type array $slug__in List of slugs to include. * @type int $wp_id Post ID of customized template. * } - * @param array $template_type wp_template or wp_template_part. + * @param array $template_type wp_template. * * @return array Templates. */ @@ -311,20 +234,11 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t ), ); - if ( 'wp_template_part' === $template_type && isset( $query['area'] ) ) { - $wp_query_args['tax_query'][] = array( - 'taxonomy' => 'wp_template_part_area', - 'field' => 'name', - 'terms' => $query['area'], - ); - $wp_query_args['tax_query']['relation'] = 'AND'; - } - if ( isset( $query['slug__in'] ) ) { $wp_query_args['post_name__in'] = $query['slug__in']; } - // This is only needed for the regular templates/template parts CPT listing and editor. + // This is only needed for the regular templates CPT listing and editor. if ( isset( $query['wp_id'] ) ) { $wp_query_args['p'] = $query['wp_id']; } else { @@ -367,7 +281,7 @@ function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_t * Retrieves a single unified template object using its id. * * @param string $id Template unique identifier (example: theme_slug//template_slug). - * @param array $template_type wp_template or wp_template_part. + * @param array $template_type wp_template. * * @return WP_Block_Template|null Template. */ @@ -410,7 +324,7 @@ function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) { * Retrieves the file template. * * @param string $id Template unique identifier (example: theme_slug//template_slug). - * @param array $template_type wp_template or wp_template_part. + * @param array $template_type wp_template. * * @return WP_Block_Template|null File template. */ @@ -432,7 +346,7 @@ function gutenberg_get_block_file_template( $id, $template_type = 'wp_template' } /** - * Generates a unique slug for templates or template parts. + * Generates a unique slug for templates. * * @param string $override_slug The filtered value of the slug (starts as `null` from apply_filter). * @param string $slug The original/un-filtered slug (post_name). @@ -442,7 +356,7 @@ function gutenberg_get_block_file_template( $id, $template_type = 'wp_template' * @return string The original, desired slug. */ function gutenberg_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { - if ( 'wp_template' !== $post_type && 'wp_template_part' !== $post_type ) { + if ( 'wp_template' !== $post_type ) { return $override_slug; } diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 109eb38a96241..7720a0db1be22 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -87,10 +87,7 @@ function locate_block_template( $template, $type, array $templates ) { * * @param string $template_type The current template type. * @param string[] $template_hierarchy (optional) The current template hierarchy, ordered by priority. - * @return null|array { - * @type WP_Post|null template_post A template post object, or null if none could be found. - * @type int[] A list of template parts IDs for the template. - * } + * @return WP_Block_Template|null template A template object, or null if none could be found. */ function gutenberg_resolve_template( $template_type, $template_hierarchy ) { if ( ! $template_type ) { @@ -203,14 +200,13 @@ function gutenberg_strip_php_suffix( $template_file ) { */ function gutenberg_template_render_without_post_block_context( $context ) { /* - * When loading a template or template part directly and not through a page + * When loading a template directly and not through a page * that resolves it, the top-level post ID and type context get set to that - * of the template part. Templates are just the structure of a site, and + * of the template. Templates are just the structure of a site, and * they should not be available as post context because blocks like Post * Content would recurse infinitely. */ - if ( isset( $context['postType'] ) && - ( 'wp_template' === $context['postType'] || 'wp_template_part' === $context['postType'] ) ) { + if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) { unset( $context['postId'] ); unset( $context['postType'] ); } diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index e6b3a90efd3d3..818b8127ed5cd 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -569,14 +569,6 @@ public function get_item_schema() { ), ); - if ( 'wp_template_part' === $this->post_type ) { - $schema['properties']['area'] = array( - 'description' => __( 'Where the template part is intended for use (header, footer, etc.)', 'gutenberg' ), - 'type' => 'string', - 'context' => array( 'embed', 'view', 'edit' ), - ); - } - $this->schema = $schema; return $this->add_additional_fields_schema( $this->schema ); diff --git a/tests/phpunit/tests/block-template-loader.php b/tests/phpunit/tests/block-template-loader.php index 022d58d54fad1..3c78af30a6cf7 100644 --- a/tests/phpunit/tests/block-template-loader.php +++ b/tests/phpunit/tests/block-template-loader.php @@ -11,7 +11,6 @@ */ class Block_Template_Loader_Test extends WP_UnitTestCase { private static $post; - private static $template_part_post; public static function wpSetUpBeforeClass() { switch_theme( 'block-template-theme' ); @@ -49,26 +48,6 @@ public static function wpSetUpBeforeClass() { ); self::$post = self::factory()->post->create_and_get( $args ); wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' ); - - // Set up template part post. - $template_part_args = array( - 'post_type' => 'wp_template_part', - 'post_name' => 'my_template_part', - 'post_title' => 'My Template Part', - 'post_content' => 'Content', - 'post_excerpt' => 'Description of my template part', - 'tax_input' => array( - 'wp_theme' => array( - get_stylesheet(), - ), - 'wp_template_part_area' => array( - WP_TEMPLATE_PART_AREA_HEADER, - ), - ), - ); - self::$template_part_post = self::factory()->post->create_and_get( $template_part_args ); - wp_set_post_terms( self::$template_part_post->ID, WP_TEMPLATE_PART_AREA_HEADER, 'wp_template_part_area' ); - wp_set_post_terms( self::$template_part_post->ID, get_stylesheet(), 'wp_theme' ); } public static function wpTearDownAfterClass() { @@ -92,25 +71,6 @@ function test_gutenberg_build_template_result_from_file() { $this->assertEquals( 'Single Post', $template->title ); $this->assertEquals( 'Template used to display a single blog post.', $template->description ); $this->assertEquals( 'wp_template', $template->type ); - - // Test template parts. - $template_part = _gutenberg_build_template_result_from_file( - array( - 'slug' => 'header', - 'path' => __DIR__ . '/fixtures/template.html', - 'area' => WP_TEMPLATE_PART_AREA_HEADER, - ), - 'wp_template_part' - ); - $this->assertEquals( get_stylesheet() . '//header', $template_part->id ); - $this->assertEquals( get_stylesheet(), $template_part->theme ); - $this->assertEquals( 'header', $template_part->slug ); - $this->assertEquals( 'publish', $template_part->status ); - $this->assertEquals( 'theme', $template_part->source ); - $this->assertEquals( 'header', $template_part->title ); - $this->assertEquals( '', $template_part->description ); - $this->assertEquals( 'wp_template_part', $template_part->type ); - $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template_part->area ); } function test_gutenberg_build_template_result_from_post() { @@ -128,63 +88,6 @@ function test_gutenberg_build_template_result_from_post() { $this->assertEquals( 'My Template', $template->title ); $this->assertEquals( 'Description of my template', $template->description ); $this->assertEquals( 'wp_template', $template->type ); - - // Test template parts. - $template_part = _gutenberg_build_template_result_from_post( - self::$template_part_post, - 'wp_template_part' - ); - $this->assertNotWPError( $template_part ); - $this->assertEquals( get_stylesheet() . '//my_template_part', $template_part->id ); - $this->assertEquals( get_stylesheet(), $template_part->theme ); - $this->assertEquals( 'my_template_part', $template_part->slug ); - $this->assertEquals( 'publish', $template_part->status ); - $this->assertEquals( 'custom', $template_part->source ); - $this->assertEquals( 'My Template Part', $template_part->title ); - $this->assertEquals( 'Description of my template part', $template_part->description ); - $this->assertEquals( 'wp_template_part', $template_part->type ); - $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template_part->area ); - } - - function test_inject_theme_attribute_in_content() { - $theme = get_stylesheet(); - $content_without_theme_attribute = ''; - $template_content = _inject_theme_attribute_in_content( - $content_without_theme_attribute, - $theme - ); - $expected = sprintf( - '', - get_stylesheet() - ); - $this->assertEquals( $expected, $template_content ); - - $content_without_theme_attribute_nested = ''; - $template_content = _inject_theme_attribute_in_content( - $content_without_theme_attribute_nested, - $theme - ); - $expected = sprintf( - '', - get_stylesheet() - ); - $this->assertEquals( $expected, $template_content ); - - // Does not inject theme when there is an existing theme attribute. - $content_with_existing_theme_attribute = ''; - $template_content = _inject_theme_attribute_in_content( - $content_with_existing_theme_attribute, - $theme - ); - $this->assertEquals( $content_with_existing_theme_attribute, $template_content ); - - // Does not inject theme when there is no template part. - $content_with_no_template_part = ''; - $template_content = _inject_theme_attribute_in_content( - $content_with_no_template_part, - $theme - ); - $this->assertEquals( $content_with_no_template_part, $template_content ); } /** @@ -199,17 +102,6 @@ function test_gutenberg_get_block_template_from_file() { $this->assertEquals( 'publish', $template->status ); $this->assertEquals( 'theme', $template->source ); $this->assertEquals( 'wp_template', $template->type ); - - // Test template parts. - $id = get_stylesheet() . '//' . 'header'; - $template = gutenberg_get_block_template( $id, 'wp_template_part' ); - $this->assertEquals( $id, $template->id ); - $this->assertEquals( get_stylesheet(), $template->theme ); - $this->assertEquals( 'header', $template->slug ); - $this->assertEquals( 'publish', $template->status ); - $this->assertEquals( 'theme', $template->source ); - $this->assertEquals( 'wp_template_part', $template->type ); - $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template->area ); } /** @@ -224,17 +116,6 @@ function test_gutenberg_get_block_template_from_post() { $this->assertEquals( 'publish', $template->status ); $this->assertEquals( 'custom', $template->source ); $this->assertEquals( 'wp_template', $template->type ); - - // Test template parts. - $id = get_stylesheet() . '//' . 'my_template_part'; - $template = gutenberg_get_block_template( $id, 'wp_template_part' ); - $this->assertEquals( $id, $template->id ); - $this->assertEquals( get_stylesheet(), $template->theme ); - $this->assertEquals( 'my_template_part', $template->slug ); - $this->assertEquals( 'publish', $template->status ); - $this->assertEquals( 'custom', $template->source ); - $this->assertEquals( 'wp_template_part', $template->type ); - $this->assertEquals( WP_TEMPLATE_PART_AREA_HEADER, $template->area ); } /** @@ -267,17 +148,6 @@ function( $template ) { $templates = gutenberg_get_block_templates( array( 'wp_id' => self::$post->ID ), 'wp_template' ); $template_ids = get_template_ids( $templates ); $this->assertEquals( array( get_stylesheet() . '//' . 'my_template' ), $template_ids ); - - // Filter template part by area. - $templates = gutenberg_get_block_templates( array( 'area' => WP_TEMPLATE_PART_AREA_HEADER ), 'wp_template_part' ); - $template_ids = get_template_ids( $templates ); - $this->assertEquals( - array( - get_stylesheet() . '//' . 'my_template_part', - get_stylesheet() . '//' . 'header', - ), - $template_ids - ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-templates-controller.php b/tests/phpunit/tests/rest-api/rest-templates-controller.php index e2d26ee4067bd..c0925f7c554be 100644 --- a/tests/phpunit/tests/rest-api/rest-templates-controller.php +++ b/tests/phpunit/tests/rest-api/rest-templates-controller.php @@ -74,31 +74,6 @@ function find_and_normalize_template_by_id( $templates, $id ) { ), find_and_normalize_template_by_id( $data, 'tt1-blocks//index' ) ); - - // Test template parts. - $request = new WP_REST_Request( 'GET', '/wp/v2/template-parts' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - - $this->assertEquals( - array( - 'id' => 'tt1-blocks//header', - 'theme' => 'tt1-blocks', - 'slug' => 'header', - 'title' => array( - 'raw' => 'header', - 'rendered' => 'header', - ), - 'description' => '', - 'status' => 'publish', - 'source' => 'theme', - 'type' => 'wp_template_part', - 'wp_id' => null, - 'area' => WP_TEMPLATE_PART_AREA_HEADER, - 'has_theme_file' => true, - ), - find_and_normalize_template_by_id( $data, 'tt1-blocks//header' ) - ); } public function test_get_item() { @@ -127,32 +102,6 @@ public function test_get_item() { ), $data ); - - // Test template parts. - $request = new WP_REST_Request( 'GET', '/wp/v2/template-parts/tt1-blocks//header' ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - unset( $data['content'] ); - unset( $data['_links'] ); - $this->assertEquals( - array( - 'id' => 'tt1-blocks//header', - 'theme' => 'tt1-blocks', - 'slug' => 'header', - 'title' => array( - 'raw' => 'header', - 'rendered' => 'header', - ), - 'description' => '', - 'status' => 'publish', - 'source' => 'theme', - 'type' => 'wp_template_part', - 'wp_id' => null, - 'area' => WP_TEMPLATE_PART_AREA_HEADER, - 'has_theme_file' => true, - ), - $data - ); } public function test_create_item() { @@ -191,44 +140,6 @@ public function test_create_item() { ), $data ); - - // Test template parts. - $request = new WP_REST_Request( 'POST', '/wp/v2/template-parts' ); - $request->set_body_params( - array( - 'slug' => 'my_custom_template_part', - 'title' => 'My Template Part', - 'description' => 'Just a description of a template part', - 'content' => 'Content', - 'area' => 'header', - ) - ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - unset( $data['_links'] ); - unset( $data['wp_id'] ); - - $this->assertEquals( - array( - 'id' => 'tt1-blocks//my_custom_template_part', - 'theme' => 'tt1-blocks', - 'slug' => 'my_custom_template_part', - 'title' => array( - 'raw' => 'My Template Part', - 'rendered' => 'My Template Part', - ), - 'description' => 'Just a description of a template part', - 'status' => 'publish', - 'source' => 'custom', - 'type' => 'wp_template_part', - 'content' => array( - 'raw' => 'Content', - ), - 'area' => 'header', - 'has_theme_file' => false, - ), - $data - ); } public function test_update_item() { @@ -243,18 +154,6 @@ public function test_update_item() { $data = $response->get_data(); $this->assertEquals( 'My new Index Title', $data['title']['raw'] ); $this->assertEquals( 'custom', $data['source'] ); - - // Test template parts. - $request = new WP_REST_Request( 'PUT', '/wp/v2/template-parts/tt1-blocks//header' ); - $request->set_body_params( - array( - 'area' => 'something unsupported', - ) - ); - $response = rest_get_server()->dispatch( $request ); - $data = $response->get_data(); - $this->assertEquals( WP_TEMPLATE_PART_AREA_UNCATEGORIZED, $data['area'] ); - $this->assertEquals( 'custom', $data['source'] ); } public function test_delete_item() { From 9c530a1ce60f6ff31ff4d7cab8cdf5e11a5307d6 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 12:14:36 +0100 Subject: [PATCH 38/57] Rename theme_supports_block_templates --- src/wp-admin/edit-form-blocks.php | 2 +- src/wp-includes/class-wp-theme.php | 2 +- src/wp-includes/post.php | 2 +- src/wp-includes/taxonomy.php | 4 ++-- src/wp-includes/theme-templates.php | 2 +- src/wp-includes/theme.php | 6 +++--- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 00fa94b7800a2..a6d6189ef18cd 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -212,7 +212,7 @@ 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), '__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(), '__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), - 'supportsTemplateMode' => gutenberg_supports_block_templates(), + 'supportsTemplateMode' => theme_supports_block_templates(), // Whether or not to load the 'postcustom' meta box is stored as a user meta // field so that we're not always loading its assets. diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 5a619197268ae..064b8ce8cb26d 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1220,7 +1220,7 @@ public function get_post_templates() { } } - if ( gutenberg_supports_block_templates() ) { + if ( theme_supports_block_templates() ) { $block_templates = gutenberg_get_block_templates( array(), 'wp_template' ); foreach ( get_post_types( array( 'public' => true ) ) as $type ) { foreach ( $block_templates as $block_template ) { diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 0f77bc7506dfd..42be948dcbf7e 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -310,7 +310,7 @@ function create_initial_post_types() { ) ); - if ( gutenberg_supports_block_templates() ) { + if ( theme_supports_block_templates() ) { register_post_type( 'wp_template', array( diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 047d0637269b2..65b2cdabb28d1 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -174,10 +174,10 @@ function create_initial_taxonomies() { ); // FIXME: Uncomment once theme.json support lands - if ( gutenberg_supports_block_templates() /* || WP_Theme_JSON_Resolver::theme_has_support() */ ) { + if ( theme_supports_block_templates() /* || WP_Theme_JSON_Resolver::theme_has_support() */ ) { register_taxonomy( 'wp_theme', - array( 'wp_template', 'wp_template_part', 'wp_global_styles' ), + array( 'wp_template', 'wp_global_styles' ), array( 'public' => false, 'hierarchical' => false, diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index a9ae7bd6e1d20..4cd01de2183dd 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -37,7 +37,7 @@ function set_unique_slug_on_create_template( $post_id ) { function gutenberg_the_skip_link() { // Early exit if not an FSE theme. - if ( ! gutenberg_supports_block_templates() ) { + if ( ! theme_supports_block_templates() ) { return; } ?> diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 72911965e76e2..6677b5178a27e 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -3233,11 +3233,11 @@ function get_registered_theme_feature( $feature ) { } /** - * Returns whether the current theme is FSE-enabled or not. + * Returns whether the current theme supports block templates * - * @return boolean Whether the current theme is FSE-enabled or not. + * @return boolean Whether the current theme supports block templates. */ -function gutenberg_supports_block_templates() { +function theme_supports_block_templates() { return current_theme_supports( 'block-templates' ); } From 0d0a58cc402df768cbdb82c51b31a15b3cfcb3d7 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 12:19:31 +0100 Subject: [PATCH 39/57] clean theme-templates.php --- src/wp-includes/block-template-loader.php | 64 ----------------- src/wp-includes/theme-templates.php | 85 +++++++++++++++++------ 2 files changed, 63 insertions(+), 86 deletions(-) diff --git a/src/wp-includes/block-template-loader.php b/src/wp-includes/block-template-loader.php index 16b6834cf1734..ca3ad22b6dea3 100644 --- a/src/wp-includes/block-template-loader.php +++ b/src/wp-includes/block-template-loader.php @@ -344,67 +344,3 @@ function gutenberg_get_block_file_template( $id, $template_type = 'wp_template' return null; } - -/** - * Generates a unique slug for templates. - * - * @param string $override_slug The filtered value of the slug (starts as `null` from apply_filter). - * @param string $slug The original/un-filtered slug (post_name). - * @param int $post_ID Post ID. - * @param string $post_status No uniqueness checks are made if the post is still draft or pending. - * @param string $post_type Post type. - * @return string The original, desired slug. - */ -function gutenberg_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { - if ( 'wp_template' !== $post_type ) { - return $override_slug; - } - - if ( ! $override_slug ) { - $override_slug = $slug; - } - - // Template slugs must be unique within the same theme. - // TODO - Figure out how to update this to work for a multi-theme - // environment. Unfortunately using `get_the_terms` for the 'wp-theme' - // term does not work in the case of new entities since is too early in - // the process to have been saved to the entity. So for now we use the - // currently activated theme for creation. - $theme = wp_get_theme()->get_stylesheet(); - $terms = get_the_terms( $post_ID, 'wp_theme' ); - if ( $terms && ! is_wp_error( $terms ) ) { - $theme = $terms[0]->name; - } - - $check_query_args = array( - 'post_name__in' => array( $override_slug ), - 'post_type' => $post_type, - 'posts_per_page' => 1, - 'no_found_rows' => true, - 'post__not_in' => array( $post_ID ), - 'tax_query' => array( - array( - 'taxonomy' => 'wp_theme', - 'field' => 'name', - 'terms' => $theme, - ), - ), - ); - $check_query = new WP_Query( $check_query_args ); - $posts = $check_query->get_posts(); - - if ( count( $posts ) > 0 ) { - $suffix = 2; - do { - $query_args = $check_query_args; - $alt_post_name = _truncate_post_slug( $override_slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; - $query_args['post_name__in'] = array( $alt_post_name ); - $query = new WP_Query( $query_args ); - $suffix++; - } while ( count( $query->get_posts() ) > 0 ); - $override_slug = $alt_post_name; - } - - return $override_slug; -} -add_filter( 'pre_wp_unique_post_slug', 'gutenberg_filter_wp_template_unique_post_slug', 10, 5 ); diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index 4cd01de2183dd..8ea49635afc64 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -1,40 +1,81 @@ post_status ) { - return; +function wp_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID, $post_status, $post_type ) { + if ( 'wp_template' !== $post_type ) { + return $override_slug; } - if ( ! $post->post_name ) { - wp_update_post( - array( - 'ID' => $post_id, - 'post_name' => 'custom_slug_' . uniqid(), - ) - ); + if ( ! $override_slug ) { + $override_slug = $slug; } - $terms = get_the_terms( $post_id, 'wp_theme' ); - if ( ! $terms || ! count( $terms ) ) { - wp_set_post_terms( $post_id, wp_get_theme()->get_stylesheet(), 'wp_theme' ); + // Template slugs must be unique within the same theme. + // TODO - Figure out how to update this to work for a multi-theme + // environment. Unfortunately using `get_the_terms` for the 'wp-theme' + // term does not work in the case of new entities since is too early in + // the process to have been saved to the entity. So for now we use the + // currently activated theme for creation. + $theme = wp_get_theme()->get_stylesheet(); + $terms = get_the_terms( $post_ID, 'wp_theme' ); + if ( $terms && ! is_wp_error( $terms ) ) { + $theme = $terms[0]->name; } + + $check_query_args = array( + 'post_name__in' => array( $override_slug ), + 'post_type' => $post_type, + 'posts_per_page' => 1, + 'no_found_rows' => true, + 'post__not_in' => array( $post_ID ), + 'tax_query' => array( + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => $theme, + ), + ), + ); + $check_query = new WP_Query( $check_query_args ); + $posts = $check_query->get_posts(); + + if ( count( $posts ) > 0 ) { + $suffix = 2; + do { + $query_args = $check_query_args; + $alt_post_name = _truncate_post_slug( $override_slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"; + $query_args['post_name__in'] = array( $alt_post_name ); + $query = new WP_Query( $query_args ); + $suffix++; + } while ( count( $query->get_posts() ) > 0 ); + $override_slug = $alt_post_name; + } + + return $override_slug; } -add_action( 'save_post_wp_template', 'set_unique_slug_on_create_template' ); +add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 ); /** * Print the skip-link script & styles. * + * @access private + * @since 5.8.0 + * * @return void */ -function gutenberg_the_skip_link() { +function the_block_template_skip_link() { // Early exit if not an FSE theme. if ( ! theme_supports_block_templates() ) { @@ -110,7 +151,7 @@ function gutenberg_the_skip_link() { skipLink = document.createElement( 'a' ); skipLink.classList.add( 'skip-link', 'screen-reader-text' ); skipLink.href = '#' + skipLinkTargetID; - skipLink.innerHTML = ''; + skipLink.innerHTML = ''; // Inject the skip link. parentEl.insertAdjacentElement( 'afterbegin', skipLink ); @@ -118,7 +159,7 @@ function gutenberg_the_skip_link() { Date: Mon, 24 May 2021 12:42:48 +0100 Subject: [PATCH 40/57] clean block-template-utils --- src/wp-includes/block-template-loader.php | 346 ------------------ src/wp-includes/block-template-utils.php | 144 ++++++++ src/wp-includes/block-template.php | 2 +- src/wp-includes/class-wp-theme.php | 2 +- .../class-wp-rest-templates-controller.php | 29 +- src/wp-settings.php | 2 +- ...te-loader.php => block-template-utils.php} | 49 +-- 7 files changed, 170 insertions(+), 404 deletions(-) delete mode 100644 src/wp-includes/block-template-loader.php create mode 100644 src/wp-includes/block-template-utils.php rename tests/phpunit/tests/{block-template-loader.php => block-template-utils.php} (67%) diff --git a/src/wp-includes/block-template-loader.php b/src/wp-includes/block-template-loader.php deleted file mode 100644 index ca3ad22b6dea3..0000000000000 --- a/src/wp-includes/block-template-loader.php +++ /dev/null @@ -1,346 +0,0 @@ - $file ) { - $path_list[] = $path; - } - } - return $path_list; -} - -/** - * Retrieves the template file from the theme for a given slug. - * - * @access private - * @internal - * - * @param array $template_type wp_template. - * @param string $slug template slug. - * - * @return array Template. - */ -function _gutenberg_get_template_file( $template_type, $slug ) { - $template_base_paths = array( - 'wp_template' => 'block-templates', - ); - $themes = array( - get_stylesheet() => get_stylesheet_directory(), - get_template() => get_template_directory(), - ); - foreach ( $themes as $theme_slug => $theme_dir ) { - $file_path = $theme_dir . '/' . $template_base_paths[ $template_type ] . '/' . $slug . '.html'; - if ( file_exists( $file_path ) ) { - $new_template_item = array( - 'slug' => $slug, - 'path' => $file_path, - 'theme' => $theme_slug, - 'type' => $template_type, - ); - - return $new_template_item; - } - } - - return null; -} - -/** - * Retrieves the template files from the theme. - * - * @access private - * @internal - * - * @param array $template_type wp_template. - * - * @return array Template. - */ -function _gutenberg_get_template_files( $template_type ) { - $template_base_paths = array( - 'wp_template' => 'block-templates', - ); - $themes = array( - get_stylesheet() => get_stylesheet_directory(), - get_template() => get_template_directory(), - ); - - $template_files = array(); - foreach ( $themes as $theme_slug => $theme_dir ) { - $theme_template_files = _gutenberg_get_template_paths( $theme_dir . '/' . $template_base_paths[ $template_type ] ); - foreach ( $theme_template_files as $template_file ) { - $template_base_path = $template_base_paths[ $template_type ]; - $template_slug = substr( - $template_file, - // Starting position of slug. - strpos( $template_file, $template_base_path . DIRECTORY_SEPARATOR ) + 1 + strlen( $template_base_path ), - // Subtract ending '.html'. - -5 - ); - $new_template_item = array( - 'slug' => $template_slug, - 'path' => $template_file, - 'theme' => $theme_slug, - 'type' => $template_type, - ); - - $template_files[] = $new_template_item; - } - - return $template_files; -} - -/** - * Returns an array containing the references of - * the passed blocks and their inner blocks. - * - * @param array $blocks array of blocks. - * - * @return array block references to the passed blocks and their inner blocks. - */ -function _flatten_blocks( &$blocks ) { - $all_blocks = array(); - $queue = array(); - foreach ( $blocks as &$block ) { - $queue[] = &$block; - } - - while ( count( $queue ) > 0 ) { - $block = &$queue[0]; - array_shift( $queue ); - $all_blocks[] = &$block; - - if ( ! empty( $block['innerBlocks'] ) ) { - foreach ( $block['innerBlocks'] as &$inner_block ) { - $queue[] = &$inner_block; - } - } - } - - return $all_blocks; -} - -/** - * Build a unified template object based on a theme file. - * - * @param array $template_file Theme file. - * @param array $template_type wp_template. - * - * @return WP_Block_Template Template. - */ -function _gutenberg_build_template_result_from_file( $template_file, $template_type ) { - $default_template_types = gutenberg_get_default_template_types(); - $template_content = file_get_contents( $template_file['path'] ); - $theme = wp_get_theme()->get_stylesheet(); - - $template = new WP_Block_Template(); - $template->id = $theme . '//' . $template_file['slug']; - $template->theme = $theme; - $template->content = $template_content; - $template->slug = $template_file['slug']; - $template->source = 'theme'; - $template->type = $template_type; - $template->title = $template_file['slug']; - $template->status = 'publish'; - $template->has_theme_file = true; - - if ( 'wp_template' === $template_type && isset( $default_template_types[ $template_file['slug'] ] ) ) { - $template->description = $default_template_types[ $template_file['slug'] ]['description']; - $template->title = $default_template_types[ $template_file['slug'] ]['title']; - } - - return $template; -} - -/** - * Build a unified template object based a post Object. - * - * @param WP_Post $post Template post. - * - * @return WP_Block_Template|WP_Error Template. - */ -function _gutenberg_build_template_result_from_post( $post ) { - $terms = get_the_terms( $post, 'wp_theme' ); - - if ( is_wp_error( $terms ) ) { - return $terms; - } - - if ( ! $terms ) { - return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'gutenberg' ) ); - } - - $theme = $terms[0]->name; - $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && - null !== _gutenberg_get_template_file( $post->post_type, $post->post_name ); - - $template = new WP_Block_Template(); - $template->wp_id = $post->ID; - $template->id = $theme . '//' . $post->post_name; - $template->theme = $theme; - $template->content = $post->post_content; - $template->slug = $post->post_name; - $template->source = 'custom'; - $template->type = $post->post_type; - $template->description = $post->post_excerpt; - $template->title = $post->post_title; - $template->status = $post->post_status; - $template->has_theme_file = $has_theme_file; - - return $template; -} - -/** - * Retrieves a list of unified template objects based on a query. - * - * @param array $query { - * Optional. Arguments to retrieve templates. - * - * @type array $slug__in List of slugs to include. - * @type int $wp_id Post ID of customized template. - * } - * @param array $template_type wp_template. - * - * @return array Templates. - */ -function gutenberg_get_block_templates( $query = array(), $template_type = 'wp_template' ) { - $wp_query_args = array( - 'post_status' => array( 'auto-draft', 'draft', 'publish' ), - 'post_type' => $template_type, - 'posts_per_page' => -1, - 'no_found_rows' => true, - 'tax_query' => array( - array( - 'taxonomy' => 'wp_theme', - 'field' => 'name', - 'terms' => wp_get_theme()->get_stylesheet(), - ), - ), - ); - - if ( isset( $query['slug__in'] ) ) { - $wp_query_args['post_name__in'] = $query['slug__in']; - } - - // This is only needed for the regular templates CPT listing and editor. - if ( isset( $query['wp_id'] ) ) { - $wp_query_args['p'] = $query['wp_id']; - } else { - $wp_query_args['post_status'] = 'publish'; - } - - $template_query = new WP_Query( $wp_query_args ); - $query_result = array(); - foreach ( $template_query->get_posts() as $post ) { - $template = _gutenberg_build_template_result_from_post( $post ); - - if ( ! is_wp_error( $template ) ) { - $query_result[] = $template; - } - } - - if ( ! isset( $query['wp_id'] ) ) { - $template_files = _gutenberg_get_template_files( $template_type ); - foreach ( $template_files as $template_file ) { - $is_not_custom = false === array_search( - wp_get_theme()->get_stylesheet() . '//' . $template_file['slug'], - array_column( $query_result, 'id' ), - true - ); - $fits_slug_query = - ! isset( $query['slug__in'] ) || in_array( $template_file['slug'], $query['slug__in'], true ); - $fits_area_query = - ! isset( $query['area'] ) || $template_file['area'] === $query['area']; - $should_include = $is_not_custom && $fits_slug_query && $fits_area_query; - if ( $should_include ) { - $query_result[] = _gutenberg_build_template_result_from_file( $template_file, $template_type ); - } - } - } - - return $query_result; -} - -/** - * Retrieves a single unified template object using its id. - * - * @param string $id Template unique identifier (example: theme_slug//template_slug). - * @param array $template_type wp_template. - * - * @return WP_Block_Template|null Template. - */ -function gutenberg_get_block_template( $id, $template_type = 'wp_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->get_posts(); - - if ( count( $posts ) > 0 ) { - $template = _gutenberg_build_template_result_from_post( $posts[0] ); - - if ( ! is_wp_error( $template ) ) { - return $template; - } - } - - return gutenberg_get_block_file_template( $id, $template_type ); -} - -/** - * Retrieves a single unified template object using its id. - * Retrieves the file template. - * - * @param string $id Template unique identifier (example: theme_slug//template_slug). - * @param array $template_type wp_template. - * - * @return WP_Block_Template|null File template. - */ -function gutenberg_get_block_file_template( $id, $template_type = 'wp_template' ) { - $parts = explode( '//', $id, 2 ); - if ( count( $parts ) < 2 ) { - return null; - } - list( $theme, $slug ) = $parts; - - if ( wp_get_theme()->get_stylesheet() === $theme ) { - $template_file = _gutenberg_get_template_file( $template_type, $slug ); - if ( null !== $template_file ) { - return _gutenberg_build_template_result_from_file( $template_file, $template_type ); - } - } - - return null; -} diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php new file mode 100644 index 0000000000000..a873b9838b4f2 --- /dev/null +++ b/src/wp-includes/block-template-utils.php @@ -0,0 +1,144 @@ +name; + + $template = new WP_Block_Template(); + $template->wp_id = $post->ID; + $template->id = $theme . '//' . $post->post_name; + $template->theme = $theme; + $template->content = $post->post_content; + $template->slug = $post->post_name; + $template->source = 'custom'; + $template->type = $post->post_type; + $template->description = $post->post_excerpt; + $template->title = $post->post_title; + $template->status = $post->post_status; + $template->has_theme_file = false; + + return $template; +} + +/** + * Retrieves a list of unified template objects based on a query. + * + * @since 5.8.0 + * + * @param array $query { + * Optional. Arguments to retrieve templates. + * + * @type array $slug__in List of slugs to include. + * @type int $wp_id Post ID of customized template. + * } + * @param string $template_type wp_template. + * + * @return array Templates. + */ +function get_block_templates( $query = array(), $template_type = 'wp_template' ) { + $wp_query_args = array( + 'post_status' => array( 'auto-draft', 'draft', 'publish' ), + 'post_type' => $template_type, + 'posts_per_page' => -1, + 'no_found_rows' => true, + 'tax_query' => array( + array( + 'taxonomy' => 'wp_theme', + 'field' => 'name', + 'terms' => wp_get_theme()->get_stylesheet(), + ), + ), + ); + + if ( isset( $query['slug__in'] ) ) { + $wp_query_args['post_name__in'] = $query['slug__in']; + } + + // This is only needed for the regular templates CPT listing and editor. + if ( isset( $query['wp_id'] ) ) { + $wp_query_args['p'] = $query['wp_id']; + } else { + $wp_query_args['post_status'] = 'publish'; + } + + $template_query = new WP_Query( $wp_query_args ); + $query_result = array(); + foreach ( $template_query->get_posts() as $post ) { + $template = _build_template_result_from_post( $post ); + + if ( ! is_wp_error( $template ) ) { + $query_result[] = $template; + } + } + + return $query_result; +} + +/** + * 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 wp_template. + * + * @return WP_Block_Template|null Template. + */ +function get_block_template( $id, $template_type = 'wp_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->get_posts(); + + if ( count( $posts ) > 0 ) { + $template = _build_template_result_from_post( $posts[0] ); + + if ( ! is_wp_error( $template ) ) { + return $template; + } + } + + return null; +} \ No newline at end of file diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 7720a0db1be22..143bed459adee 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -108,7 +108,7 @@ function gutenberg_resolve_template( $template_type, $template_hierarchy ) { 'theme' => wp_get_theme()->get_stylesheet(), 'slug__in' => $slugs, ); - $templates = gutenberg_get_block_templates( $query ); + $templates = get_block_templates( $query ); // Order these templates per slug priority. // Build map of template slugs to their priority in the current hierarchy. diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index 064b8ce8cb26d..d102fe65adc34 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1221,7 +1221,7 @@ public function get_post_templates() { } if ( theme_supports_block_templates() ) { - $block_templates = gutenberg_get_block_templates( array(), 'wp_template' ); + $block_templates = get_block_templates( array(), 'wp_template' ); foreach ( get_post_types( array( 'public' => true ) ) as $type ) { foreach ( $block_templates as $block_template ) { $post_templates[ $type ][ $block_template->slug ] = $block_template->title; diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 818b8127ed5cd..525f0fe394def 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -142,7 +142,7 @@ public function get_items( $request ) { $query['area'] = $request['area']; } $templates = array(); - foreach ( gutenberg_get_block_templates( $query, $this->post_type ) as $template ) { + foreach ( get_block_templates( $query, $this->post_type ) as $template ) { $data = $this->prepare_item_for_response( $template, $request ); $templates[] = $this->prepare_response_for_collection( $data ); } @@ -168,11 +168,7 @@ public function get_item_permissions_check( $request ) { * @return WP_REST_Response|WP_Error */ public function get_item( $request ) { - if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { - $template = gutenberg_get_block_file_template( $request['id'], $this->post_type ); - } else { - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); - } + $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); @@ -198,16 +194,11 @@ public function update_item_permissions_check( $request ) { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function update_item( $request ) { - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); + $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); } - if ( isset( $request['source'] ) && 'theme' === $request['source'] ) { - wp_delete_post( $template->wp_id, true ); - return $this->prepare_item_for_response( gutenberg_get_block_file_template( $request['id'], $this->post_type ), $request ); - } - $changes = $this->prepare_item_for_database( $request ); if ( 'custom' === $template->source ) { @@ -219,14 +210,14 @@ public function update_item( $request ) { return $result; } - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); + $template = 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; } return $this->prepare_item_for_response( - gutenberg_get_block_template( $request['id'], $this->post_type ), + get_block_template( $request['id'], $this->post_type ), $request ); } @@ -254,19 +245,19 @@ public function create_item( $request ) { if ( is_wp_error( $result ) ) { return $result; } - $posts = gutenberg_get_block_templates( array( 'wp_id' => $result ), $this->post_type ); + $posts = get_block_templates( array( 'wp_id' => $result ), $this->post_type ); if ( ! count( $posts ) ) { return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.', 'gutenberg' ) ); } $id = $posts[0]->id; - $template = gutenberg_get_block_template( $id, $this->post_type ); + $template = 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; } return $this->prepare_item_for_response( - gutenberg_get_block_template( $id, $this->post_type ), + get_block_template( $id, $this->post_type ), $request ); } @@ -288,7 +279,7 @@ public function delete_item_permissions_check( $request ) { * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. */ public function delete_item( $request ) { - $template = gutenberg_get_block_template( $request['id'], $this->post_type ); + $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); } @@ -335,7 +326,7 @@ public function delete_item( $request ) { * @return stdClass Changes to pass to wp_update_post. */ protected function prepare_item_for_database( $request ) { - $template = $request['id'] ? gutenberg_get_block_template( $request['id'], $this->post_type ) : null; + $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null; $changes = new stdClass(); $changes->post_name = $template->slug; if ( null === $template ) { diff --git a/src/wp-settings.php b/src/wp-settings.php index 6679cd9844caf..4de018e924d03 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -172,7 +172,7 @@ require ABSPATH . WPINC . '/class-wp-theme.php'; require ABSPATH . WPINC . '/default-template-types.php'; require ABSPATH . WPINC . '/class-wp-block-template.php'; -require ABSPATH . WPINC . '/block-template-loader.php'; +require ABSPATH . WPINC . '/block-template-utils.php'; require ABSPATH . WPINC . '/block-template.php'; require ABSPATH . WPINC . '/theme-templates.php'; require ABSPATH . WPINC . '/template.php'; diff --git a/tests/phpunit/tests/block-template-loader.php b/tests/phpunit/tests/block-template-utils.php similarity index 67% rename from tests/phpunit/tests/block-template-loader.php rename to tests/phpunit/tests/block-template-utils.php index 3c78af30a6cf7..ad179c02e4b06 100644 --- a/tests/phpunit/tests/block-template-loader.php +++ b/tests/phpunit/tests/block-template-utils.php @@ -9,7 +9,7 @@ /** * Tests for the Block Template Loader abstraction layer. */ -class Block_Template_Loader_Test extends WP_UnitTestCase { +class Block_Template_Utils_Test extends WP_UnitTestCase { private static $post; public static function wpSetUpBeforeClass() { @@ -54,8 +54,8 @@ public static function wpTearDownAfterClass() { wp_delete_post( self::$post->ID ); } - function test_gutenberg_build_template_result_from_file() { - $template = _gutenberg_build_template_result_from_file( + function test_build_template_result_from_file() { + $template = _build_template_result_from_file( array( 'slug' => 'single', 'path' => get_stylesheet_directory() . '/block-templates/index.html', @@ -73,8 +73,8 @@ function test_gutenberg_build_template_result_from_file() { $this->assertEquals( 'wp_template', $template->type ); } - function test_gutenberg_build_template_result_from_post() { - $template = _gutenberg_build_template_result_from_post( + function test_build_template_result_from_post() { + $template = _build_template_result_from_post( self::$post, 'wp_template' ); @@ -93,9 +93,9 @@ function test_gutenberg_build_template_result_from_post() { /** * Should retrieve the template from the theme files. */ - function test_gutenberg_get_block_template_from_file() { + function test_get_block_template_from_file() { $id = get_stylesheet() . '//' . 'index'; - $template = gutenberg_get_block_template( $id, 'wp_template' ); + $template = get_block_template( $id, 'wp_template' ); $this->assertEquals( $id, $template->id ); $this->assertEquals( get_stylesheet(), $template->theme ); $this->assertEquals( 'index', $template->slug ); @@ -107,9 +107,9 @@ function test_gutenberg_get_block_template_from_file() { /** * Should retrieve the template from the CPT. */ - function test_gutenberg_get_block_template_from_post() { + function test_get_block_template_from_post() { $id = get_stylesheet() . '//' . 'my_template'; - $template = gutenberg_get_block_template( $id, 'wp_template' ); + $template = get_block_template( $id, 'wp_template' ); $this->assertEquals( $id, $template->id ); $this->assertEquals( get_stylesheet(), $template->theme ); $this->assertEquals( 'my_template', $template->slug ); @@ -121,7 +121,7 @@ function test_gutenberg_get_block_template_from_post() { /** * Should retrieve block templates (file and CPT) */ - function test_gutenberg_get_block_templates() { + function test_get_block_templates() { function get_template_ids( $templates ) { return array_map( function( $template ) { @@ -132,7 +132,7 @@ function( $template ) { } // All results. - $templates = gutenberg_get_block_templates( array(), 'wp_template' ); + $templates = get_block_templates( array(), 'wp_template' ); $template_ids = get_template_ids( $templates ); // Avoid testing the entire array because the theme might add/remove templates. @@ -140,36 +140,13 @@ function( $template ) { $this->assertContains( get_stylesheet() . '//' . 'index', $template_ids ); // Filter by slug. - $templates = gutenberg_get_block_templates( array( 'slug__in' => array( 'my_template' ) ), 'wp_template' ); + $templates = get_block_templates( array( 'slug__in' => array( 'my_template' ) ), 'wp_template' ); $template_ids = get_template_ids( $templates ); $this->assertEquals( array( get_stylesheet() . '//' . 'my_template' ), $template_ids ); // Filter by CPT ID. - $templates = gutenberg_get_block_templates( array( 'wp_id' => self::$post->ID ), 'wp_template' ); + $templates = get_block_templates( array( 'wp_id' => self::$post->ID ), 'wp_template' ); $template_ids = get_template_ids( $templates ); $this->assertEquals( array( get_stylesheet() . '//' . 'my_template' ), $template_ids ); } - - /** - * Should flatten nested blocks - */ - function test_flatten_blocks() { - $content_template_part_inside_group = ''; - $blocks = parse_blocks( $content_template_part_inside_group ); - $actual = _flatten_blocks( $blocks ); - $expected = array( $blocks[0], $blocks[0]['innerBlocks'][0] ); - $this->assertEquals( $expected, $actual ); - - $content_template_part_inside_group_inside_group = ''; - $blocks = parse_blocks( $content_template_part_inside_group_inside_group ); - $actual = _flatten_blocks( $blocks ); - $expected = array( $blocks[0], $blocks[0]['innerBlocks'][0], $blocks[0]['innerBlocks'][0]['innerBlocks'][0] ); - $this->assertEquals( $expected, $actual ); - - $content_without_inner_blocks = ''; - $blocks = parse_blocks( $content_without_inner_blocks ); - $actual = _flatten_blocks( $blocks ); - $expected = array( $blocks[0] ); - $this->assertEquals( $expected, $actual ); - } } From e3ad8302e128499b650df8318104974eb4083e02 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 12:55:02 +0100 Subject: [PATCH 41/57] clean block-template.php --- src/wp-includes/block-template.php | 51 ++++++++++++++++++----------- src/wp-includes/template-canvas.php | 2 +- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 143bed459adee..d7dfc3a5421be 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -2,7 +2,7 @@ /** * Block template loader functions. * - * @package gutenberg + * @package WordPress */ /** @@ -10,6 +10,8 @@ * * Internally, this communicates the block content that needs to be used by the template canvas through a global variable. * + * @since 5.8.0 + * * @param string $template Path to the template. See locate_template(). * @param string $type Sanitized filename without extension. * @param array $templates A list of template candidates, in descending order of priority. @@ -38,7 +40,7 @@ function locate_block_template( $template, $type, array $templates ) { $templates = array_slice( $templates, 0, $index + 1 ); } - $block_template = gutenberg_resolve_template( $type, $templates ); + $block_template = resolve_block_template( $type, $templates ); if ( $block_template ) { if ( empty( $block_template->content ) && is_user_logged_in() ) { @@ -70,11 +72,11 @@ function locate_block_template( $template, $type, array $templates ) { // Add hooks for template canvas. // Add viewport meta tag. - add_action( 'wp_head', 'gutenberg_viewport_meta_tag', 0 ); + add_action( 'wp_head', '_block_template_viewport_meta_tag', 0 ); // Render title tag with content, regardless of whether theme has title-tag support. remove_action( 'wp_head', '_wp_render_title_tag', 1 ); // Remove conditional title tag rendering... - add_action( 'wp_head', 'gutenberg_render_title_tag', 1 ); // ...and make it unconditional. + add_action( 'wp_head', '_block_template_render_title_tag', 1 ); // ...and make it unconditional. // This file will be included instead of the theme's template file. return ABSPATH . WPINC . '/template-canvas.php'; @@ -82,6 +84,9 @@ function locate_block_template( $template, $type, array $templates ) { /** * Return the correct 'wp_template' to render for the request template type. + * + * @access private + * @since 5.8.0 * * Accepts an optional $template_hierarchy argument as a hint. * @@ -89,7 +94,7 @@ function locate_block_template( $template, $type, array $templates ) { * @param string[] $template_hierarchy (optional) The current template hierarchy, ordered by priority. * @return WP_Block_Template|null template A template object, or null if none could be found. */ -function gutenberg_resolve_template( $template_type, $template_hierarchy ) { +function resolve_block_template( $template_type, $template_hierarchy ) { if ( ! $template_type ) { return null; } @@ -99,7 +104,7 @@ function gutenberg_resolve_template( $template_type, $template_hierarchy ) { } $slugs = array_map( - 'gutenberg_strip_php_suffix', + '_strip_php_suffix', $template_hierarchy ); @@ -126,17 +131,25 @@ function ( $template_a, $template_b ) use ( $slug_priorities ) { /** * Displays title tag with content, regardless of whether theme has title-tag support. + * + * @access private + * @since 5.8.0 * * @see _wp_render_title_tag() */ -function gutenberg_render_title_tag() { +function _block_template_render_title_tag() { echo '' . wp_get_document_title() . '' . "\n"; } /** * Returns the markup for the current template. + * + * @access private + * @since 5.8.0 + * + * @return string block tempate markup. */ -function gutenberg_get_the_template_html() { +function get_the_block_template_html() { global $_wp_current_template_content; global $wp_embed; @@ -163,19 +176,15 @@ function gutenberg_get_the_template_html() { return '
' . $content . '
'; } -/** - * Renders the markup for the current template. - */ -function gutenberg_render_the_template() { - echo gutenberg_get_the_template_html(); // phpcs:ignore WordPress.Security.EscapeOutput -} - /** * Renders a 'viewport' meta tag. + * + * @access private + * @since 5.8.0 * * This is hooked into {@see 'wp_head'} to decouple its output from the default template canvas. */ -function gutenberg_viewport_meta_tag() { +function _block_template_viewport_meta_tag() { echo '' . "\n"; } @@ -183,22 +192,26 @@ function gutenberg_viewport_meta_tag() { * Strips .php suffix from template file names. * * @access private + * @since 5.8.0 * * @param string $template_file Template file name. * @return string Template file name without extension. */ -function gutenberg_strip_php_suffix( $template_file ) { +function _strip_php_suffix( $template_file ) { return preg_replace( '/\.(php|html)$/', '', $template_file ); } /** * Removes post details from block context when rendering a block template. * + * @access private + * @since 5.8.0 + * * @param array $context Default context. * * @return array Filtered context. */ -function gutenberg_template_render_without_post_block_context( $context ) { +function _block_template_render_without_post_block_context( $context ) { /* * When loading a template directly and not through a page * that resolves it, the top-level post ID and type context get set to that @@ -213,4 +226,4 @@ function gutenberg_template_render_without_post_block_context( $context ) { return $context; } -add_filter( 'render_block_context', 'gutenberg_template_render_without_post_block_context' ); +add_filter( 'render_block_context', '_block_template_render_without_post_block_context' ); diff --git a/src/wp-includes/template-canvas.php b/src/wp-includes/template-canvas.php index 4d29113dbf8e0..c68bf7a5b6399 100644 --- a/src/wp-includes/template-canvas.php +++ b/src/wp-includes/template-canvas.php @@ -9,7 +9,7 @@ * Get the template HTML. * This needs to run before so that blocks can add scripts and styles in wp_head(). */ -$template_html = gutenberg_get_the_template_html(); +$template_html = get_the_block_template_html(); ?> > From 598c152f46faf09172d9b15877288de167c3e2df Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 12:59:23 +0100 Subject: [PATCH 42/57] Remove default template types --- src/wp-includes/default-template-types.php | 124 --------------------- src/wp-settings.php | 1 - 2 files changed, 125 deletions(-) delete mode 100644 src/wp-includes/default-template-types.php diff --git a/src/wp-includes/default-template-types.php b/src/wp-includes/default-template-types.php deleted file mode 100644 index 1a9c2b023dbe8..0000000000000 --- a/src/wp-includes/default-template-types.php +++ /dev/null @@ -1,124 +0,0 @@ - array( - 'title' => _x( 'Index', 'Template name', 'gutenberg' ), - 'description' => __( 'The default template used when no other template is available. This is a required template in WordPress.', 'gutenberg' ), - ), - 'home' => array( - 'title' => _x( 'Home', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used for the main page that displays blog posts. This is the front page by default in WordPress. If a static front page is set, this is the template used for the page that contains the latest blog posts.', 'gutenberg' ), - ), - 'front-page' => array( - 'title' => _x( 'Front Page', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used to render the front page of the site, whether it displays blog posts or a static page. The front page template takes precedence over the "Home" template.', 'gutenberg' ), - ), - 'singular' => array( - 'title' => _x( 'Singular', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used for displaying single views of the content. This template is a fallback for the Single, Post, and Page templates, which take precedence when they exist.', 'gutenberg' ), - ), - 'single' => array( - 'title' => _x( 'Single Post', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used to display a single blog post.', 'gutenberg' ), - ), - 'page' => array( - 'title' => _x( 'Page', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used to display individual pages.', 'gutenberg' ), - ), - 'archive' => array( - 'title' => _x( 'Archive', 'Template name', 'gutenberg' ), - 'description' => __( 'The archive template displays multiple entries at once. It is used as a fallback for the Category, Author, and Date templates, which take precedence when they are available.', 'gutenberg' ), - ), - 'author' => array( - 'title' => _x( 'Author', 'Template name', 'gutenberg' ), - 'description' => __( 'Archive template used to display a list of posts from a single author.', 'gutenberg' ), - ), - 'category' => array( - 'title' => _x( 'Category', 'Template name', 'gutenberg' ), - 'description' => __( 'Archive template used to display a list of posts from the same category.', 'gutenberg' ), - ), - 'taxonomy' => array( - 'title' => _x( 'Taxonomy', 'Template name', 'gutenberg' ), - 'description' => __( 'Archive template used to display a list of posts from the same taxonomy.', 'gutenberg' ), - ), - 'date' => array( - 'title' => _x( 'Date', 'Template name', 'gutenberg' ), - 'description' => __( 'Archive template used to display a list of posts from a specific date.', 'gutenberg' ), - ), - 'tag' => array( - 'title' => _x( 'Tag', 'Template name', 'gutenberg' ), - 'description' => __( 'Archive template used to display a list of posts with a given tag.', 'gutenberg' ), - ), - 'attachment' => array( - 'title' => __( 'Media', 'gutenberg' ), - 'description' => __( 'Template used to display individual media items or attachments.', 'gutenberg' ), - ), - 'search' => array( - 'title' => _x( 'Search', 'Template name', 'gutenberg' ), - 'description' => __( 'Template used to display search results.', 'gutenberg' ), - ), - 'privacy-policy' => array( - 'title' => __( 'Privacy Policy', 'gutenberg' ), - 'description' => '', - ), - '404' => array( - 'title' => _x( '404', 'Template name', 'gutenberg' ), - 'description' => __( 'Template shown when no content is found.', 'gutenberg' ), - ), - ); - - /** - * Filters the list of template types. - * - * @param array $default_template_types An array of template types, formatted as [ slug => [ title, description ] ]. - * - * @since 5.x.x - */ - return apply_filters( 'default_template_types', $default_template_types ); -} - -/** - * Converts the default template types array from associative to indexed, - * to be used in JS, where numeric keys (e.g. '404') always appear before alphabetical - * ones, regardless of the actual order of the array. - * - * From slug-keyed associative array: - * `[ 'index' => [ 'title' => 'Index', 'description' => 'Index template' ] ]` - * - * ...to indexed array with slug as property: - * `[ [ 'slug' => 'index', 'title' => 'Index', 'description' => 'Index template' ] ]` - * - * @return array The default template types as an indexed array. - */ -function gutenberg_get_indexed_default_template_types() { - $indexed_template_types = array(); - $default_template_types = gutenberg_get_default_template_types(); - foreach ( $default_template_types as $slug => $template_type ) { - $template_type['slug'] = (string) $slug; - $indexed_template_types[] = $template_type; - } - return $indexed_template_types; -} - -/** - * Return a list of all overrideable default template type slugs. - * - * @see get_query_template - * - * @return string[] List of all overrideable default template type slugs. - */ -function gutenberg_get_template_type_slugs() { - return array_keys( gutenberg_get_default_template_types() ); -} diff --git a/src/wp-settings.php b/src/wp-settings.php index 4de018e924d03..d83c3d2c3341a 100644 --- a/src/wp-settings.php +++ b/src/wp-settings.php @@ -170,7 +170,6 @@ require ABSPATH . WPINC . '/class-wp-date-query.php'; require ABSPATH . WPINC . '/theme.php'; require ABSPATH . WPINC . '/class-wp-theme.php'; -require ABSPATH . WPINC . '/default-template-types.php'; require ABSPATH . WPINC . '/class-wp-block-template.php'; require ABSPATH . WPINC . '/block-template-utils.php'; require ABSPATH . WPINC . '/block-template.php'; From f2c95ab29a83e0bbc4dba1790ecc485aa9de8fdb Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 13:06:02 +0100 Subject: [PATCH 43/57] Translations cleaning --- src/wp-includes/block-template-utils.php | 2 +- src/wp-includes/block-template.php | 6 +-- src/wp-includes/post.php | 40 +++++++-------- .../class-wp-rest-templates-controller.php | 50 ++++++++----------- src/wp-includes/taxonomy.php | 4 +- 5 files changed, 46 insertions(+), 56 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index a873b9838b4f2..11e735293e96d 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -24,7 +24,7 @@ function _build_template_result_from_post( $post ) { } if ( ! $terms ) { - return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.', 'gutenberg' ) ); + return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) ); } $theme = $terms[0]->name; diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index d7dfc3a5421be..e054e7b38c6fe 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -47,7 +47,7 @@ function locate_block_template( $template, $type, array $templates ) { $_wp_current_template_content = sprintf( /* translators: %s: Template title */ - __( 'Empty template: %s', 'gutenberg' ), + __( 'Empty template: %s' ), $block_template->title ); } elseif ( ! empty( $block_template->content ) ) { @@ -63,7 +63,7 @@ function locate_block_template( $template, $type, array $templates ) { if ( 'index' === $type ) { if ( isset( $_GET['_wp-find-template'] ) ) { - wp_send_json_error( array( 'message' => __( 'No matching template found.', 'gutenberg' ) ) ); + wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) ); } } else { return false; // So that the template loader keeps looking for templates. @@ -155,7 +155,7 @@ function get_the_block_template_html() { if ( ! $_wp_current_template_content ) { if ( is_user_logged_in() ) { - return '

' . esc_html__( 'No matching template found', 'gutenberg' ) . '

'; + return '

' . esc_html__( 'No matching template found' ) . '

'; } return; } diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 42be948dcbf7e..9a7d2d9c0a485 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -315,27 +315,27 @@ function create_initial_post_types() { 'wp_template', array( 'labels' => array( - 'name' => __( 'Templates', 'gutenberg' ), - 'singular_name' => __( 'Template', 'gutenberg' ), - 'menu_name' => _x( 'Templates', 'Admin Menu text', 'gutenberg' ), - 'add_new' => _x( 'Add New', 'Template', 'gutenberg' ), - 'add_new_item' => __( 'Add New Template', 'gutenberg' ), - 'new_item' => __( 'New Template', 'gutenberg' ), - 'edit_item' => __( 'Edit Template', 'gutenberg' ), - 'view_item' => __( 'View Template', 'gutenberg' ), - 'all_items' => __( 'All Templates', 'gutenberg' ), - 'search_items' => __( 'Search Templates', 'gutenberg' ), - 'parent_item_colon' => __( 'Parent Template:', 'gutenberg' ), - 'not_found' => __( 'No templates found.', 'gutenberg' ), - 'not_found_in_trash' => __( 'No templates found in Trash.', 'gutenberg' ), - 'archives' => __( 'Template archives', 'gutenberg' ), - 'insert_into_item' => __( 'Insert into template', 'gutenberg' ), - 'uploaded_to_this_item' => __( 'Uploaded to this template', 'gutenberg' ), - 'filter_items_list' => __( 'Filter templates list', 'gutenberg' ), - 'items_list_navigation' => __( 'Templates list navigation', 'gutenberg' ), - 'items_list' => __( 'Templates list', 'gutenberg' ), + 'name' => __( 'Templates' ), + 'singular_name' => __( 'Template' ), + 'menu_name' => _x( 'Templates', 'Admin Menu text' ), + 'add_new' => _x( 'Add New', 'Template' ), + 'add_new_item' => __( 'Add New Template' ), + 'new_item' => __( 'New Template' ), + 'edit_item' => __( 'Edit Template' ), + 'view_item' => __( 'View Template' ), + 'all_items' => __( 'All Templates' ), + 'search_items' => __( 'Search Templates' ), + 'parent_item_colon' => __( 'Parent Template:' ), + 'not_found' => __( 'No templates found.' ), + 'not_found_in_trash' => __( 'No templates found in Trash.' ), + 'archives' => __( 'Template archives' ), + 'insert_into_item' => __( 'Insert into template' ), + 'uploaded_to_this_item' => __( 'Uploaded to this template' ), + 'filter_items_list' => __( 'Filter templates list' ), + 'items_list_navigation' => __( 'Templates list navigation' ), + 'items_list' => __( 'Templates list' ), ), - 'description' => __( 'Templates to include in your theme.', 'gutenberg' ), + 'description' => __( 'Templates to include in your theme.' ), 'public' => false, 'has_archive' => false, 'show_ui' => false, diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 525f0fe394def..0640c91772c9c 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -67,7 +67,7 @@ public function register_routes() { 'permission_callback' => array( $this, 'get_item_permissions_check' ), 'args' => array( 'id' => array( - 'description' => __( 'The id of a template', 'gutenberg' ), + 'description' => __( 'The id of a template' ), 'type' => 'string', ), ), @@ -86,7 +86,7 @@ public function register_routes() { 'force' => array( 'type' => 'boolean', 'default' => false, - 'description' => __( 'Whether to bypass Trash and force deletion.', 'gutenberg' ), + 'description' => __( 'Whether to bypass Trash and force deletion.' ), ), ), ), @@ -106,7 +106,7 @@ protected function permissions_check() { if ( ! current_user_can( 'edit_theme_options' ) ) { return new WP_Error( 'rest_cannot_manage_templates', - __( 'Sorry, you are not allowed to access the templates on this site.', 'gutenberg' ), + __( 'Sorry, you are not allowed to access the templates on this site.' ), array( 'status' => rest_authorization_required_code(), ) @@ -171,7 +171,7 @@ public function get_item( $request ) { $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { - return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); + return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); } return $this->prepare_item_for_response( $template, $request ); @@ -196,7 +196,7 @@ public function update_item_permissions_check( $request ) { public function update_item( $request ) { $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { - return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); + return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.' ), array( 'status' => 404 ) ); } $changes = $this->prepare_item_for_database( $request ); @@ -247,7 +247,7 @@ public function create_item( $request ) { } $posts = get_block_templates( array( 'wp_id' => $result ), $this->post_type ); if ( ! count( $posts ) ) { - return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.', 'gutenberg' ) ); + return new WP_Error( 'rest_template_insert_error', __( 'No templates exist with that id.' ) ); } $id = $posts[0]->id; $template = get_block_template( $id, $this->post_type ); @@ -281,10 +281,10 @@ public function delete_item_permissions_check( $request ) { public function delete_item( $request ) { $template = get_block_template( $request['id'], $this->post_type ); if ( ! $template ) { - return new WP_Error( 'rest_template_not_found', __( 'No templates exist with that id.', 'gutenberg' ), array( 'status' => 404 ) ); + 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.', 'gutenberg' ), array( 'status' => 400 ) ); + return new WP_Error( 'rest_invalid_template', __( 'Templates based on theme files can\'t be removed.' ), array( 'status' => 400 ) ); } $id = $template->wp_id; @@ -309,7 +309,7 @@ public function delete_item( $request ) { if ( 'trash' === $template->status ) { return new WP_Error( 'rest_template_already_trashed', - __( 'The template has already been deleted.', 'gutenberg' ), + __( 'The template has already been deleted.' ), array( 'status' => 410 ) ); } @@ -361,16 +361,6 @@ protected function prepare_item_for_database( $request ) { $changes->post_excerpt = $template->description; } - if ( 'wp_template_part' === $this->post_type ) { - if ( isset( $request['area'] ) ) { - $changes->tax_input['wp_template_part_area'] = gutenberg_filter_template_part_area( $request['area'] ); - } elseif ( null !== $template && 'custom' !== $template->source && $template->area ) { - $changes->tax_input['wp_template_part_area'] = gutenberg_filter_template_part_area( $template->area ); - } elseif ( ! $template->area ) { - $changes->tax_input['wp_template_part_area'] = WP_TEMPLATE_PART_AREA_UNCATEGORIZED; - } - } - return $changes; } @@ -475,7 +465,7 @@ public function get_collection_params() { return array( 'context' => $this->get_context_param(), 'wp_id' => array( - 'description' => __( 'Limit to the specified post id.', 'gutenberg' ), + 'description' => __( 'Limit to the specified post id.' ), 'type' => 'integer', ), ); @@ -497,13 +487,13 @@ public function get_item_schema() { 'type' => 'object', 'properties' => array( 'id' => array( - 'description' => __( 'ID of template.', 'gutenberg' ), + 'description' => __( 'ID of template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'slug' => array( - 'description' => __( 'Unique slug identifying the template.', 'gutenberg' ), + 'description' => __( 'Unique slug identifying the template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'required' => true, @@ -511,48 +501,48 @@ public function get_item_schema() { 'pattern' => '[a-zA-Z_\-]+', ), 'theme' => array( - 'description' => __( 'Theme identifier for the template.', 'gutenberg' ), + 'description' => __( 'Theme identifier for the template.' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), ), 'source' => array( - 'description' => __( 'Source of template', 'gutenberg' ), + 'description' => __( 'Source of template' ), 'type' => 'string', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'content' => array( - 'description' => __( 'Content of template.', 'gutenberg' ), + 'description' => __( 'Content of template.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), ), 'title' => array( - 'description' => __( 'Title of template.', 'gutenberg' ), + 'description' => __( 'Title of template.' ), 'type' => array( 'object', 'string' ), 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), ), 'description' => array( - 'description' => __( 'Description of template.', 'gutenberg' ), + 'description' => __( 'Description of template.' ), 'type' => 'string', 'default' => '', 'context' => array( 'embed', 'view', 'edit' ), ), 'status' => array( - 'description' => __( 'Status of template.', 'gutenberg' ), + 'description' => __( 'Status of template.' ), 'type' => 'string', 'default' => 'publish', 'context' => array( 'embed', 'view', 'edit' ), ), 'wp_id' => array( - 'description' => __( 'Post ID.', 'gutenberg' ), + 'description' => __( 'Post ID.' ), 'type' => 'integer', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, ), 'has_theme_file' => array( - 'description' => __( 'Theme file exists.', 'gutenberg' ), + 'description' => __( 'Theme file exists.' ), 'type' => 'bool', 'context' => array( 'embed', 'view', 'edit' ), 'readonly' => true, diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 65b2cdabb28d1..e3e77f7b835a0 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -182,8 +182,8 @@ function create_initial_taxonomies() { 'public' => false, 'hierarchical' => false, 'labels' => array( - 'name' => __( 'Themes', 'gutenberg' ), - 'singular_name' => __( 'Theme', 'gutenberg' ), + 'name' => __( 'Themes' ), + 'singular_name' => __( 'Theme' ), ), 'query_var' => false, 'rewrite' => false, From eec967e7b962b13676812954e084ce0eea691253 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 13:16:14 +0100 Subject: [PATCH 44/57] Adding since --- src/wp-includes/block-template-utils.php | 4 +- src/wp-includes/class-wp-block-template.php | 17 ++++++- src/wp-includes/default-filters.php | 1 - .../class-wp-rest-templates-controller.php | 47 ++++++++++++++++++- src/wp-includes/script-loader.php | 5 ++ src/wp-includes/template-canvas.php | 2 +- 6 files changed, 69 insertions(+), 7 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 11e735293e96d..90e8e55f09efe 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -2,8 +2,8 @@ /** * Utilities used to fetch and create templates. * - * @package Gutenberg - * @subpackage REST_API + * @package WordPress + * @since 5.8.0 */ /** diff --git a/src/wp-includes/class-wp-block-template.php b/src/wp-includes/class-wp-block-template.php index d8c9d5c54a2b9..704a2afc455d3 100644 --- a/src/wp-includes/class-wp-block-template.php +++ b/src/wp-includes/class-wp-block-template.php @@ -3,17 +3,20 @@ * Blocks API: WP_Block_Template class * * @package WordPress - * @since 5.5.0 + * @since 5.8.0 */ /** * Class representing a block template. + * + * @since 5.8.0 */ class WP_Block_Template { /** - * Type: wp_template or wp_template_part + * Type: wp_template. * + * @since 5.8.0 * @var string */ public $type; @@ -21,6 +24,7 @@ class WP_Block_Template { /** * Theme. * + * @since 5.8.0 * @var string */ public $theme; @@ -28,6 +32,7 @@ class WP_Block_Template { /** * Template slug. * + * @since 5.8.0 * @var string */ public $slug; @@ -35,6 +40,7 @@ class WP_Block_Template { /** * Id. * + * @since 5.8.0 * @var string */ public $id; @@ -42,6 +48,7 @@ class WP_Block_Template { /** * Title. * + * @since 5.8.0 * @var string */ public $title = ''; @@ -49,6 +56,7 @@ class WP_Block_Template { /** * Content. * + * @since 5.8.0 * @var string */ public $content = ''; @@ -56,6 +64,7 @@ class WP_Block_Template { /** * Description. * + * @since 5.8.0 * @var string */ public $description = ''; @@ -63,6 +72,7 @@ class WP_Block_Template { /** * Source of the content. `theme` and `custom` is used for now. * + * @since 5.8.0 * @var string */ public $source = 'theme'; @@ -70,6 +80,7 @@ class WP_Block_Template { /** * Post Id. * + * @since 5.8.0 * @var integer|null */ public $wp_id; @@ -77,6 +88,7 @@ class WP_Block_Template { /** * Template Status. * + * @since 5.8.0 * @var string */ public $status; @@ -84,6 +96,7 @@ class WP_Block_Template { /** * Whether a template is, or is based upon, an existing template file. * + * @since 5.8.0 * @var boolean */ public $has_theme_file; diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index cf679247d959c..0e7206662f8c0 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -555,7 +555,6 @@ add_action( 'wp_head', 'wp_maybe_inline_styles', 1 ); // Run for styles enqueued in . add_action( 'wp_footer', 'wp_maybe_inline_styles', 1 ); // Run for late-loaded styles in the footer. -add_action( 'admin_footer-toplevel_page_gutenberg-edit-site', 'wp_add_iframed_editor_assets_html' ); add_action( 'admin_footer-post.php', 'wp_add_iframed_editor_assets_html' ); add_action( 'admin_footer-post-new.php', 'wp_add_iframed_editor_assets_html' ); diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 0640c91772c9c..02bcbbc3ef586 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -2,17 +2,24 @@ /** * REST API: WP_REST_Templates_Controller class * - * @package Gutenberg + * @package WordPress * @subpackage REST_API + * @since 5.8.0 */ /** * Base Templates REST API Controller. + * + * @since 5.8.0 + * + * @see WP_REST_Controller */ class WP_REST_Templates_Controller extends WP_REST_Controller { + /** * Post type. * + * @since 5.8.0 * @var string */ protected $post_type; @@ -20,6 +27,8 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { /** * Constructor. * + * @since 5.8.0 + * * @param string $post_type Post type. */ public function __construct( $post_type ) { @@ -32,6 +41,8 @@ public function __construct( $post_type ) { /** * Registers the controllers routes. * + * @since 5.8.0 + * * @return void */ public function register_routes() { @@ -98,6 +109,8 @@ public function register_routes() { /** * Checks if the user has permissions to make the request. * + * @since 5.8.0 + * * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ protected function permissions_check() { @@ -119,6 +132,8 @@ protected function permissions_check() { /** * Checks if a given request has access to read templates. * + * @since 5.8.0 + * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access, WP_Error object otherwise. */ @@ -129,6 +144,8 @@ public function get_items_permissions_check( $request ) { /** * Returns a list of templates. * + * @since 5.8.0 + * * @param WP_REST_Request $request The request instance. * * @return WP_REST_Response @@ -153,6 +170,8 @@ public function get_items( $request ) { /** * Checks if a given request has access to read a single template. * + * @since 5.8.0 + * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has read access for the item, WP_Error object otherwise. */ @@ -163,6 +182,8 @@ public function get_item_permissions_check( $request ) { /** * Returns the given template * + * @since 5.8.0 + * * @param WP_REST_Request $request The request instance. * * @return WP_REST_Response|WP_Error @@ -180,6 +201,8 @@ public function get_item( $request ) { /** * Checks if a given request has access to write a single template. * + * @since 5.8.0 + * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has write access for the item, WP_Error object otherwise. */ @@ -190,6 +213,8 @@ public function update_item_permissions_check( $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. */ @@ -225,6 +250,8 @@ public function update_item( $request ) { /** * Checks if a given request has access to create a template. * + * @since 5.8.0 + * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has access to create items, WP_Error object otherwise. */ @@ -235,6 +262,8 @@ public function create_item_permissions_check( $request ) { /** * 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. */ @@ -265,6 +294,8 @@ public function create_item( $request ) { /** * Checks if a given request has access to delete a single template. * + * @since 5.8.0 + * * @param WP_REST_Request $request Full details about the request. * @return true|WP_Error True if the request has delete access for the item, WP_Error object otherwise. */ @@ -275,6 +306,8 @@ public function delete_item_permissions_check( $request ) { /** * 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. */ @@ -322,6 +355,8 @@ public function delete_item( $request ) { /** * Prepares a single template for create or update. * + * @since 5.8.0 + * * @param WP_REST_Request $request Request object. * @return stdClass Changes to pass to wp_update_post. */ @@ -367,6 +402,8 @@ protected function prepare_item_for_database( $request ) { /** * Prepare a single template output for response * + * @since 5.8.0 + * * @param WP_Block_Template $template Template instance. * @param WP_REST_Request $request Request object. * @@ -414,6 +451,8 @@ public function prepare_item_for_response( $template, $request ) { // phpcs:igno /** * Prepares links for the request. * + * @since 5.8.0 + * * @param integer $id ID. * @return array Links for the given post. */ @@ -438,6 +477,8 @@ protected function prepare_links( $id ) { /** * Get the link relations available for the post and current user. * + * @since 5.8.0 + * * @return array List of link relations. */ protected function get_available_actions() { @@ -459,6 +500,8 @@ protected function get_available_actions() { /** * Retrieves the query params for the posts collection. * + * @since 5.8.0 + * * @return array Collection parameters. */ public function get_collection_params() { @@ -474,6 +517,8 @@ public function get_collection_params() { /** * Retrieves the block type' schema, conforming to JSON Schema. * + * @since 5.8.0 + * * @return array Item schema data. */ public function get_item_schema() { diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 91f965c84f01a..20c3164c12754 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -2638,6 +2638,11 @@ function( $a, $b ) { } } +/** + * Inject the block editor assets that need to be loaded into the editor's iframe as an inline script. + * + * @since 5.8.0 + */ function wp_add_iframed_editor_assets_html() { $script_handles = array(); $style_handles = array( diff --git a/src/wp-includes/template-canvas.php b/src/wp-includes/template-canvas.php index c68bf7a5b6399..2ce5b12ca6596 100644 --- a/src/wp-includes/template-canvas.php +++ b/src/wp-includes/template-canvas.php @@ -2,7 +2,7 @@ /** * Template canvas file to render the current 'wp_template'. * - * @package gutenberg + * @package WordPress */ /** From 0a5e4daae1abc50fb280e0b2d3e131d3400b5387 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 13:28:46 +0100 Subject: [PATCH 45/57] Remove testing theme and clean tests --- .../block-templates/page-1.html | 3 - .../block-template-theme-child/page-home.php | 3 - .../block-template-theme-child/style.css | 4 - .../block-templates/index.html | 3 - .../block-templates/page-home.html | 3 - .../block-templates/page.html | 3 - .../themedir1/block-template-theme/page-1.php | 3 - .../themedir1/block-template-theme/style.css | 3 - tests/phpunit/tests/block-template-utils.php | 59 +-------- tests/phpunit/tests/block-template.php | 115 +----------------- .../rest-api/rest-templates-controller.php | 62 ++++++---- tests/phpunit/tests/theme/wpThemeJson.php | 1 + .../tests/theme/wpThemeJsonResolver.php | 1 + 13 files changed, 47 insertions(+), 216 deletions(-) delete mode 100644 tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html delete mode 100644 tests/phpunit/data/themedir1/block-template-theme-child/page-home.php delete mode 100644 tests/phpunit/data/themedir1/block-template-theme-child/style.css delete mode 100644 tests/phpunit/data/themedir1/block-template-theme/block-templates/index.html delete mode 100644 tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html delete mode 100644 tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html delete mode 100644 tests/phpunit/data/themedir1/block-template-theme/page-1.php delete mode 100644 tests/phpunit/data/themedir1/block-template-theme/style.css diff --git a/tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html b/tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html deleted file mode 100644 index c3e788b393ee8..0000000000000 --- a/tests/phpunit/data/themedir1/block-template-theme-child/block-templates/page-1.html +++ /dev/null @@ -1,3 +0,0 @@ - -

Page (ID 1) Template

- \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-template-theme-child/page-home.php b/tests/phpunit/data/themedir1/block-template-theme-child/page-home.php deleted file mode 100644 index 86efe80db6afb..0000000000000 --- a/tests/phpunit/data/themedir1/block-template-theme-child/page-home.php +++ /dev/null @@ -1,3 +0,0 @@ - -

Index Template

- \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html b/tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html deleted file mode 100644 index 6be0c70fb29c8..0000000000000 --- a/tests/phpunit/data/themedir1/block-template-theme/block-templates/page-home.html +++ /dev/null @@ -1,3 +0,0 @@ - -

Page (Home) Template

- \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html b/tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html deleted file mode 100644 index 61c493e1bd8e8..0000000000000 --- a/tests/phpunit/data/themedir1/block-template-theme/block-templates/page.html +++ /dev/null @@ -1,3 +0,0 @@ - -

Page Template

- \ No newline at end of file diff --git a/tests/phpunit/data/themedir1/block-template-theme/page-1.php b/tests/phpunit/data/themedir1/block-template-theme/page-1.php deleted file mode 100644 index eafbb1b6e854b..0000000000000 --- a/tests/phpunit/data/themedir1/block-template-theme/page-1.php +++ /dev/null @@ -1,3 +0,0 @@ - 'wp_template', - 'post_name' => 'my_template', - 'post_title' => 'My Template', - 'post_content' => 'Content', - 'post_excerpt' => 'Description of my template', - 'tax_input' => array( - 'wp_theme' => array( - 'this-theme-should-not-resolve', - ), - ), - ); - self::$post = self::factory()->post->create_and_get( $args ); - wp_set_post_terms( self::$post->ID, 'this-theme-should-not-resolve', 'wp_theme' ); - // Set up template post. $args = array( 'post_type' => 'wp_template', @@ -54,25 +33,6 @@ public static function wpTearDownAfterClass() { wp_delete_post( self::$post->ID ); } - function test_build_template_result_from_file() { - $template = _build_template_result_from_file( - array( - 'slug' => 'single', - 'path' => get_stylesheet_directory() . '/block-templates/index.html', - ), - 'wp_template' - ); - - $this->assertEquals( get_stylesheet() . '//single', $template->id ); - $this->assertEquals( get_stylesheet(), $template->theme ); - $this->assertEquals( 'single', $template->slug ); - $this->assertEquals( 'publish', $template->status ); - $this->assertEquals( 'theme', $template->source ); - $this->assertEquals( 'Single Post', $template->title ); - $this->assertEquals( 'Template used to display a single blog post.', $template->description ); - $this->assertEquals( 'wp_template', $template->type ); - } - function test_build_template_result_from_post() { $template = _build_template_result_from_post( self::$post, @@ -90,20 +50,6 @@ function test_build_template_result_from_post() { $this->assertEquals( 'wp_template', $template->type ); } - /** - * Should retrieve the template from the theme files. - */ - function test_get_block_template_from_file() { - $id = get_stylesheet() . '//' . 'index'; - $template = get_block_template( $id, 'wp_template' ); - $this->assertEquals( $id, $template->id ); - $this->assertEquals( get_stylesheet(), $template->theme ); - $this->assertEquals( 'index', $template->slug ); - $this->assertEquals( 'publish', $template->status ); - $this->assertEquals( 'theme', $template->source ); - $this->assertEquals( 'wp_template', $template->type ); - } - /** * Should retrieve the template from the CPT. */ @@ -119,7 +65,7 @@ function test_get_block_template_from_post() { } /** - * Should retrieve block templates (file and CPT) + * Should retrieve block templates. */ function test_get_block_templates() { function get_template_ids( $templates ) { @@ -137,7 +83,6 @@ function( $template ) { // Avoid testing the entire array because the theme might add/remove templates. $this->assertContains( get_stylesheet() . '//' . 'my_template', $template_ids ); - $this->assertContains( get_stylesheet() . '//' . 'index', $template_ids ); // Filter by slug. $templates = get_block_templates( array( 'slug__in' => array( 'my_template' ) ), 'wp_template' ); diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index bfb54e4144bd7..789b21eef163f 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -10,13 +10,10 @@ */ class Block_Template_Test extends WP_UnitTestCase { private static $post; - private static $template_part_post; private static $template_canvas_path = ABSPATH . WPINC . '/template-canvas.php'; public static function wpSetUpBeforeClass() { - switch_theme( 'block-template-theme' ); - // Set up custom template post. $args = array( 'post_type' => 'wp_template', @@ -36,8 +33,6 @@ public static function wpSetUpBeforeClass() { public static function wpTearDownAfterClass() { wp_delete_post( self::$post->ID ); - remove_filter( 'stylesheet_directory', array( __CLASS__, 'change_theme_directory' ) ); - remove_filter( 'template_directory', array( __CLASS__, 'change_theme_directory' ) ); } public function tearDown() { @@ -45,110 +40,10 @@ public function tearDown() { unset( $_wp_current_template_content ); } - function test_gutenberg_page_home_block_template_takes_precedence_over_less_specific_block_templates() { - global $_wp_current_template_content; - $type = 'page'; - $templates = array( - 'page-home.php', - 'page-1.php', - 'page.php', - ); - $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/page-home.php', $type, $templates ); - $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-home.html', $_wp_current_template_content ); - } - - function test_gutenberg_page_block_template_takes_precedence() { - global $_wp_current_template_content; - $type = 'page'; - $templates = array( - 'page-slug-doesnt-exist.php', - 'page-1.php', - 'page.php', - ); - $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/page.php', $type, $templates ); - $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page.html', $_wp_current_template_content ); - } - - function test_gutenberg_block_template_takes_precedence_over_equally_specific_php_template() { - global $_wp_current_template_content; - $type = 'index'; - $templates = array( - 'index.php', - ); - $resolved_template_path = locate_block_template( get_stylesheet_directory() . '/index.php', $type, $templates ); - $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/index.html', $_wp_current_template_content ); - } - - /** - * In a hybrid theme, a PHP template of higher specificity will take precedence over a block template - * with lower specificity. - * - * Covers https://github.com/WordPress/gutenberg/pull/29026. - */ - function test_gutenberg_more_specific_php_template_takes_precedence_over_less_specific_block_template() { - $page_id_template = 'page-1.php'; - $page_id_template_path = get_stylesheet_directory() . '/' . $page_id_template; - $type = 'page'; - $templates = array( - 'page-slug-doesnt-exist.php', - 'page-1.php', - 'page.php', - ); - $resolved_template_path = locate_block_template( $page_id_template_path, $type, $templates ); - $this->assertEquals( $page_id_template_path, $resolved_template_path ); - } - - /** - * If a theme is a child of a block-based parent theme but has php templates for some of its pages, - * a php template of the child will take precedence over the parent's block template if they have - * otherwise equal specificity. - * - * Covers https://github.com/WordPress/gutenberg/pull/31123. - */ - function test_gutenberg_child_theme_php_template_takes_precedence_over_equally_specific_parent_theme_block_template() { - switch_theme( 'block-template-theme-child' ); - - $page_slug_template = 'page-home.php'; - $page_slug_template_path = get_stylesheet_directory() . '/' . $page_slug_template; - $type = 'page'; - $templates = array( - 'page-home.php', - 'page-1.php', - 'page.php', - ); - $resolved_template_path = locate_block_template( $page_slug_template_path, $type, $templates ); - $this->assertEquals( $page_slug_template_path, $resolved_template_path ); - - switch_theme( 'block-template-theme' ); - } - - function test_gutenberg_child_theme_block_template_takes_precedence_over_equally_specific_parent_theme_php_template() { - global $_wp_current_template_content; - - switch_theme( 'block-template-theme-child' ); - - $page_template = 'page-1.php'; - $parent_theme_page_template_path = get_template_directory() . '/' . $page_template; - $type = 'page'; - $templates = array( - 'page-slug-doesnt-exist.php', - 'page-1.php', - 'page.php', - ); - $resolved_template_path = locate_block_template( $parent_theme_page_template_path, $type, $templates ); - $this->assertEquals( self::$template_canvas_path, $resolved_template_path ); - $this->assertStringEqualsFile( get_stylesheet_directory() . '/block-templates/page-1.html', $_wp_current_template_content ); - - switch_theme( 'block-template-theme' ); - } - /** * Regression: https://github.com/WordPress/gutenberg/issues/31399. */ - function test_gutenberg_custom_page_php_template_takes_precedence_over_all_other_templates() { + function test_custom_page_php_template_takes_precedence_over_all_other_templates() { $custom_page_template = 'templates/full-width.php'; $custom_page_template_path = get_stylesheet_directory() . '/' . $custom_page_template; $type = 'page'; @@ -165,7 +60,7 @@ function test_gutenberg_custom_page_php_template_takes_precedence_over_all_other /** * Covers: https://github.com/WordPress/gutenberg/pull/30438. */ - function test_gutenberg_custom_page_block_template_takes_precedence_over_all_other_templates() { + function test_custom_page_block_template_takes_precedence_over_all_other_templates() { global $_wp_current_template_content; $custom_page_block_template = 'wp-custom-template-my-block-template'; @@ -185,12 +80,8 @@ function test_gutenberg_custom_page_block_template_takes_precedence_over_all_oth /** * Regression: https://github.com/WordPress/gutenberg/issues/31652. */ - function test_gutenberg_template_remains_unchanged_if_templates_array_is_empty() { + function test_template_remains_unchanged_if_templates_array_is_empty() { $resolved_template_path = locate_block_template( '', 'search', array() ); $this->assertEquals( '', $resolved_template_path ); } - - static function change_theme_directory( $theme_dir, $theme ) { - return __DIR__ . '/fixtures/themes/' . $theme; - } } diff --git a/tests/phpunit/tests/rest-api/rest-templates-controller.php b/tests/phpunit/tests/rest-api/rest-templates-controller.php index c0925f7c554be..8fdcb05dc9d29 100644 --- a/tests/phpunit/tests/rest-api/rest-templates-controller.php +++ b/tests/phpunit/tests/rest-api/rest-templates-controller.php @@ -5,6 +5,7 @@ class WP_REST_Template_Controller_Test extends WP_Test_REST_Controller_Testcase * @var int */ protected static $admin_id; + private static $post; /** * Create fake data before our tests run. @@ -12,21 +13,38 @@ class WP_REST_Template_Controller_Test extends WP_Test_REST_Controller_Testcase * @param WP_UnitTest_Factory $factory Helper that lets us create fake data. */ public static function wpSetupBeforeClass( $factory ) { - switch_theme( 'tt1-blocks' ); self::$admin_id = $factory->user->create( array( 'role' => 'administrator', ) ); + + // Set up template post. + $args = array( + 'post_type' => 'wp_template', + 'post_name' => 'my_template', + 'post_title' => 'My Template', + 'post_content' => 'Content', + 'post_excerpt' => 'Description of my template', + 'tax_input' => array( + 'wp_theme' => array( + get_stylesheet(), + ), + ), + ); + self::$post = self::factory()->post->create_and_get( $args ); + wp_set_post_terms( self::$post->ID, get_stylesheet(), 'wp_theme' ); } + public static function wpTearDownAfterClass() { + wp_delete_post( self::$post->ID ); + } + + public function test_register_routes() { $routes = rest_get_server()->get_routes(); $this->assertArrayHasKey( '/wp/v2/templates', $routes ); $this->assertArrayHasKey( '/wp/v2/templates/(?P[\/\w-]+)', $routes ); - - $this->assertArrayHasKey( '/wp/v2/template-parts', $routes ); - $this->assertArrayHasKey( '/wp/v2/template-parts/(?P[\/\w-]+)', $routes ); } public function test_context_param() { @@ -58,27 +76,27 @@ function find_and_normalize_template_by_id( $templates, $id ) { $this->assertEquals( array( - 'id' => 'tt1-blocks//index', + 'id' => 'tt1-blocks//my_template', 'theme' => 'tt1-blocks', - 'slug' => 'index', + 'slug' => 'my_template', 'title' => array( - 'raw' => 'Index', - 'rendered' => 'Index', + 'raw' => 'My Template', + 'rendered' => 'My Template', ), - 'description' => 'The default template used when no other template is available. This is a required template in WordPress.', + 'description' => 'Description of my template.', 'status' => 'publish', - 'source' => 'theme', + 'source' => 'custom', 'type' => 'wp_template', - 'wp_id' => null, - 'has_theme_file' => true, + 'wp_id' => self::$post->ID, + 'has_theme_file' => false, ), - find_and_normalize_template_by_id( $data, 'tt1-blocks//index' ) + find_and_normalize_template_by_id( $data, 'tt1-blocks//my_template' ) ); } public function test_get_item() { wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/templates/tt1-blocks//index' ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/tt1-blocks//my_template' ); $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); unset( $data['content'] ); @@ -86,19 +104,19 @@ public function test_get_item() { $this->assertEquals( array( - 'id' => 'tt1-blocks//index', + 'id' => 'tt1-blocks//my_template', 'theme' => 'tt1-blocks', - 'slug' => 'index', + 'slug' => 'my_template', 'title' => array( - 'raw' => 'Index', - 'rendered' => 'Index', + 'raw' => 'My Template', + 'rendered' => 'My Template', ), - 'description' => 'The default template used when no other template is available. This is a required template in WordPress.', + 'description' => 'Description of my template.', 'status' => 'publish', - 'source' => 'theme', + 'source' => 'custom', 'type' => 'wp_template', - 'wp_id' => null, - 'has_theme_file' => true, + 'wp_id' => self::$post->ID, + 'has_theme_file' => false, ), $data ); diff --git a/tests/phpunit/tests/theme/wpThemeJson.php b/tests/phpunit/tests/theme/wpThemeJson.php index 0eec476712bda..12c89fad5ba7b 100644 --- a/tests/phpunit/tests/theme/wpThemeJson.php +++ b/tests/phpunit/tests/theme/wpThemeJson.php @@ -5,6 +5,7 @@ * * @package WordPress * @subpackage Theme + * * @since 5.8.0 * * @group themes diff --git a/tests/phpunit/tests/theme/wpThemeJsonResolver.php b/tests/phpunit/tests/theme/wpThemeJsonResolver.php index 8bb419acd77ca..3a2093bca4f75 100644 --- a/tests/phpunit/tests/theme/wpThemeJsonResolver.php +++ b/tests/phpunit/tests/theme/wpThemeJsonResolver.php @@ -5,6 +5,7 @@ * * @package WordPress * @subpackage Theme + * * @since 5.8.0 * * @group themes From 600db7c1b689d26358e502a00465d53e2e73dce0 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 15:10:27 +0100 Subject: [PATCH 46/57] Format changes --- src/wp-includes/block-template-utils.php | 8 ++++---- src/wp-includes/block-template.php | 14 +++++++------- src/wp-includes/theme-templates.php | 6 +++--- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/wp-includes/block-template-utils.php b/src/wp-includes/block-template-utils.php index 90e8e55f09efe..fa32393290436 100644 --- a/src/wp-includes/block-template-utils.php +++ b/src/wp-includes/block-template-utils.php @@ -27,7 +27,7 @@ function _build_template_result_from_post( $post ) { return new WP_Error( 'template_missing_theme', __( 'No theme is defined for this template.' ) ); } - $theme = $terms[0]->name; + $theme = $terms[0]->name; $template = new WP_Block_Template(); $template->wp_id = $post->ID; @@ -47,7 +47,7 @@ function _build_template_result_from_post( $post ) { /** * Retrieves a list of unified template objects based on a query. - * + * * @since 5.8.0 * * @param array $query { @@ -101,7 +101,7 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' ) /** * Retrieves a single unified template object using its id. - * + * * @since 5.8.0 * * @param string $id Template unique identifier (example: theme_slug//template_slug). @@ -141,4 +141,4 @@ function get_block_template( $id, $template_type = 'wp_template' ) { } return null; -} \ No newline at end of file +} diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index e054e7b38c6fe..3f2fd75d01ba9 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -84,7 +84,7 @@ function locate_block_template( $template, $type, array $templates ) { /** * Return the correct 'wp_template' to render for the request template type. - * + * * @access private * @since 5.8.0 * @@ -131,7 +131,7 @@ function ( $template_a, $template_b ) use ( $slug_priorities ) { /** * Displays title tag with content, regardless of whether theme has title-tag support. - * + * * @access private * @since 5.8.0 * @@ -143,10 +143,10 @@ function _block_template_render_title_tag() { /** * Returns the markup for the current template. - * + * * @access private * @since 5.8.0 - * + * * @return string block tempate markup. */ function get_the_block_template_html() { @@ -178,7 +178,7 @@ function get_the_block_template_html() { /** * Renders a 'viewport' meta tag. - * + * * @access private * @since 5.8.0 * @@ -206,7 +206,7 @@ function _strip_php_suffix( $template_file ) { * * @access private * @since 5.8.0 - * + * * @param array $context Default context. * * @return array Filtered context. @@ -219,7 +219,7 @@ function _block_template_render_without_post_block_context( $context ) { * they should not be available as post context because blocks like Post * Content would recurse infinitely. */ - if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) { + if ( isset( $context['postType'] ) && 'wp_template' === $context['postType'] ) { unset( $context['postId'] ); unset( $context['postType'] ); } diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index 8ea49635afc64..086e3d40739e5 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -2,7 +2,7 @@ /** * Generates a unique slug for templates. - * + * * @access private * @since 5.8.0 * @@ -72,7 +72,7 @@ function wp_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID * * @access private * @since 5.8.0 - * + * * @return void */ function the_block_template_skip_link() { @@ -162,4 +162,4 @@ function the_block_template_skip_link() { add_action( 'wp_footer', 'the_block_template_skip_link' ); // By default, themes support block templates. -add_theme_support( 'block-templates' ); \ No newline at end of file +add_theme_support( 'block-templates' ); From 2fc65d07685c86748f4cec97307829a14113a27d Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 17:00:15 +0100 Subject: [PATCH 47/57] Fix unit tests --- .../class-wp-rest-templates-controller.php | 5 +-- tests/phpunit/tests/block-template.php | 2 +- .../rest-api/rest-templates-controller.php | 31 ++++++++++--------- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 02bcbbc3ef586..a2c0a68ed2902 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -363,20 +363,21 @@ public function delete_item( $request ) { protected function prepare_item_for_database( $request ) { $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null; $changes = new stdClass(); - $changes->post_name = $template->slug; if ( null === $template ) { $changes->post_type = $this->post_type; $changes->post_status = 'publish'; $changes->tax_input = array( - 'wp_theme' => isset( $request['theme'] ) ? $request['content'] : wp_get_theme()->get_stylesheet(), + 'wp_theme' => isset( $request['theme'] ) ? $request['theme'] : wp_get_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, ); } else { + $changes->post_name = $template->slug; $changes->ID = $template->wp_id; $changes->post_status = 'publish'; } diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index 789b21eef163f..77a133247aeef 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -1,7 +1,7 @@ 'my_template', 'post_title' => 'My Template', 'post_content' => 'Content', - 'post_excerpt' => 'Description of my template', + 'post_excerpt' => 'Description of my template.', 'tax_input' => array( 'wp_theme' => array( get_stylesheet(), @@ -76,8 +82,8 @@ function find_and_normalize_template_by_id( $templates, $id ) { $this->assertEquals( array( - 'id' => 'tt1-blocks//my_template', - 'theme' => 'tt1-blocks', + 'id' => 'default//my_template', + 'theme' => 'default', 'slug' => 'my_template', 'title' => array( 'raw' => 'My Template', @@ -90,13 +96,13 @@ function find_and_normalize_template_by_id( $templates, $id ) { 'wp_id' => self::$post->ID, 'has_theme_file' => false, ), - find_and_normalize_template_by_id( $data, 'tt1-blocks//my_template' ) + find_and_normalize_template_by_id( $data, 'default//my_template' ) ); } public function test_get_item() { wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'GET', '/wp/v2/templates/tt1-blocks//my_template' ); + $request = new WP_REST_Request( 'GET', '/wp/v2/templates/default//my_template' ); $response = rest_get_server()->dispatch( $request ); $data = $response->get_data(); unset( $data['content'] ); @@ -104,8 +110,8 @@ public function test_get_item() { $this->assertEquals( array( - 'id' => 'tt1-blocks//my_template', - 'theme' => 'tt1-blocks', + 'id' => 'default//my_template', + 'theme' => 'default', 'slug' => 'my_template', 'title' => array( 'raw' => 'My Template', @@ -140,8 +146,8 @@ public function test_create_item() { $this->assertEquals( array( - 'id' => 'tt1-blocks//my_custom_template', - 'theme' => 'tt1-blocks', + 'id' => 'default//my_custom_template', + 'theme' => 'default', 'slug' => 'my_custom_template', 'title' => array( 'raw' => 'My Template', @@ -162,7 +168,7 @@ public function test_create_item() { public function test_update_item() { wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'PUT', '/wp/v2/templates/tt1-blocks//index' ); + $request = new WP_REST_Request( 'PUT', '/wp/v2/templates/default//my_template' ); $request->set_body_params( array( 'title' => 'My new Index Title', @@ -179,11 +185,6 @@ public function test_delete_item() { $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/justrandom//template' ); $response = rest_get_server()->dispatch( $request ); $this->assertErrorResponse( 'rest_template_not_found', $response, 404 ); - - wp_set_current_user( self::$admin_id ); - $request = new WP_REST_Request( 'DELETE', '/wp/v2/templates/tt1-blocks//single' ); - $response = rest_get_server()->dispatch( $request ); - $this->assertErrorResponse( 'rest_invalid_template', $response, 400 ); } public function test_prepare_item() { From 0270bb25121a585fee45c1bf7c2635e2014f1370 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 17:14:35 +0100 Subject: [PATCH 48/57] more formatting issues --- .../endpoints/class-wp-rest-templates-controller.php | 6 +++--- tests/phpunit/tests/block-template.php | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index a2c0a68ed2902..ff71dc024a989 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -361,8 +361,8 @@ public function delete_item( $request ) { * @return stdClass Changes to pass to wp_update_post. */ protected function prepare_item_for_database( $request ) { - $template = $request['id'] ? get_block_template( $request['id'], $this->post_type ) : null; - $changes = new stdClass(); + $template = $request['id'] ? 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'; @@ -377,7 +377,7 @@ protected function prepare_item_for_database( $request ) { 'wp_theme' => $template->theme, ); } else { - $changes->post_name = $template->slug; + $changes->post_name = $template->slug; $changes->ID = $template->wp_id; $changes->post_status = 'publish'; } diff --git a/tests/phpunit/tests/block-template.php b/tests/phpunit/tests/block-template.php index 77a133247aeef..789b21eef163f 100644 --- a/tests/phpunit/tests/block-template.php +++ b/tests/phpunit/tests/block-template.php @@ -1,7 +1,7 @@ Date: Mon, 24 May 2021 17:57:40 +0100 Subject: [PATCH 49/57] Fix theme unit test --- src/wp-includes/block-template.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 3f2fd75d01ba9..6214c74b3bbd3 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -66,7 +66,7 @@ function locate_block_template( $template, $type, array $templates ) { wp_send_json_error( array( 'message' => __( 'No matching template found.' ) ) ); } } else { - return false; // So that the template loader keeps looking for templates. + return ''; // So that the template loader keeps looking for templates. } } From 595b6c8cda043d7121b7cf3d965d810de793a908 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 18:16:14 +0100 Subject: [PATCH 50/57] Fix rest api test --- tests/phpunit/tests/rest-api/rest-schema-setup.php | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/phpunit/tests/rest-api/rest-schema-setup.php b/tests/phpunit/tests/rest-api/rest-schema-setup.php index ed608d57a7bcd..359af6cc9d53b 100644 --- a/tests/phpunit/tests/rest-api/rest-schema-setup.php +++ b/tests/phpunit/tests/rest-api/rest-schema-setup.php @@ -129,6 +129,12 @@ public function test_expected_routes_in_schema() { '/wp/v2/block-types/(?P[a-zA-Z0-9_-]+)', '/wp/v2/block-types/(?P[a-zA-Z0-9_-]+)/(?P[a-zA-Z0-9_-]+)', '/wp/v2/settings', + '/wp/v2/templates', + '/wp/v2/templates/(?P[\/\w-]+)', + '/wp/v2/templates/(?P[\d]+)/autosaves', + '/wp/v2/templates/(?P[\d]+)/autosaves/(?P[\d]+)', + '/wp/v2/templates/(?P[\d]+)/revisions', + '/wp/v2/templates/(?P[\d]+)/revisions/(?P[\d]+)', '/wp/v2/themes', '/wp/v2/themes/(?P[\w-]+)', '/wp/v2/plugins', From de87bd23cd5ab468823aedae3256f52d4d54b42f Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Mon, 24 May 2021 18:29:20 +0100 Subject: [PATCH 51/57] Move filters to default-filters.php --- src/wp-includes/block-template.php | 1 - src/wp-includes/default-filters.php | 5 +++++ src/wp-includes/theme-templates.php | 2 -- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 6214c74b3bbd3..0db8a40c2c800 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -226,4 +226,3 @@ function _block_template_render_without_post_block_context( $context ) { return $context; } -add_filter( 'render_block_context', '_block_template_render_without_post_block_context' ); diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 0e7206662f8c0..535ed7261c3c2 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -636,4 +636,9 @@ add_filter( 'user_has_cap', 'wp_maybe_grant_resume_extensions_caps', 1 ); add_filter( 'user_has_cap', 'wp_maybe_grant_site_health_caps', 1, 4 ); +// Block Templates CPT and Rendering +add_filter( 'render_block_context', '_block_template_render_without_post_block_context' ); +add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 ); +add_action( 'wp_footer', 'the_block_template_skip_link' ); + unset( $filter, $action ); diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index 086e3d40739e5..9d54a1ce519ff 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -65,7 +65,6 @@ function wp_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID return $override_slug; } -add_filter( 'pre_wp_unique_post_slug', 'wp_filter_wp_template_unique_post_slug', 10, 5 ); /** * Print the skip-link script & styles. @@ -159,7 +158,6 @@ function the_block_template_skip_link() { Date: Mon, 24 May 2021 18:31:04 +0100 Subject: [PATCH 52/57] no need for taxonomy in classic themes --- src/wp-includes/taxonomy.php | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index e3e77f7b835a0..6e7d4dcdc49c4 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -173,11 +173,10 @@ function create_initial_taxonomies() { ) ); - // FIXME: Uncomment once theme.json support lands - if ( theme_supports_block_templates() /* || WP_Theme_JSON_Resolver::theme_has_support() */ ) { + if ( theme_supports_block_templates() ) { register_taxonomy( 'wp_theme', - array( 'wp_template', 'wp_global_styles' ), + array( 'wp_template' ), array( 'public' => false, 'hierarchical' => false, From 71d29fce164e736853fe321a9055bc8552bf33b1 Mon Sep 17 00:00:00 2001 From: Riad Benguella Date: Tue, 25 May 2021 09:12:49 +0100 Subject: [PATCH 53/57] Fix capabilities --- src/wp-includes/post.php | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 9a7d2d9c0a485..e32fa063b05a8 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -347,14 +347,17 @@ function create_initial_post_types() { 'rest_controller_class' => 'WP_REST_Templates_Controller', 'capability_type' => array( 'template', 'templates' ), 'capabilities' => array( - 'edit_posts' => 'edit_theme_options', - 'edit_others_posts' => 'edit_theme_options', - 'edit_published_posts' => 'edit_theme_options', - 'edit_private_posts' => 'edit_theme_options', + 'create_posts' => 'edit_theme_options', 'delete_posts' => 'edit_theme_options', 'delete_others_posts' => 'edit_theme_options', - 'delete_published_posts' => 'edit_theme_options', 'delete_private_posts' => 'edit_theme_options', + 'delete_published_posts' => 'edit_theme_options', + 'edit_posts' => 'edit_theme_options', + 'edit_others_posts' => 'edit_theme_options', + 'edit_private_posts' => 'edit_theme_options', + 'edit_published_posts' => 'edit_theme_options', + 'publish_posts' => 'edit_theme_options', + 'read' => 'edit_theme_options', 'read_private_posts' => 'edit_theme_options', ), 'map_meta_cap' => true, From e4ecc6b39085704cd38679306936a6d8cc801461 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 25 May 2021 15:04:13 +0200 Subject: [PATCH 54/57] Inline theme_supports_block_templates --- src/wp-admin/edit-form-blocks.php | 2 +- src/wp-includes/class-wp-theme.php | 2 +- src/wp-includes/post.php | 2 +- src/wp-includes/taxonomy.php | 2 +- src/wp-includes/theme-templates.php | 2 +- src/wp-includes/theme.php | 9 --------- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index a6d6189ef18cd..99025d4611f97 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -212,7 +212,7 @@ 'supportsLayout' => WP_Theme_JSON_Resolver::theme_has_support(), '__experimentalBlockPatterns' => WP_Block_Patterns_Registry::get_instance()->get_all_registered(), '__experimentalBlockPatternCategories' => WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), - 'supportsTemplateMode' => theme_supports_block_templates(), + 'supportsTemplateMode' => current_theme_supports( 'block-templates' ), // Whether or not to load the 'postcustom' meta box is stored as a user meta // field so that we're not always loading its assets. diff --git a/src/wp-includes/class-wp-theme.php b/src/wp-includes/class-wp-theme.php index d102fe65adc34..ac04a1c54e556 100644 --- a/src/wp-includes/class-wp-theme.php +++ b/src/wp-includes/class-wp-theme.php @@ -1220,7 +1220,7 @@ public function get_post_templates() { } } - if ( theme_supports_block_templates() ) { + if ( current_theme_supports( 'block-templates' ) ) { $block_templates = get_block_templates( array(), 'wp_template' ); foreach ( get_post_types( array( 'public' => true ) ) as $type ) { foreach ( $block_templates as $block_template ) { diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index e32fa063b05a8..9392af252cc8f 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -310,7 +310,7 @@ function create_initial_post_types() { ) ); - if ( theme_supports_block_templates() ) { + if ( current_theme_supports( 'block-templates' ) ) { register_post_type( 'wp_template', array( diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 6e7d4dcdc49c4..0417d8e42da18 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -173,7 +173,7 @@ function create_initial_taxonomies() { ) ); - if ( theme_supports_block_templates() ) { + if ( current_theme_supports( 'block-templates' ) ) { register_taxonomy( 'wp_theme', array( 'wp_template' ), diff --git a/src/wp-includes/theme-templates.php b/src/wp-includes/theme-templates.php index 9d54a1ce519ff..5cce35cd994ce 100644 --- a/src/wp-includes/theme-templates.php +++ b/src/wp-includes/theme-templates.php @@ -77,7 +77,7 @@ function wp_filter_wp_template_unique_post_slug( $override_slug, $slug, $post_ID function the_block_template_skip_link() { // Early exit if not an FSE theme. - if ( ! theme_supports_block_templates() ) { + if ( ! current_theme_supports( 'block-templates' ) ) { return; } ?> diff --git a/src/wp-includes/theme.php b/src/wp-includes/theme.php index 6677b5178a27e..458b8e6b3a403 100644 --- a/src/wp-includes/theme.php +++ b/src/wp-includes/theme.php @@ -3232,15 +3232,6 @@ function get_registered_theme_feature( $feature ) { return isset( $_wp_registered_theme_features[ $feature ] ) ? $_wp_registered_theme_features[ $feature ] : null; } -/** - * Returns whether the current theme supports block templates - * - * @return boolean Whether the current theme supports block templates. - */ -function theme_supports_block_templates() { - return current_theme_supports( 'block-templates' ); -} - /** * Checks an attachment being deleted to see if it's a header or background image. * From 34714049dd0ca549e6938b4c6b1f7e057e94598a Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 25 May 2021 15:06:59 +0200 Subject: [PATCH 55/57] Make CPT registration unconditional --- src/wp-includes/post.php | 120 +++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 61 deletions(-) diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 9392af252cc8f..e184298410870 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -310,67 +310,65 @@ function create_initial_post_types() { ) ); - if ( current_theme_supports( 'block-templates' ) ) { - register_post_type( - 'wp_template', - array( - 'labels' => array( - 'name' => __( 'Templates' ), - 'singular_name' => __( 'Template' ), - 'menu_name' => _x( 'Templates', 'Admin Menu text' ), - 'add_new' => _x( 'Add New', 'Template' ), - 'add_new_item' => __( 'Add New Template' ), - 'new_item' => __( 'New Template' ), - 'edit_item' => __( 'Edit Template' ), - 'view_item' => __( 'View Template' ), - 'all_items' => __( 'All Templates' ), - 'search_items' => __( 'Search Templates' ), - 'parent_item_colon' => __( 'Parent Template:' ), - 'not_found' => __( 'No templates found.' ), - 'not_found_in_trash' => __( 'No templates found in Trash.' ), - 'archives' => __( 'Template archives' ), - 'insert_into_item' => __( 'Insert into template' ), - 'uploaded_to_this_item' => __( 'Uploaded to this template' ), - 'filter_items_list' => __( 'Filter templates list' ), - 'items_list_navigation' => __( 'Templates list navigation' ), - 'items_list' => __( 'Templates list' ), - ), - 'description' => __( 'Templates to include in your theme.' ), - 'public' => false, - 'has_archive' => false, - 'show_ui' => false, - 'show_in_menu' => false, - 'show_in_admin_bar' => false, - 'show_in_rest' => true, - 'rewrite' => false, - 'rest_base' => 'templates', - 'rest_controller_class' => 'WP_REST_Templates_Controller', - 'capability_type' => array( 'template', 'templates' ), - 'capabilities' => array( - 'create_posts' => 'edit_theme_options', - 'delete_posts' => 'edit_theme_options', - 'delete_others_posts' => 'edit_theme_options', - 'delete_private_posts' => 'edit_theme_options', - 'delete_published_posts' => 'edit_theme_options', - 'edit_posts' => 'edit_theme_options', - 'edit_others_posts' => 'edit_theme_options', - 'edit_private_posts' => 'edit_theme_options', - 'edit_published_posts' => 'edit_theme_options', - 'publish_posts' => 'edit_theme_options', - 'read' => 'edit_theme_options', - 'read_private_posts' => 'edit_theme_options', - ), - 'map_meta_cap' => true, - 'supports' => array( - 'title', - 'slug', - 'excerpt', - 'editor', - 'revisions', - ), - ) - ); - } + register_post_type( + 'wp_template', + array( + 'labels' => array( + 'name' => __( 'Templates' ), + 'singular_name' => __( 'Template' ), + 'menu_name' => _x( 'Templates', 'Admin Menu text' ), + 'add_new' => _x( 'Add New', 'Template' ), + 'add_new_item' => __( 'Add New Template' ), + 'new_item' => __( 'New Template' ), + 'edit_item' => __( 'Edit Template' ), + 'view_item' => __( 'View Template' ), + 'all_items' => __( 'All Templates' ), + 'search_items' => __( 'Search Templates' ), + 'parent_item_colon' => __( 'Parent Template:' ), + 'not_found' => __( 'No templates found.' ), + 'not_found_in_trash' => __( 'No templates found in Trash.' ), + 'archives' => __( 'Template archives' ), + 'insert_into_item' => __( 'Insert into template' ), + 'uploaded_to_this_item' => __( 'Uploaded to this template' ), + 'filter_items_list' => __( 'Filter templates list' ), + 'items_list_navigation' => __( 'Templates list navigation' ), + 'items_list' => __( 'Templates list' ), + ), + 'description' => __( 'Templates to include in your theme.' ), + 'public' => false, + 'has_archive' => false, + 'show_ui' => false, + 'show_in_menu' => false, + 'show_in_admin_bar' => false, + 'show_in_rest' => true, + 'rewrite' => false, + 'rest_base' => 'templates', + 'rest_controller_class' => 'WP_REST_Templates_Controller', + 'capability_type' => array( 'template', 'templates' ), + 'capabilities' => array( + 'create_posts' => 'edit_theme_options', + 'delete_posts' => 'edit_theme_options', + 'delete_others_posts' => 'edit_theme_options', + 'delete_private_posts' => 'edit_theme_options', + 'delete_published_posts' => 'edit_theme_options', + 'edit_posts' => 'edit_theme_options', + 'edit_others_posts' => 'edit_theme_options', + 'edit_private_posts' => 'edit_theme_options', + 'edit_published_posts' => 'edit_theme_options', + 'publish_posts' => 'edit_theme_options', + 'read' => 'edit_theme_options', + 'read_private_posts' => 'edit_theme_options', + ), + 'map_meta_cap' => true, + 'supports' => array( + 'title', + 'slug', + 'excerpt', + 'editor', + 'revisions', + ), + ) + ); register_post_status( 'publish', From cba764850f40bac3669973049b91934431053411 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 25 May 2021 15:07:29 +0200 Subject: [PATCH 56/57] Make wp_theme taxonomy registration unconditional --- src/wp-includes/taxonomy.php | 38 +++++++++++++++++------------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/src/wp-includes/taxonomy.php b/src/wp-includes/taxonomy.php index 0417d8e42da18..0e7f1312dd0fd 100644 --- a/src/wp-includes/taxonomy.php +++ b/src/wp-includes/taxonomy.php @@ -173,26 +173,24 @@ function create_initial_taxonomies() { ) ); - if ( current_theme_supports( 'block-templates' ) ) { - register_taxonomy( - 'wp_theme', - array( 'wp_template' ), - array( - 'public' => false, - 'hierarchical' => false, - 'labels' => array( - 'name' => __( 'Themes' ), - 'singular_name' => __( 'Theme' ), - ), - 'query_var' => false, - 'rewrite' => false, - 'show_ui' => false, - '_builtin' => true, - 'show_in_nav_menus' => false, - 'show_in_rest' => false, - ) - ); - } + register_taxonomy( + 'wp_theme', + array( 'wp_template' ), + array( + 'public' => false, + 'hierarchical' => false, + 'labels' => array( + 'name' => __( 'Themes' ), + 'singular_name' => __( 'Theme' ), + ), + 'query_var' => false, + 'rewrite' => false, + 'show_ui' => false, + '_builtin' => true, + 'show_in_nav_menus' => false, + 'show_in_rest' => false, + ) + ); } /** From bf8d81ef8930352d505fa491fcc6a517e47e3f94 Mon Sep 17 00:00:00 2001 From: Bernie Reiter Date: Tue, 25 May 2021 15:14:24 +0200 Subject: [PATCH 57/57] Rename _strip_php_suffix to _strip_template_file_suffix --- src/wp-includes/block-template.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/block-template.php b/src/wp-includes/block-template.php index 0db8a40c2c800..c93a083472a10 100644 --- a/src/wp-includes/block-template.php +++ b/src/wp-includes/block-template.php @@ -104,7 +104,7 @@ function resolve_block_template( $template_type, $template_hierarchy ) { } $slugs = array_map( - '_strip_php_suffix', + '_strip_template_file_suffix', $template_hierarchy ); @@ -189,7 +189,7 @@ function _block_template_viewport_meta_tag() { } /** - * Strips .php suffix from template file names. + * Strips .php or .html suffix from template file names. * * @access private * @since 5.8.0 @@ -197,7 +197,7 @@ function _block_template_viewport_meta_tag() { * @param string $template_file Template file name. * @return string Template file name without extension. */ -function _strip_php_suffix( $template_file ) { +function _strip_template_file_suffix( $template_file ) { return preg_replace( '/\.(php|html)$/', '', $template_file ); }