From 6680737ac097ccad85726faca3abdffcaf381498 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Wed, 21 Sep 2022 16:09:26 +0100 Subject: [PATCH] Update: Make template names and descriptions dynamic. (#43862) --- .../wordpress-6.1/block-template-utils.php | 227 ++++++++++++++++++ .../src/components/add-new-template/utils.js | 97 +------- 2 files changed, 236 insertions(+), 88 deletions(-) diff --git a/lib/compat/wordpress-6.1/block-template-utils.php b/lib/compat/wordpress-6.1/block-template-utils.php index ee4016a1a080b5..5ee02f222d9521 100644 --- a/lib/compat/wordpress-6.1/block-template-utils.php +++ b/lib/compat/wordpress-6.1/block-template-utils.php @@ -248,6 +248,136 @@ function gutenberg_get_block_template( $id, $template_type = 'wp_template' ) { return apply_filters( 'get_block_template', $block_template, $id, $template_type ); } +/** + * Builds the title and description of a post specific template based on the underlying referenced post. + * Mutates the underlying template object. + * + * @access private + * @internal + * + * @param string $post_type Post type e.g.: page, post, product. + * @param string $slug Slug of the post e.g.: a-story-about-shoes. + * @param WP_Block_Template $template Template to mutate adding the description and title computed. + * + * @return boolean Returns true if the referenced post was found and false otherwise. + */ +function _gutenberg_build_title_and_description_for_single_post_type_block_template( $post_type, $slug, WP_Block_Template $template ) { + $post_type_object = get_post_type_object( $post_type ); + + $posts = get_posts( + array( + 'name' => $slug, + 'post_type' => $post_type, + ) + ); + if ( empty( $posts ) ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor referencing a post that was not found, where %1$s is the singular name of a post type and %2$s is the slug of the deleted post, e.g. "Not found: Page(hello)". + __( 'Not found: %1$s(%2$s)', 'gutenberg' ), + $post_type_object->labels->singular_name, + $slug + ); + return false; + } + + $post_title = $posts[0]->post_title; + + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type and %2$s is the name of the post, e.g. "Page: Hello". + __( '%1$s: %2$s', 'gutenberg' ), + $post_type_object->labels->singular_name, + $post_title + ); + $template->description = sprintf( + // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Page: Hello". + __( 'Template for %1$s', 'gutenberg' ), + $post_title + ); + + $posts_with_same_title = get_posts( + array( + 'title' => $post_title, + 'post_type' => $post_type, + 'post_status' => 'publish', + ) + ); + if ( count( $posts_with_same_title ) > 1 ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the post type, e.g. "Project: Hello (project_type)". + __( '%1$s (%2$s)', 'gutenberg' ), + $template->title, + $slug + ); + } + return true; +} + +/** + * Builds the title and description of a taxonomy specific template based on the underlying entity referenced. + * Mutates the underlying template object. + * + * @access private + * @internal + * + * @param string $taxonomy Identifier of the taxonomy, e.g.: category. + * @param string $slug Slug of the term, e.g.: shoes. + * @param WP_Block_Template $template Template to mutate adding the description and title computed. + * + * @return boolean True if an term referenced was found and false otherwise. + */ +function _gutenberg_build_title_and_description_for_taxonomy_block_template( $taxonomy, $slug, WP_Block_Template $template ) { + $taxonomy_object = get_taxonomy( $taxonomy ); + + $terms = get_terms( + array( + 'taxonomy' => $taxonomy, + 'hide_empty' => false, + 'slug' => $slug, + ) + ); + + if ( empty( $terms ) ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor referencing a taxonomy term that was not found, where %1$s is the singular name of a taxonomy and %2$s is the slug of the deleted term, e.g. "Not found: Category(shoes)". + __( 'Not found: %1$s(%2$s)', 'gutenberg' ), + $taxonomy_object->labels->singular_name, + $slug + ); + return false; + } + + $term_title = $terms[0]->name; + + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a taxonomy and %2$s is the name of the term, e.g. "Category: shoes". + __( '%1$s: %2$s', 'gutenberg' ), + $taxonomy_object->labels->singular_name, + $term_title + ); + $template->description = sprintf( + // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Category: shoes". + __( 'Template for %1$s', 'gutenberg' ), + $term_title + ); + + $terms_with_same_title = get_terms( + array( + 'taxonomy' => $taxonomy, + 'hide_empty' => false, + 'name' => $term_title, + ) + ); + if ( count( $terms_with_same_title ) > 1 ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the taxonomy, e.g. "Category: shoes (product_tag)". + __( '%1$s (%2$s)', 'gutenberg' ), + $template->title, + $slug + ); + } + return true; +} + /** * Build a unified template object based a post Object. * @@ -305,6 +435,103 @@ function gutenberg_build_block_template_result_from_post( $post ) { $template->area = $type_terms[0]->name; } } + // If it is a block template without description and without title or with title equal to the slug. + if ( 'wp_template' === $post->post_type && empty( $template->description ) && ( empty( $template->title ) || $template->title === $template->slug ) ) { + $matches = array(); + // If it is a block template for a single author, page, post, tag, category, custom post type or custom taxonomy. + if ( preg_match( '/(author|page|single|tag|category|taxonomy)-(.+)/', $template->slug, $matches ) ) { + $type = $matches[1]; + $slug_remaining = $matches[2]; + switch ( $type ) { + case 'author': + $nice_name = $slug_remaining; + $users = get_users( + array( + 'capability' => 'edit_posts', + 'search' => $nice_name, + 'search_columns' => array( 'user_nicename' ), + 'fields' => 'display_name', + ) + ); + + if ( empty( $users ) ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor referencing a deleted author, where %s is the author's nicename, e.g. "Deleted author: jane-doe". + __( 'Deleted author: %s', 'gutenberg' ), + $nice_name + ); + } else { + $author_name = $users[0]; + + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %s is the author's name, e.g. "Author: Jane Doe". + __( 'Author: %s', 'gutenberg' ), + $author_name + ); + $template->description = sprintf( + // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Author: Jane Doe". + __( 'Template for %1$s', 'gutenberg' ), + $author_name + ); + + $users_with_same_name = get_users( + array( + 'capability' => 'edit_posts', + 'search' => $author_name, + 'search_columns' => array( 'display_name' ), + 'fields' => 'display_name', + ) + ); + if ( count( $users_with_same_name ) > 1 ) { + $template->title = sprintf( + // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title of an author template and %2$s is the nicename of the author, e.g. "Author: Jorge (jorge-costa)". + __( '%1$s (%2$s)', 'gutenberg' ), + $template->title, + $nice_name + ); + } + } + break; + case 'page': + _gutenberg_build_title_and_description_for_single_post_type_block_template( 'page', $slug_remaining, $template ); + break; + case 'single': + $post_types = get_post_types(); + foreach ( $post_types as $post_type ) { + $post_type_length = strlen( $post_type ) + 1; + // If $slug_remaining starts with $post_type followed by a hyphen. + if ( 0 === strncmp( $slug_remaining, $post_type . '-', $post_type_length ) ) { + $slug = substr( $slug_remaining, $post_type_length, strlen( $slug_remaining ) ); + $found = _gutenberg_build_title_and_description_for_single_post_type_block_template( $post_type, $slug, $template ); + if ( $found ) { + break; + } + } + } + break; + case 'tag': + _gutenberg_build_title_and_description_for_taxonomy_block_template( 'post_tag', $slug_remaining, $template ); + break; + case 'category': + _gutenberg_build_title_and_description_for_taxonomy_block_template( 'category', $slug_remaining, $template ); + break; + case 'taxonomy': + $taxonomies = get_taxonomies(); + foreach ( $taxonomies as $taxonomy ) { + $taxonomy_length = strlen( $taxonomy ) + 1; + // If $slug_remaining starts with $taxonomy followed by a hyphen. + if ( 0 === strncmp( $slug_remaining, $taxonomy . '-', $taxonomy_length ) ) { + $slug = substr( $slug_remaining, $taxonomy_length, strlen( $slug_remaining ) ); + $found = _gutenberg_build_title_and_description_for_taxonomy_block_template( $taxonomy, $slug, $template ); + if ( $found ) { + break; + } + } + } + break; + } + } + } return $template; } diff --git a/packages/edit-site/src/components/add-new-template/utils.js b/packages/edit-site/src/components/add-new-template/utils.js index 4063509a6ddb56..7309f2ff711ca9 100644 --- a/packages/edit-site/src/components/add-new-template/utils.js +++ b/packages/edit-site/src/components/add-new-template/utils.js @@ -253,29 +253,10 @@ export const usePostTypeMenuItems = ( onClickMenuItem ) => { }; }, getSpecificTemplate: ( suggestion ) => { - let title = sprintf( - // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a post type and %2$s is the name of the post, e.g. "Page: Hello". - __( '%1$s: %2$s' ), - labels.singular_name, - suggestion.name - ); - const description = sprintf( - // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Page: Hello" - __( 'Template for %1$s' ), - title - ); - if ( _needsUniqueIdentifier ) { - title = sprintf( - // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the post type, e.g. "Project: Hello (project_type)" - __( '%1$s (%2$s)' ), - title, - slug - ); - } + const templateSlug = `${ templatePrefixes[ slug ] }-${ suggestion.slug }`; return { - title, - description, - slug: `${ templatePrefixes[ slug ] }-${ suggestion.slug }`, + title: templateSlug, + slug: templateSlug, templatePrefix: templatePrefixes[ slug ], }; }, @@ -417,29 +398,10 @@ export const useTaxonomiesMenuItems = ( onClickMenuItem ) => { }; }, getSpecificTemplate: ( suggestion ) => { - let title = sprintf( - // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the singular name of a taxonomy and %2$s is the name of the term, e.g. "Category: shoes". - __( '%1$s: %2$s' ), - labels.singular_name, - suggestion.name - ); - const description = sprintf( - // translators: Represents the description of a user's custom template in the Site Editor, e.g. "Template for Category: shoes" - __( 'Template for %1$s' ), - title - ); - if ( _needsUniqueIdentifier ) { - title = sprintf( - // translators: Represents the title of a user's custom template in the Site Editor, where %1$s is the template title and %2$s is the slug of the taxonomy, e.g. "Category: shoes (product_tag)" - __( '%1$s (%2$s)' ), - title, - slug - ); - } + const templateSlug = `${ templatePrefixes[ slug ] }-${ suggestion.slug }`; return { - title, - description, - slug: `${ templatePrefixes[ slug ] }-${ suggestion.slug }`, + title: templateSlug, + slug: templateSlug, templatePrefix: templatePrefixes[ slug ], }; }, @@ -480,26 +442,6 @@ export const useTaxonomiesMenuItems = ( onClickMenuItem ) => { return taxonomiesMenuItems; }; -function useAuthorNeedsUniqueIndentifier() { - const authors = useSelect( - ( select ) => - select( coreStore ).getUsers( { who: 'authors', per_page: -1 } ), - [] - ); - const authorsCountByName = useMemo( () => { - return ( authors || [] ).reduce( ( authorsCount, { name } ) => { - authorsCount[ name ] = ( authorsCount[ name ] || 0 ) + 1; - return authorsCount; - }, {} ); - }, [ authors ] ); - return useCallback( - ( name ) => { - return authorsCountByName[ name ] > 1; - }, - [ authorsCountByName ] - ); -} - const USE_AUTHOR_MENU_ITEM_TEMPLATE_PREFIX = { user: 'author' }; const USE_AUTHOR_MENU_ITEM_QUERY_PARAMETERS = { user: { who: 'authors' } }; export function useAuthorMenuItem( onClickMenuItem ) { @@ -510,7 +452,6 @@ export function useAuthorMenuItem( onClickMenuItem ) { USE_AUTHOR_MENU_ITEM_TEMPLATE_PREFIX, USE_AUTHOR_MENU_ITEM_QUERY_PARAMETERS ); - const authorNeedsUniqueId = useAuthorNeedsUniqueIndentifier(); let authorMenuItem = defaultTemplateTypes?.find( ( { slug } ) => slug === 'author' ); @@ -542,30 +483,10 @@ export function useAuthorMenuItem( onClickMenuItem ) { }; }, getSpecificTemplate: ( suggestion ) => { - const needsUniqueId = authorNeedsUniqueId( - suggestion.name - ); - const title = needsUniqueId - ? sprintf( - // translators: %1$s: Represents the name of an author e.g: "Jorge", %2$s: Represents the slug of an author e.g: "author-jorge-slug". - __( 'Author: %1$s (%2$s)' ), - suggestion.name, - suggestion.slug - ) - : sprintf( - // translators: %s: Represents the name of an author e.g: "Jorge". - __( 'Author: %s' ), - suggestion.name - ); - const description = sprintf( - // translators: %s: Represents the name of an author e.g: "Jorge". - __( 'Template for Author: %s' ), - suggestion.name - ); + const templateSlug = `author-${ suggestion.slug }`; return { - title, - description, - slug: `author-${ suggestion.slug }`, + title: templateSlug, + slug: templateSlug, templatePrefix: 'author', }; },