From 777b92781a61cdc90ee1f7bb01333f5482bed21e Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 09:39:59 +1300 Subject: [PATCH 01/12] Update pattern categories endpoint --- ...st-block-pattern-categories-controller.php | 119 ++++++++++++++++++ lib/compat/wordpress-6.5/rest-api.php | 10 +- lib/load.php | 1 + .../inserter/hooks/use-patterns-state.js | 27 +--- .../src/components/category-selector.js | 6 +- .../src/components/create-pattern-modal.js | 48 ++----- 6 files changed, 146 insertions(+), 65 deletions(-) create mode 100644 lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php new file mode 100644 index 00000000000000..dc0d30e021f29e --- /dev/null +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -0,0 +1,119 @@ +get_all_registered(); + $user_categories = get_terms( array( + 'taxonomy' => 'wp_pattern_category', + 'hide_empty' => false, + ) ); + + foreach ( $user_categories as $user_category ) { + $prepared_category = $this->prepare_item_for_response( array( + 'name' => $user_category->slug, + 'label' => $user_category->name, + 'description' => $user_category->description, + 'id' => $user_category->term_id, + ), $request ); + $response[] = $this->prepare_response_for_collection( $prepared_category ); + $unique_categories[] = $user_category->name; + } + foreach ( $categories as $category ) { + if ( in_array( $category['label'], $unique_categories ) ) { + continue; + } + $prepared_category = $this->prepare_item_for_response( $category, $request ); + $response[] = $this->prepare_response_for_collection( $prepared_category ); + } + + return rest_ensure_response( $response ); + } + + /** + * Prepare a raw block pattern category before it gets output in a REST API response. + * + * @since 6.0.0 + * @since 6.5 Added `id` field for identifying user categories + * + * @param array $item Raw category as registered, before any changes. + * @param WP_REST_Request $request Request object. + * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure. + */ + public function prepare_item_for_response( $item, $request ) { + $fields = $this->get_fields_for_response( $request ); + $keys = array( 'name', 'label', 'description', 'id' ); + $data = array(); + foreach ( $keys as $key ) { + if ( isset( $item[ $key ] ) && rest_is_field_included( $key, $fields ) ) { + $data[ $key ] = $item[ $key ]; + } + } + + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; + $data = $this->add_additional_fields_to_object( $data, $request ); + $data = $this->filter_response_by_context( $data, $context ); + + return rest_ensure_response( $data ); + } + + /** + * Retrieves the block pattern category schema, conforming to JSON Schema. + * + * @since 6.0.0 + * @since 6.5 Added `id` field for identifying user categories + * + * @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' => 'block-pattern-category', + 'type' => 'object', + 'properties' => array( + 'name' => array( + 'description' => __( 'The category name.' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'label' => array( + 'description' => __( 'The category label, in human readable format.' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'description' => array( + 'description' => __( 'The category description, in human readable format.' ), + 'type' => 'string', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + 'id' => array( + 'id' => __( 'An optional category id, currently used to provide id for user wp_pattern_category terms' ), + 'type' => 'number', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), + ), + ), + ); + + $this->schema = $schema; + + return $this->add_additional_fields_schema( $this->schema ); + } +} diff --git a/lib/compat/wordpress-6.5/rest-api.php b/lib/compat/wordpress-6.5/rest-api.php index dd372eff7943b7..75e38a0f2f3748 100644 --- a/lib/compat/wordpress-6.5/rest-api.php +++ b/lib/compat/wordpress-6.5/rest-api.php @@ -17,5 +17,13 @@ function gutenberg_register_global_styles_revisions_endpoints() { $global_styles_revisions_controller = new Gutenberg_REST_Global_Styles_Revisions_Controller_6_5(); $global_styles_revisions_controller->register_routes(); } - add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' ); + +/** + * Registers the block pattern categories REST API routes. + */ +function gutenberg_register_rest_block_pattern_categories_routes() { + $block_patterns = new Gutenberg_REST_Block_Pattern_Categories_Controller(); + $block_patterns->register_routes(); +} +add_action( 'rest_api_init', 'gutenberg_register_rest_block_pattern_categories_routes' ); diff --git a/lib/load.php b/lib/load.php index 38111d9ed5d3d5..3d91c4b16bc098 100644 --- a/lib/load.php +++ b/lib/load.php @@ -58,6 +58,7 @@ function gutenberg_is_experiment_enabled( $name ) { // WordPress 6.5 compat. require_once __DIR__ . '/compat/wordpress-6.5/class-gutenberg-rest-global-styles-revisions-controller-6-5.php'; + require __DIR__ . '/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php'; require_once __DIR__ . '/compat/wordpress-6.5/rest-api.php'; // Plugin specific code. diff --git a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js index 1924187e04179f..094fd6e1b17b48 100644 --- a/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js +++ b/packages/block-editor/src/components/inserter/hooks/use-patterns-state.js @@ -1,7 +1,7 @@ /** * WordPress dependencies */ -import { useCallback, useMemo } from '@wordpress/element'; +import { useCallback } from '@wordpress/element'; import { cloneBlock, createBlock } from '@wordpress/blocks'; import { useDispatch, useSelect } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; @@ -21,38 +21,19 @@ import { store as blockEditorStore } from '../../../store'; * @return {Array} Returns the patterns state. (patterns, categories, onSelect handler) */ const usePatternsState = ( onInsert, rootClientId ) => { - const { patternCategories, patterns, userPatternCategories } = useSelect( + const { patternCategories, patterns } = useSelect( ( select ) => { const { __experimentalGetAllowedPatterns, getSettings } = select( blockEditorStore ); - const { - __experimentalUserPatternCategories, - __experimentalBlockPatternCategories, - } = getSettings(); + const { __experimentalBlockPatternCategories } = getSettings(); return { patterns: __experimentalGetAllowedPatterns( rootClientId ), - userPatternCategories: __experimentalUserPatternCategories, patternCategories: __experimentalBlockPatternCategories, }; }, [ rootClientId ] ); - const allCategories = useMemo( () => { - const categories = [ ...patternCategories ]; - userPatternCategories?.forEach( ( userCategory ) => { - if ( - ! categories.find( - ( existingCategory ) => - existingCategory.name === userCategory.name - ) - ) { - categories.push( userCategory ); - } - } ); - return categories; - }, [ patternCategories, userPatternCategories ] ); - const { createSuccessNotice } = useDispatch( noticesStore ); const onClickPattern = useCallback( ( pattern, blocks ) => { @@ -79,7 +60,7 @@ const usePatternsState = ( onInsert, rootClientId ) => { [ createSuccessNotice, onInsert ] ); - return [ patterns, allCategories, onClickPattern ]; + return [ patterns, patternCategories, onClickPattern ]; }; export default usePatternsState; diff --git a/packages/patterns/src/components/category-selector.js b/packages/patterns/src/components/category-selector.js index 7f00350e278ecf..c7a4ab0f3b6f27 100644 --- a/packages/patterns/src/components/category-selector.js +++ b/packages/patterns/src/components/category-selector.js @@ -16,13 +16,13 @@ export const CATEGORY_SLUG = 'wp_pattern_category'; export default function CategorySelector( { categoryTerms, onChange, - categoryMap, + categories, } ) { const [ search, setSearch ] = useState( '' ); const debouncedSearch = useDebounce( setSearch, 500 ); const suggestions = useMemo( () => { - return Array.from( categoryMap.values() ) + return categories .map( ( category ) => unescapeString( category.label ) ) .filter( ( category ) => { if ( search !== '' ) { @@ -33,7 +33,7 @@ export default function CategorySelector( { return true; } ) .sort( ( a, b ) => a.localeCompare( b ) ); - }, [ search, categoryMap ] ); + }, [ search, categories ] ); function handleChange( termNames ) { const uniqueTerms = termNames.reduce( ( terms, newTerm ) => { diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index f5e6e85b8602d2..378d495081f4c5 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -10,7 +10,7 @@ import { ToggleControl, } from '@wordpress/components'; import { __, _x } from '@wordpress/i18n'; -import { useState, useMemo } from '@wordpress/element'; +import { useState } from '@wordpress/element'; import { useDispatch, useSelect } from '@wordpress/data'; import { store as noticesStore } from '@wordpress/notices'; import { store as coreStore } from '@wordpress/core-data'; @@ -48,41 +48,11 @@ export default function CreatePatternModal( { const { saveEntityRecord, invalidateResolution } = useDispatch( coreStore ); const { createErrorNotice } = useDispatch( noticesStore ); - const { corePatternCategories, userPatternCategories } = useSelect( - ( select ) => { - const { getUserPatternCategories, getBlockPatternCategories } = - select( coreStore ); + const patternCategories = useSelect( ( select ) => { + const { getBlockPatternCategories } = select( coreStore ); - return { - corePatternCategories: getBlockPatternCategories(), - userPatternCategories: getUserPatternCategories(), - }; - } - ); - - const categoryMap = useMemo( () => { - // Merge the user and core pattern categories and remove any duplicates. - const uniqueCategories = new Map(); - [ ...userPatternCategories, ...corePatternCategories ].forEach( - ( category ) => { - if ( - ! uniqueCategories.has( category.label ) && - // There are two core categories with `Post` label so explicitly remove the one with - // the `query` slug to avoid any confusion. - category.name !== 'query' - ) { - // We need to store the name separately as this is used as the slug in the - // taxonomy and may vary from the label. - uniqueCategories.set( category.label, { - label: category.label, - value: category.label, - name: category.name, - } ); - } - } - ); - return uniqueCategories; - }, [ userPatternCategories, corePatternCategories ] ); + return getBlockPatternCategories(); + } ); async function onCreate( patternTitle, sync ) { if ( ! title || isSaving ) { @@ -128,7 +98,9 @@ export default function CreatePatternModal( { try { // We need to match any existing term to the correct slug to prevent duplicates, eg. // the core `Headers` category uses the singular `header` as the slug. - const existingTerm = categoryMap.get( term ); + const existingTerm = patternCategories.find( + ( category ) => category.label === term + ); const termData = existingTerm ? { name: existingTerm.label, slug: existingTerm.name } : { name: term }; @@ -138,7 +110,7 @@ export default function CreatePatternModal( { termData, { throwOnError: true } ); - invalidateResolution( 'getUserPatternCategories' ); + invalidateResolution( 'getBlockPatternCategories' ); return newTerm.id; } catch ( error ) { if ( error.code !== 'term_exists' ) { @@ -176,7 +148,7 @@ export default function CreatePatternModal( { Date: Tue, 14 Nov 2023 09:47:00 +1300 Subject: [PATCH 02/12] Update pattern categories endpoint --- ...st-block-pattern-categories-controller.php | 2 +- .../delete-category-menu-item.js | 2 +- .../rename-category-menu-item.js | 6 ++-- .../template-panel/pattern-categories.js | 2 +- .../use-pattern-categories.js | 35 ++++++------------- .../rename-pattern-category-modal.js | 2 +- 6 files changed, 17 insertions(+), 32 deletions(-) diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index dc0d30e021f29e..72a71ac3e548a5 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -30,7 +30,7 @@ public function get_items( $request ) { $unique_categories[] = $user_category->name; } foreach ( $categories as $category ) { - if ( in_array( $category['label'], $unique_categories ) ) { + if ( in_array( $category['label'], $unique_categories ) || 'query' === $category['name'] ) { continue; } $prepared_category = $this->prepare_item_for_response( $category, $request ); diff --git a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js index 0a9a36d93d0099..c02630c6f1f6ac 100644 --- a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js +++ b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js @@ -42,7 +42,7 @@ export default function DeleteCategoryMenuItem( { category, onClose } ) { // Prevent the need to refresh the page to get up-to-date categories // and pattern categorization. - invalidateResolution( 'getUserPatternCategories' ); + invalidateResolution( 'getBlockPatternCategories' ); invalidateResolution( 'getEntityRecords', [ 'postType', PATTERN_TYPES.user, diff --git a/packages/edit-site/src/components/page-patterns/rename-category-menu-item.js b/packages/edit-site/src/components/page-patterns/rename-category-menu-item.js index 3dc3b4f7919dcd..5bd5716e7b2421 100644 --- a/packages/edit-site/src/components/page-patterns/rename-category-menu-item.js +++ b/packages/edit-site/src/components/page-patterns/rename-category-menu-item.js @@ -39,12 +39,10 @@ export default function RenameCategoryMenuItem( { category, onClose } ) { } function RenameModal( { category, onClose } ) { - // User created pattern categories have their properties updated when - // retrieved via `getUserPatternCategories`. The rename modal expects an - // object that will match the pattern category entity. + // The rename modal expects an object that will match the pattern category entity. const normalizedCategory = { id: category.id, - slug: category.slug, + slug: category.name, name: category.label, }; diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js index 3740b622361ff5..822b4fe1587f73 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js @@ -163,7 +163,7 @@ export default function PatternCategories( { post } ) { const newTerm = await saveEntityRecord( 'taxonomy', slug, term, { throwOnError: true, } ); - invalidateResolution( 'getUserPatternCategories' ); + invalidateResolution( 'getBlockPatternCategories' ); return unescapeTerm( newTerm ); } catch ( error ) { if ( error.code !== 'term_exists' ) { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js index 4dee1bae3f314f..cb16c74cbd8e9b 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-pattern-categories.js @@ -24,8 +24,7 @@ export default function usePatternCategories() { label: __( 'Uncategorized' ), } ); const themePatterns = useThemePatterns(); - const { patterns: userPatterns, categories: userPatternCategories } = - usePatterns( PATTERN_TYPES.user ); + const { patterns: userPatterns } = usePatterns( PATTERN_TYPES.user ); const patternCategories = useMemo( () => { const categoryMap = {}; @@ -37,11 +36,6 @@ export default function usePatternCategories() { categoryMap[ category.name ] = { ...category, count: 0 }; } } ); - userPatternCategories.forEach( ( category ) => { - if ( ! categoryMap[ category.name ] ) { - categoryMap[ category.name ] = { ...category, count: 0 }; - } - } ); // Update the category counts to reflect theme registered patterns. themePatterns.forEach( ( pattern ) => { @@ -70,18 +64,16 @@ export default function usePatternCategories() { } ); // Filter categories so we only have those containing patterns. - [ ...defaultCategories, ...userPatternCategories ].forEach( - ( category ) => { - if ( - categoryMap[ category.name ].count && - ! categoriesWithCounts.find( - ( cat ) => cat.name === category.name - ) - ) { - categoriesWithCounts.push( categoryMap[ category.name ] ); - } + [ ...defaultCategories ].forEach( ( category ) => { + if ( + categoryMap[ category.name ].count && + ! categoriesWithCounts.find( + ( cat ) => cat.name === category.name + ) + ) { + categoriesWithCounts.push( categoryMap[ category.name ] ); } - ); + } ); const sortedCategories = categoriesWithCounts.sort( ( a, b ) => a.label.localeCompare( b.label ) ); @@ -100,12 +92,7 @@ export default function usePatternCategories() { } ); return sortedCategories; - }, [ - defaultCategories, - themePatterns, - userPatternCategories, - userPatterns, - ] ); + }, [ defaultCategories, themePatterns, userPatterns ] ); return { patternCategories, hasPatterns: !! patternCategories.length }; } diff --git a/packages/patterns/src/components/rename-pattern-category-modal.js b/packages/patterns/src/components/rename-pattern-category-modal.js index 3e9e90da2f8212..e0e0b36f180cad 100644 --- a/packages/patterns/src/components/rename-pattern-category-modal.js +++ b/packages/patterns/src/components/rename-pattern-category-modal.js @@ -101,7 +101,7 @@ export default function RenamePatternCategoryModal( { } ); - invalidateResolution( 'getUserPatternCategories' ); + invalidateResolution( 'getBlockPatternCategories' ); onSuccess?.( savedRecord ); onClose(); From 137180f64e40cb2b8aa7ef06c4fa84fb7f548c80 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 3 Nov 2023 11:52:13 +1300 Subject: [PATCH 03/12] Fix linting issue --- ...st-block-pattern-categories-controller.php | 75 ++++++++++++------- 1 file changed, 47 insertions(+), 28 deletions(-) diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index 72a71ac3e548a5..c22a76865de293 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -1,38 +1,57 @@ get_all_registered(); - $user_categories = get_terms( array( - 'taxonomy' => 'wp_pattern_category', - 'hide_empty' => false, - ) ); + $response = array(); + $unique_categories = array(); + $categories = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(); + $user_categories = get_terms( + array( + 'taxonomy' => 'wp_pattern_category', + 'hide_empty' => false, + ) + ); - foreach ( $user_categories as $user_category ) { - $prepared_category = $this->prepare_item_for_response( array( - 'name' => $user_category->slug, - 'label' => $user_category->name, - 'description' => $user_category->description, - 'id' => $user_category->term_id, - ), $request ); + foreach ( $user_categories as $user_category ) { + $prepared_category = $this->prepare_item_for_response( + array( + 'name' => $user_category->slug, + 'label' => $user_category->name, + 'description' => $user_category->description, + 'id' => $user_category->term_id, + ), + $request + ); $response[] = $this->prepare_response_for_collection( $prepared_category ); - $unique_categories[] = $user_category->name; + $unique_categories[] = $user_category->name; } foreach ( $categories as $category ) { - if ( in_array( $category['label'], $unique_categories ) || 'query' === $category['name'] ) { - continue; - } + if ( in_array( $category['label'], $unique_categories ) || 'query' === $category['name'] ) { + continue; + } $prepared_category = $this->prepare_item_for_response( $category, $request ); $response[] = $this->prepare_response_for_collection( $prepared_category ); } @@ -40,11 +59,11 @@ public function get_items( $request ) { return rest_ensure_response( $response ); } - /** + /** * Prepare a raw block pattern category before it gets output in a REST API response. * * @since 6.0.0 - * @since 6.5 Added `id` field for identifying user categories + * @since 6.5 Added `id` field for identifying user categories * * @param array $item Raw category as registered, before any changes. * @param WP_REST_Request $request Request object. @@ -67,11 +86,11 @@ public function prepare_item_for_response( $item, $request ) { return rest_ensure_response( $data ); } - /** + /** * Retrieves the block pattern category schema, conforming to JSON Schema. * * @since 6.0.0 - * @since 6.5 Added `id` field for identifying user categories + * @since 6.5 Added `id` field for identifying user categories * * @return array Item schema data. */ @@ -103,11 +122,11 @@ public function get_item_schema() { 'readonly' => true, 'context' => array( 'view', 'edit', 'embed' ), ), - 'id' => array( - 'id' => __( 'An optional category id, currently used to provide id for user wp_pattern_category terms' ), - 'type' => 'number', - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), + 'id' => array( + 'id' => __( 'An optional category id, currently used to provide id for user wp_pattern_category terms' ), + 'type' => 'number', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), ), ), ); From b9e8780fb19a39643ed7c6a848382f64112516ca Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Fri, 3 Nov 2023 11:55:52 +1300 Subject: [PATCH 04/12] Another linting fix --- ...class-gutenberg-rest-block-pattern-categories-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index c22a76865de293..cc62ef18007326 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -49,7 +49,7 @@ public function get_items( $request ) { $unique_categories[] = $user_category->name; } foreach ( $categories as $category ) { - if ( in_array( $category['label'], $unique_categories ) || 'query' === $category['name'] ) { + if ( in_array( $category['label'], $unique_categories, true ) || 'query' === $category['name'] ) { continue; } $prepared_category = $this->prepare_item_for_response( $category, $request ); From 105356fcfa6a2ab01b926d7968328be40e7a5b81 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 09:50:30 +1300 Subject: [PATCH 05/12] Update endpoint to only return new data if explicitly requested --- docs/reference-guides/data/data-core.md | 12 +++ ...st-block-pattern-categories-controller.php | 87 ++++++++++++++----- packages/block-editor/src/store/selectors.js | 15 ++-- packages/core-data/README.md | 12 +++ packages/core-data/src/reducer.js | 9 ++ packages/core-data/src/resolvers.js | 15 ++++ packages/core-data/src/selectors.ts | 13 +++ .../delete-category-menu-item.js | 2 +- .../template-panel/pattern-categories.js | 2 +- .../use-pattern-details.js | 17 ++-- .../use-default-pattern-categories.js | 2 +- .../provider/use-block-editor-settings.js | 7 +- .../src/components/create-pattern-modal.js | 6 +- .../src/components/duplicate-pattern-modal.js | 12 +-- .../rename-pattern-category-modal.js | 2 +- 15 files changed, 156 insertions(+), 57 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index ea97ce28e4d85c..b074eb36ddedba 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -372,6 +372,18 @@ _Returns_ - `any`: The entity record's save error. +### getPatternCategories + +Retrieve the core and user pattern categories. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Array< unknown >`: User patterns category array. + ### getRawEntityRecord Returns the entity's record object by key, with its attributes mapped to their raw values. diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index cc62ef18007326..6d6161d6f8ae59 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -25,6 +25,11 @@ class Gutenberg_REST_Block_Pattern_Categories_Controller extends WP_REST_Block_P * @return WP_Error|WP_REST_Response Response object on success, or WP_Error object on failure. */ public function get_items( $request ) { + $valid_query_args = array( + 'source' => true, + ); + + $query_args = array_intersect_key( $request->get_params(), $valid_query_args ); $response = array(); $unique_categories = array(); $categories = WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(); @@ -35,25 +40,30 @@ public function get_items( $request ) { ) ); - foreach ( $user_categories as $user_category ) { - $prepared_category = $this->prepare_item_for_response( - array( - 'name' => $user_category->slug, - 'label' => $user_category->name, - 'description' => $user_category->description, - 'id' => $user_category->term_id, - ), - $request - ); - $response[] = $this->prepare_response_for_collection( $prepared_category ); - $unique_categories[] = $user_category->name; + if ( is_array( $query_args['source'] ) && in_array( 'user', $query_args['source'], true ) ) { + foreach ( $user_categories as $user_category ) { + $prepared_category = $this->prepare_item_for_response( + array( + 'name' => $user_category->slug, + 'label' => $user_category->name, + 'description' => $user_category->description, + 'id' => $user_category->term_id, + ), + $request + ); + $response[] = $this->prepare_response_for_collection( $prepared_category ); + $unique_categories[] = $user_category->name; + } } - foreach ( $categories as $category ) { - if ( in_array( $category['label'], $unique_categories, true ) || 'query' === $category['name'] ) { - continue; + + if ( ! isset( $query_args['source'] ) || in_array( 'core', $query_args['source'], true ) ) { + foreach ( $categories as $category ) { + if ( in_array( $category['label'], $unique_categories, true ) || 'query' === $category['name'] ) { + continue; + } + $prepared_category = $this->prepare_item_for_response( $category, $request ); + $response[] = $this->prepare_response_for_collection( $prepared_category ); } - $prepared_category = $this->prepare_item_for_response( $category, $request ); - $response[] = $this->prepare_response_for_collection( $prepared_category ); } return rest_ensure_response( $response ); @@ -71,7 +81,7 @@ public function get_items( $request ) { */ public function prepare_item_for_response( $item, $request ) { $fields = $this->get_fields_for_response( $request ); - $keys = array( 'name', 'label', 'description', 'id' ); + $keys = array( 'name', 'label', 'description' ); $data = array(); foreach ( $keys as $key ) { if ( isset( $item[ $key ] ) && rest_is_field_included( $key, $fields ) ) { @@ -79,6 +89,11 @@ public function prepare_item_for_response( $item, $request ) { } } + // For backwards compatibility we only want to include the id if the field is explicitly requested. + if ( rest_is_field_included( 'id', $fields ) && isset( $item['id'] ) ) { + $data['id'] = $item['id']; + } + $context = ! empty( $request['context'] ) ? $request['context'] : 'view'; $data = $this->add_additional_fields_to_object( $data, $request ); $data = $this->filter_response_by_context( $data, $context ); @@ -123,10 +138,10 @@ public function get_item_schema() { 'context' => array( 'view', 'edit', 'embed' ), ), 'id' => array( - 'id' => __( 'An optional category id, currently used to provide id for user wp_pattern_category terms' ), - 'type' => 'number', - 'readonly' => true, - 'context' => array( 'view', 'edit', 'embed' ), + 'description' => __( 'An optional category id, currently used to provide id for user wp_pattern_category terms' ), + 'type' => 'number', + 'readonly' => true, + 'context' => array( 'view', 'edit', 'embed' ), ), ), ); @@ -135,4 +150,32 @@ public function get_item_schema() { return $this->add_additional_fields_schema( $this->schema ); } + + /** + * Retrieves the search parameters for the block pattern categories. + * + * @since 6.5.0 Added to request. + * + * @return array Collection parameters. + */ + public function get_collection_params() { + $query_params = parent::get_collection_params(); + + $query_params['source'] = array( + 'description' => __( 'Limit result set to comments assigned to specific sources, `core` or `user`' ), + 'type' => 'array', + 'items' => array( + 'type' => 'string', + ), + ); + + /** + * Filter collection parameters for the block pattern categories controller. + * + * @since 5.8.0 + * + * @param array $query_params JSON Schema-formatted collection parameters. + */ + return apply_filters( 'rest_pattern_directory_collection_params', $query_params ); + } } diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 548ad71664b5e6..2185b017509ec0 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2277,12 +2277,15 @@ const checkAllowListRecursive = ( blocks, allowedBlockTypes ) => { function getUserPatterns( state ) { const userPatterns = state?.settings?.__experimentalReusableBlocks ?? EMPTY_ARRAY; - const userPatternCategories = - state?.settings?.__experimentalUserPatternCategories ?? []; + const patternCategories = + state?.settings?.__experimentalBlockPatternCategories ?? []; const categories = new Map(); - userPatternCategories.forEach( ( userCategory ) => - categories.set( userCategory.id, userCategory ) - ); + patternCategories.forEach( ( category ) => { + if ( category.id ) { + categories.set( category.id, category ); + } + } ); + return userPatterns.map( ( userPattern ) => { return { name: `core/block/${ userPattern.id }`, @@ -2290,7 +2293,7 @@ function getUserPatterns( state ) { title: userPattern.title.raw, categories: userPattern.wp_pattern_category.map( ( catId ) => categories && categories.get( catId ) - ? categories.get( catId ).slug + ? categories.get( catId ).name : catId ), content: userPattern.content.raw, diff --git a/packages/core-data/README.md b/packages/core-data/README.md index ef5d9c1197f099..ae6cbd9b15a31c 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -679,6 +679,18 @@ _Returns_ - `any`: The entity record's save error. +### getPatternCategories + +Retrieve the core and user pattern categories. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Array< unknown >`: User patterns category array. + ### getRawEntityRecord Returns the entity's record object by key, with its attributes mapped to their raw values. diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index a21623d8ba89d3..11e9e05df10b68 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -543,6 +543,14 @@ export function userPatternCategories( state = [], action ) { return state; } +export function patternCategories( state = [], action ) { + switch ( action.type ) { + case 'RECEIVE_PATTERN_CATEGORIES': + return action.patternCategories; + } + return state; +} + export function navigationFallbackId( state = null, action ) { switch ( action.type ) { case 'RECEIVE_NAVIGATION_FALLBACK_ID': @@ -611,6 +619,7 @@ export default combineReducers( { blockPatterns, blockPatternCategories, userPatternCategories, + patternCategories, navigationFallbackId, defaultTemplates, } ); diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index cd2a65a60b0139..3ad428601c5092 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -668,6 +668,21 @@ export const getUserPatternCategories = } ); }; +export const getPatternCategories = + () => + async ( { dispatch } ) => { + const patternCategories = await apiFetch( { + path: addQueryArgs( '/wp/v2/block-patterns/categories', { + _fields: 'name,label,description, id', + source: [ 'core', 'user' ], + } ), + } ); + dispatch( { + type: 'RECEIVE_PATTERN_CATEGORIES', + patternCategories, + } ); + }; + export const getNavigationFallbackId = () => async ( { dispatch, select } ) => { diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 2a046941611c7d..8a274e3dd4b76a 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -47,6 +47,7 @@ export interface State { navigationFallbackId: EntityRecordKey; userPatternCategories: Array< UserPatternCategory >; defaultTemplates: Record< string, string >; + patternCategories: Array< unknown >; } type EntityRecordKey = string | number; @@ -1339,6 +1340,18 @@ export function getUserPatternCategories( return state.userPatternCategories; } +/** + * Retrieve the core and user pattern categories. + * + * @param state Data state. + * + * @return User patterns category array. + */ + +export function getPatternCategories( state: State ): Array< unknown > { + return state.patternCategories; +} + /** * Returns the revisions of the current global styles theme. * diff --git a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js index c02630c6f1f6ac..f13364ea4a1c28 100644 --- a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js +++ b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js @@ -42,7 +42,7 @@ export default function DeleteCategoryMenuItem( { category, onClose } ) { // Prevent the need to refresh the page to get up-to-date categories // and pattern categorization. - invalidateResolution( 'getBlockPatternCategories' ); + invalidateResolution( 'getPatternCategories' ); invalidateResolution( 'getEntityRecords', [ 'postType', PATTERN_TYPES.user, diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js index 822b4fe1587f73..e7f11da38be5e1 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js @@ -163,7 +163,7 @@ export default function PatternCategories( { post } ) { const newTerm = await saveEntityRecord( 'taxonomy', slug, term, { throwOnError: true, } ); - invalidateResolution( 'getBlockPatternCategories' ); + invalidateResolution( 'getPatternCategories' ); return unescapeTerm( newTerm ); } catch ( error ) { if ( error.code !== 'term_exists' ) { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js index 4e1e9ec6a11aa8..b6a5a7948ea8a2 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js @@ -41,13 +41,12 @@ export default function usePatternDetails( postType, postId ) { select( editorStore ).__experimentalGetDefaultTemplatePartAreas(), [] ); - const { currentTheme, userPatternCategories } = useSelect( ( select ) => { - const { getCurrentTheme, getUserPatternCategories } = - select( coreStore ); + const { currentTheme, patternCategories } = useSelect( ( select ) => { + const { getCurrentTheme, getPatternCategories } = select( coreStore ); return { currentTheme: getCurrentTheme(), - userPatternCategories: getUserPatternCategories(), + patternCategories: getPatternCategories(), }; }, [] ); @@ -105,14 +104,16 @@ export default function usePatternDetails( postType, postId ) { } ); } if ( record.wp_pattern_category?.length > 0 ) { - const patternCategories = new Map(); - userPatternCategories.forEach( ( userCategory ) => + const patternCategoriesMap = new Map(); + patternCategories.forEach( ( userCategory ) => patternCategories.set( userCategory.id, userCategory ) ); const categories = record.wp_pattern_category - .filter( ( category ) => patternCategories.get( category ) ) - .map( ( category ) => patternCategories.get( category ).label ); + .filter( ( category ) => patternCategoriesMap.get( category ) ) + .map( + ( category ) => patternCategoriesMap.get( category ).label + ); details.push( { label: __( 'Categories' ), diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js index 014d0e2e65b0ce..1e8adbcebb6374 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js @@ -22,7 +22,7 @@ export default function useDefaultPatternCategories() { } ); const restBlockPatternCategories = useSelect( ( select ) => - select( coreStore ).getBlockPatternCategories() + select( coreStore ).getPatternCategories() ); return [ diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index c0804febab0db5..52b86cd4267ff0 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -97,7 +97,6 @@ function useBlockEditorSettings( settings, postType, postId ) { userCanCreatePages, pageOnFront, pageForPosts, - userPatternCategories, } = useSelect( ( select ) => { const isWeb = Platform.OS === 'web'; @@ -105,7 +104,6 @@ function useBlockEditorSettings( settings, postType, postId ) { canUser, getRawEntityRecord, getEntityRecord, - getUserPatternCategories, getEntityRecords, } = select( coreStore ); @@ -128,7 +126,6 @@ function useBlockEditorSettings( settings, postType, postId ) { userCanCreatePages: canUser( 'create', 'pages' ), pageOnFront: siteSettings?.page_on_front, pageForPosts: siteSettings?.page_for_posts, - userPatternCategories: getUserPatternCategories(), }; }, [ postType, postId ] @@ -145,7 +142,7 @@ function useBlockEditorSettings( settings, postType, postId ) { ( select ) => ( { restBlockPatterns: select( coreStore ).getBlockPatterns(), restBlockPatternCategories: - select( coreStore ).getBlockPatternCategories(), + select( coreStore ).getPatternCategories(), } ), [] ); @@ -218,7 +215,6 @@ function useBlockEditorSettings( settings, postType, postId ) { __experimentalReusableBlocks: reusableBlocks, __experimentalBlockPatterns: blockPatterns, __experimentalBlockPatternCategories: blockPatternCategories, - __experimentalUserPatternCategories: userPatternCategories, __experimentalFetchLinkSuggestions: ( search, searchOptions ) => fetchLinkSuggestions( search, searchOptions, settings ), inserterMediaCategories, @@ -242,7 +238,6 @@ function useBlockEditorSettings( settings, postType, postId ) { settings, hasUploadPermissions, reusableBlocks, - userPatternCategories, blockPatterns, blockPatternCategories, canUseUnfilteredHTML, diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 378d495081f4c5..65975b2ef031d5 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -49,9 +49,9 @@ export default function CreatePatternModal( { const { createErrorNotice } = useDispatch( noticesStore ); const patternCategories = useSelect( ( select ) => { - const { getBlockPatternCategories } = select( coreStore ); + const { getPatternCategories } = select( coreStore ); - return getBlockPatternCategories(); + return getPatternCategories(); } ); async function onCreate( patternTitle, sync ) { @@ -110,7 +110,7 @@ export default function CreatePatternModal( { termData, { throwOnError: true } ); - invalidateResolution( 'getBlockPatternCategories' ); + invalidateResolution( 'getPatternCategories' ); return newTerm.id; } catch ( error ) { if ( error.code !== 'term_exists' ) { diff --git a/packages/patterns/src/components/duplicate-pattern-modal.js b/packages/patterns/src/components/duplicate-pattern-modal.js index baf977a7b27e2f..4271e251fb3be1 100644 --- a/packages/patterns/src/components/duplicate-pattern-modal.js +++ b/packages/patterns/src/components/duplicate-pattern-modal.js @@ -15,14 +15,14 @@ import { PATTERN_SYNC_TYPES } from '../constants'; function getTermLabels( pattern, categories ) { // Theme patterns don't have an id and rely on core pattern categories. if ( ! pattern.id ) { - return categories.core + return categories ?.filter( ( category ) => pattern.categories.includes( category.name ) ) .map( ( category ) => category.label ); } - return categories.user + return categories ?.filter( ( category ) => pattern.wp_pattern_category.includes( category.id ) ) @@ -36,13 +36,9 @@ export default function DuplicatePatternModal( { } ) { const { createSuccessNotice } = useDispatch( noticesStore ); const categories = useSelect( ( select ) => { - const { getUserPatternCategories, getBlockPatternCategories } = - select( coreStore ); + const { getPatternCategories } = select( coreStore ); - return { - core: getBlockPatternCategories(), - user: getUserPatternCategories(), - }; + return getPatternCategories(); } ); if ( ! pattern ) { diff --git a/packages/patterns/src/components/rename-pattern-category-modal.js b/packages/patterns/src/components/rename-pattern-category-modal.js index e0e0b36f180cad..7f44f63daa3d89 100644 --- a/packages/patterns/src/components/rename-pattern-category-modal.js +++ b/packages/patterns/src/components/rename-pattern-category-modal.js @@ -101,7 +101,7 @@ export default function RenamePatternCategoryModal( { } ); - invalidateResolution( 'getBlockPatternCategories' ); + invalidateResolution( 'getPatternCategories' ); onSuccess?.( savedRecord ); onClose(); From 3a4d6c8aa041b07277437454f0da00d26107395c Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Mon, 6 Nov 2023 14:41:38 +1300 Subject: [PATCH 06/12] fix bug with adding new categories in site editor --- .../components/page-patterns/use-patterns.js | 17 +++++++++-------- .../use-pattern-details.js | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 9cb6c8b998c412..10862ead87db2f 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -192,7 +192,7 @@ const patternBlockToPattern = ( patternBlock, categories ) => ( { categories: patternBlock.wp_pattern_category.map( ( patternCategoryId ) => categories && categories.get( patternCategoryId ) - ? categories.get( patternCategoryId ).slug + ? categories.get( patternCategoryId ).name : patternCategoryId ), } ), @@ -211,7 +211,7 @@ const patternBlockToPattern = ( patternBlock, categories ) => ( { const selectUserPatterns = createSelector( ( select, syncStatus, search = '' ) => { - const { getEntityRecords, getIsResolving, getUserPatternCategories } = + const { getEntityRecords, getIsResolving, getPatternCategories } = select( coreStore ); const query = { per_page: -1 }; @@ -220,11 +220,13 @@ const selectUserPatterns = createSelector( PATTERN_TYPES.user, query ); - const userPatternCategories = getUserPatternCategories(); + const patternCategories = getPatternCategories(); const categories = new Map(); - userPatternCategories.forEach( ( userCategory ) => - categories.set( userCategory.id, userCategory ) - ); + patternCategories.forEach( ( category ) => { + if ( category.id ) { + categories.set( category.id, category ); + } + } ); let patterns = records ? records.map( ( record ) => patternBlockToPattern( record, categories ) @@ -249,11 +251,10 @@ const selectUserPatterns = createSelector( // to be in the category. hasCategory: () => true, } ); - return { patterns, isResolving, - categories: userPatternCategories, + categories: patternCategories, }; }, ( select ) => [ diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js index b6a5a7948ea8a2..efa121768d0521 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js @@ -106,7 +106,7 @@ export default function usePatternDetails( postType, postId ) { if ( record.wp_pattern_category?.length > 0 ) { const patternCategoriesMap = new Map(); patternCategories.forEach( ( userCategory ) => - patternCategories.set( userCategory.id, userCategory ) + patternCategoriesMap.set( userCategory.id, userCategory ) ); const categories = record.wp_pattern_category From 3a2c12085da74abd8aec1d5c807afc8b9ffb5b54 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 09:59:17 +1300 Subject: [PATCH 07/12] Fix lint issue --- lib/compat/wordpress-6.5/rest-api.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.5/rest-api.php b/lib/compat/wordpress-6.5/rest-api.php index 75e38a0f2f3748..2f41bdd0a1d2e9 100644 --- a/lib/compat/wordpress-6.5/rest-api.php +++ b/lib/compat/wordpress-6.5/rest-api.php @@ -19,7 +19,7 @@ function gutenberg_register_global_styles_revisions_endpoints() { } add_action( 'rest_api_init', 'gutenberg_register_global_styles_revisions_endpoints' ); -/** +/** * Registers the block pattern categories REST API routes. */ function gutenberg_register_rest_block_pattern_categories_routes() { From de4003642698dcdfc848898da0e54bbd1136d592 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 10:13:43 +1300 Subject: [PATCH 08/12] Rename from getPatternCategories to getAllPatternCategories --- docs/reference-guides/data/data-core.md | 24 +++++++++---------- packages/core-data/README.md | 24 +++++++++---------- packages/core-data/src/reducer.js | 8 +++---- packages/core-data/src/resolvers.js | 8 +++---- packages/core-data/src/selectors.ts | 6 ++--- .../delete-category-menu-item.js | 2 +- .../components/page-patterns/use-patterns.js | 4 ++-- .../template-panel/pattern-categories.js | 2 +- .../use-pattern-details.js | 5 ++-- .../use-default-pattern-categories.js | 2 +- .../provider/use-block-editor-settings.js | 2 +- .../src/components/create-pattern-modal.js | 6 ++--- .../src/components/duplicate-pattern-modal.js | 4 ++-- .../rename-pattern-category-modal.js | 2 +- 14 files changed, 50 insertions(+), 49 deletions(-) diff --git a/docs/reference-guides/data/data-core.md b/docs/reference-guides/data/data-core.md index b074eb36ddedba..b7864b30c5fe4e 100644 --- a/docs/reference-guides/data/data-core.md +++ b/docs/reference-guides/data/data-core.md @@ -44,6 +44,18 @@ _Returns_ - `boolean | undefined`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. +### getAllPatternCategories + +Retrieve the core and user pattern categories. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Array< unknown >`: User patterns category array. + ### getAuthors > **Deprecated** since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead. @@ -372,18 +384,6 @@ _Returns_ - `any`: The entity record's save error. -### getPatternCategories - -Retrieve the core and user pattern categories. - -_Parameters_ - -- _state_ `State`: Data state. - -_Returns_ - -- `Array< unknown >`: User patterns category array. - ### getRawEntityRecord Returns the entity's record object by key, with its attributes mapped to their raw values. diff --git a/packages/core-data/README.md b/packages/core-data/README.md index ae6cbd9b15a31c..3f7d1fd32ce2c9 100644 --- a/packages/core-data/README.md +++ b/packages/core-data/README.md @@ -351,6 +351,18 @@ _Returns_ - `boolean | undefined`: Whether or not the user can edit, or `undefined` if the OPTIONS request is still being made. +### getAllPatternCategories + +Retrieve the core and user pattern categories. + +_Parameters_ + +- _state_ `State`: Data state. + +_Returns_ + +- `Array< unknown >`: User patterns category array. + ### getAuthors > **Deprecated** since 11.3. Callers should use `select( 'core' ).getUsers({ who: 'authors' })` instead. @@ -679,18 +691,6 @@ _Returns_ - `any`: The entity record's save error. -### getPatternCategories - -Retrieve the core and user pattern categories. - -_Parameters_ - -- _state_ `State`: Data state. - -_Returns_ - -- `Array< unknown >`: User patterns category array. - ### getRawEntityRecord Returns the entity's record object by key, with its attributes mapped to their raw values. diff --git a/packages/core-data/src/reducer.js b/packages/core-data/src/reducer.js index 11e9e05df10b68..807d1c77094ff6 100644 --- a/packages/core-data/src/reducer.js +++ b/packages/core-data/src/reducer.js @@ -543,10 +543,10 @@ export function userPatternCategories( state = [], action ) { return state; } -export function patternCategories( state = [], action ) { +export function allPatternCategories( state = [], action ) { switch ( action.type ) { - case 'RECEIVE_PATTERN_CATEGORIES': - return action.patternCategories; + case 'RECEIVE_ALL_PATTERN_CATEGORIES': + return action.allPatternCategories; } return state; } @@ -619,7 +619,7 @@ export default combineReducers( { blockPatterns, blockPatternCategories, userPatternCategories, - patternCategories, + allPatternCategories, navigationFallbackId, defaultTemplates, } ); diff --git a/packages/core-data/src/resolvers.js b/packages/core-data/src/resolvers.js index 3ad428601c5092..b280f86e45dba3 100644 --- a/packages/core-data/src/resolvers.js +++ b/packages/core-data/src/resolvers.js @@ -668,18 +668,18 @@ export const getUserPatternCategories = } ); }; -export const getPatternCategories = +export const getAllPatternCategories = () => async ( { dispatch } ) => { - const patternCategories = await apiFetch( { + const allPatternCategories = await apiFetch( { path: addQueryArgs( '/wp/v2/block-patterns/categories', { _fields: 'name,label,description, id', source: [ 'core', 'user' ], } ), } ); dispatch( { - type: 'RECEIVE_PATTERN_CATEGORIES', - patternCategories, + type: 'RECEIVE_ALL_PATTERN_CATEGORIES', + allPatternCategories, } ); }; diff --git a/packages/core-data/src/selectors.ts b/packages/core-data/src/selectors.ts index 8a274e3dd4b76a..60c08615f7edfd 100644 --- a/packages/core-data/src/selectors.ts +++ b/packages/core-data/src/selectors.ts @@ -47,7 +47,7 @@ export interface State { navigationFallbackId: EntityRecordKey; userPatternCategories: Array< UserPatternCategory >; defaultTemplates: Record< string, string >; - patternCategories: Array< unknown >; + allPatternCategories: Array< unknown >; } type EntityRecordKey = string | number; @@ -1348,8 +1348,8 @@ export function getUserPatternCategories( * @return User patterns category array. */ -export function getPatternCategories( state: State ): Array< unknown > { - return state.patternCategories; +export function getAllPatternCategories( state: State ): Array< unknown > { + return state.allPatternCategories; } /** diff --git a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js index f13364ea4a1c28..ef9ae0551521dd 100644 --- a/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js +++ b/packages/edit-site/src/components/page-patterns/delete-category-menu-item.js @@ -42,7 +42,7 @@ export default function DeleteCategoryMenuItem( { category, onClose } ) { // Prevent the need to refresh the page to get up-to-date categories // and pattern categorization. - invalidateResolution( 'getPatternCategories' ); + invalidateResolution( 'getAllPatternCategories' ); invalidateResolution( 'getEntityRecords', [ 'postType', PATTERN_TYPES.user, diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 10862ead87db2f..7d29fe43a887ae 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -211,7 +211,7 @@ const patternBlockToPattern = ( patternBlock, categories ) => ( { const selectUserPatterns = createSelector( ( select, syncStatus, search = '' ) => { - const { getEntityRecords, getIsResolving, getPatternCategories } = + const { getEntityRecords, getIsResolving, getAllPatternCategories } = select( coreStore ); const query = { per_page: -1 }; @@ -220,7 +220,7 @@ const selectUserPatterns = createSelector( PATTERN_TYPES.user, query ); - const patternCategories = getPatternCategories(); + const patternCategories = getAllPatternCategories(); const categories = new Map(); patternCategories.forEach( ( category ) => { if ( category.id ) { diff --git a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js index e7f11da38be5e1..0ccd0e8ddd3277 100644 --- a/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-edit-mode/template-panel/pattern-categories.js @@ -163,7 +163,7 @@ export default function PatternCategories( { post } ) { const newTerm = await saveEntityRecord( 'taxonomy', slug, term, { throwOnError: true, } ); - invalidateResolution( 'getPatternCategories' ); + invalidateResolution( 'getAllPatternCategories' ); return unescapeTerm( newTerm ); } catch ( error ) { if ( error.code !== 'term_exists' ) { diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js index efa121768d0521..6f5cee3aeabd84 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-pattern/use-pattern-details.js @@ -42,11 +42,12 @@ export default function usePatternDetails( postType, postId ) { [] ); const { currentTheme, patternCategories } = useSelect( ( select ) => { - const { getCurrentTheme, getPatternCategories } = select( coreStore ); + const { getCurrentTheme, getAllPatternCategories } = + select( coreStore ); return { currentTheme: getCurrentTheme(), - patternCategories: getPatternCategories(), + patternCategories: getAllPatternCategories(), }; }, [] ); diff --git a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js index 1e8adbcebb6374..3605ba6d5b7b35 100644 --- a/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js +++ b/packages/edit-site/src/components/sidebar-navigation-screen-patterns/use-default-pattern-categories.js @@ -22,7 +22,7 @@ export default function useDefaultPatternCategories() { } ); const restBlockPatternCategories = useSelect( ( select ) => - select( coreStore ).getPatternCategories() + select( coreStore ).getAllPatternCategories() ); return [ diff --git a/packages/editor/src/components/provider/use-block-editor-settings.js b/packages/editor/src/components/provider/use-block-editor-settings.js index 52b86cd4267ff0..3bf49991d5f18a 100644 --- a/packages/editor/src/components/provider/use-block-editor-settings.js +++ b/packages/editor/src/components/provider/use-block-editor-settings.js @@ -142,7 +142,7 @@ function useBlockEditorSettings( settings, postType, postId ) { ( select ) => ( { restBlockPatterns: select( coreStore ).getBlockPatterns(), restBlockPatternCategories: - select( coreStore ).getPatternCategories(), + select( coreStore ).getAllPatternCategories(), } ), [] ); diff --git a/packages/patterns/src/components/create-pattern-modal.js b/packages/patterns/src/components/create-pattern-modal.js index 65975b2ef031d5..17b80c0461bbac 100644 --- a/packages/patterns/src/components/create-pattern-modal.js +++ b/packages/patterns/src/components/create-pattern-modal.js @@ -49,9 +49,9 @@ export default function CreatePatternModal( { const { createErrorNotice } = useDispatch( noticesStore ); const patternCategories = useSelect( ( select ) => { - const { getPatternCategories } = select( coreStore ); + const { getAllPatternCategories } = select( coreStore ); - return getPatternCategories(); + return getAllPatternCategories(); } ); async function onCreate( patternTitle, sync ) { @@ -110,7 +110,7 @@ export default function CreatePatternModal( { termData, { throwOnError: true } ); - invalidateResolution( 'getPatternCategories' ); + invalidateResolution( 'getAllPatternCategories' ); return newTerm.id; } catch ( error ) { if ( error.code !== 'term_exists' ) { diff --git a/packages/patterns/src/components/duplicate-pattern-modal.js b/packages/patterns/src/components/duplicate-pattern-modal.js index 4271e251fb3be1..e9e3387f27fc8d 100644 --- a/packages/patterns/src/components/duplicate-pattern-modal.js +++ b/packages/patterns/src/components/duplicate-pattern-modal.js @@ -36,9 +36,9 @@ export default function DuplicatePatternModal( { } ) { const { createSuccessNotice } = useDispatch( noticesStore ); const categories = useSelect( ( select ) => { - const { getPatternCategories } = select( coreStore ); + const { getAllPatternCategories } = select( coreStore ); - return getPatternCategories(); + return getAllPatternCategories(); } ); if ( ! pattern ) { diff --git a/packages/patterns/src/components/rename-pattern-category-modal.js b/packages/patterns/src/components/rename-pattern-category-modal.js index 7f44f63daa3d89..274e079e599f8b 100644 --- a/packages/patterns/src/components/rename-pattern-category-modal.js +++ b/packages/patterns/src/components/rename-pattern-category-modal.js @@ -101,7 +101,7 @@ export default function RenamePatternCategoryModal( { } ); - invalidateResolution( 'getPatternCategories' ); + invalidateResolution( 'getAllPatternCategories' ); onSuccess?.( savedRecord ); onClose(); From be3c9bd0a2d57aec3f80b4c6e35a0a897c69c409 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 10:52:27 +1300 Subject: [PATCH 09/12] Make sure selector refreshes when categories update --- packages/block-editor/src/store/selectors.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/block-editor/src/store/selectors.js b/packages/block-editor/src/store/selectors.js index 2185b017509ec0..6154e254d4357d 100644 --- a/packages/block-editor/src/store/selectors.js +++ b/packages/block-editor/src/store/selectors.js @@ -2330,7 +2330,7 @@ export const __experimentalGetParsedPattern = createSelector( ( state ) => [ state.settings.__experimentalBlockPatterns, state.settings.__experimentalReusableBlocks, - state?.settings?.__experimentalUserPatternCategories, + state.settings.__experimentalBlockPatternCategories, ] ); @@ -2355,7 +2355,7 @@ const getAllAllowedPatterns = createSelector( state.settings.__experimentalBlockPatterns, state.settings.__experimentalReusableBlocks, state.settings.allowedBlockTypes, - state?.settings?.__experimentalUserPatternCategories, + state.settings.__experimentalBlockPatternCategories, ] ); @@ -2382,6 +2382,7 @@ export const __experimentalGetAllowedPatterns = createSelector( ( state, rootClientId ) => [ state.settings.__experimentalBlockPatterns, state.settings.__experimentalReusableBlocks, + state.settings.__experimentalBlockPatternCategories, state.settings.allowedBlockTypes, state.settings.templateLock, state.blockListSettings[ rootClientId ], From 9012906238e1d211037f72bbe38f0014d6343a1c Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 11:15:23 +1300 Subject: [PATCH 10/12] Fix undefined index error --- ...class-gutenberg-rest-block-pattern-categories-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index 6d6161d6f8ae59..5eea1f8f0168da 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -40,7 +40,7 @@ public function get_items( $request ) { ) ); - if ( is_array( $query_args['source'] ) && in_array( 'user', $query_args['source'], true ) ) { + if ( isset( $query_args['source'] ) && is_array( $query_args['source'] ) && in_array( 'user', $query_args['source'], true ) ) { foreach ( $user_categories as $user_category ) { $prepared_category = $this->prepare_item_for_response( array( From f3bd021c0e3f7ae7ed167dd5799dbacbb2f3c696 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 11:59:41 +1300 Subject: [PATCH 11/12] Fix broken test --- ...class-gutenberg-rest-block-pattern-categories-controller.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php index 5eea1f8f0168da..1ac1cd89cd1676 100644 --- a/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php +++ b/lib/compat/wordpress-6.5/class-gutenberg-rest-block-pattern-categories-controller.php @@ -58,7 +58,7 @@ public function get_items( $request ) { if ( ! isset( $query_args['source'] ) || in_array( 'core', $query_args['source'], true ) ) { foreach ( $categories as $category ) { - if ( in_array( $category['label'], $unique_categories, true ) || 'query' === $category['name'] ) { + if ( in_array( $category['label'], $unique_categories, true ) ) { continue; } $prepared_category = $this->prepare_item_for_response( $category, $request ); From 343f7bc755159d3fe0e8fbe781e27f27d8ab6032 Mon Sep 17 00:00:00 2001 From: Glen Davies Date: Tue, 14 Nov 2023 12:33:26 +1300 Subject: [PATCH 12/12] Fix dependency --- packages/edit-site/src/components/page-patterns/use-patterns.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/edit-site/src/components/page-patterns/use-patterns.js b/packages/edit-site/src/components/page-patterns/use-patterns.js index 7d29fe43a887ae..a47ee55c0c1f35 100644 --- a/packages/edit-site/src/components/page-patterns/use-patterns.js +++ b/packages/edit-site/src/components/page-patterns/use-patterns.js @@ -266,7 +266,7 @@ const selectUserPatterns = createSelector( PATTERN_TYPES.user, { per_page: -1 }, ] ), - select( coreStore ).getUserPatternCategories(), + select( coreStore ).getAllPatternCategories(), ] );