diff --git a/wp-includes/block-template-utils.php b/wp-includes/block-template-utils.php index 54413d809b..a16fe2914c 100644 --- a/wp-includes/block-template-utils.php +++ b/wp-includes/block-template-utils.php @@ -147,7 +147,7 @@ function get_default_block_template_types() { ), 'category' => array( 'title' => _x( 'Category', 'Template name' ), - 'description' => __( 'Displays latest posts in single post category.' ), + 'description' => __( 'Displays latest posts from a single post category.' ), ), 'taxonomy' => array( 'title' => _x( 'Taxonomy', 'Template name' ), @@ -555,7 +555,8 @@ function _build_block_template_result_from_post( $post ) { $template_file = _get_block_template_file( $post->post_type, $post->post_name ); $has_theme_file = wp_get_theme()->get_stylesheet() === $theme && null !== $template_file; - $origin = get_post_meta( $post->ID, 'origin', true ); + $origin = get_post_meta( $post->ID, 'origin', true ); + $is_wp_suggestion = get_post_meta( $post->ID, 'is_wp_suggestion', true ); $template = new WP_Block_Template(); $template->wp_id = $post->ID; @@ -570,7 +571,7 @@ function _build_block_template_result_from_post( $post ) { $template->title = $post->post_title; $template->status = $post->post_status; $template->has_theme_file = $has_theme_file; - $template->is_custom = true; + $template->is_custom = empty( $is_wp_suggestion ); $template->author = $post->post_author; if ( 'wp_template' === $post->post_type && $has_theme_file && isset( $template_file['postTypes'] ) ) { @@ -679,7 +680,8 @@ function get_block_templates( $query = array(), $template_type = 'wp_template' ) continue; } - if ( $post_type && + if ( + $post_type && isset( $template->post_types ) && ! in_array( $post_type, $template->post_types, true ) ) { @@ -912,9 +914,10 @@ function block_footer_area() { * @return Bool Whether this file is in an ignored directory. */ function wp_is_theme_directory_ignored( $path ) { - $directories_to_ignore = array( '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); + $directories_to_ignore = array( '.DS_Store', '.svn', '.git', '.hg', '.bzr', 'node_modules', 'vendor' ); + foreach ( $directories_to_ignore as $directory ) { - if ( strpos( $path, $directory ) === 0 ) { + if ( str_starts_with( $path, $directory ) ) { return true; } } @@ -1023,3 +1026,74 @@ function wp_generate_block_templates_export_file() { return $filename; } + +/** + * Gets the template hierarchy for the given template slug to be created. + * + * + * Note: Always add `index` as the last fallback template. + * + * @since 6.1.0 + * + * @param string $slug The template slug to be created. + * @param boolean $is_custom Optional. Indicates if a template is custom or + * part of the template hierarchy. Default false. + * @param string $template_prefix Optional. The template prefix for the created template. + * Used to extract the main template type, e.g. + * in `taxonomy-books` the `taxonomy` is extracted. + * Default empty string. + * @return string[] The template hierarchy. + */ +function get_template_hierarchy( $slug, $is_custom = false, $template_prefix = '' ) { + if ( 'index' === $slug ) { + return array( 'index' ); + } + if ( $is_custom ) { + return array( 'page', 'singular', 'index' ); + } + if ( 'front-page' === $slug ) { + return array( 'front-page', 'home', 'index' ); + } + + $template_hierarchy = array( $slug ); + + // Most default templates don't have `$template_prefix` assigned. + if ( $template_prefix ) { + list( $type ) = explode( '-', $template_prefix ); + // These checks are needed because the `$slug` above is always added. + if ( ! in_array( $template_prefix, array( $slug, $type ), true ) ) { + $template_hierarchy[] = $template_prefix; + } + if ( $slug !== $type ) { + $template_hierarchy[] = $type; + } + } + + // Handle `archive` template. + if ( + str_starts_with( $slug, 'author' ) || + str_starts_with( $slug, 'taxonomy' ) || + str_starts_with( $slug, 'category' ) || + str_starts_with( $slug, 'tag' ) || + 'date' === $slug + ) { + $template_hierarchy[] = 'archive'; + } + // Handle `single` template. + if ( 'attachment' === $slug ) { + $template_hierarchy[] = 'single'; + } + + // Handle `singular` template. + if ( + str_starts_with( $slug, 'single' ) || + str_starts_with( $slug, 'page' ) || + 'attachment' === $slug + ) { + $template_hierarchy[] = 'singular'; + } + + $template_hierarchy[] = 'index'; + + return $template_hierarchy; +}; diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php index cb2daa4b29..8223f1dd6f 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php @@ -186,54 +186,58 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { $fields = $this->get_fields_for_response( $request ); $data = array(); - if ( in_array( 'capabilities', $fields, true ) ) { + if ( rest_is_field_included( 'capabilities', $fields ) ) { $data['capabilities'] = $post_type->cap; } - if ( in_array( 'description', $fields, true ) ) { + if ( rest_is_field_included( 'description', $fields ) ) { $data['description'] = $post_type->description; } - if ( in_array( 'hierarchical', $fields, true ) ) { + if ( rest_is_field_included( 'hierarchical', $fields ) ) { $data['hierarchical'] = $post_type->hierarchical; } - if ( in_array( 'visibility', $fields, true ) ) { + if ( rest_is_field_included( 'visibility', $fields ) ) { $data['visibility'] = array( 'show_in_nav_menus' => (bool) $post_type->show_in_nav_menus, 'show_ui' => (bool) $post_type->show_ui, ); } - if ( in_array( 'viewable', $fields, true ) ) { + if ( rest_is_field_included( 'viewable', $fields ) ) { $data['viewable'] = is_post_type_viewable( $post_type ); } - if ( in_array( 'labels', $fields, true ) ) { + if ( rest_is_field_included( 'labels', $fields ) ) { $data['labels'] = $post_type->labels; } - if ( in_array( 'name', $fields, true ) ) { + if ( rest_is_field_included( 'name', $fields ) ) { $data['name'] = $post_type->label; } - if ( in_array( 'slug', $fields, true ) ) { + if ( rest_is_field_included( 'slug', $fields ) ) { $data['slug'] = $post_type->name; } - if ( in_array( 'supports', $fields, true ) ) { + if ( rest_is_field_included( 'icon', $fields ) ) { + $data['icon'] = $post_type->menu_icon; + } + + if ( rest_is_field_included( 'supports', $fields ) ) { $data['supports'] = $supports; } - if ( in_array( 'taxonomies', $fields, true ) ) { + if ( rest_is_field_included( 'taxonomies', $fields ) ) { $data['taxonomies'] = array_values( $taxonomies ); } - if ( in_array( 'rest_base', $fields, true ) ) { + if ( rest_is_field_included( 'rest_base', $fields ) ) { $data['rest_base'] = $base; } - if ( in_array( 'rest_namespace', $fields, true ) ) { + if ( rest_is_field_included( 'rest_namespace', $fields ) ) { $data['rest_namespace'] = $namespace; } @@ -287,6 +291,7 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { * @since 4.7.0 * @since 4.8.0 The `supports` property was added. * @since 5.9.0 The `visibility` and `rest_namespace` properties were added. + * @since 6.1.0 The `icon` property was added. * * @return array Item schema data. */ @@ -385,6 +390,12 @@ class WP_REST_Post_Types_Controller extends WP_REST_Controller { ), ), ), + 'icon' => array( + 'description' => __( 'The icon for the post type.' ), + 'type' => array( 'string', 'null' ), + 'context' => array( 'view', 'edit', 'embed' ), + 'readonly' => true, + ), ), ); diff --git a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php index 7e60674890..e26b4d17e5 100644 --- a/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php +++ b/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php @@ -42,6 +42,7 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { * Registers the controllers routes. * * @since 5.8.0 + * @since 6.1.0 Endpoint for fallback template content. */ public function register_routes() { // Lists all templates. @@ -65,6 +66,34 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { ) ); + // Get fallback template content. + register_rest_route( + $this->namespace, + '/' . $this->rest_base . '/lookup', + array( + array( + 'methods' => WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_template_fallback' ), + 'permission_callback' => array( $this, 'get_item_permissions_check' ), + 'args' => array( + 'slug' => array( + 'description' => __( 'The slug of the template to get the fallback for' ), + 'type' => 'string', + 'required' => true, + ), + 'is_custom' => array( + 'description' => __( ' Indicates if a template is custom or part of the template hierarchy' ), + 'type' => 'boolean', + ), + 'template_prefix' => array( + 'description' => __( 'The template prefix for the created template. This is used to extract the main template type, e.g. in `taxonomy-books` extracts the `taxonomy`' ), + 'type' => 'string', + ), + ), + ), + ) + ); + // Lists/updates a single template based on the given id. register_rest_route( $this->namespace, @@ -117,6 +146,21 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { ); } + /** + * Returns the fallback template for the given slug. + * + * @since 6.1.0 + * + * @param WP_REST_Request $request The request instance. + * @return WP_REST_Response|WP_Error + */ + public function get_template_fallback( $request ) { + $hierarchy = get_template_hierarchy( $request['slug'], $request['is_custom'], $request['template_prefix'] ); + $fallback_template = resolve_block_template( $request['slug'], $hierarchy, '' ); + $response = $this->prepare_item_for_response( $fallback_template, $request ); + return rest_ensure_response( $response ); + } + /** * Checks if the user has permissions to make the request. * @@ -525,6 +569,15 @@ class WP_REST_Templates_Controller extends WP_REST_Controller { $changes->post_excerpt = $template->description; } + if ( 'wp_template' === $this->post_type && isset( $request['is_wp_suggestion'] ) ) { + $changes->meta_input = wp_parse_args( + array( + 'is_wp_suggestion' => $request['is_wp_suggestion'], + ), + $changes->meta_input = array() + ); + } + if ( 'wp_template_part' === $this->post_type ) { if ( isset( $request['area'] ) ) { $changes->tax_input['wp_template_part_area'] = _filter_block_template_part_area( $request['area'] ); diff --git a/wp-includes/version.php b/wp-includes/version.php index fefafaad78..b413168572 100644 --- a/wp-includes/version.php +++ b/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '6.1-alpha-54268'; +$wp_version = '6.1-alpha-54269'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.