From 6a04d57b280490ec1a33c168c3f3f47603b08161 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9?= <583546+oandregal@users.noreply.github.com> Date: Tue, 10 Oct 2023 19:28:20 +0200 Subject: [PATCH 01/32] Set status as no sortable (#55210) --- packages/edit-site/src/components/page-pages/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/edit-site/src/components/page-pages/index.js b/packages/edit-site/src/components/page-pages/index.js index 6ee6c8bc1bace..56575248453f0 100644 --- a/packages/edit-site/src/components/page-pages/index.js +++ b/packages/edit-site/src/components/page-pages/index.js @@ -116,6 +116,7 @@ export default function PagePages() { id: 'status', accessorFn: ( page ) => postStatuses[ page.status ] ?? page.status, + enableSorting: false, }, { header: { __( 'Actions' ) }, From da3d90b6e5a3c9b3bd7a6b0b37e332638662896e Mon Sep 17 00:00:00 2001 From: Matias Benedetto Date: Tue, 10 Oct 2023 16:45:34 -0300 Subject: [PATCH 02/32] Use all the settings origins for a block that consumes paths with merge. (#55219) Co-authored-by: Jason Crist <146530+pbking@users.noreply.github.com> --- packages/block-editor/src/components/use-setting/index.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/block-editor/src/components/use-setting/index.js b/packages/block-editor/src/components/use-setting/index.js index c1222c9116ae6..1ae672103015c 100644 --- a/packages/block-editor/src/components/use-setting/index.js +++ b/packages/block-editor/src/components/use-setting/index.js @@ -189,7 +189,12 @@ export default function useSetting( path ) { // Return if the setting was found in either the block instance or the store. if ( result !== undefined ) { if ( PATHS_WITH_MERGE[ normalizedPath ] ) { - return result.custom ?? result.theme ?? result.default; + return [ 'default', 'theme', 'custom' ].reduce( + ( acc, key ) => { + return acc.concat( result[ key ] ?? [] ); + }, + [] + ); } return result; } From 8d26e5d60c6f509c5a5944161084dfe618398abd Mon Sep 17 00:00:00 2001 From: Jeff Ong Date: Tue, 10 Oct 2023 17:23:00 -0400 Subject: [PATCH 03/32] Font Library: show error if fetching collection fails (#54919) * Throw and render error if fetching font collections fail. * use the existing notice state to dispay the error --------- Co-authored-by: Matias Benedetto --- .../font-library-modal/context.js | 28 +++++++++++-------- .../font-library-modal/font-collection.js | 28 ++++++++++++------- 2 files changed, 35 insertions(+), 21 deletions(-) diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/context.js b/packages/edit-site/src/components/global-styles/font-library-modal/context.js index 8ab067495fcc0..33a5b0910f052 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/context.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/context.js @@ -323,17 +323,23 @@ function FontLibraryProvider( { children } ) { setFontCollections( response ); }; const getFontCollection = async ( id ) => { - const hasData = !! collections.find( - ( collection ) => collection.id === id - )?.data; - if ( hasData ) return; - const response = await fetchFontCollection( id ); - const updatedCollections = collections.map( ( collection ) => - collection.id === id - ? { ...collection, data: { ...response?.data } } - : collection - ); - setFontCollections( updatedCollections ); + try { + const hasData = !! collections.find( + ( collection ) => collection.id === id + )?.data; + if ( hasData ) return; + const response = await fetchFontCollection( id ); + const updatedCollections = collections.map( ( collection ) => + collection.id === id + ? { ...collection, data: { ...response?.data } } + : collection + ); + setFontCollections( updatedCollections ); + } catch ( e ) { + // eslint-disable-next-line no-console + console.error( e ); + throw e; + } }; useEffect( () => { diff --git a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js index a3b697efcfb8b..61de80838f637 100644 --- a/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js +++ b/packages/edit-site/src/components/global-styles/font-library-modal/font-collection.js @@ -72,20 +72,32 @@ function FontCollection( { id } ) { }, [ id, requiresPermission ] ); useEffect( () => { - getFontCollection( id ); - resetFilters(); + const fetchFontCollection = async () => { + try { + await getFontCollection( id ); + resetFilters(); + } catch ( e ) { + setNotice( { + type: 'error', + message: e?.message, + duration: 0, // Don't auto-hide. + } ); + } + }; + fetchFontCollection(); }, [ id, getFontCollection ] ); useEffect( () => { setSelectedFont( null ); + setNotice( null ); }, [ id ] ); // Reset notice after 5 seconds useEffect( () => { - if ( notice ) { + if ( notice && notice?.duration !== 0 ) { const timeout = setTimeout( () => { setNotice( null ); - }, 5000 ); + }, notice.duration ?? 5000 ); return () => clearTimeout( timeout ); } }, [ notice ] ); @@ -167,10 +179,6 @@ function FontCollection( { id } ) { ) } - { ! renderConfirmDialog && ! selectedCollection.data && ( - - ) } - { notice && ( <> @@ -227,9 +235,9 @@ function FontCollection( { id } ) { ) } - { ! renderConfirmDialog && - ! selectedCollection?.data?.fontFamilies && } + ! selectedCollection?.data?.fontFamilies && + ! notice && } { ! renderConfirmDialog && !! selectedCollection?.data?.fontFamilies?.length && From cf3b27f199512e08c17f07b093957a656f9b081b Mon Sep 17 00:00:00 2001 From: Dennis Snell Date: Tue, 10 Oct 2023 13:42:24 -0700 Subject: [PATCH 04/32] HTML API: Backup updates from Core - add `has_class()` and `class_list()` methods [#59209-trac](https://core.trac.wordpress.org/ticket/59209) - add `matches_breadcrumbs()` method [#59400-trac](https://core.trac.wordpress.org/ticket/59400) - rename `createFramgent()` to `create_fragment()` [#59547-trac](https://core.trac.wordpress.org/ticket/59547) --- ...class-gutenberg-html-tag-processor-6-4.php | 147 +++++++++++------- .../html-api/class-wp-html-processor.php | 88 ++++++++--- 2 files changed, 154 insertions(+), 81 deletions(-) diff --git a/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php b/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php index 7a87bddd7f1f7..13f0ec5fad479 100644 --- a/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php +++ b/lib/compat/wordpress-6.4/html-api/class-gutenberg-html-tag-processor-6-4.php @@ -626,6 +626,94 @@ public function next_tag( $query = null ) { } + /** + * Generator for a foreach loop to step through each class name for the matched tag. + * + * This generator function is designed to be used inside a "foreach" loop. + * + * Example: + * + * $p = new WP_HTML_Tag_Processor( "
" ); + * $p->next_tag(); + * foreach ( $p->class_list() as $class_name ) { + * echo "{$class_name} "; + * } + * // Outputs: "free lang-en " + * + * @since 6.4.0 + */ + public function class_list() { + /** @var string $class contains the string value of the class attribute, with character references decoded. */ + $class = $this->get_attribute( 'class' ); + + if ( ! is_string( $class ) ) { + return; + } + + $seen = array(); + + $at = 0; + while ( $at < strlen( $class ) ) { + // Skip past any initial boundary characters. + $at += strspn( $class, " \t\f\r\n", $at ); + if ( $at >= strlen( $class ) ) { + return; + } + + // Find the byte length until the next boundary. + $length = strcspn( $class, " \t\f\r\n", $at ); + if ( 0 === $length ) { + return; + } + + /* + * CSS class names are case-insensitive in the ASCII range. + * + * @see https://www.w3.org/TR/CSS2/syndata.html#x1 + */ + $name = strtolower( substr( $class, $at, $length ) ); + $at += $length; + + /* + * It's expected that the number of class names for a given tag is relatively small. + * Given this, it is probably faster overall to scan an array for a value rather + * than to use the class name as a key and check if it's a key of $seen. + */ + if ( in_array( $name, $seen, true ) ) { + continue; + } + + $seen[] = $name; + yield $name; + } + } + + + /** + * Returns if a matched tag contains the given ASCII case-insensitive class name. + * + * @since 6.4.0 + * + * @param string $wanted_class Look for this CSS class name, ASCII case-insensitive. + * @return bool|null Whether the matched tag contains the given class name, or null if not matched. + */ + public function has_class( $wanted_class ) { + if ( ! $this->tag_name_starts_at ) { + return null; + } + + $wanted_class = strtolower( $wanted_class ); + + foreach ( $this->class_list() as $class_name ) { + if ( $class_name === $wanted_class ) { + return true; + } + } + + return false; + } + + /** * Sets a bookmark in the HTML document. * @@ -2347,64 +2435,7 @@ private function matches() { } } - $needs_class_name = null !== $this->sought_class_name; - - if ( $needs_class_name && ! isset( $this->attributes['class'] ) ) { - return false; - } - - /* - * Match byte-for-byte (case-sensitive and encoding-form-sensitive) on the class name. - * - * This will overlook certain classes that exist in other lexical variations - * than was supplied to the search query, but requires more complicated searching. - */ - if ( $needs_class_name ) { - $class_start = $this->attributes['class']->value_starts_at; - $class_end = $class_start + $this->attributes['class']->value_length; - $class_at = $class_start; - - /* - * Ensure that boundaries surround the class name to avoid matching on - * substrings of a longer name. For example, the sequence "not-odd" - * should not match for the class "odd" even though "odd" is found - * within the class attribute text. - * - * See https://html.spec.whatwg.org/#attributes-3 - * See https://html.spec.whatwg.org/#space-separated-tokens - */ - while ( - // phpcs:ignore WordPress.CodeAnalysis.AssignmentInCondition.FoundInWhileCondition - false !== ( $class_at = strpos( $this->html, $this->sought_class_name, $class_at ) ) && - $class_at < $class_end - ) { - /* - * Verify this class starts at a boundary. - */ - if ( $class_at > $class_start ) { - $character = $this->html[ $class_at - 1 ]; - - if ( ' ' !== $character && "\t" !== $character && "\f" !== $character && "\r" !== $character && "\n" !== $character ) { - $class_at += strlen( $this->sought_class_name ); - continue; - } - } - - /* - * Verify this class ends at a boundary as well. - */ - if ( $class_at + strlen( $this->sought_class_name ) < $class_end ) { - $character = $this->html[ $class_at + strlen( $this->sought_class_name ) ]; - - if ( ' ' !== $character && "\t" !== $character && "\f" !== $character && "\r" !== $character && "\n" !== $character ) { - $class_at += strlen( $this->sought_class_name ); - continue; - } - } - - return true; - } - + if ( null !== $this->sought_class_name && ! $this->has_class( $this->sought_class_name ) ) { return false; } diff --git a/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php b/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php index 2e4b5a47589e8..e53e64c80e2e0 100644 --- a/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php +++ b/lib/compat/wordpress-6.4/html-api/class-wp-html-processor.php @@ -43,7 +43,7 @@ * * Example: * - * $processor = WP_HTML_Processor::createFragment( $html ); + * $processor = WP_HTML_Processor::create_fragment( $html ); * if ( $processor->next_tag( array( 'breadcrumbs' => array( 'DIV', 'FIGURE', 'IMG' ) ) ) ) { * $processor->add_class( 'responsive-image' ); * } @@ -62,7 +62,7 @@ * Since all elements find themselves inside a full HTML document * when parsed, the return value from `get_breadcrumbs()` will always * contain any implicit outermost elements. For example, when parsing - * with `createFragment()` in the `BODY` context (the default), any + * with `create_fragment()` in the `BODY` context (the default), any * tag in the given HTML document will contain `array( 'HTML', 'BODY', … )` * in its breadcrumbs. * @@ -243,7 +243,7 @@ class WP_HTML_Processor extends Gutenberg_HTML_Tag_Processor_6_4 { * @param string $encoding Text encoding of the document; must be default of 'UTF-8'. * @return WP_HTML_Processor|null The created processor if successful, otherwise null. */ - public static function createFragment( $html, $context = '', $encoding = 'UTF-8' ) { + public static function create_fragment( $html, $context = '', $encoding = 'UTF-8' ) { if ( '' !== $context || 'UTF-8' !== $encoding ) { return null; } @@ -284,7 +284,7 @@ public static function createFragment( $html, $context = '', $encoding = ' * * @since 6.4.0 * - * @see WP_HTML_Processor::createFragment() + * @see WP_HTML_Processor::create_fragment() * * @param string $html HTML to process. * @param string|null $use_the_static_create_methods_instead This constructor should not be called manually. @@ -296,9 +296,9 @@ public function __construct( $html, $use_the_static_create_methods_instead = nul _doing_it_wrong( __METHOD__, sprintf( - /* translators: %s: WP_HTML_Processor::createFragment. */ + /* translators: %s: WP_HTML_Processor::create_fragment(). */ __( 'Call %s to create an HTML Processor instead of calling the constructor directly.' ), - 'WP_HTML_Processor::createFragment' + 'WP_HTML_Processor::create_fragment()' ), '6.4.0' ); @@ -328,7 +328,7 @@ public function __construct( $html, $use_the_static_create_methods_instead = nul * * Example * - * $processor = WP_HTML_Processor::createFragment( '