diff --git a/docs/designers-developers/developers/block-api/block-patterns.md b/docs/designers-developers/developers/block-api/block-patterns.md index 9587628c6b29c..9d06a01cb1098 100644 --- a/docs/designers-developers/developers/block-api/block-patterns.md +++ b/docs/designers-developers/developers/block-api/block-patterns.md @@ -4,15 +4,19 @@ Patterns are predefined block layouts, ready to insert and tweak. **Note** Patterns are still under heavy development and the APIs are subject to change. -#### register_block_pattern +## Patterns Registration + +### register_block_pattern The editor comes with a list of built-in patterns. Theme and plugin authors can register addition custom patterns using the `register_block_pattern` function. The `register_block_pattern` function receives the name of the pattern as the first argument and an array describing properties of the pattern as the second argument. -The properties of the style array must include `name` and `label`: - - `title`: A human-readable title for the pattern. - - `content`: Raw HTML content for the pattern. +The properties of the pattern include: + - `title` (required): A human-readable title for the pattern. + - `content` (required): Raw HTML content for the pattern. + - `categories`: A list of pattern categories used to group patterns. Patterns can be shown on multiple categories. + - `keywords`: Aliases or keywords that help users discover it while searching. ```php register_block_pattern( @@ -24,7 +28,7 @@ register_block_pattern( ); ``` -#### unregister_block_pattern +### unregister_block_pattern `unregister_block_pattern` allows unregistering a pattern previously registered on the server using `register_block_pattern`. @@ -35,3 +39,33 @@ The following code sample unregisters the style named 'my-plugin/my-awesome-patt ```php unregister_block_pattern( 'my-plugin/my-awesome-pattern' ); ``` + +## Pattern Categories + +Patterns can be grouped using categories. The block editor comes with bundled categories you can use on your custom patterns. You can also register your own pattern categories. + +### register_block_pattern_category + +The `register_block_pattern_category` function receives the name of the category as the first argument and an array describing properties of the category as the second argument. + +The properties of the pattern categories include: + - `label` (required): A human-readable label for the pattern category. + +```php +register_block_pattern_category( + 'hero', + array( 'label' => __( 'Hero', 'my-plugin' ) ) +); +``` + +### unregister_block_pattern_category + +`unregister_block_pattern_category` allows unregistering a pattern category. + +The function's argument is the name of the pattern category to unregister. + +The following code sample unregisters the category named 'hero': + +```php +unregister_block_pattern_category( 'hero' ); +``` diff --git a/lib/class-wp-block-pattern-categories-registry.php b/lib/class-wp-block-pattern-categories-registry.php new file mode 100644 index 0000000000000..157f00ae24f56 --- /dev/null +++ b/lib/class-wp-block-pattern-categories-registry.php @@ -0,0 +1,139 @@ +registered_categories[ $category_name ] = array_merge( + array( 'name' => $category_name ), + $category_properties + ); + + return true; + } + + /** + * Unregisters a pattern category. + * + * @param string $category_name Pattern name including namespace. + * @return boolean True if the pattern was unregistered with success and false otherwise. + */ + public function unregister( $category_name ) { + if ( ! $this->is_registered( $category_name ) ) { + /* translators: 1: Block pattern name. */ + $message = sprintf( __( 'Block pattern category "%1$s" not found.', 'gutenberg' ), $category_name ); + _doing_it_wrong( __METHOD__, $message, '8.1.0' ); + return false; + } + + unset( $this->registered_categories[ $category_name ] ); + + return true; + } + + /** + * Retrieves an array containing the properties of a registered pattern category. + * + * @param string $category_name Pattern category name. + * @return array Registered pattern properties. + */ + public function get_registered( $category_name ) { + if ( ! $this->is_registered( $category_name ) ) { + return null; + } + + return $this->registered_categories[ $category_name ]; + } + + /** + * Retrieves all registered pattern categories. + * + * @return array Array of arrays containing the registered pattern categories properties. + */ + public function get_all_registered() { + return array_values( $this->registered_categories ); + } + + /** + * Checks if a pattern category is registered. + * + * @param string $category_name Pattern category name. + * @return bool True if the pattern category is registered, false otherwise. + */ + public function is_registered( $category_name ) { + return isset( $this->registered_categories[ $category_name ] ); + } + + /** + * Utility method to retrieve the main instance of the class. + * + * The instance will be created if it does not exist yet. + * + * @since 5.3.0 + * + * @return WP_Block_Pattern_Categories_Registry The main instance. + */ + public static function get_instance() { + if ( null === self::$instance ) { + self::$instance = new self(); + } + + return self::$instance; + } +} + +/** + * Registers a new pattern category. + * + * @param string $category_name Pattern category name. + * @param array $category_properties Array containing the properties of the category. + * + * @return boolean True if the pattern category was registered with success and false otherwise. + */ +function register_block_pattern_category( $category_name, $category_properties ) { + return WP_Block_Pattern_Categories_Registry::get_instance()->register( $category_name, $category_properties ); +} + +/** + * Unregisters a pattern category. + * + * @param string $category_name Pattern category name including namespace. + * + * @return boolean True if the pattern category was unregistered with success and false otherwise. + */ +function unregister_block_pattern_category( $category_name ) { + return WP_Block_Pattern_Categories_Registry::get_instance()->unregister( $category_name ); +} diff --git a/lib/client-assets.php b/lib/client-assets.php index 5427ee3abfdf3..e53a05a2f64ff 100644 --- a/lib/client-assets.php +++ b/lib/client-assets.php @@ -649,6 +649,15 @@ function gutenberg_extend_settings_block_patterns( $settings ) { $settings['__experimentalBlockPatterns'] ); + if ( empty( $settings['__experimentalBlockPatternCategories'] ) ) { + $settings['__experimentalBlockPatternCategories'] = array(); + } + + $settings['__experimentalBlockPatternCategories'] = array_merge( + WP_Block_Pattern_Categories_Registry::get_instance()->get_all_registered(), + $settings['__experimentalBlockPatternCategories'] + ); + return $settings; } add_filter( 'block_editor_settings', 'gutenberg_extend_settings_block_patterns', 0 ); @@ -695,3 +704,16 @@ function gutenberg_extend_settings_custom_units( $settings ) { register_block_pattern( 'core/hero-right-column', gutenberg_load_block_pattern( 'hero-right-column' ) ); register_block_pattern( 'core/testimonials', gutenberg_load_block_pattern( 'testimonials' ) ); } + +/* + * Register default pattern categories if not registered in Core already. + */ +if ( class_exists( 'WP_Block_Pattern_Categories_Registry' ) ) { + register_block_pattern_category( 'text', array( 'label' => __( 'Text', 'gutenberg' ) ) ); + register_block_pattern_category( 'hero', array( 'label' => __( 'Hero', 'gutenberg' ) ) ); + register_block_pattern_category( 'columns', array( 'label' => __( 'Columns', 'gutenberg' ) ) ); + register_block_pattern_category( 'buttons', array( 'label' => __( 'Buttons', 'gutenberg' ) ) ); + register_block_pattern_category( 'gallery', array( 'label' => __( 'Gallery', 'gutenberg' ) ) ); + register_block_pattern_category( 'features', array( 'label' => __( 'Features', 'gutenberg' ) ) ); + register_block_pattern_category( 'testimonials', array( 'label' => __( 'Testimonials', 'gutenberg' ) ) ); +} diff --git a/lib/load.php b/lib/load.php index e0dbcd56431a8..71f5c0191068b 100644 --- a/lib/load.php +++ b/lib/load.php @@ -63,6 +63,10 @@ function gutenberg_is_experiment_enabled( $name ) { require dirname( __FILE__ ) . '/class-wp-block-patterns-registry.php'; } +if ( ! class_exists( 'WP_Block_Pattern_Categories_Registry' ) ) { + require dirname( __FILE__ ) . '/class-wp-block-pattern-categories-registry.php'; +} + if ( ! class_exists( 'WP_Block' ) ) { require dirname( __FILE__ ) . '/class-wp-block.php'; } diff --git a/lib/patterns/cover-abc.php b/lib/patterns/cover-abc.php index b2a50cadcdd33..c8fc8fa6a7e1c 100644 --- a/lib/patterns/cover-abc.php +++ b/lib/patterns/cover-abc.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Cover', 'gutenberg' ), - 'content' => "\n
\n

" . _x( 'abc!', 'pattern', 'gutenberg' ) . "

\n
\n", + 'title' => __( 'Cover', 'gutenberg' ), + 'categories' => array( 'hero' ), + 'content' => "\n
\n

" . _x( 'abc!', 'pattern', 'gutenberg' ) . "

\n
\n", ); diff --git a/lib/patterns/hero-right-column.php b/lib/patterns/hero-right-column.php index 19bf4e44fee4f..a392cbfce2398 100644 --- a/lib/patterns/hero-right-column.php +++ b/lib/patterns/hero-right-column.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Hero Right Column', 'gutenberg' ), - 'content' => "\n
\n
\n
\n

Easy & Accessible

\n
\n
\n\n\n\n
\n
\n\n\n\n
\n
\n\n\n\n

Extend it with over 54,000 plugins to help your website meet your needs. Hundreds of thousands of developers and site owners trust it worldwide. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n

Hundreds of thousands of developers and site owners trust it worldwide. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n
\n\n\n\n\n
\n
\n
\n", + 'title' => __( 'Hero Right Column', 'gutenberg' ), + 'categories' => array( 'hero', 'columns' ), + 'content' => "\n
\n
\n
\n

Easy & Accessible

\n
\n
\n\n\n\n
\n
\n\n\n\n
\n
\n\n\n\n

Extend it with over 54,000 plugins to help your website meet your needs. Hundreds of thousands of developers and site owners trust it worldwide. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n

Hundreds of thousands of developers and site owners trust it worldwide. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n
\n\n\n\n\n
\n
\n
\n", ); diff --git a/lib/patterns/hero-two-columns.php b/lib/patterns/hero-two-columns.php index c23b8456a5d79..24e9850c42c24 100644 --- a/lib/patterns/hero-two-columns.php +++ b/lib/patterns/hero-two-columns.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Hero Two Columns', 'gutenberg' ), - 'content' => "\n
\n

Enjoy a wide variety of

\n\n\n\n

Custom Designs

\n\n\n\n
\n
\n

Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more. Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n\n\n\n
\n

Hundreds of thousands of developers and site owners trust it worldwide. Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n
\n
\n
\n", + 'title' => __( 'Hero Two Columns', 'gutenberg' ), + 'categories' => array( 'columns' ), + 'content' => "\n
\n

Enjoy a wide variety of

\n\n\n\n

Custom Designs

\n\n\n\n
\n
\n

Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more. Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n\n\n\n
\n

Hundreds of thousands of developers and site owners trust it worldwide. Extend it with over 54,000 plugins to help your website meet your needs. Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n
\n
\n
\n", ); diff --git a/lib/patterns/its-time.php b/lib/patterns/its-time.php index 8f927f8d376c0..7291b3594b336 100644 --- a/lib/patterns/its-time.php +++ b/lib/patterns/its-time.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'It\'s time', 'gutenberg' ), - 'content' => "\n
\n
\n
\n

NEW

\n\n\n\n

John Lenwood \"Jackie\" McLean was an American jazz alto saxophonist, composer, bandleader, and educator, and is one of the few musicians to be elected to the DownBeat Hall of Fame in the year of their death.

\n
\n\n\n\n
\n

space

\n\n\n\n

Derek Ansell's full-length biography of McLean, Sugar Free Saxophone (London: Northway Books, 2012), details the story of his career and provides a full analysis of his music on record.

\n
\n
\n\n\n\n
\n
\n\n\n\n
\n

it's time

\n
\n
\n
\n", + 'title' => __( 'It\'s time', 'gutenberg' ), + 'categories' => array( 'text', 'columns' ), + 'content' => "\n
\n
\n
\n

NEW

\n\n\n\n

John Lenwood \"Jackie\" McLean was an American jazz alto saxophonist, composer, bandleader, and educator, and is one of the few musicians to be elected to the DownBeat Hall of Fame in the year of their death.

\n
\n\n\n\n
\n

space

\n\n\n\n

Derek Ansell's full-length biography of McLean, Sugar Free Saxophone (London: Northway Books, 2012), details the story of his career and provides a full analysis of his music on record.

\n
\n
\n\n\n\n
\n
\n\n\n\n
\n

it's time

\n
\n
\n
\n", ); diff --git a/lib/patterns/numbered-features.php b/lib/patterns/numbered-features.php index ab6b1a7371900..84d461efd1445 100644 --- a/lib/patterns/numbered-features.php +++ b/lib/patterns/numbered-features.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Numbered Features', 'gutenberg' ), - 'content' => "\n
\n
\n
\n
\n

1

\n
\n\n\n\n
\n

Custom Designs

\n\n\n\n

Extend it with over 54,000 plugins to help your website meet your needs.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

2

\n
\n\n\n\n
\n

High Performance

\n\n\n\n

Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

3

\n
\n\n\n\n
\n

Easy and Accessible

\n\n\n\n

Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n
\n
\n
\n", + 'title' => __( 'Numbered Features', 'gutenberg' ), + 'categories' => array( 'features' ), + 'content' => "\n
\n
\n
\n
\n

1

\n
\n\n\n\n
\n

Custom Designs

\n\n\n\n

Extend it with over 54,000 plugins to help your website meet your needs.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

2

\n
\n\n\n\n
\n

High Performance

\n\n\n\n

Add an online store, galleries, mailing lists, forums, analytics, and much more.

\n\n\n\n
\n
\n
\n
\n\n\n\n
\n
\n
\n

3

\n
\n\n\n\n
\n

Easy and Accessible

\n\n\n\n

Hundreds of thousands of developers and site owners trust it worldwide.

\n
\n
\n
\n
\n", ); diff --git a/lib/patterns/testimonials.php b/lib/patterns/testimonials.php index 504ece83ea7e8..1288d5eec14e4 100644 --- a/lib/patterns/testimonials.php +++ b/lib/patterns/testimonials.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Testimonials', 'gutenberg' ), - 'content' => "\n
\n
\n
\n
\n

\"This software is designed for everyone, emphasizing accessibility, performance, security, and ease of use.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Doris Som

\n
\n
\n
\n\n\n\n
\n
\n

\"We believe great software should work with minimum set up, so you can focus on sharing your story, or services freely.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Walt Art

\n
\n
\n
\n\n\n\n
\n
\n

\"The product is simple and predictable so you can easily get started. It also offers powerful features for success.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Moly Neo

\n
\n
\n
\n
\n
\n", + 'title' => __( 'Testimonials', 'gutenberg' ), + 'categories' => array( 'testimonials' ), + 'content' => "\n
\n
\n
\n
\n

\"This software is designed for everyone, emphasizing accessibility, performance, security, and ease of use.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Doris Som

\n
\n
\n
\n\n\n\n
\n
\n

\"We believe great software should work with minimum set up, so you can focus on sharing your story, or services freely.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Walt Art

\n
\n
\n
\n\n\n\n
\n
\n

\"The product is simple and predictable so you can easily get started. It also offers powerful features for success.\"

\n
\n\n\n\n
\n
\n
\"\"/
\n
\n\n\n\n
\n

Moly Neo

\n
\n
\n
\n
\n
\n", ); diff --git a/lib/patterns/text-two-columns.php b/lib/patterns/text-two-columns.php index 0df940ba26e47..ad297deb29745 100644 --- a/lib/patterns/text-two-columns.php +++ b/lib/patterns/text-two-columns.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Two Columns of Text', 'gutenberg' ), - 'content' => "\n
\n
\n

CHAPTER 1. Loomings

\n\n\n\n

Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation.

\n
\n\n\n\n
\n

Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can.

\n
\n
\n", + 'title' => __( 'Two Columns of Text', 'gutenberg' ), + 'categories' => array( 'columns', 'text' ), + 'content' => "\n
\n
\n

CHAPTER 1. Loomings

\n\n\n\n

Call me Ishmael. Some years ago—never mind how long precisely—having little or no money in my purse, and nothing particular to interest me on shore, I thought I would sail about a little and see the watery part of the world. It is a way I have of driving off the spleen and regulating the circulation.

\n
\n\n\n\n
\n

Whenever I find myself growing grim about the mouth; whenever it is a damp, drizzly November in my soul; whenever I find myself involuntarily pausing before coffin warehouses, and bringing up the rear of every funeral I meet; and especially whenever my hypos get such an upper hand of me, that it requires a strong moral principle to prevent me from deliberately stepping into the street, and methodically knocking people’s hats off—then, I account it high time to get to sea as soon as I can.

\n
\n
\n", ); diff --git a/lib/patterns/two-buttons.php b/lib/patterns/two-buttons.php index 377c58c43da4c..ff434b858782d 100644 --- a/lib/patterns/two-buttons.php +++ b/lib/patterns/two-buttons.php @@ -9,4 +9,5 @@ 'title' => __( 'Two Buttons', 'gutenberg' ), 'content' => "\n
\n
Button One
\n\n\n\n
Button Two
\n
\n", 'viewportWidth' => 500, + 'categories' => array( 'buttons' ), ); diff --git a/lib/patterns/two-images.php b/lib/patterns/two-images.php index f4ef009d97f83..a998d86f2fc86 100644 --- a/lib/patterns/two-images.php +++ b/lib/patterns/two-images.php @@ -6,6 +6,7 @@ */ return array( - 'title' => __( 'Two images side by side', 'gutenberg' ), - 'content' => "\n\n", + 'title' => __( 'Two images side by side', 'gutenberg' ), + 'categories' => array( 'gallery' ), + 'content' => "\n\n", ); diff --git a/packages/block-editor/src/components/inserter/block-patterns.js b/packages/block-editor/src/components/inserter/block-patterns.js index bed321dcd348a..58def74eb93b1 100644 --- a/packages/block-editor/src/components/inserter/block-patterns.js +++ b/packages/block-editor/src/components/inserter/block-patterns.js @@ -8,7 +8,7 @@ import { map } from 'lodash'; */ import { useMemo, useCallback } from '@wordpress/element'; import { parse, cloneBlock } from '@wordpress/blocks'; -import { useDispatch } from '@wordpress/data'; +import { useDispatch, useSelect } from '@wordpress/data'; import { ENTER, SPACE } from '@wordpress/keycodes'; import { __, sprintf, _x } from '@wordpress/i18n'; @@ -21,6 +21,35 @@ import InserterPanel from './panel'; import { searchItems } from './search-items'; import InserterNoResults from './no-results'; +const usePatternsState = ( onInsert ) => { + const { patternCategories, patterns } = useSelect( ( select ) => { + const { + __experimentalBlockPatterns, + __experimentalBlockPatternCategories, + } = select( 'core/block-editor' ).getSettings(); + return { + patterns: __experimentalBlockPatterns, + patternCategories: __experimentalBlockPatternCategories, + }; + }, [] ); + const { createSuccessNotice } = useDispatch( 'core/notices' ); + const onClickPattern = useCallback( ( pattern, blocks ) => { + onInsert( map( blocks, ( block ) => cloneBlock( block ) ) ); + createSuccessNotice( + sprintf( + /* translators: %s: block pattern title. */ + __( 'Pattern "%s" inserted.' ), + pattern.title + ), + { + type: 'snackbar', + } + ); + }, [] ); + + return [ patterns, patternCategories, onClickPattern ]; +}; + function BlockPattern( { pattern, onClick } ) { const { content, viewportWidth } = pattern; const blocks = useMemo( () => parse( content ), [ content ] ); @@ -52,49 +81,130 @@ function BlockPatternPlaceholder() { ); } -function BlockPatterns( { patterns, onInsert, filterValue } ) { +function BlockPatternList( { patterns, shownPatterns, onClickPattern } ) { + return patterns.map( ( pattern ) => { + const isShown = shownPatterns.includes( pattern ); + return isShown ? ( + + ) : ( + + ); + } ); +} + +function BlockPatternsSearchResults( { filterValue, onInsert } ) { + const [ patterns, , onClick ] = usePatternsState( onInsert ); + const currentShownPatterns = useAsyncList( patterns ); + const filteredPatterns = useMemo( () => searchItems( patterns, filterValue ), [ filterValue, patterns ] ); - const currentShownPatterns = useAsyncList( filteredPatterns ); - const { createSuccessNotice } = useDispatch( 'core/notices' ); - const onClickPattern = useCallback( ( pattern, blocks ) => { - onInsert( map( blocks, ( block ) => cloneBlock( block ) ) ); - createSuccessNotice( - sprintf( - /* translators: %s: block pattern title. */ - __( 'Pattern "%s" inserted.' ), - pattern.title - ), - { - type: 'snackbar', - } + + if ( filterValue ) { + return !! filteredPatterns.length ? ( + + + + ) : ( + ); - }, [] ); + } +} - return !! filteredPatterns.length ? ( - { + if ( ! pattern.categories || ! pattern.categories.length ) { + return Infinity; } - > - { filteredPatterns.map( ( pattern, index ) => - currentShownPatterns[ index ] === pattern ? ( - - ) : ( - + const indexedCategories = Object.fromEntries( + categories.map( ( { name }, index ) => [ name, index ] ) + ); + return Math.min( + ...pattern.categories.map( ( category ) => + indexedCategories[ category ] !== undefined + ? indexedCategories[ category ] + : Infinity ) + ); + }, + [ categories ] + ); + + // Ordering the patterns per category is important for the async rendering. + const orderedPatterns = useMemo( () => { + return patterns.sort( ( a, b ) => { + return getPatternIndex( a ) - getPatternIndex( b ); + } ); + }, [ patterns, getPatternIndex ] ); + + const currentShownPatterns = useAsyncList( orderedPatterns ); + + // Uncategorized Patterns + const uncategorizedPatterns = useMemo( + () => + patterns.filter( + ( pattern ) => getPatternIndex( pattern ) === Infinity + ), + [ patterns, getPatternIndex ] + ); + + return ( + <> + { categories.map( ( patternCategory ) => { + const categoryPatterns = patterns.filter( + ( pattern ) => + pattern.categories && + pattern.categories.includes( patternCategory.name ) + ); + return ( + !! categoryPatterns.length && ( + + + + ) + ); + } ) } + + { !! uncategorizedPatterns.length && ( + + + ) } - + + ); +} + +function BlockPatterns( { onInsert, filterValue } ) { + return filterValue ? ( + ) : ( - + ); } diff --git a/packages/block-editor/src/components/inserter/menu.js b/packages/block-editor/src/components/inserter/menu.js index 3d9864fc14a3e..a1811e85dba6a 100644 --- a/packages/block-editor/src/components/inserter/menu.js +++ b/packages/block-editor/src/components/inserter/menu.js @@ -36,44 +36,47 @@ function InserterMenu( { const [ hoveredItem, setHoveredItem ] = useState( null ); const { destinationRootClientId, - patterns, + hasPatterns, getSelectedBlock, getBlockIndex, getBlockSelectionEnd, getBlockOrder, - } = useSelect( ( select ) => { - const { - getSettings, - getBlockRootClientId, - getBlockSelectionEnd: _getBlockSelectionEnd, - } = select( 'core/block-editor' ); + } = useSelect( + ( select ) => { + const { + getSettings, + getBlockRootClientId, + getBlockSelectionEnd: _getBlockSelectionEnd, + } = select( 'core/block-editor' ); - let destRootClientId = rootClientId; - if ( ! destRootClientId && ! clientId && ! isAppender ) { - const end = _getBlockSelectionEnd(); - if ( end ) { - destRootClientId = getBlockRootClientId( end ) || undefined; + let destRootClientId = rootClientId; + if ( ! destRootClientId && ! clientId && ! isAppender ) { + const end = _getBlockSelectionEnd(); + if ( end ) { + destRootClientId = getBlockRootClientId( end ) || undefined; + } } - } - return { - patterns: getSettings().__experimentalBlockPatterns, - destinationRootClientId: destRootClientId, - ...pick( select( 'core/block-editor' ), [ - 'getSelectedBlock', - 'getBlockIndex', - 'getBlockSelectionEnd', - 'getBlockOrder', - ] ), - }; - }, [] ); + return { + hasPatterns: !! getSettings().__experimentalBlockPatterns + ?.length, + destinationRootClientId: destRootClientId, + ...pick( select( 'core/block-editor' ), [ + 'getSelectedBlock', + 'getBlockIndex', + 'getBlockSelectionEnd', + 'getBlockOrder', + ] ), + }; + }, + [ isAppender, clientId, rootClientId ] + ); const { replaceBlocks, insertBlocks, showInsertionPoint, hideInsertionPoint, } = useDispatch( 'core/block-editor' ); - const hasPatterns = - ! destinationRootClientId && !! patterns && !! patterns.length; + const showPatterns = ! destinationRootClientId && hasPatterns; const onKeyDown = ( event ) => { if ( includes( @@ -163,7 +166,6 @@ function InserterMenu( { const patternsTab = (
@@ -184,7 +186,7 @@ function InserterMenu( { >
- { hasPatterns && ( + { showPatterns && ( ) } - { ! hasPatterns && blocksTab } + { ! showPatterns && blocksTab }
{ showInserterHelpPanel && hoveredItem && (
diff --git a/packages/editor/src/components/provider/index.js b/packages/editor/src/components/provider/index.js index 2868759b6b0d9..142d6725a88e8 100644 --- a/packages/editor/src/components/provider/index.js +++ b/packages/editor/src/components/provider/index.js @@ -113,6 +113,7 @@ class EditorProvider extends Component { ...pick( settings, [ '__experimentalBlockDirectory', '__experimentalBlockPatterns', + '__experimentalBlockPatternCategories', '__experimentalDisableCustomUnits', '__experimentalDisableCustomLineHeight', '__experimentalDisableDropCap',