From c32435a79d89417cac4f45ede7859d6dca4c4580 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 14 Jul 2026 19:47:07 +0200 Subject: [PATCH 001/138] HTML API: Add failing duplicate removal tests --- .../tests/html-api/wpHtmlTagProcessor.php | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php index 84d90a84190fc..a628c34ea0e74 100644 --- a/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php +++ b/tests/phpunit/tests/html-api/wpHtmlTagProcessor.php @@ -1354,6 +1354,93 @@ public function test_remove_attribute_with_duplicated_attributes_removes_all_of_ $this->assertNull( $processor->get_attribute( $attribute_to_remove ), 'Failed to remove all copies of duplicated attributes when getting updated HTML.' ); } + /** + * @covers WP_HTML_Tag_Processor::remove_attribute + * @covers WP_HTML_Tag_Processor::seek + * + * @dataProvider data_remove_attribute_with_duplicated_attributes_is_idempotent + * + * @param string $html HTML containing duplicated attributes and a later PATH tag. + * @param string $tag_name Name of the tag containing the duplicated attributes. + * @param string|null $expected_html Expected HTML after one removal, or null to use the actual result. + */ + public function test_remove_attribute_with_duplicated_attributes_is_idempotent( $html, $tag_name, $expected_html ) { + $single_removal = new WP_HTML_Tag_Processor( $html ); + $this->assertTrue( $single_removal->next_tag( $tag_name ), 'Failed to find the tag containing duplicated attributes.' ); + $this->assertTrue( $single_removal->remove_attribute( 'a' ), 'Failed to remove the attribute.' ); + $single_removal_html = $single_removal->get_updated_html(); + if ( null !== $expected_html ) { + $this->assertSame( $expected_html, $single_removal_html, 'Removing duplicated attributes once produced unexpected HTML.' ); + } + + $processor = new WP_HTML_Tag_Processor( $html ); + $this->assertTrue( $processor->next_tag( $tag_name ), 'Failed to find the tag containing duplicated attributes.' ); + + $this->assertTrue( $processor->remove_attribute( 'a' ), 'Failed to remove the attribute.' ); + $this->assertTrue( $processor->remove_attribute( 'a' ), 'Failed to remove the attribute again.' ); + + $this->assertTrue( $processor->next_tag( 'path' ), 'Failed to find the PATH tag.' ); + $this->assertTrue( $processor->set_bookmark( 'path' ), 'Failed to set a bookmark on the PATH tag.' ); + + $this->assertSame( $single_removal_html, $processor->get_updated_html(), 'Removing duplicated attributes twice should have the same effect as removing them once.' ); + $this->assertTrue( $processor->seek( 'path' ), 'Failed to seek to the bookmark after removing duplicated attributes twice.' ); + $this->assertSame( 'PATH', $processor->get_tag(), 'The bookmark moved away from the bookmarked tag.' ); + $this->assertSame( 'x', $processor->get_attribute( 'id' ), 'The bookmark moved away from the bookmarked tag attributes.' ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_with_duplicated_attributes_is_idempotent() { + return array( + 'Duplicated attributes' => array( '
ok', 'div', '
ok' ), + 'Duplicate attribute after a solidus' => array( 'ok', 'g', null ), + ); + } + + /** + * @covers WP_HTML_Tag_Processor::remove_attribute + * @covers WP_HTML_Tag_Processor::seek + * + * @dataProvider data_remove_attribute_supersedes_enqueued_update_to_duplicate + * + * @param string $enqueued_text Text already enqueued over a duplicate attribute's span. + */ + public function test_remove_attribute_supersedes_enqueued_update_to_duplicate( $enqueued_text ) { + $processor = new class('ok') extends WP_HTML_Tag_Processor { + public function enqueue_replacement( int $start, int $length, string $text ): void { + $this->lexical_updates[] = new WP_HTML_Text_Replacement( $start, $length, $text ); + } + }; + $this->assertTrue( $processor->next_tag( 'g' ), 'Failed to find the tag containing duplicated attributes.' ); + + // Enqueue an update over the first duplicate "a", at offset 5. + $processor->enqueue_replacement( 5, 1, $enqueued_text ); + $this->assertTrue( $processor->remove_attribute( 'a' ), 'Failed to remove the attribute.' ); + + $this->assertTrue( $processor->next_tag( 'path' ), 'Failed to find the PATH tag.' ); + $this->assertTrue( $processor->set_bookmark( 'path' ), 'Failed to set a bookmark on the PATH tag.' ); + + $this->assertSame( 'ok', $processor->get_updated_html(), 'Removing the attribute produced unexpected HTML.' ); + $this->assertTrue( $processor->seek( 'path' ), 'Failed to seek to the bookmark after removing the attribute.' ); + $this->assertSame( 'PATH', $processor->get_tag(), 'The bookmark moved away from the bookmarked tag.' ); + $this->assertSame( 'x', $processor->get_attribute( 'id' ), 'The bookmark moved away from the bookmarked tag attributes.' ); + } + + /** + * Data provider. + * + * @return array[] + */ + public static function data_remove_attribute_supersedes_enqueued_update_to_duplicate() { + return array( + 'Already-enqueued removal' => array( '' ), + 'Already-enqueued replacement' => array( 'b' ), + ); + } + /** * @ticket 58119 * From 3943c29fecd52827ce9c40bf01dbfff4c9712aa6 Mon Sep 17 00:00:00 2001 From: Jon Surrell Date: Tue, 14 Jul 2026 19:49:15 +0200 Subject: [PATCH 002/138] HTML API: Make duplicate attribute removal idempotent --- .../html-api/class-wp-html-tag-processor.php | 25 +++++++++++++++---- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index ace3e14bea565..07ae17da061a5 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -4753,11 +4753,26 @@ public function remove_attribute( $name ): bool { // Removes any duplicated attributes if they were also present. foreach ( $this->duplicate_attributes[ $name ] ?? array() as $attribute_token ) { - $this->lexical_updates[] = new WP_HTML_Text_Replacement( - $attribute_token->start, - $attribute_token->length, - '' - ); + /* + * Each span may adjust cursor and bookmark positions only once, so + * removal supersedes an update already enqueued for the exact span. + */ + $has_update = false; + foreach ( $this->lexical_updates as $update ) { + if ( $attribute_token->start === $update->start && $attribute_token->length === $update->length ) { + $update->text = ''; + $has_update = true; + break; + } + } + + if ( ! $has_update ) { + $this->lexical_updates[] = new WP_HTML_Text_Replacement( + $attribute_token->start, + $attribute_token->length, + '' + ); + } } return true; From 2459eed5574683a94d17d499b8823d2d72a6427e Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Thu, 23 Jul 2026 15:33:51 +0000 Subject: [PATCH 003/138] Comments: allow the Notes @mention chip markup in comment content. The Notes @mention completer stores a mention as a non-interactive chip, `@Name`, the `user-N` class token carrying the mentioned user's ID. Fix an issue where the default comment kses allowlist does not permit `span`, so for users without the `unfiltered_html` capability the mention markup is stripped when the note is saved. See related Gutenberg pull requests: https://github.com/WordPress/gutenberg/pull/79604 and https://github.com/WordPress/gutenberg/pull/80528. Props mamaduka, westonruter, t-hamano, luisdavid01, vedantere. Fixes #65622. git-svn-id: https://develop.svn.wordpress.org/trunk@62832 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/default-filters.php | 5 + src/wp-includes/kses.php | 83 +++++++++++ tests/phpunit/tests/kses.php | 221 ++++++++++++++++++++++++++++ 3 files changed, 309 insertions(+) diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index d9a05c829646a..b2790c7d43ec9 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -310,6 +310,11 @@ add_action( 'check_comment_flood', 'check_comment_flood_db', 10, 4 ); add_filter( 'comment_flood_filter', 'wp_throttle_comment_flood', 10, 3 ); add_filter( 'pre_comment_content', 'wp_rel_ugc', 15 ); + +// Note mention chips in comment content: allow `span` through comment kses, +// then reduce its classes to the mention tokens right after `wp_filter_kses`. +add_filter( 'wp_kses_allowed_html', '_wp_kses_allow_note_mention_span', 10, 2 ); +add_filter( 'pre_comment_content', '_wp_kses_sanitize_note_mention_classes', 11 ); add_filter( 'comment_email', 'antispambot' ); add_filter( 'option_tag_base', '_wp_filter_taxonomy_base' ); add_filter( 'option_category_base', '_wp_filter_taxonomy_base' ); diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php index 37d457a3e18a2..46cd2c4576c03 100644 --- a/src/wp-includes/kses.php +++ b/src/wp-includes/kses.php @@ -1131,6 +1131,89 @@ function wp_kses_allowed_html( $context = '' ) { } } +/** + * Allows the note mention chip markup in comment content. + * + * The notes `@` mention completer stores a mention as a chip carrying the + * mentioned user's ID in a class token: + * `@Name`. The default comment + * allowlist does not allow `span` at all, so for users without + * `unfiltered_html` the mention would be stripped on save. + * + * The allowance is deliberately narrow and always on: `span` is a + * semantics-free element and _wp_kses_sanitize_note_mention_classes() + * reduces its `class` to the two mention tokens right after kses runs, so + * regular (including anonymous) commenters gain nothing beyond the inert + * mention markup itself. + * + * @since 7.1.0 + * @access private + * + * @param array> $allowed The allowed tags structure for the context. + * @param string $context The kses context. + * @return array> Modified allowed tags structure. + */ +function _wp_kses_allow_note_mention_span( $allowed, $context ): array { + if ( ! is_array( $allowed ) ) { + $allowed = array(); + } + if ( 'pre_comment_content' !== $context ) { + return $allowed; + } + + if ( ! isset( $allowed['span'] ) || ! is_array( $allowed['span'] ) ) { + $allowed['span'] = array(); + } + + $allowed['span']['class'] = true; + + return $allowed; +} + +/** + * Reduces `span` classes in comment content to the note mention tokens. + * + * _wp_kses_allow_note_mention_span() lets `class` through kses on `span` so + * the mention chip survives, but `class` is an open-ended styling and + * scripting hook, so this companion pass - running right after + * `wp_filter_kses` at priority 10 - strips every class token except the two + * the mention markup uses: `wp-note-mention` and `user-N`. `span` is the only + * comment tag allowed to carry `class` at all, so walking `span` tags covers + * the entire allowance. + * + * The pass only applies while the restrictive comment allowlist is active: + * users with `unfiltered_html` are filtered through `wp_filter_post_kses` + * (or not at all), where arbitrary classes are already permitted, and + * narrowing their markup here would restrict what core allows them to post. + * + * @since 7.1.0 + * @access private + * + * @param string $content Slashed comment content, already filtered by kses. + * @return string Slashed comment content with span classes reduced. + */ +function _wp_kses_sanitize_note_mention_classes( $content ): string { + if ( ! is_string( $content ) ) { + $content = ''; + } + if ( false === has_filter( 'pre_comment_content', 'wp_filter_kses' ) ) { + return $content; + } + + $processor = new WP_HTML_Tag_Processor( wp_unslash( $content ) ); + + while ( $processor->next_tag( 'SPAN' ) ) { + foreach ( $processor->class_list() as $token ) { + if ( 'wp-note-mention' !== $token && ! preg_match( '/^user-[1-9][0-9]*$/', $token ) ) { + // Removing the last class also removes the attribute itself. + $processor->remove_class( $token ); + } + } + } + + return wp_slash( $processor->get_updated_html() ); +} + /** * You add any KSES hooks here. * diff --git a/tests/phpunit/tests/kses.php b/tests/phpunit/tests/kses.php index 59353a2b7a20c..1afd7e0884a64 100644 --- a/tests/phpunit/tests/kses.php +++ b/tests/phpunit/tests/kses.php @@ -536,6 +536,227 @@ public function test_wp_kses_allowed_html() { $this->assertSame( $allowedtags, wp_kses_allowed_html( 'data' ) ); } + /** + * Tests that the comment content context allows only the mention span beyond the defaults. + * + * @ticket 65622 + * + * @covers ::_wp_kses_allow_note_mention_span + */ + public function test_wp_kses_allowed_html_pre_comment_content_allows_only_the_mention_span() { + global $allowedtags; + + $allowed = wp_kses_allowed_html( 'pre_comment_content' ); + + $this->assertSame( + array( 'class' => true ), + $allowed['span'], + 'The mention span should be allowed in comment content.' + ); + + unset( $allowed['span'] ); + $this->assertSame( + $allowedtags, + $allowed, + 'Nothing beyond the mention span should be allowed on top of the default comment tags.' + ); + } + + /** + * Tests that a note mention survives content sanitization of a `note` comment. + * + * @ticket 65622 + * + * @covers ::_wp_kses_allow_note_mention_span + * @covers ::_wp_kses_sanitize_note_mention_classes + */ + public function test_note_mention_markup_survives_note_content_sanitization() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + + $content = 'Hello @admin!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'note', $content ) ) ); + + remove_filter( 'pre_comment_content', 'wp_filter_kses' ); + + $this->assertSame( $content, wp_unslash( $filtered['comment_content'] ) ); + } + + /** + * Tests that the mention markup also survives in regular comment content. + * + * The allowance is always on rather than scoped per comment type: the + * mention markup is inert, so uniform sanitization avoids stateful + * arming and disarming of kses filters around each note write. + * + * @ticket 65622 + * + * @covers ::_wp_kses_allow_note_mention_span + * @covers ::_wp_kses_sanitize_note_mention_classes + */ + public function test_note_mention_markup_survives_regular_comment_content_sanitization() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + $content = 'Hello @admin!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'comment', $content ) ) ); + + $this->assertSame( $content, wp_unslash( $filtered['comment_content'] ) ); + } + + /** + * Tests that span classes are reduced to the two mention tokens. + * + * @ticket 65622 + * + * @covers ::_wp_kses_sanitize_note_mention_classes + */ + public function test_note_mention_span_classes_are_reduced_to_the_mention_tokens() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + $content = 'Hello @admin!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'note', $content ) ) ); + + $this->assertSame( + 'Hello @admin!', + wp_unslash( $filtered['comment_content'] ), + 'Class tokens beyond `wp-note-mention` and `user-N` should be stripped from spans.' + ); + } + + /** + * Tests that class tokens are reduced on spans regardless of tag-name casing. + * + * kses preserves tag-name casing, so the class reduction must match `SPAN` + * case-insensitively rather than bail on a `get_mention_commentdata( 'note', $content ) ) ); + + $this->assertEqualHTML( + 'Hello @admin!', + wp_unslash( $filtered['comment_content'] ), + '', + 'Class tokens should be reduced on spans regardless of tag-name casing.' + ); + } + + /** + * Tests that the class attribute is removed when no mention tokens remain. + * + * @ticket 65622 + * + * @covers ::_wp_kses_sanitize_note_mention_classes + */ + public function test_note_mention_class_attribute_removed_when_no_tokens_remain() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + $content = 'Hello there!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'comment', $content ) ) ); + + // Markup-equivalence assertion: the HTML API's whitespace handling + // when removing the final attribute is not part of its contract. + $this->assertEqualHTML( + 'Hello there!', + wp_unslash( $filtered['comment_content'] ), + '', + 'A span with no valid mention tokens should lose its class attribute entirely.' + ); + } + + /** + * Tests that only the `class` attribute is allowed on mention spans. + * + * @ticket 65622 + * + * @covers ::_wp_kses_allow_note_mention_span + */ + public function test_note_mention_allows_only_class_on_mention_spans() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + $content = 'Hello @admin!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'note', $content ) ) ); + + $this->assertSame( + 'Hello @admin!', + wp_unslash( $filtered['comment_content'] ), + 'Attributes beyond `class` should be stripped from spans.' + ); + } + + /** + * Tests that `class` is still stripped from links in comment content. + * + * @ticket 65622 + * + * @covers ::_wp_kses_allow_note_mention_span + */ + public function test_class_is_still_stripped_from_links_in_comment_content() { + add_filter( 'pre_comment_content', 'wp_filter_kses' ); + + /* + * The href is external to the test site so that wp_rel_ugc() - which + * applies to notes like any other comment - deterministically appends + * `rel="nofollow ugc"`. + */ + $content = 'Hello @admin!'; + $filtered = wp_filter_comment( wp_slash( $this->get_mention_commentdata( 'note', $content ) ) ); + + $this->assertSame( + 'Hello @admin!', + wp_unslash( $filtered['comment_content'] ), + 'The class allowance is scoped to spans; links keep the default sanitization.' + ); + } + + /** + * Tests that the class reduction is skipped while the restrictive comment kses is inactive. + * + * Users with `unfiltered_html` are filtered through `wp_filter_post_kses` + * (or not at all), where arbitrary classes are permitted; the mention + * class reduction must not narrow what they can post. + * + * @ticket 65622 + * + * @covers ::_wp_kses_sanitize_note_mention_classes + */ + public function test_note_mention_class_reduction_skipped_when_restrictive_kses_is_inactive() { + // kses_init() hooks wp_filter_kses by default in the test + // environment, so detach it to simulate the unfiltered_html setup. + // The test framework restores filters after each test. + remove_filter( 'pre_comment_content', 'wp_filter_kses' ); + + $content = 'Hello there!'; + + $this->assertSame( + wp_slash( $content ), + _wp_kses_sanitize_note_mention_classes( wp_slash( $content ) ), + 'Span classes should be left untouched when wp_filter_kses is not active.' + ); + } + + /** + * Builds a complete commentdata array for wp_filter_comment(). + * + * @param 'note'|'comment' $comment_type The comment type. + * @param string $content The comment content. + * @return array{ + * comment_content: string, + * ... + * } + */ + private function get_mention_commentdata( string $comment_type, string $content ): array { + return array( + 'comment_content' => $content, + 'comment_type' => $comment_type, + 'comment_author' => 'admin', + 'comment_author_IP' => '127.0.0.1', + 'comment_author_url' => 'http://example.org', + 'comment_author_email' => 'admin@example.org', + 'comment_agent' => '', + ); + } + public function test_hyphenated_tag() { $content = 'Alot of hyphens.'; $custom_tags = array( From b0e62d8e0ae405ab3f36a87d4181885e2de2e0e8 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 23 Jul 2026 16:18:56 +0000 Subject: [PATCH 004/138] Docs: Require view config filter callbacks to return the container. Corrects the get_entity_view_config_{$kind}_{$name} filter docblock: callbacks must return the container they receive. Also fixes a doubled "the" in the same paragraph. Follow-up to [62825]. Props jorgefilipecosta, oandregal. Fixes #65577. git-svn-id: https://develop.svn.wordpress.org/trunk@62833 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-view-config-data.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wp-includes/class-wp-view-config-data.php b/src/wp-includes/class-wp-view-config-data.php index 99ea816aee96e..b2e107608ac84 100644 --- a/src/wp-includes/class-wp-view-config-data.php +++ b/src/wp-includes/class-wp-view-config-data.php @@ -159,10 +159,12 @@ public function apply_filters( $kind, $name ) { * individual list members. * * A change that declares an unsupported schema version is rejected and does - * not alter anything. Callbacks mutate the container in place, so there is no - * need to return it; any returned value is ignored. Callbacks must not replace - * the container with a different value, as later callbacks receive whatever the - * the previous one returned. + * not alter anything. As with any filter, each callback's return value is + * passed to the next callback as `$data`, so callbacks must return the + * container they received: a callback that returns nothing, or any other + * value, hands that result to every callback hooked at a later priority + * instead of the container. Since the write methods return the container, + * a callback can end with `return $data->merge( $patch, $version );`. * * @since 7.1.0 * From 5fd5a8eec5cfb3e1cd74695dabb5c6b93666dcf2 Mon Sep 17 00:00:00 2001 From: Jorge Costa Date: Thu, 23 Jul 2026 16:37:54 +0000 Subject: [PATCH 005/138] View config: reject shape-mismatched merges, define empty-array semantics, strip nulls from appended members. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes three silent data-loss defects in WP_View_Config_Data's merge engine: - An associative patch value over a list (or a non-empty list over an associative value) discarded the whole current value. It is now rejected with _doing_it_wrong() and the current value is kept. - An empty array under merge() wiped associative values but no-oped on lists. It is now a no-op for both shapes — clear a list with replace() and an empty list, reset a key with null. - A list member appended by merge() kept nested nulls that every other write path drops. Appended members now go through strip_nulls(). Follow-up to [62825]. Props jorgefilipecosta, oandregal. See #65577. git-svn-id: https://develop.svn.wordpress.org/trunk@62834 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-view-config-data.php | 63 ++++- tests/phpunit/tests/view-config-data.php | 227 ++++++++++++++++++ 2 files changed, 287 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/class-wp-view-config-data.php b/src/wp-includes/class-wp-view-config-data.php index b2e107608ac84..8c3d255fab82d 100644 --- a/src/wp-includes/class-wp-view-config-data.php +++ b/src/wp-includes/class-wp-view-config-data.php @@ -40,7 +40,10 @@ * key by key (an associative array merges member by member, a nested `null` * deletes just that leaf, a scalar replaces just that value), while `set()` * swaps the whole value. A nested `null` deletes just the leaf it names in - * every case. Each patch also declares the configuration schema + * every case. A patch value whose shape does not match the current value — + * an associative array where a list lives, or the reverse — is rejected with + * a notice rather than merged, and an empty array under `merge()` is a + * no-op. Each patch also declares the configuration schema * version it was written against (currently 1), so a future WordPress release * that changes the configuration shape can migrate existing patches forward * instead of breaking them. @@ -308,6 +311,12 @@ public function remove( array $spec, int $version ) { * stops inheriting core's future additions to it — but it's useful when a * contributor needs to pin a list to an exact set of members. * + * The shape rule applies here too: a patch value whose shape does not match + * the current value — an associative array where a list lives, or a + * non-empty list where an associative value lives — is rejected with a + * notice and leaves the current value unchanged. An empty array is exempt, + * so replacing a list with an empty list still clears it. + * * A patch that declares an unsupported schema version is rejected and does * not change anything. * @@ -354,6 +363,13 @@ public function replace( array $patch, int $version ) { * - default_layouts will be updated so that newField is appended to the badgeFields. * - view_list will be updated so that the view with slug 'table' has its title changed to 'New title'. * + * A patch value only merges into a current value of the same shape: an + * associative array where a list lives, or a non-empty list where an + * associative value lives, is rejected with a notice and leaves the current + * value unchanged. An empty array merges nothing and is a no-op — clear a + * list with replace() and an empty list, or reset a key to its default with + * a top-level `null`. + * * A patch that declares an unsupported schema version is rejected and does * not change anything. * @@ -477,6 +493,15 @@ private function strip_nulls( $value ) { * $replace_lists flag is carried down through associative nesting so that, * under replace(), every list reached along the way is swapped wholesale. * + * An array in $incoming only merges into a current value of the same shape. + * A non-empty mismatch — an associative array where a list lives, or a + * non-empty list where an associative value lives — is reported with + * _doing_it_wrong() and leaves the current value unchanged, so a malformed + * patch cannot silently destroy configuration. An empty array is + * shape-ambiguous and merges nothing, so it is a no-op: clearing a list is + * spelled replace() with an empty list, and resetting a key is spelled + * `null`. + * * @since 7.1.0 * * @param mixed $current The current value. @@ -493,6 +518,18 @@ private function merge_properties( $current, $incoming, $replace_lists ) { // Numerical indexed arrays are expected to be lists (sequential integer keys starting at 0). if ( array_is_list( $incoming ) ) { + // A non-empty list only lands where a list (or nothing) lives, under + // merge() and replace() alike. An empty array is shape-ambiguous and + // exempt, so replace() with an empty list can still clear a list. + if ( array() !== $incoming && is_array( $current ) && ! array_is_list( $current ) && array() !== $current ) { + _doing_it_wrong( + __METHOD__, + esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ), + '7.1.0' + ); + return $current; + } + // replace() takes an incoming list as-is; merge() merges it by member identity. if ( $replace_lists ) { // As-is except for nulls: a list swapped in wholesale has no @@ -500,6 +537,13 @@ private function merge_properties( $current, $incoming, $replace_lists ) { // set()), so a null member is dropped rather than stored. return $this->strip_nulls( $incoming ); } + + // An empty list has no members to merge, and an empty array is + // shape-ambiguous, so merging one is a no-op rather than a reset. + if ( array() === $incoming ) { + return $current; + } + return $this->merge_list_by_identity( is_array( $current ) && array_is_list( $current ) ? $current : array(), $incoming @@ -507,6 +551,15 @@ private function merge_properties( $current, $incoming, $replace_lists ) { } // Consider any other array as associative (keys are strings). + if ( is_array( $current ) && array_is_list( $current ) && array() !== $current ) { + _doing_it_wrong( + __METHOD__, + esc_html__( 'A view configuration patch value must match the shape of the value it patches: a list merges into a list, and an associative array into an associative array.' ), + '7.1.0' + ); + return $current; + } + $result = is_array( $current ) && ! array_is_list( $current ) ? $current : array(); foreach ( $incoming as $key => $value ) { // A null patch value deletes the property. @@ -603,7 +656,9 @@ private function remove_list_member( array $members, $identity ) { * A member of the incoming list whose identity matches one already present * merges into it in place, keeping its position; an unmatched member is * appended to the end, except a literal `null`, which carries no identity - * and holds nothing to merge and so is dropped. A matched member's contents + * and holds nothing to merge and so is dropped. An appended member has no + * existing leaf for a nested `null` to delete (the same rationale as set()), + * so its nulls are stripped rather than stored. A matched member's contents * merge recursively with the same rules (merge_properties), so the * identity-aware merge applies at * any nesting level: each key named by the patch is substituted while the @@ -639,7 +694,9 @@ private function merge_list_by_identity( array $current, array $incoming ) { } } if ( null === $index ) { - $result[] = $item; + // An appended member has no existing leaf for a nested null to + // delete, so nulls are dropped rather than stored. + $result[] = $this->strip_nulls( $item ); continue; } diff --git a/tests/phpunit/tests/view-config-data.php b/tests/phpunit/tests/view-config-data.php index 1d56adb786644..68940ad6c2d5c 100644 --- a/tests/phpunit/tests/view-config-data.php +++ b/tests/phpunit/tests/view-config-data.php @@ -1721,6 +1721,233 @@ public function test_merge_rejects_unknown_key() { $this->assertSame( array( 'default_view' => array( 'type' => 'table' ) ), self::read_config( $data ) ); } + /** + * merge() rejects an associative patch value where a list lives: the shapes + * do not line up, so merging would have to guess what the string keys mean. + * The current list survives untouched instead of being discarded. + * + * @ticket 65577 + * + * @covers ::merge + */ + public function test_merge_rejects_associative_patch_over_a_list() { + $this->setExpectedIncorrectUsage( 'WP_View_Config_Data::merge_properties' ); + + $data = new WP_View_Config_Data( + array( + 'view_list' => array( + array( + 'slug' => 'all', + 'title' => 'All items', + ), + ), + ) + ); + $before = self::read_config( $data ); + + // The pre-7.1 slug-keyed shape, not the documented list of members. + $data->merge( + array( + 'view_list' => array( + 'published' => array( 'title' => 'Live' ), + ), + ), + 1 + ); + + $this->assertSame( $before, self::read_config( $data ) ); + } + + /** + * merge() rejects a non-empty list patch value where an associative value + * lives, the mirror of the associative-over-list mismatch: the current map + * survives untouched instead of being discarded. + * + * @ticket 65577 + * + * @covers ::merge + */ + public function test_merge_rejects_list_patch_over_an_associative_value() { + $this->setExpectedIncorrectUsage( 'WP_View_Config_Data::merge_properties' ); + + $data = new WP_View_Config_Data( + array( + 'default_view' => array( + 'sort' => array( + 'field' => 'title', + 'direction' => 'asc', + ), + ), + ) + ); + $before = self::read_config( $data ); + + $data->merge( + array( + 'default_view' => array( + 'sort' => array( 'title', 'asc' ), + ), + ), + 1 + ); + + $this->assertSame( $before, self::read_config( $data ) ); + } + + /** + * An empty array under merge() is a no-op for both shapes: it has no + * members to merge, and being shape-ambiguous it must not reset the + * current value either. Clearing a list is spelled replace() with an + * empty list; resetting a key is spelled null. + * + * @ticket 65577 + * + * @covers ::merge + */ + public function test_merge_empty_array_is_a_noop() { + $data = new WP_View_Config_Data( + array( + 'default_view' => array( + 'filters' => array( + array( + 'field' => 'author', + 'operator' => 'isAny', + ), + ), + 'sort' => array( + 'field' => 'title', + 'direction' => 'asc', + ), + ), + ) + ); + $before = self::read_config( $data ); + + $data->merge( + array( + 'default_view' => array( + 'filters' => array(), + 'sort' => array(), + ), + ), + 1 + ); + + $this->assertSame( $before, self::read_config( $data ) ); + } + + /** + * A nested null deletes just the leaf it names in every case, including + * inside a list member that did not exist yet: an appended member has no + * existing leaf to delete, so its nulls are dropped rather than stored + * (the same rationale as set() and the lists replace() swaps in). + * + * @ticket 65577 + * + * @covers ::merge + */ + public function test_merge_appended_member_drops_nested_nulls() { + $data = new WP_View_Config_Data( + array( + 'view_list' => array( + array( + 'slug' => 'all', + 'title' => 'All items', + ), + ), + ) + ); + $data->merge( + array( + 'view_list' => array( + array( + 'slug' => 'mine', + 'view' => array( 'filters' => null ), + ), + ), + ), + 1 + ); + + $this->assertSame( + array( + 'view_list' => array( + array( + 'slug' => 'all', + 'title' => 'All items', + ), + array( + 'slug' => 'mine', + 'view' => array(), + ), + ), + ), + self::read_config( $data ) + ); + } + + /** + * replace() rejects a non-empty list patch value where an associative value + * lives, the same rule merge() enforces: a list in the patch replaces the + * current list wholesale, but it cannot land where a map lives. The current + * map survives untouched instead of being discarded. + * + * @ticket 65577 + * + * @covers ::replace + */ + public function test_replace_rejects_list_patch_over_an_associative_value() { + $this->setExpectedIncorrectUsage( 'WP_View_Config_Data::merge_properties' ); + + $data = new WP_View_Config_Data( + array( + 'default_view' => array( + 'sort' => array( + 'field' => 'title', + 'direction' => 'asc', + ), + ), + ) + ); + $before = self::read_config( $data ); + + $data->replace( + array( + 'default_view' => array( + 'sort' => array( 'title', 'asc' ), + ), + ), + 1 + ); + + $this->assertSame( $before, self::read_config( $data ) ); + } + + /** + * An empty array is exempt from the shape guard, so replace() with an + * empty list stays the documented way to clear a list. + * + * @ticket 65577 + * + * @covers ::replace + */ + public function test_replace_empty_list_still_clears_a_list() { + $data = new WP_View_Config_Data( + array( + 'view_list' => array( + array( + 'slug' => 'all', + 'title' => 'All items', + ), + ), + ) + ); + + $data->replace( array( 'view_list' => array() ), 1 ); + + $this->assertSame( array( 'view_list' => array() ), self::read_config( $data ) ); + } + /** * merge() treats a scalar list member as its own identity: an incoming From 78e0b517ad73b95dbfb5f81f52f5ac0a375950d4 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 23 Jul 2026 20:14:22 +0000 Subject: [PATCH 006/138] Code Quality: Preserve `string[]` input type in `wp_parse_list()` return. This prevents unintentional widening of a `string[]` input to a `scalar[]` output, since strings are scalars. Follow-up to r62797. See #64898. git-svn-id: https://develop.svn.wordpress.org/trunk@62835 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/functions.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/wp-includes/functions.php b/src/wp-includes/functions.php index dca95d69b69fe..9a688b9866ce0 100644 --- a/src/wp-includes/functions.php +++ b/src/wp-includes/functions.php @@ -5034,9 +5034,13 @@ function wp_parse_args( $args, $defaults = array() ) { * @since 5.1.0 * * @param mixed[]|string $input_list List of values. - * @return array Array of values. A string is split into a list, while an array + * @return array Array of scalar values. A string is split into a list, while an array * keeps its keys, so the result is not necessarily a list. - * @phpstan-return ( $input_list is string ? list : array ) + * @phpstan-return ( + * $input_list is string ? list : ( + * $input_list is array ? array : array + * ) + * ) */ function wp_parse_list( $input_list ): array { if ( ! is_array( $input_list ) ) { From 4f0a5c704a04228ff924747c3f9ad3c2489aba16 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Thu, 23 Jul 2026 20:37:50 +0000 Subject: [PATCH 007/138] Code Quality: Document that `sanitize_key()` returns `lowercase-string`. This is a narrower PHPStan type compared to just `string`. See #64898. git-svn-id: https://develop.svn.wordpress.org/trunk@62836 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/formatting.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/wp-includes/formatting.php b/src/wp-includes/formatting.php index 8f8af4a082196..74a28109b6536 100644 --- a/src/wp-includes/formatting.php +++ b/src/wp-includes/formatting.php @@ -2186,6 +2186,7 @@ function sanitize_user( $username, $strict = false ) { * * @param string $key String key. * @return string Sanitized key. + * @phpstan-return lowercase-string */ function sanitize_key( $key ) { $sanitized_key = ''; From 8f7c6bc192161722fcc4769aaacfcc350dd3a7a9 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Thu, 23 Jul 2026 20:41:20 +0000 Subject: [PATCH 008/138] Docs: Correct the type for `WP_Screen::$_screen_settings`. This reflects the property's initial `null` state prior to initialization. Follow-up to [55693], [61300]. Props Chouby, arkaprabhachowdhury, SergeyBiryukov. Fixes #56607. git-svn-id: https://develop.svn.wordpress.org/trunk@62837 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/class-wp-screen.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/includes/class-wp-screen.php b/src/wp-admin/includes/class-wp-screen.php index ab7dfef77f67c..b0b689d412edb 100644 --- a/src/wp-admin/includes/class-wp-screen.php +++ b/src/wp-admin/includes/class-wp-screen.php @@ -89,7 +89,7 @@ final class WP_Screen { * have a `$parent_base` of 'edit'. * * @since 3.3.0 - * @var string|null + * @var ?string */ public $parent_base; @@ -99,7 +99,7 @@ final class WP_Screen { * Some `$parent_file` values are 'edit.php?post_type=page', 'edit.php', and 'options-general.php'. * * @since 3.3.0 - * @var string|null + * @var ?string */ public $parent_file; @@ -186,7 +186,7 @@ final class WP_Screen { * Stores the 'screen_settings' section of screen options. * * @since 3.3.0 - * @var string + * @var ?string */ private $_screen_settings; From 0029901b39ca9389114f1c59240504e99598daa7 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Thu, 23 Jul 2026 20:59:29 +0000 Subject: [PATCH 009/138] Administration: Use post title column as table header in post lists. The `select` column has been the `th` with row scope for post list tables since at least 2010. This results in a row name for screen readers that is based on the checkbox input and its label, which can be an empty value when that input is not available. Move the `th` to the post title column, change the select column to `td`, and add `aria-label` to the `th` to provide a simplified row name to supporting screen readers. Styles are additive, to retain support for custom list table implementations. Developed in https://github.com/WordPress/wordpress-develop/pull/9761 Props afercia, abcd95, ozgursar, nikunj8866, joedolson. Fixes #32892. git-svn-id: https://develop.svn.wordpress.org/trunk@62838 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/common.css | 6 ++- src/wp-admin/css/forms.css | 3 +- src/wp-admin/css/list-tables.css | 37 +++++++++---- src/wp-admin/includes/class-wp-list-table.php | 53 +++++++++++++++---- .../class-wp-ms-themes-list-table.php | 8 +-- .../includes/class-wp-plugins-list-table.php | 6 +-- .../includes/class-wp-posts-list-table.php | 22 +++++++- .../includes/class-wp-users-list-table.php | 14 +++-- 8 files changed, 114 insertions(+), 35 deletions(-) diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index c2ab1c31b5c34..88c1c0d6ac0d1 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -514,6 +514,7 @@ code { } .widefat th, +.widefat tbody td.check-column, .widefat thead td, .widefat tfoot td { text-align: left; @@ -521,6 +522,7 @@ code { font-size: 14px; } +.widefat td.check-column input, .widefat th input, .updates-table td input, .widefat thead td input, @@ -536,12 +538,14 @@ code { vertical-align: top; } -.widefat tbody th.check-column { +.widefat tbody th.check-column, +.widefat tbody td.check-column { padding: 9px 0 22px; } .widefat thead td.check-column, .widefat tbody th.check-column, +.widefat tbody td.check-column, .updates-table tbody td.check-column, .widefat tfoot td.check-column { padding: 11px 0 0 3px; diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css index c17d038c5d2c6..dd19e1ba8070a 100644 --- a/src/wp-admin/css/forms.css +++ b/src/wp-admin/css/forms.css @@ -1967,7 +1967,8 @@ table.form-table td .updated p { margin-left: 0; } - .wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) td.column-primary:not(.check-column) { + .wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) td.column-primary:not(.check-column), + .wp-list-table.privacy_requests tr:not(.inline-edit-row):not(.no-items) th.column-primary:not(.check-column) { display: table-cell; } diff --git a/src/wp-admin/css/list-tables.css b/src/wp-admin/css/list-tables.css index 731168f97fc8d..46c2002e3e3a1 100644 --- a/src/wp-admin/css/list-tables.css +++ b/src/wp-admin/css/list-tables.css @@ -222,11 +222,13 @@ background-color: #fcf9e8; } -#the-comment-list .unapproved th.check-column { +#the-comment-list .unapproved th.check-column, +#the-comment-list .unapproved td.check-column { border-left: 4px solid #d63638; } -#the-comment-list .unapproved th.check-column input { +#the-comment-list .unapproved th.check-column input, +#the-comment-list .unapproved td.check-column input { margin-left: 4px; } @@ -1221,11 +1223,13 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before { ------------------------------------------------------------------------------*/ .plugins tbody th.check-column, +.plugins tbody td.check-column, .plugins tbody { padding: 8px 0 0 2px; } -.plugins tbody th.check-column input[type=checkbox] { +.plugins tbody th.check-column input[type=checkbox], +.plugins tbody td.check-column input[type=checkbox] { margin-top: 4px; } @@ -1235,7 +1239,8 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before { .plugins thead td.check-column, .plugins tfoot td.check-column, -.plugins .inactive th.check-column { +.plugins .inactive th.check-column, +.plugins .inactive td.check-column { padding-left: 6px; } @@ -1325,6 +1330,7 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before { } .plugins .active th.check-column, +.plugins .active td.check-column, .plugin-update-tr.active td { border-left: 4px solid var(--wp-admin-theme-color); } @@ -1410,7 +1416,8 @@ ul.cat-checklist input[name="post_category[]"]:indeterminate::before { text-decoration: underline; } -.plugins tr.paused th.check-column { +.plugins tr.paused th.check-column, +.plugins tr.paused td.check-column { border-left: 4px solid #b32d2e; } @@ -1909,7 +1916,8 @@ div.action-links, } .wp-list-table th.column-primary ~ th, - .wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column) { + .wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column), + .wp-list-table tr:not(.inline-edit-row):not(.no-items) th.column-primary ~ td:not(.check-column) { display: none; } @@ -1918,7 +1926,8 @@ div.action-links, } /* Checkboxes need to show */ - .wp-list-table tr th.check-column { + .wp-list-table tr th.check-column, + .wp-list-table tr td.check-column { display: table-cell; } @@ -1936,11 +1945,13 @@ div.action-links, width: auto !important; /* needs to override some columns that are more specifically targeted */ } - .wp-list-table td.column-primary { + .wp-list-table td.column-primary, + .wp-list-table th.column-primary { padding-right: 50px; /* space for toggle button */ } - .wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column) { + .wp-list-table tr:not(.inline-edit-row):not(.no-items) td.column-primary ~ td:not(.check-column), + .wp-list-table tr:not(.inline-edit-row):not(.no-items) th.column-primary ~ td:not(.check-column) { padding: 3px 8px 3px 35%; } @@ -2269,12 +2280,14 @@ div.action-links, } .plugins tr.active + tr.inactive th.check-column, + .plugins tr.active + tr.inactive td.check-column, .plugins tr.active + tr.inactive td.column-description, .plugins .plugin-update-tr:before { box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1); } .plugins tr.active + tr.inactive th.check-column, + .plugins tr.active + tr.inactive td.check-column, .plugins tr.active + tr.inactive td { border-top: none; } @@ -2309,13 +2322,15 @@ div.action-links, line-height: 1.5; } - .plugins tbody th.check-column { + .plugins tbody th.check-column, + .plugins tbody td.check-column { padding: 8px 0 0 5px; } .plugins thead td.check-column, .plugins tfoot td.check-column, - .plugins .inactive th.check-column { + .plugins .inactive th.check-column, + .plugins .inactive td.check-column { padding-left: 9px; } diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php index d32f08a438c60..b78af78abc03e 100644 --- a/src/wp-admin/includes/class-wp-list-table.php +++ b/src/wp-admin/includes/class-wp-list-table.php @@ -1767,6 +1767,26 @@ protected function column_default( $item, $column_name ) {} */ protected function column_cb( $item ) {} + /** + * Returns a clean, human-readable label for the primary column's row header. + * + * Used as the `aria-label` attribute value on the `` element, + * giving screen readers a concise cell name instead of computing it from + * the full cell content (which may include row action links, excerpts, etc.). + * + * Subclasses should override this method to return the item's primary + * identifier (e.g. post title, plugin name, username). Return an empty string + * to omit the attribute. + * + * @since 6.9.0 + * + * @param object|array $item The current item. + * @return string The aria-label value, or an empty string. + */ + protected function get_primary_column_aria_label( $item ) { + return ''; + } + /** * Generates the columns for a single row of the table. * @@ -1796,9 +1816,9 @@ protected function single_row_columns( $item ) { $attributes = "class='$classes' $data"; if ( 'cb' === $column_name ) { - echo ''; + echo ''; echo $this->column_cb( $item ); - echo ''; + echo ''; } elseif ( method_exists( $this, '_column_' . $column_name ) ) { echo call_user_func( array( $this, '_column_' . $column_name ), @@ -1807,16 +1827,29 @@ protected function single_row_columns( $item ) { $data, $primary ); - } elseif ( method_exists( $this, 'column_' . $column_name ) ) { - echo ""; - echo call_user_func( array( $this, 'column_' . $column_name ), $item ); - echo $this->handle_row_actions( $item, $column_name, $primary ); - echo ''; } else { - echo ""; - echo $this->column_default( $item, $column_name ); + $is_primary = ( $primary === $column_name ); + $tag = $is_primary ? 'th' : 'td'; + $scope = $is_primary ? ' scope="row"' : ''; + + $aria_label = ''; + if ( $is_primary ) { + $label = $this->get_primary_column_aria_label( $item ); + if ( '' !== $label ) { + $aria_label = ' aria-label="' . esc_attr( $label ) . '"'; + } + } + + echo "<$tag $attributes$scope$aria_label>"; + + if ( method_exists( $this, 'column_' . $column_name ) ) { + echo call_user_func( array( $this, 'column_' . $column_name ), $item ); + } else { + echo $this->column_default( $item, $column_name ); + } + echo $this->handle_row_actions( $item, $column_name, $primary ); - echo ''; + echo ""; } } } diff --git a/src/wp-admin/includes/class-wp-ms-themes-list-table.php b/src/wp-admin/includes/class-wp-ms-themes-list-table.php index a0fca2fd60fe4..81c35414d9053 100644 --- a/src/wp-admin/includes/class-wp-ms-themes-list-table.php +++ b/src/wp-admin/includes/class-wp-ms-themes-list-table.php @@ -940,11 +940,11 @@ public function single_row_columns( $item ) { switch ( $column_name ) { case 'cb': - echo ''; + echo ''; $this->column_cb( $item ); - echo ''; + echo ''; break; case 'name': @@ -966,11 +966,11 @@ public function single_row_columns( $item ) { } } - echo "" . $item->display( 'Name' ) . $active_theme_label . ''; + echo "" . $item->display( 'Name' ) . $active_theme_label . ''; $this->column_name( $item ); - echo ''; + echo ''; break; case 'description': diff --git a/src/wp-admin/includes/class-wp-plugins-list-table.php b/src/wp-admin/includes/class-wp-plugins-list-table.php index 08b2e982e702f..d8945e103064e 100644 --- a/src/wp-admin/includes/class-wp-plugins-list-table.php +++ b/src/wp-admin/includes/class-wp-plugins-list-table.php @@ -1233,12 +1233,12 @@ public function single_row( $item ) { switch ( $column_name ) { case 'cb': - echo "$checkbox"; + echo "$checkbox"; break; case 'name': - echo "$plugin_name"; + echo "$plugin_name"; echo $this->row_actions( $actions, true ); - echo ''; + echo ''; break; case 'description': $classes = 'column-description desc'; diff --git a/src/wp-admin/includes/class-wp-posts-list-table.php b/src/wp-admin/includes/class-wp-posts-list-table.php index 7522f8561ba44..3795495d6d21a 100644 --- a/src/wp-admin/includes/class-wp-posts-list-table.php +++ b/src/wp-admin/includes/class-wp-posts-list-table.php @@ -1114,10 +1114,28 @@ public function column_cb( $item ) { * @param string $primary */ protected function _column_title( $post, $classes, $data, $primary ) { - echo ''; + $aria_label = $this->get_primary_column_aria_label( $post ); + $aria_attr = ( '' !== $aria_label ) ? ' aria-label="' . esc_attr( $aria_label ) . '"' : ''; + echo ''; echo $this->column_title( $post ); echo $this->handle_row_actions( $post, 'title', $primary ); - echo ''; + echo ''; + } + + /** + * Returns a clean label for the primary (title) column's row header `aria-label`. + * + * Provides screen readers with just the post title as the row header name, + * preventing them from computing the name from the full cell content + * (which includes row action links, post states, and possibly an excerpt). + * + * @since 6.9.0 + * + * @param WP_Post $item The current post object. + * @return string The post title, or 'no title' if no title. + */ + protected function get_primary_column_aria_label( $item ) { + return isset( $item->post_title ) && ! empty( $item->post_title ) ? $item->post_title : __( 'no title' ); } /** diff --git a/src/wp-admin/includes/class-wp-users-list-table.php b/src/wp-admin/includes/class-wp-users-list-table.php index 9a8709b438e05..dd54b200bafaf 100644 --- a/src/wp-admin/includes/class-wp-users-list-table.php +++ b/src/wp-admin/includes/class-wp-users-list-table.php @@ -563,9 +563,16 @@ public function single_row( $user_object, $style = '', $role = '', $numposts = 0 $attributes = "class='$classes' $data"; if ( 'cb' === $column_name ) { - $row .= "$checkbox"; + $row .= "$checkbox"; } else { - $row .= ""; + $is_primary = ( $primary === $column_name ); + $tag = $is_primary ? 'th' : 'td'; + $scope = $is_primary ? ' scope="row"' : ''; + $aria_label = ''; + if ( $is_primary ) { + $aria_label = ' aria-label="' . esc_attr( $user_object->user_login ) . '"'; + } + $row .= "<$tag $attributes$scope$aria_label>"; switch ( $column_name ) { case 'username': $row .= "$avatar $edit"; @@ -628,7 +635,8 @@ public function single_row( $user_object, $style = '', $role = '', $numposts = 0 if ( $primary === $column_name ) { $row .= $this->row_actions( $actions ); } - $row .= ''; + $tag = ( $primary === $column_name ) ? 'th' : 'td'; + $row .= ""; } } $row .= ''; From 2d1c511ed5ea456ad77e5de19a4548a7caa44641 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Thu, 23 Jul 2026 21:41:40 +0000 Subject: [PATCH 010/138] Administration: Update bulk edit validity checks & CSS. Omitted to update the scripting validating bulk edit selections when changing the list table `th`. Add overlooked CSS to set post title `th` to `vertical-align: top`. Follow up to [62838]. Developed in https://github.com/WordPress/wordpress-develop/pull/12666 Props joedolson, tobiasbg. Fixes #32892. git-svn-id: https://develop.svn.wordpress.org/trunk@62839 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/_enqueues/admin/inline-edit-post.js | 4 ++-- src/wp-admin/css/common.css | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/js/_enqueues/admin/inline-edit-post.js b/src/js/_enqueues/admin/inline-edit-post.js index 6e9f4e9f20503..36ffaf18ef778 100644 --- a/src/js/_enqueues/admin/inline-edit-post.js +++ b/src/js/_enqueues/admin/inline-edit-post.js @@ -191,7 +191,7 @@ window.wp = window.wp || {}; */ setBulk : function(){ var te = '', type = this.type, c = true; - var checkedPosts = $( 'tbody th.check-column input[type="checkbox"]:checked' ); + var checkedPosts = $( 'tbody .check-column input[type="checkbox"]:checked' ); var categories = {}; this.revert(); @@ -207,7 +207,7 @@ window.wp = window.wp || {}; * * Get the selected posts based on the checked checkboxes in the post table. */ - $( 'tbody th.check-column input[type="checkbox"]' ).each( function() { + $( 'tbody .check-column input[type="checkbox"]' ).each( function() { // If the checkbox for a post is selected, add the post to the edit list. if ( $(this).prop('checked') ) { diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index 88c1c0d6ac0d1..c286b8fa9ae0c 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -501,6 +501,7 @@ code { border-bottom-width: 0; } +.widefat th, .widefat td { vertical-align: top; } From baf6c2bbd6cccab264501d6a0d52bd535dee86fb Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Fri, 24 Jul 2026 02:24:38 +0000 Subject: [PATCH 011/138] Media: Accessibility: Fix labels in scale tool. The field for setting width in the media editor scale inputs had an incorrect label. Additionally, both the width and height labels had extraneous adjectives describing the fields. These are not necessary given the `fieldset` and `legend` providing context. Change the 'width' label from 'scale height' to 'Width'. Change the 'height' label from 'scale height' to 'Height'. Props csmcneill, nilambar, tusharaddweb, khokansardar, mukesh27, joedolson, afercia. Fixes #65685. git-svn-id: https://develop.svn.wordpress.org/trunk@62840 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/image-edit.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/wp-admin/includes/image-edit.php b/src/wp-admin/includes/image-edit.php index a9ddc55e1bf96..a192ef0000c17 100644 --- a/src/wp-admin/includes/image-edit.php +++ b/src/wp-admin/includes/image-edit.php @@ -151,12 +151,17 @@ function wp_image_editor( $post_id, $msg = false ) { - +
From 58b28ff78834dbec24a29acc2def1753361aadcf Mon Sep 17 00:00:00 2001 From: Andrew Serong Date: Fri, 24 Jul 2026 02:42:23 +0000 Subject: [PATCH 012/138] REST API: Enforce multisite upload limits when sideloading media from a URL. The attachments controller's URL-based creation path, `create_item_from_url()`, passed the downloaded file to `media_handle_sideload()` without running `check_upload_size()`. Unlike the multipart and raw-body upload paths, it did not enforce the multisite maximum file size or the site's upload space quota. Run `check_upload_size()` on the downloaded file before sideloading it, for parity with the other upload paths, and remove the temporary file when the check fails. Developed in: https://github.com/WordPress/wordpress-develop/pull/12670 Follow-up to [62659]. Props andrewserong, ramonopoly. Fixes #65517. git-svn-id: https://develop.svn.wordpress.org/trunk@62841 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-attachments-controller.php | 8 +++ .../rest-api/rest-attachments-controller.php | 64 +++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 609b133ca4cfc..6e06f1563c50c 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -641,6 +641,14 @@ protected function create_item_from_url( $request ) { 'tmp_name' => $tmp_file, ); + $size_check = self::check_upload_size( $file_array ); + if ( is_wp_error( $size_check ) ) { + if ( file_exists( $tmp_file ) ) { + wp_delete_file( $tmp_file ); + } + return $size_check; + } + $attachment_id = media_handle_sideload( $file_array, $post_id ); if ( is_wp_error( $attachment_id ) ) { diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 268ac019c3bc9..90899df850d47 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -5330,6 +5330,70 @@ public function test_create_item_from_url_returns_error_on_download_failure() { $this->assertSame( 500, $response->get_status() ); } + /** + * Verifies that the URL sideload path enforces the multisite maximum file + * size, for parity with the multipart and raw-body upload paths. + * + * @ticket 65517 + * @group multisite + * @group ms-required + * + * @covers WP_REST_Attachments_Controller::create_item_from_url + * @covers WP_REST_Attachments_Controller::check_upload_size + */ + public function test_create_item_from_url_exceeds_multisite_max_filesize() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + update_site_option( 'fileupload_maxk', 1 ); + update_site_option( 'upload_space_check_disabled', false ); + + // Ensure ample space is available so the file-size limit is what rejects it. + add_filter( 'pre_get_space_used', '__return_zero' ); + add_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/too-big.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + + $response = rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10 ); + + $this->assertErrorResponse( 'rest_upload_file_too_big', $response, 400 ); + } + + /** + * Verifies that the URL sideload path enforces the multisite site upload + * space quota, for parity with the multipart and raw-body upload paths. + * + * @ticket 65517 + * @group multisite + * @group ms-required + * + * @covers WP_REST_Attachments_Controller::create_item_from_url + * @covers WP_REST_Attachments_Controller::check_upload_size + */ + public function test_create_item_from_url_exceeds_multisite_site_upload_space() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + add_filter( 'get_space_allowed', '__return_zero' ); + update_site_option( 'upload_space_check_disabled', false ); + + add_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/no-space.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + + $response = rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10 ); + + $this->assertErrorResponse( 'rest_upload_limited_space', $response, 400 ); + } + /** * Verifies that a URL with no usable path bails with a 400 before any * download is attempted, rather than handing an empty filename to the From 53119d1e58a3ab1460c36ca719bf73829275381c Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Fri, 24 Jul 2026 12:40:43 +0000 Subject: [PATCH 013/138] Plugins: Remove redundant type casting in `wp_filter_build_unique_id()`. The `(object)` type casting was preceded by an `is_object()` check and can be safely removed. The `isset()` language construct is enough to check for an array when detecting malformed callbacks, so the `(array)` type casting is not required. Removing the type casting results in an additional performance improvement up to ~8% for the function. Follow-up to [62408]. See #58291, #64898. git-svn-id: https://develop.svn.wordpress.org/trunk@62842 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/plugin.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/wp-includes/plugin.php b/src/wp-includes/plugin.php index 55459c0dd96c8..f64b584374c8e 100644 --- a/src/wp-includes/plugin.php +++ b/src/wp-includes/plugin.php @@ -1005,10 +1005,9 @@ function _wp_filter_build_unique_id( $hook_name, $callback, $priority ): ?string } if ( is_object( $callback ) ) { - return (string) spl_object_id( (object) $callback ); + return (string) spl_object_id( $callback ); } - $callback = (array) $callback; if ( ! isset( $callback[1] ) || ! is_string( $callback[1] ) ) { return null; } From d88c95d9da1123ff6bf5d2042922b3c2cf8615db Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Fri, 24 Jul 2026 15:35:47 +0000 Subject: [PATCH 014/138] Administration: Improve UI when adding or removing tags. Improve AJAX interactions in the user interface when adding or removing tags by exposing the default `No tags found` row and removing bulk actions and search when the last tag is removed, and by showing bulk actions when tags are added, and incrementing item counts when adding or deleting. Developed in https://github.com/WordPress/wordpress-develop/pull/8761 Props sainathpoojary, sirlouen, rishabhwp, yashjawale, wildworks, madhavishah01, khokansardar, joedolson. Fixes #63372. git-svn-id: https://develop.svn.wordpress.org/trunk@62843 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/_enqueues/admin/tags.js | 57 ++++++++++++++++++- src/wp-admin/includes/class-wp-list-table.php | 14 +++-- 2 files changed, 64 insertions(+), 7 deletions(-) diff --git a/src/js/_enqueues/admin/tags.js b/src/js/_enqueues/admin/tags.js index ff7761adb8d3e..88e38b6926309 100644 --- a/src/js/_enqueues/admin/tags.js +++ b/src/js/_enqueues/admin/tags.js @@ -59,8 +59,10 @@ jQuery( function($) { nextFocus = prevFocus; } } - - tr.fadeOut('normal', function(){ tr.remove(); }); + tr.fadeOut('normal', function() { + tr.remove(); + updateTableNavCount(); + }); /** * Removes the term from the parent box and the tag cloud. @@ -73,7 +75,7 @@ jQuery( function($) { $('a.tag-link-' + data.match(/tag_ID=(\d+)/)[1]).remove(); nextFocus.trigger( 'focus' ); message = wp.i18n.__( 'The selected tag has been deleted.' ); - + } else if ( '-1' == r ) { message = wp.i18n.__( 'Sorry, you are not allowed to do that.' ); $('#ajax-response').empty().append('

' + message + '

'); @@ -103,6 +105,53 @@ jQuery( function($) { tr.find( ':input, a' ).prop( 'disabled', false ).removeAttr( 'tabindex' ); } + /** + * Updates the item count and table navigation after a tag is added or removed. + * + * Tags are added and removed client-side, but the item count, the `.tablenav` + * regions, the search box, and the empty-state row are otherwise only + * reconciled by PHP on a full page reload. This keeps them in sync. + * + * @param {string} [action] Pass 'add' when a tag was added. Any other value, + * including none, is treated as a removal. + * + * @return {void} + */ + function updateTableNavCount( action ) { + var $displayingNum = $( '.tablenav-pages .displaying-num' ), + currentCount = parseInt( $displayingNum.first().text().replace( /[^0-9]/g, '' ), 10 ) || 0, + itemCount = ( 'add' === action ) ? currentCount + 1 : Math.max( currentCount - 1, 0 ), + formattedCount = itemCount.toLocaleString(); + + $displayingNum.text( + wp.i18n.sprintf( + /* translators: %s: Number of items. */ + wp.i18n._n( '%s item', '%s items', itemCount ), + formattedCount + ) + ); + + if ( itemCount < 1 ) { + // No tags remain: show the empty-state row and hide the navigation. + var $list = $( '#the-list' ); + + if ( ! $list.find( 'tr.no-items' ).length ) { + var colspan = $list.closest( 'table' ).find( 'thead > tr' ).first().children( ':not(.hidden)' ).length; + $list.append( + '' + + wp.i18n.__( 'No tags found.' ) + + '' + ); + } + $( '.tablenav > *' ).hide(); + $( 'p.search-box' ).hide(); + } else { + $( '#the-list' ).find( 'tr.no-items' ).remove(); + $( '.tablenav > *' ).show(); + $( 'p.search-box' ).show(); + } + } + /** * Adds a deletion confirmation when removing a tag. * @@ -192,6 +241,8 @@ jQuery( function($) { } $('input:not([type="checkbox"]):not([type="radio"]):not([type="button"]):not([type="submit"]):not([type="reset"]):visible, textarea:visible', form).val(''); + + updateTableNavCount( 'add' ); }); return false; diff --git a/src/wp-admin/includes/class-wp-list-table.php b/src/wp-admin/includes/class-wp-list-table.php index b78af78abc03e..6ebae0e98eb86 100644 --- a/src/wp-admin/includes/class-wp-list-table.php +++ b/src/wp-admin/includes/class-wp-list-table.php @@ -1029,6 +1029,8 @@ protected function get_items_per_page( $option, $default_value = 20 ) { */ protected function pagination( $which ) { if ( empty( $this->_pagination_args['total_items'] ) ) { + // translators: Number is a fixed value. This is default text when no items are found. + echo '
' . __( '0 items' ) . '
'; return; } @@ -1685,12 +1687,16 @@ protected function display_tablenav( $which ) { ?>
- has_items() ) : ?> -
+ has_items() ) { + $visibility = ''; + } + ?> +
bulk_actions( $which ); ?>
- extra_tablenav( $which ); $this->pagination( $which ); ?> From 5830b7cfcaa698f5136ffa0b19e8b555d800eef1 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Fri, 24 Jul 2026 15:47:25 +0000 Subject: [PATCH 015/138] Privacy: More accurate admin notices when saving. When saving Privacy Policy page settings, show a notice that indicates there is no Privacy Policy page set instead of "Privacy Policy page updated successfully" if no page is selected. Differentiate between removing the current page and saving settings with no changes. Developed in https://github.com/WordPress/wordpress-develop/pull/12247 Props anveshika, audrasjb, masteradhoc, micahele, adrianduffell, pedrofigueroa1989, joedolson. Fixes #59276. git-svn-id: https://develop.svn.wordpress.org/trunk@62844 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/options-privacy.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/options-privacy.php b/src/wp-admin/options-privacy.php index 4205967acb3a8..739c8edab1cda 100644 --- a/src/wp-admin/options-privacy.php +++ b/src/wp-admin/options-privacy.php @@ -51,12 +51,15 @@ static function ( $body_class ) { check_admin_referer( $action ); if ( 'set-privacy-page' === $action ) { - $privacy_policy_page_id = isset( $_POST['page_for_privacy_policy'] ) ? (int) $_POST['page_for_privacy_policy'] : 0; + $previous_privacy_policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); + $privacy_policy_page_id = isset( $_POST['page_for_privacy_policy'] ) ? (int) $_POST['page_for_privacy_policy'] : 0; update_option( 'wp_page_for_privacy_policy', $privacy_policy_page_id ); - $privacy_page_updated_message = __( 'Privacy Policy page updated successfully.' ); + $privacy_page_message_type = 'success'; if ( $privacy_policy_page_id ) { + $privacy_page_updated_message = __( 'Privacy Policy page updated successfully.' ); + /* * Don't always link to the menu customizer: * @@ -75,9 +78,16 @@ static function ( $body_class ) { esc_url( add_query_arg( 'autofocus[panel]', 'nav_menus', admin_url( 'customize.php' ) ) ) ); } + } elseif ( $previous_privacy_policy_page_id ) { + // A previously set Privacy Policy page was cleared. + $privacy_page_updated_message = __( 'Privacy Policy page removed.' ); + } else { + // No Privacy Policy page was set before, and none is set now. + $privacy_page_updated_message = __( 'No Privacy Policy page is currently set.' ); + $privacy_page_message_type = 'info'; } - add_settings_error( 'page_for_privacy_policy', 'page_for_privacy_policy', $privacy_page_updated_message, 'success' ); + add_settings_error( 'page_for_privacy_policy', 'page_for_privacy_policy', $privacy_page_updated_message, $privacy_page_message_type ); } elseif ( 'create-privacy-page' === $action ) { if ( ! class_exists( 'WP_Privacy_Policy_Content' ) ) { From 6d1d03da1ec1266e5681e5cd8e36275798e728bb Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Fri, 24 Jul 2026 18:57:29 +0000 Subject: [PATCH 016/138] Privacy: Delete Privacy Policy setting when page deleted. If the privacy page is deleted but the setting is left intact, an admin_hook would fire on every admin screen attempting to notify about changes in the privacy policy. With the page deleted, this database read is never cached, since it returns no results. Add a `before_delete_post` hook to reset setting if the post is deleted. Add a guard to reset the option on the privacy screen to cover edge cases. Developed in https://github.com/WordPress/wordpress-develop/pull/11443, https://github.com/WordPress/wordpress-develop/pull/11520 Props johnjamesjacoby, masteradhoc, westonruter, nimeshatxecurify, mukesh27, joedolson. Fixes #56694. git-svn-id: https://develop.svn.wordpress.org/trunk@62845 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-privacy-policy-content.php | 6 + src/wp-includes/default-filters.php | 1 + src/wp-includes/post.php | 16 ++ .../wpPrivacyResetPolicyPageForPost.php | 172 ++++++++++++++++++ 4 files changed, 195 insertions(+) create mode 100644 tests/phpunit/tests/privacy/wpPrivacyResetPolicyPageForPost.php diff --git a/src/wp-admin/includes/class-wp-privacy-policy-content.php b/src/wp-admin/includes/class-wp-privacy-policy-content.php index 2f7ec2108d22f..141f073cd260c 100644 --- a/src/wp-admin/includes/class-wp-privacy-policy-content.php +++ b/src/wp-admin/includes/class-wp-privacy-policy-content.php @@ -329,6 +329,12 @@ public static function notice( $post = null ) { $current_screen = get_current_screen(); $policy_page_id = (int) get_option( 'wp_page_for_privacy_policy' ); + // If the privacy policy page has been deleted, reset the option and bail. + if ( $policy_page_id && ! get_post( $policy_page_id ) ) { + update_option( 'wp_page_for_privacy_policy', 0 ); + return; + } + if ( 'post' !== $current_screen->base || $policy_page_id !== $post->ID ) { return; } diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index b2790c7d43ec9..66504d37ad84d 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -590,6 +590,7 @@ add_action( 'init', 'create_initial_post_types', 0 ); // Highest priority. add_action( 'admin_menu', '_add_post_type_submenus' ); add_action( 'before_delete_post', '_reset_front_page_settings_for_post' ); +add_action( 'before_delete_post', '_reset_privacy_policy_page_for_post' ); add_action( 'wp_trash_post', '_reset_front_page_settings_for_post' ); add_action( 'change_locale', 'create_initial_post_types' ); diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index 3813176140bb4..da3abfbd7d61c 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -4052,6 +4052,22 @@ function _reset_front_page_settings_for_post( $post_id ) { unstick_post( $post->ID ); } +/** + * Resets the Privacy Policy page ID option when the Privacy Policy page + * is permanently deleted, to prevent uncached database queries for a + * non-existent page. + * + * @since 7.1.0 + * @access private + * + * @param int $post_id The ID of the post being deleted. + */ +function _reset_privacy_policy_page_for_post( int $post_id ): void { + if ( 'page' === get_post_type( $post_id ) && ( (int) get_option( 'wp_page_for_privacy_policy' ) === $post_id ) ) { + update_option( 'wp_page_for_privacy_policy', 0 ); + } +} + /** * Moves a post or page to the Trash * diff --git a/tests/phpunit/tests/privacy/wpPrivacyResetPolicyPageForPost.php b/tests/phpunit/tests/privacy/wpPrivacyResetPolicyPageForPost.php new file mode 100644 index 0000000000000..50ce04cb1bd44 --- /dev/null +++ b/tests/phpunit/tests/privacy/wpPrivacyResetPolicyPageForPost.php @@ -0,0 +1,172 @@ +post->create( array( 'post_type' => 'page' ) ); + assert( is_int( $page_id ) ); + $this->policy_page_id = $page_id; + update_option( 'wp_page_for_privacy_policy', $this->policy_page_id ); + } + + public function tear_down(): void { + delete_option( 'wp_page_for_privacy_policy' ); + parent::tear_down(); + } + + /** + * Tests that trashing the Privacy Policy page does NOT reset the option, + * so that restoring from trash preserves the assignment. + * + * @ticket 56694 + */ + public function test_trashing_privacy_policy_page_does_not_reset_option(): void { + wp_trash_post( $this->policy_page_id ); + + $this->assertSame( + $this->policy_page_id, + (int) get_option( 'wp_page_for_privacy_policy' ), + 'Trashing the Privacy Policy page should not reset wp_page_for_privacy_policy.' + ); + } + + /** + * Tests that permanently deleting the Privacy Policy page resets the option to 0. + * + * @ticket 56694 + */ + public function test_deleting_privacy_policy_page_resets_option(): void { + wp_delete_post( $this->policy_page_id, true ); + + $this->assertSame( 0, (int) get_option( 'wp_page_for_privacy_policy' ) ); + } + + /** + * Tests that trashing a different page does not change the option. + * + * @ticket 56694 + */ + public function test_trashing_a_different_page_does_not_reset_option(): void { + $other_page_id = self::factory()->post->create( array( 'post_type' => 'page' ) ); + $this->assertIsInt( $other_page_id ); + wp_trash_post( $other_page_id ); + + $this->assertSame( + $this->policy_page_id, + (int) get_option( 'wp_page_for_privacy_policy' ), + 'Trashing an unrelated page should not reset wp_page_for_privacy_policy.' + ); + } + + /** + * Tests that deleting a non-page post type does not change the option. + * + * @ticket 56694 + */ + public function test_deleting_non_page_post_type_does_not_reset_option(): void { + $post_id = self::factory()->post->create( array( 'post_type' => 'post' ) ); + $this->assertIsInt( $post_id ); + wp_delete_post( $post_id, true ); + + $this->assertSame( + $this->policy_page_id, + (int) get_option( 'wp_page_for_privacy_policy' ), + 'Deleting a non-page post should not reset wp_page_for_privacy_policy.' + ); + } + + /** + * Tests that WP_Privacy_Policy_Content::notice() resets the option to 0 + * when the stored ID points to a page that no longer exists. + * + * @ticket 56694 + * + * @covers WP_Privacy_Policy_Content::notice + */ + public function test_notice_self_heals_when_policy_page_does_not_exist(): void { + require_once ABSPATH . 'wp-admin/includes/class-wp-privacy-policy-content.php'; + + update_option( 'wp_page_for_privacy_policy', 99999 ); + + $user_id = self::factory()->user->create( array( 'role' => 'administrator' ) ); + $this->assertIsInt( $user_id ); + wp_set_current_user( $user_id ); + if ( is_multisite() ) { + grant_super_admin( $user_id ); + } + set_current_screen( 'post' ); + + $post = self::factory()->post->create_and_get( array( 'post_type' => 'page' ) ); + $this->assertInstanceOf( WP_Post::class, $post ); + WP_Privacy_Policy_Content::notice( $post ); + + $this->assertSame( + 0, + (int) get_option( 'wp_page_for_privacy_policy' ), + 'notice() should reset the option to 0 when the stored page does not exist.' + ); + } + + /** + * Tests that _reset_privacy_policy_page_for_post() does not call + * update_option() when wp_page_for_privacy_policy is already 0. + * + * @ticket 56694 + */ + public function test_no_update_option_when_policy_page_already_zero(): void { + update_option( 'wp_page_for_privacy_policy', 0 ); + + $call_count = 0; + add_filter( + 'pre_update_option_wp_page_for_privacy_policy', + static function ( $value ) use ( &$call_count ) { + ++$call_count; + return $value; + } + ); + + $other_page_id = self::factory()->post->create( array( 'post_type' => 'page' ) ); + $this->assertIsInt( $other_page_id ); + wp_delete_post( $other_page_id, true ); + + $this->assertSame( + 0, + $call_count, + 'update_option() should not be called when wp_page_for_privacy_policy is already 0.' + ); + } + + /** + * Tests that untrashing the Privacy Policy page preserves the option, + * confirming the trash/restore cycle keeps the assignment intact. + * + * @ticket 56694 + */ + public function test_untrashing_privacy_policy_page_preserves_option(): void { + wp_trash_post( $this->policy_page_id ); + wp_untrash_post( $this->policy_page_id ); + + $this->assertSame( + $this->policy_page_id, + (int) get_option( 'wp_page_for_privacy_policy' ), + 'Untrashing the Privacy Policy page should preserve wp_page_for_privacy_policy.' + ); + } +} From c6d10e9441880426be4330e75457507c7ef40477 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Fri, 24 Jul 2026 22:12:57 +0000 Subject: [PATCH 017/138] Editor: Sync the REST index preload field list with core-data. Sync the REST index preload field list in the post and site editors with the list the client requests, fixing a mismatch that left the preloaded response unused and logged a console warning on every editor load. Follow-up to [61703], [62806]. Props wildworks, westonruter. Fixes #65699. git-svn-id: https://develop.svn.wordpress.org/trunk@62846 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/edit-form-blocks.php | 14 ++++++++------ src/wp-admin/site-editor.php | 12 +++++++----- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 44fd623fa5ad2..a6d198ff15343 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -85,19 +85,21 @@ static function ( $classes ) { '/wp/v2/global-styles/' . WP_Theme_JSON_Resolver::get_user_global_styles_post_id() . '?context=' . $global_styles_endpoint_context, // Used by getBlockPatternCategories in useBlockEditorSettings. '/wp/v2/block-patterns/categories', - // @see packages/core-data/src/entities.js + /** + * The preloaded URL must exactly match the request the client makes, + * including the field order. + * @link https://github.com/WordPress/gutenberg/blob/trunk/packages/core-data/src/entities.js + */ '/?_fields=' . implode( ',', array( 'description', 'gmt_offset', 'home', + 'image_max_bit_depth', 'image_sizes', 'image_size_threshold', - 'image_output_formats', - 'jpeg_interlaced', - 'png_interlaced', - 'gif_interlaced', + 'image_strip_meta', 'name', 'site_icon', 'site_icon_url', @@ -109,7 +111,7 @@ static function ( $classes ) { 'show_on_front', ) ), - $paths[] = add_query_arg( + add_query_arg( 'slug', // @link https://github.com/WordPress/gutenberg/blob/e093fefd041eb6cc4a4e7f67b92ab54fd75c8858/packages/core-data/src/private-selectors.ts#L244-L254 $template_lookup_slug, diff --git a/src/wp-admin/site-editor.php b/src/wp-admin/site-editor.php index 9a8268c3392d7..4289f89f7102c 100644 --- a/src/wp-admin/site-editor.php +++ b/src/wp-admin/site-editor.php @@ -211,19 +211,21 @@ static function ( $classes ) { array( '/wp/v2/settings', 'OPTIONS' ), // Used by getBlockPatternCategories in useBlockEditorSettings. '/wp/v2/block-patterns/categories', - // @see packages/core-data/src/entities.js + /** + * The preloaded URL must exactly match the request the client makes, + * including the field order. + * @link https://github.com/WordPress/gutenberg/blob/trunk/packages/core-data/src/entities.js + */ '/?_fields=' . implode( ',', array( 'description', 'gmt_offset', 'home', + 'image_max_bit_depth', 'image_sizes', 'image_size_threshold', - 'image_output_formats', - 'jpeg_interlaced', - 'png_interlaced', - 'gif_interlaced', + 'image_strip_meta', 'name', 'site_icon', 'site_icon_url', From 749e622f7380686b71e9c9610161b38f8f7a6458 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Fri, 24 Jul 2026 22:31:58 +0000 Subject: [PATCH 018/138] Privacy: Fix type inconsistencies in data erasure inline notices. Additional messages can be inserted by plugins using the `wp_privacy_personal_data_erasers` filter, and are generated as list items (`li`) inside the notice markup. However, `li` was not targeted with notice-specific styling, and inherited the list item styles from the containing table. Add additional styles targeting list items inside notices in list tables to equalize font sizes and styling. Developed in https://github.com/WordPress/wordpress-develop/pull/12021 Props kimannwall, masteradhoc, joedolson. Fixes #53611. git-svn-id: https://develop.svn.wordpress.org/trunk@62847 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/common.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/wp-admin/css/common.css b/src/wp-admin/css/common.css index c286b8fa9ae0c..e1e5ee3181330 100644 --- a/src/wp-admin/css/common.css +++ b/src/wp-admin/css/common.css @@ -523,6 +523,13 @@ code { font-size: 14px; } +.widefat td .notice ul li, +.widefat th .notice ul li { + font-size: 13px; + line-height: 1.54; + margin: 0.5em 0; +} + .widefat td.check-column input, .widefat th input, .updates-table td input, From 3300b8b51acdcd53df7dd5f2cbabe6593a475cf1 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Sat, 25 Jul 2026 02:37:01 +0000 Subject: [PATCH 019/138] Administration: Make the Events widget no-JS notice translatable. The no-JavaScript fallback notice in `wp_print_community_events_markup()` wrapped its string in bare parentheses instead of `__()`, so it was never translated. Wrap it in `__()` to match the surrounding notices. Follow-up to [56599]. Props hbhalodia, mukesh27, wildworks. Fixes #65705. git-svn-id: https://develop.svn.wordpress.org/trunk@62848 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/dashboard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index a0b0ac6c77239..e74c31750513d 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -1377,7 +1377,7 @@ function wp_dashboard_events_news() { * @since 4.8.0 */ function wp_print_community_events_markup() { - $community_events_notice = '

' . ( 'This widget requires JavaScript.' ) . '

'; + $community_events_notice = '

' . __( 'This widget requires JavaScript.' ) . '

'; $community_events_notice .= ''; $community_events_notice .= ''; From 07b1f8b1d25db182d1ac4c2529d97e3d0cb04aea Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 25 Jul 2026 20:43:21 +0000 Subject: [PATCH 020/138] Docs: Fix typo in a comment in `wp_dashboard_rss_control()`. Follow-up to [6705]. Props mukesh27. See #64896. git-svn-id: https://develop.svn.wordpress.org/trunk@62849 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/dashboard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index e74c31750513d..5fdbaf7a4fa40 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -1294,7 +1294,7 @@ function wp_dashboard_rss_control( $widget_id, $form_inputs = array() ) { $widget_options[ $widget_id ] = wp_widget_rss_process( $_POST['widget-rss'][ $number ] ); $widget_options[ $widget_id ]['number'] = $number; - // Title is optional. If black, fill it if possible. + // Title is optional. If blank, fill it if possible. if ( ! $widget_options[ $widget_id ]['title'] && isset( $_POST['widget-rss'][ $number ]['title'] ) ) { $rss = fetch_feed( $widget_options[ $widget_id ]['url'] ); if ( is_wp_error( $rss ) ) { From 05d3b3cec4e761cbc0dc9b39d37116af2397950e Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 26 Jul 2026 15:04:51 +0000 Subject: [PATCH 021/138] KSES: Allow the autofocus attribute on dialog elements. First step to allow the usage of the autofocus attribute for native dialog elements. More work will follow to add a context-aware mechanism to KSES and allow the attribute on dialog element children. Props westonruter, joedolson, mukesh27, afercia. Fixes #65491. git-svn-id: https://develop.svn.wordpress.org/trunk@62850 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/kses.php | 7 ++++--- tests/phpunit/tests/kses.php | 12 ++++++++++++ 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php index 46cd2c4576c03..d68021c3a8b30 100644 --- a/src/wp-includes/kses.php +++ b/src/wp-includes/kses.php @@ -158,9 +158,10 @@ 'popover' => true, ), 'dialog' => array( - 'closedby' => true, - 'open' => true, - 'popover' => true, + 'closedby' => true, + 'open' => true, + 'popover' => true, + 'autofocus' => true, ), 'dl' => array(), 'dt' => array(), diff --git a/tests/phpunit/tests/kses.php b/tests/phpunit/tests/kses.php index 1afd7e0884a64..f560d88403524 100644 --- a/tests/phpunit/tests/kses.php +++ b/tests/phpunit/tests/kses.php @@ -2183,6 +2183,18 @@ public function test_wp_kses_main_tag_standard_attributes() { $this->assertEqualHTML( $html, wp_kses_post( $html ) ); } + /** + * Tests that the autofocus attribute is allowed on dialog elements and removed from other focusable elements. + * + * @ticket 65491 + */ + public function test_wp_kses_dialog_autofocus_attribute() { + $html = 'Content
Some content
'; + $expected = 'Content
Some content
'; + + $this->assertEqualHTML( $expected, wp_kses_post( $html ) ); + } + /** * Test that Invoker Commands API attributes are preserved on buttons in post content. * From 17d5f5f09e9d78f6ef65355206c50601dcf637ae Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sun, 26 Jul 2026 20:53:31 +0000 Subject: [PATCH 022/138] Media: Restore the label of the 'Filter by date' select in the Media grid. Fixes a typo after [62326] that prevented the 'Filter by date' select label from rendering. Props joedolson, mirmpro, afercia. Fixes #65711. git-svn-id: https://develop.svn.wordpress.org/trunk@62851 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/media/views/attachments/browser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/media/views/attachments/browser.js b/src/js/media/views/attachments/browser.js index 26218ea2fa1ae..5533110d815f9 100644 --- a/src/js/media/views/attachments/browser.js +++ b/src/js/media/views/attachments/browser.js @@ -223,7 +223,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro this.toolbar.set( 'filters', Filters.render() ); } } - + /* * Feels odd to bring the global media library switcher into the Attachment browser view. * Is this a use case for doAction( 'add:toolbar-items:attachments-browser', this.toolbar ); @@ -241,7 +241,7 @@ AttachmentsBrowser = View.extend(/** @lends wp.media.view.AttachmentsBrowser.pro }).render() ); // DateFilter is a + +

diff --git a/src/wp-admin/options-reading.php b/src/wp-admin/options-reading.php index 31facac7edcca..d52d51bbe3ae4 100644 --- a/src/wp-admin/options-reading.php +++ b/src/wp-admin/options-reading.php @@ -175,14 +175,14 @@ - + - + - - + + From 455fb3f01faa13a53a37d93ba2cfc350b2809495 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Sat, 1 Aug 2026 09:10:32 +0000 Subject: [PATCH 088/138] Media: Restore selection previews in the Media dialog bottom toolbar. Developed in https://github.com/WordPress/wordpress-develop/pull/12784 Props sukhendu2002, mukesh27, iqbal1hossain, afercia. Fixes #65767. git-svn-id: https://develop.svn.wordpress.org/trunk@62962 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/css/media-views.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index 089baaed6c7ab..227be604f7852 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -332,7 +332,6 @@ .media-toolbar-secondary { float: left; height: 100%; - position: relative; display: grid; grid-template-columns: repeat( 2, 1fr ); grid-template-rows: repeat( 2, 1fr ); @@ -1309,6 +1308,7 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { .attachments-browser .media-toolbar-secondary { max-width: 66%; + position: relative; } .uploader-inline .close { From 1606cb0cc05ab4c3da33db6f3f49b5ec885d5846 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Sat, 1 Aug 2026 12:29:43 +0000 Subject: [PATCH 089/138] Media: Fix a jQuery Migrate warning for disabled buttons. Under jQuery 4.0, disabling a media button or the image cropper's action button triggered a jQuery Migrate warning about the boolean `disabled` attribute. These buttons now toggle the `disabled` property instead, which removes the warning and keeps the behavior unchanged. Developed in: https://github.com/WordPress/wordpress-develop/pull/10661 Props audrasjb, azaozz, hbhalodia, neo2k23, wildworks. See #64425. git-svn-id: https://develop.svn.wordpress.org/trunk@62963 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/media/controllers/cropper.js | 2 +- src/js/media/views/button.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/js/media/controllers/cropper.js b/src/js/media/controllers/cropper.js index b0a7a394400e5..2685f743ea8c7 100644 --- a/src/js/media/controllers/cropper.js +++ b/src/js/media/controllers/cropper.js @@ -116,7 +116,7 @@ Cropper = wp.media.controller.State.extend(/** @lends wp.media.controller.Croppe selection.set({cropDetails: controller.state().imgSelect.getSelection()}); this.$el.text(l10n.cropping); - this.$el.attr('disabled', true); + this.$el.prop( 'disabled', true ); controller.state().doCrop( selection ).done( function( croppedImage ) { controller.trigger('cropped', croppedImage ); diff --git a/src/js/media/views/button.js b/src/js/media/views/button.js index 988c95ccb1bf3..5b380d13d19f0 100644 --- a/src/js/media/views/button.js +++ b/src/js/media/views/button.js @@ -64,7 +64,7 @@ var Button = wp.media.View.extend(/** @lends wp.media.view.Button.prototype */{ classes = _.uniq( classes.concat( this.options.classes ) ); this.el.className = classes.join(' '); - this.$el.attr( 'disabled', model.disabled ); + this.$el.prop( 'disabled', model.disabled ); this.$el.text( this.model.get('text') ); return this; From f408760d5767018c2cf495fe2375e562f4942013 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sat, 1 Aug 2026 16:42:13 +0000 Subject: [PATCH 090/138] HTML API: Use `str_contains()` instead of `strpos()` in `WP_HTML_Tag_Processor`. The `str_contains()` function was introduced in PHP 8.0 and a polyfill is available in WordPress Core, making the intent of the check clearer than comparing the result of `strpos()` against false. Follow-up to [62687]. Props Soean, mukesh27, westonruter. See #64897. git-svn-id: https://develop.svn.wordpress.org/trunk@62964 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/html-api/class-wp-html-tag-processor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/html-api/class-wp-html-tag-processor.php b/src/wp-includes/html-api/class-wp-html-tag-processor.php index ba33bea28506c..7ca5191a0f162 100644 --- a/src/wp-includes/html-api/class-wp-html-tag-processor.php +++ b/src/wp-includes/html-api/class-wp-html-tag-processor.php @@ -2073,7 +2073,7 @@ private function parse_next_tag(): bool { */ $is_valid_pi = ( 0 !== $target_length && - false !== strpos( " \t\f\r\n?>", $html[ $target_at + $target_length ] ) && + str_contains( " \t\f\r\n?>", $html[ $target_at + $target_length ] ) && ! ( 3 === $target_length && 0 === substr_compare( $html, 'xml', $target_at, 3, true ) ) && ! ( 14 === $target_length && 0 === substr_compare( $html, 'xml-stylesheet', $target_at, 14, true ) ) ); From 47a5084d3fcffc10db2a69a57c69f9dc948f32ac Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 2 Aug 2026 06:51:36 +0000 Subject: [PATCH 091/138] Build/Test Tools: Improve the constants defined for PHPStan. Many constants were defined as empty strings, including ones that never hold an empty value in a real install. Realistic values are provided for those, matching what wp-settings.php and default-constants.php would produce, so that functions building on them can be given narrower types without the placeholder itself violating them. Constants core itself defines as empty, such as WP_DEVELOPMENT_MODE and COOKIE_DOMAIN, are left as they were. Developed as subset of https://github.com/WordPress/wordpress-develop/pull/11851. See #64898. git-svn-id: https://develop.svn.wordpress.org/trunk@62965 602fd350-edb4-49c9-b593-d223f7449a82 --- tests/phpstan/bootstrap.php | 70 +++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 31 deletions(-) diff --git a/tests/phpstan/bootstrap.php b/tests/phpstan/bootstrap.php index 6eedeec93c4a7..db0b05e9ed880 100644 --- a/tests/phpstan/bootstrap.php +++ b/tests/phpstan/bootstrap.php @@ -7,7 +7,14 @@ * Loaded as a `bootstrapFile` by PHPStan; see `base.neon`. */ -// wp_initial_constants() +/* + * A fixed, fictional path rather than the real checkout location. PHPStan resolves + * no files through this constant, and deriving it from __DIR__ embeds the developer's + * own path in error messages, making output differ between machines. + */ +define( 'ABSPATH', '/var/www/html/' ); + +/** @see wp_initial_constants() */ define( 'KB_IN_BYTES', 1024 ); define( 'MB_IN_BYTES', 1024 * KB_IN_BYTES ); define( 'GB_IN_BYTES', 1024 * MB_IN_BYTES ); @@ -16,9 +23,10 @@ define( 'EB_IN_BYTES', 1024 * PB_IN_BYTES ); define( 'ZB_IN_BYTES', 1024 * EB_IN_BYTES ); define( 'YB_IN_BYTES', 1024 * ZB_IN_BYTES ); -define( 'WP_START_TIMESTAMP', microtime( true ) ); -define( 'WP_MEMORY_LIMIT', '' ); -define( 'WP_MAX_MEMORY_LIMIT', '' ); +define( 'WP_START_TIMESTAMP', 1700000000.0 ); // Fixed rather than microtime( true ), whose value would differ on every run. +define( 'WP_MEMORY_LIMIT', '40M' ); +define( 'WP_MAX_MEMORY_LIMIT', '256M' ); +define( 'WP_CONTENT_DIR', ABSPATH . 'wp-content' ); define( 'WP_DEVELOPMENT_MODE', '' ); define( 'WP_DEBUG', false ); define( 'WP_DEBUG_DISPLAY', false ); @@ -35,25 +43,25 @@ define( 'MONTH_IN_SECONDS', 30 * DAY_IN_SECONDS ); define( 'YEAR_IN_SECONDS', 365 * DAY_IN_SECONDS ); -// wp_set_lang_dir() -define( 'WP_LANG_DIR', '' ); +/** @see wp_set_lang_dir() */ +define( 'WP_LANG_DIR', WP_CONTENT_DIR . '/languages' ); // wp_plugin_directory_constants() -define( 'WP_CONTENT_URL', '' ); -define( 'WP_PLUGIN_DIR', '' ); -define( 'WP_PLUGIN_URL', '' ); -define( 'PLUGINDIR', '' ); -define( 'WPMU_PLUGIN_DIR', '' ); -define( 'WPMU_PLUGIN_URL', '' ); -define( 'MUPLUGINDIR', '' ); +define( 'WP_CONTENT_URL', 'https://example.com/wp-content' ); +define( 'WP_PLUGIN_DIR', WP_CONTENT_DIR . '/plugins' ); +define( 'WP_PLUGIN_URL', WP_CONTENT_URL . '/plugins' ); +define( 'PLUGINDIR', 'wp-content/plugins' ); +define( 'WPMU_PLUGIN_DIR', WP_CONTENT_DIR . '/mu-plugins' ); +define( 'WPMU_PLUGIN_URL', WP_CONTENT_URL . '/mu-plugins' ); +define( 'MUPLUGINDIR', 'wp-content/mu-plugins' ); -// ms_cookie_constants() +/** @see ms_cookie_constants() */ define( 'COOKIEPATH', '' ); define( 'SITECOOKIEPATH', '' ); define( 'ADMIN_COOKIE_PATH', '' ); define( 'COOKIE_DOMAIN', '' ); -// wp_cookie_constants() +/** @see wp_cookie_constants() */ define( 'COOKIEHASH', '' ); define( 'USER_COOKIE', '' ); define( 'PASS_COOKIE', '' ); @@ -64,34 +72,34 @@ define( 'PLUGINS_COOKIE_PATH', '' ); define( 'RECOVERY_MODE_COOKIE', '' ); -// wp_ssl_constants() +/** @see wp_ssl_constants() */ define( 'FORCE_SSL_LOGIN', false ); define( 'FORCE_SSL_ADMIN', false ); -// wp_functionality_constants() +/** @see wp_functionality_constants() */ define( 'AUTOSAVE_INTERVAL', MINUTE_IN_SECONDS ); define( 'EMPTY_TRASH_DAYS', 1 ); define( 'WP_POST_REVISIONS', true ); define( 'WP_CRON_LOCK_TIMEOUT', MINUTE_IN_SECONDS ); -// wp_templating_constants() -define( 'TEMPLATEPATH', '' ); -define( 'STYLESHEETPATH', '' ); -define( 'WP_DEFAULT_THEME', '' ); +/** @see wp_templating_constants() */ +define( 'TEMPLATEPATH', WP_CONTENT_DIR . '/themes/twentytwentyfive' ); +define( 'STYLESHEETPATH', WP_CONTENT_DIR . '/themes/twentytwentyfive' ); +define( 'WP_DEFAULT_THEME', 'twentytwentyfive' ); -// ms_file_constants() +/** @see ms_file_constants() */ define( 'WPMU_SENDFILE', false ); define( 'WPMU_ACCEL_REDIRECT', false ); -// ms_load_current_site_and_network() +/** @see ms_load_current_site_and_network() */ define( 'NOBLOGREDIRECT', '' ); -// ms_upload_constants() -define( 'UPLOADBLOGSDIR', '' ); -define( 'BLOGUPLOADDIR', '' ); +/** @see ms_upload_constants() */ +define( 'UPLOADBLOGSDIR', 'wp-content/blogs.dir' ); +define( 'BLOGUPLOADDIR', WP_CONTENT_DIR . '/blogs.dir/1/files/' ); -// Misc constants not part of the default lifecycle. -define( 'FS_CONNECT_TIMEOUT', 1 ); -define( 'FS_TIMEOUT', 1 ); -define( 'FS_CHMOD_DIR', 1 ); -define( 'FS_CHMOD_FILE', 1 ); +/** @see WP_Filesystem() */ +define( 'FS_CONNECT_TIMEOUT', 30 ); // 30 seconds. +define( 'FS_TIMEOUT', 30 ); // 30 seconds. +define( 'FS_CHMOD_DIR', 0755 ); +define( 'FS_CHMOD_FILE', 0644 ); From 29fe42e5fb586b0131f1ea821c478ca6d3a521be Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Sun, 2 Aug 2026 07:05:51 +0000 Subject: [PATCH 092/138] Docs: Improve block asset registration docblocks. Per the inline documentation standards, a docblock's summary belongs on its own line separated from the description, and the description should not open with "It". This is applied to `register_block_script_module_id()`, `register_block_script_handle()`, and `register_block_style_handle()`, together with some missing articles in the same descriptions. Two of those descriptions no longer matched the code. `register_block_script_handle()` said the script is registered under an automatically generated handle, but since 6.5.0 the handle is taken from the asset file whenever one provides it, and generation is only the fallback. `register_block_style_handle()` said it returns the unprocessed style handle otherwise, which does not hold for the first style of a core block: that one is registered from the block's own stylesheet when separate core block assets are loaded, and skipped entirely when they are not. The same functions gain `@phpstan-` annotations describing the shape of the `$metadata` they accept and the narrower strings they return. The shapes follow the `block.json` schema, which constrains only `name`, so the remaining fields stay plain strings; `file` is nullable and `name` optional because `register_block_type_from_metadata()` can reach all three functions with neither present. Developed in https://github.com/WordPress/wordpress-develop/pull/11851. Follow-up to r48141, r55447, r57559, r57565. Props deepakrohilla, westonruter, sabernhardt, wildworks, audrasjb. See #64898. Fixes #65259. git-svn-id: https://develop.svn.wordpress.org/trunk@62966 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/blocks.php | 86 ++++++++++++++++++++++++++++++++------ 1 file changed, 73 insertions(+), 13 deletions(-) diff --git a/src/wp-includes/blocks.php b/src/wp-includes/blocks.php index 41e11f4a2a75f..a0360ffdc8bf8 100644 --- a/src/wp-includes/blocks.php +++ b/src/wp-includes/blocks.php @@ -43,6 +43,11 @@ function remove_block_asset_path_prefix( $asset_handle_or_path ) { * @param int $index Optional. Index of the asset when multiple items passed. * Default 0. * @return string Generated asset name for the block's field. + * + * @phpstan-param non-falsy-string $block_name + * @phpstan-param 'editorScript'|'editorStyle'|'script'|'style'|'viewScript'|'viewScriptModule'|'viewStyle' $field_name + * @phpstan-param int<0, max> $index + * @phpstan-return non-falsy-string */ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { if ( str_starts_with( $block_name, 'core/' ) ) { @@ -86,6 +91,8 @@ function generate_block_asset_handle( $block_name, $field_name, $index = 0 ) { * * @param string $path A normalized path to a block asset. * @return string|false The URL to the block asset or false on failure. + * + * @phpstan-return non-falsy-string|false */ function get_block_asset_url( $path ) { if ( empty( $path ) ) { @@ -102,6 +109,7 @@ function get_block_asset_url( $path ) { return includes_url( str_replace( $wpinc_path_norm, '', $path ) ); } + /** @var array $template_paths_norm */ static $template_paths_norm = array(); $template = get_template(); @@ -128,11 +136,12 @@ function get_block_asset_url( $path ) { } /** - * Finds a script module ID for the selected block metadata field. It detects - * when a path to file was provided and optionally finds a corresponding asset - * file with details necessary to register the script module under with an - * automatically generated module ID. It returns unprocessed script module - * ID otherwise. + * Finds a script module ID for the selected block metadata field. + * + * Detects when a path to a file was provided and optionally finds a + * corresponding asset file with details necessary to register the script + * module with an automatically generated module ID. It returns the + * unprocessed script module ID otherwise. * * @since 6.5.0 * @@ -141,6 +150,21 @@ function get_block_asset_url( $path ) { * @param int $index Optional. Index of the script module ID to register when multiple * items passed. Default 0. * @return string|false Script module ID or false on failure. + * + * @phpstan-param array{ + * name?: non-falsy-string, + * file: non-falsy-string|null, + * version?: string, + * supports?: array{ + * interactivity?: bool|array{interactive?: bool, clientNavigation?: bool, ...}, + * ... + * }, + * viewScriptModule?: string|list, + * ... + * } $metadata + * @phpstan-param 'viewScriptModule' $field_name + * @phpstan-param int<0, max> $index + * @phpstan-return non-falsy-string|false */ function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { if ( empty( $metadata[ $field_name ] ) ) { @@ -170,6 +194,7 @@ function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { $module_path_norm = wp_normalize_path( realpath( $path . '/' . $module_path ) ); $module_uri = get_block_asset_url( $module_path_norm ); + /** @var array{ dependencies?: list, version?: string|false|null, ... } $module_asset */ $module_asset = ! empty( $module_asset_path ) ? require $module_asset_path : array(); $module_dependencies = $module_asset['dependencies'] ?? array(); $block_version = $metadata['version'] ?? false; @@ -206,10 +231,13 @@ function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { } /** - * Finds a script handle for the selected block metadata field. It detects - * when a path to file was provided and optionally finds a corresponding asset - * file with details necessary to register the script under automatically - * generated handle name. It returns unprocessed script handle otherwise. + * Finds a script handle for the selected block metadata field. + * + * Detects when a path to a file was provided and optionally finds a + * corresponding asset file with details necessary to register the script. The + * handle is taken from the asset file when it provides one, and is otherwise + * generated automatically. It returns the unprocessed script handle when a + * handle rather than a path was given. * * @since 5.5.0 * @since 6.1.0 Added `$index` parameter. @@ -221,6 +249,20 @@ function register_block_script_module_id( $metadata, $field_name, $index = 0 ) { * Default 0. * @return string|false Script handle provided directly or created through * script's registration, or false on failure. + * + * @phpstan-param array{ + * name?: non-falsy-string, + * file: non-falsy-string|null, + * version?: string, + * textdomain?: string, + * editorScript?: string|list, + * script?: string|list, + * viewScript?: string|list, + * ... + * } $metadata + * @phpstan-param 'editorScript'|'script'|'viewScript' $field_name + * @phpstan-param int<0, max> $index + * @phpstan-return non-falsy-string|false */ function register_block_script_handle( $metadata, $field_name, $index = 0 ) { if ( empty( $metadata[ $field_name ] ) ) { @@ -247,6 +289,7 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) { ); // Asset file for blocks is optional. See https://core.trac.wordpress.org/ticket/60460. + /** @var array{ handle?: non-falsy-string, dependencies?: list, version?: string|false|null, ... } $script_asset */ $script_asset = ! empty( $script_asset_path ) ? require $script_asset_path : array(); $script_handle = $script_asset['handle'] ?? generate_block_asset_handle( $metadata['name'], $field_name, $index ); @@ -283,9 +326,13 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) { } /** - * Finds a style handle for the block metadata field. It detects when a path - * to file was provided and registers the style under automatically - * generated handle name. It returns unprocessed style handle otherwise. + * Finds a style handle for the block metadata field. + * + * Detects when a path to a file was provided and registers the style under an + * automatically generated handle name. It returns the unprocessed style handle + * otherwise, except for the first style of a core block, which is instead + * registered from the block's own stylesheet when separate core block assets + * are loaded. Core blocks accept only handles, not paths. * * @since 5.5.0 * @since 6.1.0 Added `$index` parameter. @@ -296,6 +343,19 @@ function register_block_script_handle( $metadata, $field_name, $index = 0 ) { * Default 0. * @return string|false Style handle provided directly or created through * style's registration, or false on failure. + * + * @phpstan-param array{ + * name?: non-falsy-string, + * file: non-falsy-string|null, + * version?: string, + * editorStyle?: string|list, + * style?: string|list, + * viewStyle?: string|list, + * ... + * } $metadata + * @phpstan-param 'editorStyle'|'style'|'viewStyle' $field_name + * @phpstan-param int<0, max> $index + * @phpstan-return non-falsy-string|false */ function register_block_style_handle( $metadata, $field_name, $index = 0 ) { if ( empty( $metadata[ $field_name ] ) ) { @@ -2778,7 +2838,7 @@ function build_query_vars_from_query_block( $block, $page ) { if ( 'only' === $block->context['query']['sticky'] ) { /* * Passing an empty array to post__in will return have_posts() as true (and all posts will be returned). - * Logic should be used before hand to determine if WP_Query should be used in the event that the array + * Logic should be used beforehand to determine if WP_Query should be used in the event that the array * being passed to post__in is empty. * * @see https://core.trac.wordpress.org/ticket/28099 From 89685c5790c29aa1a0e618e51a708c505c0c022a Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Sun, 2 Aug 2026 21:59:17 +0000 Subject: [PATCH 093/138] Users: Show/hide password button icon misaligned. In several contexts (Add New User, Install, and Setup/Config), the show/hide password icon was misaligned in varying amounts in different viewports. Add the classes `wp-hide-pw` and `user-new-password-toggle` to the button container to re-use existing CSS consistently. Developed in https://github.com/WordPress/wordpress-develop/pull/12472 Props sanayasir, iamchitti, softglaze, shailu25, soyebsalar01, noruzzaman, ugyensupport, wildworks, ankitpatel1578, praful2111, joedolson, sabernhardt. Fixes #65605. git-svn-id: https://develop.svn.wordpress.org/trunk@62967 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/install.php | 2 +- src/wp-admin/setup-config.php | 2 +- src/wp-admin/user-new.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-admin/install.php b/src/wp-admin/install.php index 737d1b73f1855..b6b7a08f2a5aa 100644 --- a/src/wp-admin/install.php +++ b/src/wp-admin/install.php @@ -143,7 +143,7 @@ function display_setup_form( $error = null ) {

- diff --git a/src/wp-admin/setup-config.php b/src/wp-admin/setup-config.php index dd6794d5f8e27..ec4d1a8bbbdbc 100644 --- a/src/wp-admin/setup-config.php +++ b/src/wp-admin/setup-config.php @@ -240,7 +240,7 @@ function setup_config_display_header( $body_classes = array() ) {
- diff --git a/src/wp-admin/user-new.php b/src/wp-admin/user-new.php index ba027b06bb366..3136705f60a03 100644 --- a/src/wp-admin/user-new.php +++ b/src/wp-admin/user-new.php @@ -603,7 +603,7 @@
- From d1c6be6bdae3fb1ef62321df1a8f36060ab26069 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Sun, 2 Aug 2026 22:23:00 +0000 Subject: [PATCH 094/138] Widgets: Show post excerpts in On This Day widget if no title. Match the behavior of posts in list tables by showing a short excerpt in the On This Day widget when the post does not have a saved title. Developed in https://github.com/WordPress/wordpress-develop/pull/12581 Props alshakero, softglaze, iamraju, mirmpro, shailu25, bph, nazmulasif, wildworks, annezazu, mukesh27, peterwilsoncc, joedolson. Fixes #65658. git-svn-id: https://develop.svn.wordpress.org/trunk@62968 602fd350-edb4-49c9-b593-d223f7449a82 --- .../includes/dashboard-on-this-day.php | 20 +- .../tests/admin/wpDashboardOnThisDay.php | 191 +++++++++++++++++- 2 files changed, 200 insertions(+), 11 deletions(-) diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php index 1939f8ca4b0e3..e9557a60720c8 100644 --- a/src/wp-admin/includes/dashboard-on-this-day.php +++ b/src/wp-admin/includes/dashboard-on-this-day.php @@ -114,10 +114,19 @@ function wp_dashboard_on_this_day() {
    ID ) && ! post_password_required( $year_post ) ) { + $excerpt = get_the_excerpt( $year_post ); + + if ( is_string( $excerpt ) && '' !== $excerpt ) { + $no_title_excerpt = wp_trim_words( $excerpt, 15 ); + } + } } $author_id = (int) $year_post->post_author; @@ -125,7 +134,14 @@ function wp_dashboard_on_this_day() { $show_author = '' !== trim( $author_name ) && get_current_user_id() !== $author_id; ?>
  • - + + + + ' . esc_html( diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php index 471324f9648ec..a2b1cdbfaff1f 100644 --- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php +++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php @@ -58,23 +58,28 @@ private function set_up_dashboard_screen() { * @param string $title Post title. * @param int $years_ago Number of years before today. * @param string $time Post time. + * @param array $post_args Additional post arguments. * @return int Post ID. */ private function create_matching_post( int $author_id, string $title = 'A memory from last year', int $years_ago = 1, - string $time = '12:00:00' + string $time = '12:00:00', + array $post_args = array() ): int { $post_date = current_datetime()->modify( '-' . $years_ago . ' years' )->format( 'Y-m-d' ) . ' ' . $time; return self::factory()->post->create( - array( - 'post_author' => $author_id, - 'post_date' => $post_date, - 'post_date_gmt' => get_gmt_from_date( $post_date ), - 'post_status' => 'publish', - 'post_title' => $title, + array_merge( + array( + 'post_author' => $author_id, + 'post_date' => $post_date, + 'post_date_gmt' => get_gmt_from_date( $post_date ), + 'post_status' => 'publish', + 'post_title' => $title, + ), + $post_args ) ); } @@ -338,6 +343,162 @@ public function test_widget_groups_posts_by_year() { /** * @ticket 65116 * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_includes_trimmed_excerpt_for_untitled_posts() { + wp_set_current_user( self::$user_id ); + + $words = array(); + for ( $n = 1; $n <= 20; $n++ ) { + $words[] = 'word' . $n; + } + + $this->create_matching_post( + self::$user_id, + '', + 1, + '12:00:00', + array( + 'post_excerpt' => implode( ' ', $words ), + ) + ); + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertStringContainsString( '(no title)', $output ); + $this->assertStringContainsString( 'word15', $output, 'The 15th word should be present.' ); + $this->assertStringNotContainsString( 'word16', $output, 'The 16th word should be trimmed.' ); + $this->assertStringContainsString( '…', $output, 'The excerpt should end with an ellipsis.' ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_does_not_append_excerpt_to_titled_posts() { + wp_set_current_user( self::$user_id ); + + $this->create_matching_post( + self::$user_id, + 'A titled anniversary memory', + 1, + '12:00:00', + array( + 'post_excerpt' => 'This excerpt should not be shown.', + ) + ); + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'A titled anniversary memory', $output ); + $this->assertStringNotContainsString( 'This excerpt should not be shown.', $output ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_authored_by_current_user() { + $this->set_up_dashboard_screen(); + + wp_set_current_user( self::$user_id ); + + $this->create_matching_post( + self::$user_id, + '', + 1, + '12:00:00', + array( + 'post_excerpt' => 'Readable private anniversary memory.', + 'post_status' => 'private', + ) + ); + + add_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); + + ob_start(); + try { + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + } finally { + remove_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); + } + + $this->assertStringContainsString( '(no title)', $output ); + $this->assertStringContainsString( 'Readable private anniversary memory.', $output ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() { + $this->set_up_dashboard_screen(); + + wp_set_current_user( self::$user_id ); + + $post_id = $this->create_matching_post( + self::$other_user_id, + '', + 1, + '12:00:00', + array( + 'post_excerpt' => 'Unreadable private anniversary memory.', + 'post_status' => 'private', + ) + ); + + add_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); + + ob_start(); + try { + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + } finally { + remove_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); + } + + $this->assertFalse( current_user_can( 'read_post', $post_id ) ); + $this->assertStringContainsString( '(no title)', $output ); + $this->assertStringNotContainsString( 'Unreadable private anniversary memory.', $output ); + } + + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_hides_untitled_post_excerpt_for_password_protected_posts() { + $this->set_up_dashboard_screen(); + + wp_set_current_user( self::$user_id ); + + $this->create_matching_post( + self::$user_id, + '', + 1, + '12:00:00', + array( + 'post_excerpt' => 'Private anniversary memory.', + 'post_password' => 'secret', + ) + ); + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertStringNotContainsString( 'Private anniversary memory.', $output ); + } + + /** * @covers ::wp_dashboard_on_this_day * @covers ::wp_dashboard_on_this_day_get_posts */ @@ -353,8 +514,20 @@ public function test_widget_limits_posts_to_ten() { $output = ob_get_clean(); $this->assertStringContainsString( '10 posts have been published on ' . wp_date( 'F jS' ) . ':', $output ); - $this->assertStringContainsString( 'Anniversary post 1<', $output ); - $this->assertStringContainsString( 'Anniversary post 10<', $output ); + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 1\s*<\/a>/', $output ); + $this->assertMatchesRegularExpression( '/>\s*Anniversary post 10\s*<\/a>/', $output ); $this->assertStringNotContainsString( 'Anniversary post 11', $output ); } + + /** + * Filters the On This Day query to include private posts. + * + * @param array $args WP_Query arguments. + * @return array Filtered query arguments. + */ + public function filter_on_this_day_query_private_posts( $args ) { + $args['post_status'] = array( 'private' ); + + return $args; + } } From a379d09c5be455a9fdea5168c9380c0d98d593d4 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Sun, 2 Aug 2026 23:48:34 +0000 Subject: [PATCH 095/138] Tests: Use `assertTrue()`/`assertFalse()` instead of `assertSame()` with booleans. Using the dedicated boolean assertions clarifies intent and produces more descriptive failure messages. Follow-up to [51453]. Props Soean, mukesh27. See #64894. git-svn-id: https://develop.svn.wordpress.org/trunk@62969 602fd350-edb4-49c9-b593-d223f7449a82 --- tests/phpunit/tests/blocks/wpBlockType.php | 8 ++++---- .../interactivity-api/wpInteractivityAPI-wp-bind.php | 4 ++-- tests/phpunit/tests/rest-api/rest-post-meta-fields.php | 2 +- tests/phpunit/tests/rest-api/wpRestMenusController.php | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/phpunit/tests/blocks/wpBlockType.php b/tests/phpunit/tests/blocks/wpBlockType.php index a73efa8ce8a7d..3e69b67d965db 100644 --- a/tests/phpunit/tests/blocks/wpBlockType.php +++ b/tests/phpunit/tests/blocks/wpBlockType.php @@ -528,9 +528,9 @@ public function test_variations_callback_are_lazy_loaded() { ) ); - $this->assertSame( false, $callback_called, 'The callback should not be called before the variations are accessed.' ); + $this->assertFalse( $callback_called, 'The callback should not be called before the variations are accessed.' ); $block_type->variations; // access the variations. - $this->assertSame( true, $callback_called, 'The callback should be called when the variations are accessed.' ); + $this->assertTrue( $callback_called, 'The callback should be called when the variations are accessed.' ); } /** @@ -555,7 +555,7 @@ public function test_variations_precedence_over_callback_post_registration() { // If the variations are defined after registration but before first access, the callback should not override it. $this->assertSameSets( $test_variations, $block_type->get_variations(), 'Variations are same as variations set' ); - $this->assertSame( false, $callback_called, 'The callback was never called.' ); + $this->assertFalse( $callback_called, 'The callback was never called.' ); } /** @@ -617,7 +617,7 @@ public function test_get_block_type_variations_filter_with_variation_callback() $obtained_variations = $block_type->variations; // access the variations. - $this->assertSame( true, $callback_called, 'The callback should be called when the variations are accessed.' ); + $this->assertTrue( $callback_called, 'The callback should be called when the variations are accessed.' ); $this->assertSameSets( $obtained_variations, $expected_variations, 'The variations obtained from the callback should be filtered.' ); } diff --git a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php index e80930357b6fc..1951919941a32 100644 --- a/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php +++ b/tests/phpunit/tests/interactivity-api/wpInteractivityAPI-wp-bind.php @@ -454,7 +454,7 @@ public function test_wp_bind_handles_nested_bindings() { public function test_wp_bind_handles_true_value() { $html = '
    '; list($p) = $this->process_directives( $html ); - $this->assertSame( true, $p->get_attribute( 'id' ) ); + $this->assertTrue( $p->get_attribute( 'id' ) ); } /** @@ -467,7 +467,7 @@ public function test_wp_bind_handles_true_value() { public function test_wp_bind_ignores_unique_ids() { $html = '
    '; list($p) = $this->process_directives( $html ); - $this->assertSame( true, $p->get_attribute( 'id' ) ); + $this->assertTrue( $p->get_attribute( 'id' ) ); $html = '
    '; list($p) = $this->process_directives( $html ); diff --git a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php index 5ce72a57fa55f..0f8584f469892 100644 --- a/tests/phpunit/tests/rest-api/rest-post-meta-fields.php +++ b/tests/phpunit/tests/rest-api/rest-post-meta-fields.php @@ -2348,7 +2348,7 @@ public function test_update_meta_with_unchanged_values_and_custom_authentication $this->assertSame( 200, $response->get_status() ); $data = $response->get_data(); - $this->assertSame( false, $data['meta']['authenticated'] ); + $this->assertFalse( $data['meta']['authenticated'] ); } /** diff --git a/tests/phpunit/tests/rest-api/wpRestMenusController.php b/tests/phpunit/tests/rest-api/wpRestMenusController.php index 864b09417d2cb..46f9877e3cfc0 100644 --- a/tests/phpunit/tests/rest-api/wpRestMenusController.php +++ b/tests/phpunit/tests/rest-api/wpRestMenusController.php @@ -316,7 +316,7 @@ public function test_update_item() { $data = $response->get_data(); $this->assertSame( 'New Name', $data['name'] ); $this->assertSame( 'New Description', $data['description'] ); - $this->assertSame( true, $data['auto_add'] ); + $this->assertTrue( $data['auto_add'] ); $this->assertSame( 'new-name', $data['slug'] ); $this->assertSame( 'just meta', $data['meta']['test_single_menu'] ); $this->assertFalse( isset( $data['meta']['test_cat_meta'] ) ); From 07220f23b7e49acf0195820471cc318e2556a639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= Date: Mon, 3 Aug 2026 10:36:23 +0000 Subject: [PATCH 096/138] View config filters: lowercase dynamic filter names. Props oandregal, ntsekouras. See #65577. git-svn-id: https://develop.svn.wordpress.org/trunk@62970 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-view-config-data.php | 12 +++--- src/wp-includes/default-filters.php | 4 +- src/wp-includes/view-config.php | 41 +++++++++++++++---- tests/phpunit/tests/view-config.php | 24 ++++++++++- 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/wp-includes/class-wp-view-config-data.php b/src/wp-includes/class-wp-view-config-data.php index 8c3d255fab82d..fa04ced6de026 100644 --- a/src/wp-includes/class-wp-view-config-data.php +++ b/src/wp-includes/class-wp-view-config-data.php @@ -121,9 +121,9 @@ private function get_data() { * Applies the entity view configuration filter and returns the result. * * Exposes the container through the dynamic - * `get_entity_view_config_{$kind}_{$name}` filter so that core and third - * parties can provide the configuration for a specific entity, then - * reconciles the filtered container back into a plain configuration array, + * `get_entity_view_config_{$kind}_{$name}` filter (with the dynamic portions + * lowercased), so that core and third parties can provide the configuration for a specific entity, + * then reconciles the filtered container back into a plain configuration array, * limited to the documented configuration keys. * * @since 7.1.0 @@ -137,7 +137,9 @@ public function apply_filters( $kind, $name ) { * Filters the view configuration for a given entity. * * The dynamic portions of the hook name, `$kind` and `$name`, refer to the - * entity kind (e.g. `postType`) and the entity name (e.g. `page`). + * entity kind (e.g. `postType`) and the entity name (e.g. `page`), + * lowercased — so the `postType`/`page` entity maps to the + * `get_entity_view_config_posttype_page` hook. * * Callbacks receive a WP_View_Config_Data object and change the * configuration through its methods. Each write method takes the schema @@ -183,7 +185,7 @@ public function apply_filters( $kind, $name ) { * } */ apply_filters( - "get_entity_view_config_{$kind}_{$name}", + wp_get_entity_view_config_hook_name( $kind, $name ), $this, array( 'kind' => $kind, diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index 66504d37ad84d..ea6fee0dab3ad 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -827,8 +827,8 @@ // callbacks registered at the default compose on top of them // regardless of registration order. add_filter( - "get_entity_view_config_postType_{$post_type}", - "_wp_get_entity_view_config_post_type_{$post_type}", + "get_entity_view_config_posttype_{$post_type}", + "_wp_get_entity_view_config_posttype_{$post_type}", 5 ); } diff --git a/src/wp-includes/view-config.php b/src/wp-includes/view-config.php index c4d20979b846f..b97b221ec2a32 100644 --- a/src/wp-includes/view-config.php +++ b/src/wp-includes/view-config.php @@ -4,12 +4,33 @@ * * Builds the default view configuration for an entity and exposes it through * the dynamic `get_entity_view_config_{$kind}_{$name}` filter so core and third - * parties can provide the configuration for a specific entity. + * parties can provide the configuration for a specific entity. The dynamic + * portions of the hook name are lowercased, e.g. + * `get_entity_view_config_posttype_page` for the `page` post type. * * @package WordPress * @since 7.1.0 */ +/** + * Builds the name of the dynamic filter that provides the view configuration + * for an entity. + * + * The entity kind and name are embedded in the hook name lowercased, so the + * hook follows the WordPress convention of lowercase hook names regardless of + * how the entity identifiers are spelled: the `postType`/`page` entity maps to + * the `get_entity_view_config_posttype_page` hook. + * + * @since 7.1.0 + * + * @param string $kind The entity kind (e.g. `postType`). + * @param string $name The entity name (e.g. `page`). + * @return string The filter name. + */ +function wp_get_entity_view_config_hook_name( $kind, $name ) { + return strtolower( "get_entity_view_config_{$kind}_{$name}" ); +} + /** * Builds the default `form` configuration for post types that don't provide their own. * @@ -27,7 +48,7 @@ * * @return array The default form configuration. */ -function _wp_get_default_post_type_form() { +function _wp_get_default_posttype_form() { return array( 'layout' => array( 'type' => 'panel' ), 'fields' => array( @@ -97,8 +118,10 @@ function _wp_get_default_post_type_form() { * Returns the view configuration for the given entity. * * Builds the default configuration shared by all entities and then exposes it - * through the dynamic `get_entity_view_config_{$kind}_{$name}` filter so that core - * and third parties can provide the configuration for a specific entity. + * through the dynamic `get_entity_view_config_{$kind}_{$name}` filter — with the + * dynamic portions lowercased, see wp_get_entity_view_config_hook_name() + * — so that core and third parties can provide the configuration for a + * specific entity. * * @since 7.1.0 * @@ -148,7 +171,7 @@ function wp_get_entity_view_config( $kind, $name ) { 'default_view' => $default_view, 'default_layouts' => $default_layouts, 'view_list' => $view_list, - 'form' => 'postType' === $kind ? _wp_get_default_post_type_form() : array(), + 'form' => 'postType' === $kind ? _wp_get_default_posttype_form() : array(), ); $data = new WP_View_Config_Data( $config ); @@ -164,7 +187,7 @@ function wp_get_entity_view_config( $kind, $name ) { * @param WP_View_Config_Data $data The view configuration container for the entity. * @return WP_View_Config_Data The updated view configuration container. */ -function _wp_get_entity_view_config_post_type_page( $data ) { +function _wp_get_entity_view_config_posttype_page( $data ) { $default_layouts = array( 'table' => array( 'layout' => array( @@ -304,7 +327,7 @@ function _wp_get_entity_view_config_post_type_page( $data ) { * @param WP_View_Config_Data $data The view configuration container for the entity. * @return WP_View_Config_Data The updated view configuration container. */ -function _wp_get_entity_view_config_post_type_wp_block( $data ) { +function _wp_get_entity_view_config_posttype_wp_block( $data ) { $default_layouts = array( 'table' => array( 'layout' => array( @@ -422,7 +445,7 @@ function _wp_get_entity_view_config_post_type_wp_block( $data ) { * @param WP_View_Config_Data $data The view configuration container for the entity. * @return WP_View_Config_Data The updated view configuration container. */ -function _wp_get_entity_view_config_post_type_wp_template_part( $data ) { +function _wp_get_entity_view_config_posttype_wp_template_part( $data ) { $default_layouts = array( 'table' => array( 'layout' => array( @@ -524,7 +547,7 @@ function _wp_get_entity_view_config_post_type_wp_template_part( $data ) { * @param WP_View_Config_Data $data The view configuration container for the entity. * @return WP_View_Config_Data The updated view configuration container. */ -function _wp_get_entity_view_config_post_type_wp_template( $data ) { +function _wp_get_entity_view_config_posttype_wp_template( $data ) { $default_view = array( 'type' => 'grid', 'perPage' => 20, diff --git a/tests/phpunit/tests/view-config.php b/tests/phpunit/tests/view-config.php index 75e5c3327266b..cabd15d831494 100644 --- a/tests/phpunit/tests/view-config.php +++ b/tests/phpunit/tests/view-config.php @@ -69,7 +69,7 @@ class Tests_View_Config_API extends WP_UnitTestCase { * Tears down each test. */ public function tear_down() { - remove_all_filters( 'get_entity_view_config_postType_unregistered_cpt' ); + remove_all_filters( 'get_entity_view_config_posttype_unregistered_cpt' ); remove_all_filters( 'get_entity_view_config_custom_kind_custom_name' ); parent::tear_down(); } @@ -119,6 +119,28 @@ public function test_view_list_uses_post_type_all_items_label() { unregister_post_type( 'view_config_cpt' ); } + /** + * The dynamic filter name lowercases the entity kind and name. + */ + public function test_filter_hook_name_is_lowercased() { + $called = false; + add_filter( + 'get_entity_view_config_posttype_unregistered_cpt', + function ( $data ) use ( &$called ) { + $called = true; + return $data; + } + ); + + wp_get_entity_view_config( 'postType', 'Unregistered_CPT' ); + + $this->assertTrue( $called ); + $this->assertSame( + 'get_entity_view_config_posttype_unregistered_cpt', + wp_get_entity_view_config_hook_name( 'postType', 'Unregistered_CPT' ) + ); + } + /** * The dynamic filter receives the data container and the entity descriptor. */ From 3d9a592faf76bf2b24c5676347cc89418cb21952 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Mon, 3 Aug 2026 11:35:52 +0000 Subject: [PATCH 097/138] Docs: Restore the `@return` tag for `WP_Duotone::is_preset()`. Removes a duplicate `@param` tag carrying an outdated type and restores the description of the returned value. Developed in: https://github.com/WordPress/wordpress-develop/pull/12791 Follow-up to [61603]. Props bejignesh, mukesh27, wildworks. See #64896. git-svn-id: https://develop.svn.wordpress.org/trunk@62971 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-duotone.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/class-wp-duotone.php b/src/wp-includes/class-wp-duotone.php index b75b01619fbee..0e12e7ca7f306 100644 --- a/src/wp-includes/class-wp-duotone.php +++ b/src/wp-includes/class-wp-duotone.php @@ -569,8 +569,8 @@ private static function get_slug_from_attribute( $duotone_attr ) { * * @since 6.3.0 * - * @param string $duotone_attr The duotone attribute from a block. * @param string|string[] $duotone_attr The duotone attribute from a block. + * @return bool True if the duotone preset present and valid. */ private static function is_preset( $duotone_attr ) { if ( ! is_string( $duotone_attr ) ) { From be1c69c4c97a80a24620b960ff8719a01097751e Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Mon, 3 Aug 2026 12:13:24 +0000 Subject: [PATCH 098/138] Administration: Fix install button icon alignment in theme preview. When installing a theme from the Details & Preview overlay, the animated icon shown in the Install button was taller than the button itself, so the button grew and its label shifted while the install was in progress. Matching the icon height to the button height keeps the button at a stable size and the icon aligned with the label throughout the updating and updated states. Developed in: https://github.com/WordPress/wordpress-develop/pull/12799 Follow-up to [62516]. Props eishanoor, kosvrouvas, mosescursor, r1k0, shailu25, ugyensupport, vedantere, wildworks. Fixes #65601. git-svn-id: https://develop.svn.wordpress.org/trunk@62972 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/themes.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/wp-admin/css/themes.css b/src/wp-admin/css/themes.css index be495568c89b7..24be8ac58c5be 100644 --- a/src/wp-admin/css/themes.css +++ b/src/wp-admin/css/themes.css @@ -1976,6 +1976,11 @@ body.full-overlay-active { line-height: 2.30769231; /* 30px for 32px height with 13px font */ } +.theme-install-overlay .wp-full-overlay-header .button.updating-message:before, +.theme-install-overlay .wp-full-overlay-header .button.updated-message:before { + line-height: 1.5; /* 30px (20px * 1.5) - matches the button above */ +} + .theme-install-overlay .wp-full-overlay-sidebar { background: #f0f0f1; border-right: 1px solid #dcdcde; From 5bc2c6228c78ca17552a906c2bb4e47a97e87bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Maneiro?= Date: Mon, 3 Aug 2026 14:20:36 +0000 Subject: [PATCH 099/138] View config REST Endpoint: remove `search` and `page`. The `search` and `page` parameters source of truth is the URL, and cannot be configured via the filters. Props oandregal, ntsekouras, jorgefilipecosta. Fixes #65577. git-svn-id: https://develop.svn.wordpress.org/trunk@62973 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-view-config-data.php | 4 +-- .../class-wp-rest-view-config-controller.php | 9 +++---- .../rest-api/rest-view-config-controller.php | 25 +++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/wp-includes/class-wp-view-config-data.php b/src/wp-includes/class-wp-view-config-data.php index fa04ced6de026..be85e9dc10d60 100644 --- a/src/wp-includes/class-wp-view-config-data.php +++ b/src/wp-includes/class-wp-view-config-data.php @@ -355,13 +355,13 @@ public function replace( array $patch, int $version ) { * * ```php * array( - * 'default_view' => array( 'search' => 'new search', 'fields' => array( 'newField' ) ), + * 'default_view' => array( 'titleField' => 'newTitleField', 'fields' => array( 'newField' ) ), * 'default_layouts' => array( 'grid' => array( 'layout' => array( 'badgeFields' => array( 'newField' ) ) ) ), * 'view_list' => array( array( 'slug' => 'table', 'title' => 'New title' ) ), * ) * ``` * - * - default_view will be updated so the search string is 'new search' and the newField is appended to the list of fields. + * - default_view will be updated so the titleField is 'newTitleField' and the newField is appended to the list of fields. * - default_layouts will be updated so that newField is appended to the badgeFields. * - view_list will be updated so that the view with slug 'table' has its title changed to 'New title'. * diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php index 6b23f35cbaf47..64c1ebe1ba921 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-view-config-controller.php @@ -391,15 +391,15 @@ public function get_item_schema() { /** * Returns the schema properties shared by all view types (ViewBase), excluding 'type'. * + * Note that `search` and `page` are not part of the schema: they are managed + * via the URL, which is their only source of truth. + * * @since 7.1.0 * * @return array Schema properties for the base view configuration. */ protected function get_view_base_schema() { return array( - 'search' => array( - 'type' => 'string', - ), 'filters' => array( 'type' => 'array', 'items' => array( @@ -444,9 +444,6 @@ protected function get_view_base_schema() { ), ), ), - 'page' => array( - 'type' => 'integer', - ), 'perPage' => array( 'type' => 'integer', ), diff --git a/tests/phpunit/tests/rest-api/rest-view-config-controller.php b/tests/phpunit/tests/rest-api/rest-view-config-controller.php index 9bfbdd67c7021..34fcd55e2466d 100644 --- a/tests/phpunit/tests/rest-api/rest-view-config-controller.php +++ b/tests/phpunit/tests/rest-api/rest-view-config-controller.php @@ -385,4 +385,29 @@ public function test_get_item_schema() { array_keys( $schema['properties'] ) ); } + + /** + * `search` and `page` are not part of the view schema: they are managed via + * the URL, which is their only source of truth. + * + * @covers ::get_item_schema + */ + public function test_get_item_schema_excludes_url_managed_view_properties() { + $controller = new WP_REST_View_Config_Controller(); + $schema = $controller->get_item_schema(); + + $views = array( + 'default_view' => $schema['properties']['default_view']['properties'], + 'view_list item view' => $schema['properties']['view_list']['items']['properties']['view']['properties'], + 'default_layouts.table' => $schema['properties']['default_layouts']['properties']['table']['properties'], + 'default_layouts.grid' => $schema['properties']['default_layouts']['properties']['grid']['properties'], + 'default_layouts.list' => $schema['properties']['default_layouts']['properties']['list']['properties'], + 'default_layouts.activity' => $schema['properties']['default_layouts']['properties']['activity']['properties'], + ); + + foreach ( $views as $label => $properties ) { + $this->assertArrayNotHasKey( 'search', $properties, "$label should not declare a `search` property." ); + $this->assertArrayNotHasKey( 'page', $properties, "$label should not declare a `page` property." ); + } + } } From dcf58dc786d736306609c4804464db501f74359e Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Mon, 3 Aug 2026 16:56:56 +0000 Subject: [PATCH 100/138] Build/Test Tools: Make runner override variable more general. [62891] introduced the ability to override the runner used for a GitHub Actions job using a repository or organization variable. While initially named `PHPUNIT_RUNNER`, overriding the runner for a specific job could be useful in more situations. This renames the variable chacked to `RUNNER_GROUP`. Fixes #65749. git-svn-id: https://develop.svn.wordpress.org/trunk@62974 602fd350-edb4-49c9-b593-d223f7449a82 --- .github/workflows/reusable-phpunit-tests-v3.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-phpunit-tests-v3.yml b/.github/workflows/reusable-phpunit-tests-v3.yml index 4ce4e65b0ba12..abe472e03b6d1 100644 --- a/.github/workflows/reusable-phpunit-tests-v3.yml +++ b/.github/workflows/reusable-phpunit-tests-v3.yml @@ -129,7 +129,7 @@ jobs: # - Submit the test results to the WordPress.org host test results. phpunit-tests: name: ${{ ( inputs.phpunit-test-groups || inputs.coverage-report ) && format( 'PHP {0} with ', inputs.php ) || '' }} ${{ 'mariadb' == inputs.db-type && 'MariaDB' || 'MySQL' }} ${{ inputs.db-version }}${{ inputs.multisite && ' multisite' || '' }}${{ inputs.db-innovation && ' (innovation release)' || '' }}${{ inputs.memcached && ' with memcached' || '' }}${{ inputs.report && ' (test reporting enabled)' || '' }} ${{ 'example.org' != inputs.tests-domain && inputs.tests-domain || '' }} - runs-on: ${{ vars.PHPUNIT_RUNNER || inputs.os }} + runs-on: ${{ vars.RUNNER_GROUP || inputs.os }} timeout-minutes: ${{ inputs.coverage-report && 120 || inputs.php == '8.4' && 30 || 20 }} permissions: contents: read From 878af1bb999fabd044264fa1a63072b3b6cff851 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Mon, 3 Aug 2026 18:58:00 +0000 Subject: [PATCH 101/138] External Libraries: Upgrade PHPMailer to version 7.1.1. This is a maintenance and minor security release. References: * [https://github.com/PHPMailer/PHPMailer/releases/tag/v7.1.1 PHPMailer 7.1.1 release notes] * [https://github.com/PHPMailer/PHPMailer/releases/tag/v7.1.0 PHPMailer 7.1.0 release notes] * [https://github.com/PHPMailer/PHPMailer/compare/v7.0.2...v7.1.1 Full list of changes in PHPMailer 7.1.1] Follow-up to [54937], [55557], [56484], [57137], [59246], [59481], [60623], [60813], [60888], [61249], [61468]. Props hareesh-pillai, Synchro, jrf. Fixes #65790. git-svn-id: https://develop.svn.wordpress.org/trunk@62975 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/PHPMailer/PHPMailer.php | 99 ++++++++++++++++++++----- src/wp-includes/PHPMailer/POP3.php | 25 +++++-- src/wp-includes/PHPMailer/SMTP.php | 4 +- 3 files changed, 101 insertions(+), 27 deletions(-) diff --git a/src/wp-includes/PHPMailer/PHPMailer.php b/src/wp-includes/PHPMailer/PHPMailer.php index 2bb3578c7e0d9..4900cbc43afef 100644 --- a/src/wp-includes/PHPMailer/PHPMailer.php +++ b/src/wp-includes/PHPMailer/PHPMailer.php @@ -59,6 +59,7 @@ class PHPMailer const ICAL_METHOD_REFRESH = 'REFRESH'; const ICAL_METHOD_COUNTER = 'COUNTER'; const ICAL_METHOD_DECLINECOUNTER = 'DECLINECOUNTER'; + const RFC822_DATE_FORMAT = 'D, j M Y H:i:s O'; /** * Email priority. @@ -77,7 +78,7 @@ class PHPMailer public $CharSet = self::CHARSET_ISO88591; /** - * The MIME Content-type of the message. + * The MIME Content-Type of the message. * * @var string */ @@ -159,7 +160,7 @@ class PHPMailer public $Ical = ''; /** - * Value-array of "method" in Contenttype header "text/calendar" + * Value-array of "method" in Content-Type header "text/calendar" * * @var string[] */ @@ -768,7 +769,7 @@ class PHPMailer * * @var string */ - const VERSION = '7.0.2'; + const VERSION = '7.1.1'; /** * Error severity: message only, continue processing. @@ -1283,26 +1284,27 @@ protected function addAnAddress($kind, $address, $name = '') /** * Parse and validate a string containing one or more RFC822-style comma-separated email addresses * of the form "display name
    " into an array of name/address pairs. - * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available. + * Uses the imap_rfc822_parse_adrlist function if the IMAP extension is available and + * the deprecated $useimap argument is truthy. * Note that quotes in the name part are removed. * * @see https://www.andrew.cmu.edu/user/agreen1/testing/mrbs/web/Mail/RFC822.php A more careful implementation * * @param string $addrstr The address list string - * @param null $useimap Unused. Argument has been deprecated in PHPMailer 6.11.0. - * Previously this argument determined whether to use - * the IMAP extension to parse the list and accepted a boolean value. + * @param bool|null $useimap Deprecated in PHPMailer 6.11.0. + * Truthy values request the deprecated IMAP parser + * and trigger a deprecation warning. * @param string $charset The charset to use when decoding the address list string. * * @return array */ public static function parseAddresses($addrstr, $useimap = null, $charset = self::CHARSET_ISO88591) { - if ($useimap !== null) { + if ($useimap == true) { trigger_error(self::lang('deprecated_argument') . '$useimap', E_USER_DEPRECATED); } $addresses = []; - if (function_exists('imap_rfc822_parse_adrlist')) { + if ($useimap == true && function_exists('imap_rfc822_parse_adrlist')) { //Use this built-in parser if it's available // phpcs:ignore PHPCompatibility.FunctionUse.RemovedFunctions.imap_rfc822_parse_adrlistRemoved -- wrapped in function_exists() $list = imap_rfc822_parse_adrlist($addrstr, ''); @@ -1779,6 +1781,8 @@ public function preSend() //Trim subject consistently $this->Subject = trim($this->Subject); + + //Create body before headers in case body makes changes to headers (e.g. altering transfer encoding) $this->MIMEHeader = ''; $this->MIMEBody = $this->createBody(); @@ -1853,7 +1857,7 @@ public function postSend() return $this->mailSend($this->MIMEHeader, $this->MIMEBody); default: $sendMethod = $this->Mailer . 'Send'; - if (method_exists($this, $sendMethod)) { + if (!empty($this->Mailer) && method_exists($this, $sendMethod)) { return $this->{$sendMethod}($this->MIMEHeader, $this->MIMEBody); } @@ -1911,7 +1915,7 @@ protected function sendmailSend($header, $body) // CVE-2016-10033, CVE-2016-10045: Don't pass -f if characters will be escaped. // Also don't add the -f automatically unless it has been set either via Sender - // or sendmail_path. Otherwise it can introduce new problems. + // or sendmail_path. Otherwise, it can introduce new problems. // @see http://github.com/PHPMailer/PHPMailer/issues/2298 if (!empty($this->Sender) && static::validateAddress($this->Sender) && self::isShellSafe($this->Sender)) { $sendmailArgs[] = '-f' . $this->Sender; @@ -2510,7 +2514,7 @@ public static function setLanguage($langcode = 'en', $lang_path = '') 'authenticate' => 'SMTP Error: Could not authenticate.', 'buggy_php' => 'Your version of PHP is affected by a bug that may result in corrupted messages.' . ' To fix it, switch to sending using SMTP, disable the mail.add_x_header option in' . - ' your php.ini, switch to MacOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', + ' your php.ini, switch to macOS or Linux, or upgrade your PHP to version 7.0.17+ or 7.1.3+.', 'connect_host' => 'SMTP Error: Could not connect to SMTP host.', 'data_not_accepted' => 'SMTP Error: data not accepted.', 'empty_message' => 'Message body empty', @@ -2847,7 +2851,10 @@ public function createHeader() { $result = ''; - $result .= $this->headerLine('Date', '' === $this->MessageDate ? self::rfcDate() : $this->MessageDate); + $result .= $this->headerLine( + 'Date', + self::sanitiseDate($this->MessageDate) + ); //The To header is created automatically by mail(), so needs to be omitted here if ('mail' !== $this->Mailer) { @@ -2916,7 +2923,7 @@ public function createHeader() ); } elseif (is_string($this->XMailer) && trim($this->XMailer) !== '') { //Some string - $result .= $this->headerLine('X-Mailer', trim($this->XMailer)); + $result .= $this->headerLine('X-Mailer', $this->secureHeader(trim($this->XMailer))); } //Other values result in no X-Mailer header if ('' !== $this->ConfirmReadingTo) { @@ -2966,13 +2973,20 @@ public function getMailMIME() break; default: //Catches case 'plain': and case '': - $result .= $this->textLine('Content-Type: ' . $this->ContentType . '; charset=' . $this->CharSet); + $result .= $this->textLine( + 'Content-Type: ' . + $this->secureHeader($this->ContentType) . + '; charset=' . $this->secureHeader($this->CharSet) + ); $ismultipart = false; break; } + if (!$this->validateEncoding($this->Encoding)) { + throw new Exception(self::lang('encoding') . $this->Encoding); + } //RFC1341 part 5 says 7bit is assumed if not specified if (static::ENCODING_7BIT !== $this->Encoding) { - //RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit or binary CTE + //RFC 2045 section 6.4 says multipart MIME parts may only use 7bit, 8bit, or binary CTE if ($ismultipart) { if (static::ENCODING_8BIT === $this->Encoding) { $result .= $this->headerLine('Content-Transfer-Encoding', static::ENCODING_8BIT); @@ -3047,6 +3061,9 @@ public function createBody() $this->setWordWrap(); + if (!$this->validateEncoding($this->Encoding)) { + throw new Exception(self::lang('encoding') . $this->Encoding); + } $bodyEncoding = $this->Encoding; $bodyCharSet = $this->CharSet; //Can we do a 7-bit downgrade? @@ -4166,7 +4183,7 @@ public function addStringEmbeddedImage( protected function validateEncoding($encoding) { return in_array( - $encoding, + strtolower($encoding), [ self::ENCODING_7BIT, self::ENCODING_QUOTED_PRINTABLE, @@ -4426,7 +4443,7 @@ protected function setError($msg) } /** - * Return an RFC 822 formatted date. + * Return the current date and time as an RFC 822 formatted date. * * @return string */ @@ -4436,7 +4453,51 @@ public static function rfcDate() //Will default to UTC if it's not set properly in php.ini date_default_timezone_set(@date_default_timezone_get()); - return date('D, j M Y H:i:s O'); + return date(self::RFC822_DATE_FORMAT); + } + + /** + * Normalise a user-supplied date into a correctly-formatted RFC 5322 date value + * string suitable for use in the Date header. + * + * Accepts: + * - A {@see \DateTime} (or \DateTimeImmutable) object + * - Any date/time string understood by PHP's DateTime constructor (RFC 5322, ISO 8601, + * Unix timestamp with leading "@", natural-language strings, etc.) + * + * Dates in the future are not permitted for email headers; if the parsed date is later + * than "now" the method falls back to the current time via {@see self::rfcDate()}. + * An empty value, a non-string/non-DateTime argument, or any value that cannot be + * parsed will likewise fall back to {@see self::rfcDate()}. + * + * @param \DateTime|\DateTimeImmutable|string $date The date to normalise + * + * @return string An RFC 5322-formatted date string + */ + private static function sanitiseDate($date) + { + try { + //Ensure the default timezone is set properly + date_default_timezone_set(@date_default_timezone_get()); + + if ($date instanceof \DateTimeInterface) { + $dt = $date; + } elseif (is_string($date) && $date !== '') { + $dt = new \DateTime($date); + } else { + //Empty string, null, or any unsupported type + return self::rfcDate(); + } + + //Reject future dates — they are invalid for outgoing message headers + if ($dt->getTimestamp() > time()) { + return self::rfcDate(); + } + + return $dt->format(self::RFC822_DATE_FORMAT); + } catch (\Exception $e) { + return self::rfcDate(); + } } /** diff --git a/src/wp-includes/PHPMailer/POP3.php b/src/wp-includes/PHPMailer/POP3.php index 186fe9fe47ab7..0ba9678373217 100644 --- a/src/wp-includes/PHPMailer/POP3.php +++ b/src/wp-includes/PHPMailer/POP3.php @@ -47,7 +47,7 @@ class POP3 * @var string * @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead. */ - const VERSION = '7.0.2'; + const VERSION = '7.1.1'; /** * Default POP3 port number. @@ -212,9 +212,9 @@ public function authorise($host, $port = false, $timeout = false, $username = '' } else { $this->tval = (int) $timeout; } - $this->do_debug = $debug_level; - $this->username = $username; - $this->password = $password; + $this->do_debug = (int) $debug_level; + $this->username = self::stripControls($username); + $this->password = self::stripControls($password); //Reset the error log $this->errors = []; //Connect @@ -319,7 +319,8 @@ public function login($username = '', $password = '') if (empty($password)) { $password = $this->password; } - + $username = self::stripControls($username); + $password = self::stripControls($password); //Send the Username $this->sendString("USER $username" . static::LE); $pop3_response = $this->getResponse(); @@ -407,7 +408,7 @@ protected function sendString($string) /** * Checks the POP3 server response. - * Looks for for +OK or -ERR. + * Looks for +OK or -ERR. * * @param string $string * @@ -467,4 +468,16 @@ protected function catchWarning($errno, $errstr, $errfile, $errline) "errno: $errno errstr: $errstr; errfile: $errfile; errline: $errline" ); } + + /** + * Strip all control chars from a string. + * + * @param $string + * + * @return string + */ + protected static function stripControls($string) + { + return preg_replace('/[\x00-\x1F\x7F]/u', '', $string); + } } diff --git a/src/wp-includes/PHPMailer/SMTP.php b/src/wp-includes/PHPMailer/SMTP.php index 559b52c45e8f8..f0957b80a919f 100644 --- a/src/wp-includes/PHPMailer/SMTP.php +++ b/src/wp-includes/PHPMailer/SMTP.php @@ -36,7 +36,7 @@ class SMTP * @var string * @deprecated This constant will be removed in PHPMailer 8.0. Use `PHPMailer::VERSION` instead. */ - const VERSION = '7.0.2'; + const VERSION = '7.1.1'; /** * SMTP line break constant. @@ -1289,7 +1289,7 @@ public function getServerExtList() * 3. EHLO has been sent - * $name == 'HELO'|'EHLO': returns the server name * $name == any other string: if extension $name exists, returns True - * or its options (e.g. AUTH mechanisms supported). Otherwise returns False. + * or its options (e.g. AUTH mechanisms supported). Otherwise, returns False. * * @param string $name Name of SMTP extension or 'HELO'|'EHLO' * From aea966d3d51a6d8495a08c6d0c22529ed6fa04f8 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Mon, 3 Aug 2026 19:42:08 +0000 Subject: [PATCH 102/138] Media: Equalize padding for filter bar between list and grid views. The list and grid filter panels had different padding following [61757]. This is an undesirable difference, and should be equalized. Apply scoped padding to match the two filter bars. Developed in https://github.com/WordPress/wordpress-develop/pull/12664 Props afercia, softglaze, khokansardar, joedolson. Fixes #65697. git-svn-id: https://develop.svn.wordpress.org/trunk@62976 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/media.css | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/wp-admin/css/media.css b/src/wp-admin/css/media.css index 5a033b98ba350..3d7b0c9455c83 100644 --- a/src/wp-admin/css/media.css +++ b/src/wp-admin/css/media.css @@ -451,6 +451,16 @@ border color while dragging a file over the uploader drop area */ margin: 0 6px 0 0; } +/* Match the spacing the grid view toolbar gets from + `.attachments-browser .media-toolbar` in media-views.css, so the Media + Library filter bar is consistent in both modes. The grid view toolbar is + excluded so that rule stays the single source of its own padding: media.css + is printed after media-views.css here, so an unscoped rule would override + it. */ +.upload-php .wp-filter:not(.media-toolbar) { + padding: 12px 16px; +} + /** * Media Library grid view */ From 6693ea1fec9db0f9324262db344d6267abb6e22b Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Mon, 3 Aug 2026 19:59:48 +0000 Subject: [PATCH 103/138] Widgets: Always render the On This Day widget. While the intention was to only render the On This Day widget when it returned results, this proved to create a variety of implementation complications and some significant points of confusion for users. Remove the conditional rendering of the On This Day widget. When active without posts, display a message inviting the user to publish a new post. Developed in https://github.com/WordPress/wordpress-develop/pull/12575 Props iamchitti, mirmpro, shailu25, ugyensupport, iamraju, nazmulasif, wildworks, joedolson, mukesh27, annezazu, paaljoachim, joen. Fixes #65647. git-svn-id: https://develop.svn.wordpress.org/trunk@62977 602fd350-edb4-49c9-b593-d223f7449a82 --- .../includes/dashboard-on-this-day.php | 59 +++------ src/wp-admin/includes/dashboard.php | 4 +- .../tests/admin/wpDashboardOnThisDay.php | 116 +++++------------- 3 files changed, 46 insertions(+), 133 deletions(-) diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php index e9557a60720c8..948e128f72c59 100644 --- a/src/wp-admin/includes/dashboard-on-this-day.php +++ b/src/wp-admin/includes/dashboard-on-this-day.php @@ -7,48 +7,6 @@ * @since 7.1.0 */ -/** - * Registers the On This Day dashboard widget. - * - * Designed to be the single entry point called from the dashboard setup - * routine. The widget is always registered so that it remains available in - * Screen Options and keeps its user-customized position. When there are no - * matching posts, a marker class is added to the postbox so the widget can be - * hidden with CSS. - * - * @since 7.1.0 - */ -function wp_dashboard_on_this_day_setup() { - add_filter( 'postbox_classes_dashboard_wp_dashboard_on_this_day', 'wp_dashboard_on_this_day_postbox_classes' ); - - wp_add_dashboard_widget( - 'wp_dashboard_on_this_day', - __( 'On This Day' ), - 'wp_dashboard_on_this_day' - ); -} - -/** - * Hides the On This Day postbox when there are no posts to show. - * - * Adds the core `hidden` class so the widget stays registered — preserving its - * Screen Options entry and user-customized position — while being hidden when - * empty. A user can still reveal it via Screen Options, in which case the - * placeholder message is shown. - * - * @since 7.1.0 - * - * @param string[] $classes An array of postbox classes. - * @return string[] Filtered postbox classes. - */ -function wp_dashboard_on_this_day_postbox_classes( $classes ) { - if ( empty( wp_dashboard_on_this_day_get_posts() ) ) { - $classes[] = 'hidden'; - } - - return $classes; -} - /** * Renders the On This Day dashboard widget. * @@ -60,9 +18,20 @@ function wp_dashboard_on_this_day() { $posts = wp_dashboard_on_this_day_get_posts(); if ( empty( $posts ) ) { - // Placeholder shown when a user reveals the hidden widget via Screen - // Options on a day with no matching posts. - echo '

    ' . esc_html__( 'No posts were published on this day in previous years.' ) . '

    '; + // Placeholder shown on a day with no matching posts in previous years. + echo '

    '; + + if ( current_user_can( 'edit_posts' ) ) { + printf( + /* translators: %s: URL to the new post screen. */ + __( 'No posts were published on this day in previous years. Write one today, and be reminded about it next year.' ), + esc_url( admin_url( 'post-new.php' ) ) + ); + } else { + echo esc_html__( 'No posts were published on this day in previous years.' ); + } + + echo '

    '; return; } diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index 5fdbaf7a4fa40..a0c2a23189644 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -89,11 +89,11 @@ function wp_dashboard_setup() { } // On This Day. - if ( ! function_exists( 'wp_dashboard_on_this_day_setup' ) ) { + if ( ! function_exists( 'wp_dashboard_on_this_day' ) ) { require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php'; } - wp_dashboard_on_this_day_setup(); + wp_add_dashboard_widget( 'wp_dashboard_on_this_day', __( 'On This Day' ), 'wp_dashboard_on_this_day' ); // WordPress Events and News. wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' ); diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php index a2b1cdbfaff1f..728b9bcef64d0 100644 --- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php +++ b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php @@ -10,6 +10,8 @@ class Tests_Admin_wpDashboardOnThisDay extends WP_UnitTestCase { protected static int $other_user_id; + protected static int $subscriber_id; + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php'; @@ -25,30 +27,24 @@ public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { 'role' => 'author', ) ); + self::$subscriber_id = $factory->user->create( + array( + 'display_name' => 'Reader', + 'role' => 'subscriber', + ) + ); } public static function wpTearDownAfterClass() { self::delete_user( self::$user_id ); self::delete_user( self::$other_user_id ); + self::delete_user( self::$subscriber_id ); } - public function tear_down() { - unset( $GLOBALS['wp_meta_boxes']['dashboard'] ); - - parent::tear_down(); - } - - /** - * Sets up the globals needed to register dashboard widgets. - */ - private function set_up_dashboard_screen() { - if ( ! function_exists( 'wp_add_dashboard_widget' ) ) { - require_once ABSPATH . 'wp-admin/includes/dashboard.php'; - } + public function set_up() { + parent::set_up(); set_current_screen( 'dashboard' ); - - $GLOBALS['wp_meta_boxes']['dashboard'] = array(); } /** @@ -119,71 +115,6 @@ private static function get_date_query_clause( string $date ): array { return _wp_dashboard_on_this_day_date_query_clause( new DateTimeImmutable( $date, wp_timezone() ) ); } - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day_setup - */ - public function test_setup_always_registers_widget_and_postbox_class_filter() { - $this->set_up_dashboard_screen(); - - wp_set_current_user( self::$user_id ); - - wp_dashboard_on_this_day_setup(); - - $dashboard_widgets = $GLOBALS['wp_meta_boxes']['dashboard']['normal']['core'] ?? array(); - - $this->assertArrayHasKey( 'wp_dashboard_on_this_day', $dashboard_widgets ); - $this->assertSame( 'On This Day', $dashboard_widgets['wp_dashboard_on_this_day']['title'] ); - $this->assertNotFalse( - has_filter( - 'postbox_classes_dashboard_wp_dashboard_on_this_day', - 'wp_dashboard_on_this_day_postbox_classes' - ) - ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day_postbox_classes - */ - public function test_postbox_classes_hides_widget_without_matching_posts() { - wp_set_current_user( self::$user_id ); - - $this->assertContains( 'hidden', wp_dashboard_on_this_day_postbox_classes( array( '' ) ) ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day_postbox_classes - */ - public function test_postbox_classes_does_not_hide_widget_with_matching_posts() { - wp_set_current_user( self::$user_id ); - $this->create_matching_post( self::$user_id ); - - $this->assertNotContains( 'hidden', wp_dashboard_on_this_day_postbox_classes( array( '' ) ) ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day_setup - */ - public function test_setup_adds_dashboard_widget_with_matching_post_from_another_author() { - $this->set_up_dashboard_screen(); - - wp_set_current_user( self::$user_id ); - $this->create_matching_post( self::$other_user_id ); - - wp_dashboard_on_this_day_setup(); - - $dashboard_widgets = $GLOBALS['wp_meta_boxes']['dashboard']['normal']['core'] ?? array(); - - $this->assertArrayHasKey( 'wp_dashboard_on_this_day', $dashboard_widgets ); - } - /** * @ticket 65116 * @@ -255,9 +186,28 @@ public function test_widget_outputs_placeholder_without_matching_posts() { $output = ob_get_clean(); $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output ); + $this->assertStringContainsString( 'Write one today', $output ); + $this->assertStringContainsString( admin_url( 'post-new.php' ), $output ); $this->assertStringNotContainsString( '
      ', $output ); } + /** + * @ticket 65116 + * + * @covers ::wp_dashboard_on_this_day + */ + public function test_widget_placeholder_omits_link_without_edit_posts_capability() { + wp_set_current_user( self::$subscriber_id ); + + ob_start(); + wp_dashboard_on_this_day(); + $output = ob_get_clean(); + + $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output ); + $this->assertStringNotContainsString( 'Write one today', $output ); + $this->assertStringNotContainsString( admin_url( 'post-new.php' ), $output ); + } + /** * @ticket 65116 * @@ -405,8 +355,6 @@ public function test_widget_does_not_append_excerpt_to_titled_posts() { * @covers ::wp_dashboard_on_this_day */ public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_authored_by_current_user() { - $this->set_up_dashboard_screen(); - wp_set_current_user( self::$user_id ); $this->create_matching_post( @@ -440,8 +388,6 @@ public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_ * @covers ::wp_dashboard_on_this_day */ public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() { - $this->set_up_dashboard_screen(); - wp_set_current_user( self::$user_id ); $post_id = $this->create_matching_post( @@ -476,8 +422,6 @@ public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() { * @covers ::wp_dashboard_on_this_day */ public function test_widget_hides_untitled_post_excerpt_for_password_protected_posts() { - $this->set_up_dashboard_screen(); - wp_set_current_user( self::$user_id ); $this->create_matching_post( From 5c45958340bf33b11ebf60f05a98e933bca7534e Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Mon, 3 Aug 2026 20:38:03 +0000 Subject: [PATCH 104/138] Media: Normalize non-numeric attachment `filesize` metadata. The stored `filesize` attachment metadata was read without validation in `wp_prepare_attachment_for_js()` and `attachment_submitbox_metadata()`. Attachment metadata is untyped, and the `filesize` key is commonly written by offloading plugins from a remote storage API response, so it can arrive as a numeric string, or be empty, non-numeric, or negative when the remote lookup fails. A numeric string was passed through verbatim, making `filesizeInBytes` a string in the media modal while the `wp_filesize()` branch of the very same conditional yielded an `int`; a non-numeric value such as `'unknown'` was truthy and suppressed the fallback entirely, so `size_format()` returned `false` and the file size rendered empty even when the real file was readable. Both call sites now only trust the stored value when it is numeric and casts to an integer greater than zero, and otherwise recompute the size with `wp_filesize()`. The fallback condition also replaces `file_exists()` with `is_readable()` guarded on a non-empty string, since `get_attached_file()` can be filtered to return a non-string. PHPUnit coverage is added for both functions. Developed in https://github.com/WordPress/wordpress-develop/pull/12632. Follow-up to r34258, r52837, r62813, r62815. Props mukesh27, westonruter. See #65670. Fixes #65686. git-svn-id: https://develop.svn.wordpress.org/trunk@62978 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/media.php | 6 +- src/wp-includes/media.php | 6 +- tests/phpunit/tests/admin/includesMedia.php | 177 ++++++++++++++++++++ tests/phpunit/tests/media.php | 162 ++++++++++++++++++ 4 files changed, 345 insertions(+), 6 deletions(-) create mode 100644 tests/phpunit/tests/admin/includesMedia.php diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index c2d15d758ef2e..6c50a1daba4fd 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -3425,9 +3425,9 @@ function attachment_submitbox_metadata() { $file_size = false; - if ( isset( $meta['filesize'] ) ) { - $file_size = $meta['filesize']; - } elseif ( file_exists( $file ) ) { + if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && (int) $meta['filesize'] > 0 ) { + $file_size = (int) $meta['filesize']; + } elseif ( is_string( $file ) && '' !== $file && is_readable( $file ) ) { $file_size = wp_filesize( $file ); } diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 7d0a0b5d0e737..9f98538d2757f 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -4716,9 +4716,9 @@ function wp_prepare_attachment_for_js( $attachment ) { $attached_file = get_attached_file( $attachment->ID ); - if ( isset( $meta['filesize'] ) ) { - $bytes = $meta['filesize']; - } elseif ( file_exists( $attached_file ) ) { + if ( isset( $meta['filesize'] ) && is_numeric( $meta['filesize'] ) && (int) $meta['filesize'] > 0 ) { + $bytes = (int) $meta['filesize']; + } elseif ( is_string( $attached_file ) && '' !== $attached_file && is_readable( $attached_file ) ) { $bytes = wp_filesize( $attached_file ); } else { $bytes = ''; diff --git a/tests/phpunit/tests/admin/includesMedia.php b/tests/phpunit/tests/admin/includesMedia.php new file mode 100644 index 0000000000000..35c542009db8d --- /dev/null +++ b/tests/phpunit/tests/admin/includesMedia.php @@ -0,0 +1,177 @@ +|null $expected The expected file size in bytes, or null if none should be displayed. + */ + public function test_attachment_submitbox_metadata_filesize( $filesize, ?int $expected ) { + $id = self::factory()->attachment->create_object( + array( + 'file' => 'test-image.jpg', + 'post_title' => 'Attachment Title', + 'post_parent' => 0, + 'post_mime_type' => 'image/jpeg', + ) + ); + $this->assertIsInt( $id ); + + wp_update_attachment_metadata( + $id, + array( + 'width' => 50, + 'height' => 50, + 'file' => 'test-image.jpg', + 'filesize' => $filesize, + ) + ); + + $GLOBALS['post'] = get_post( $id ); + + $output = get_echo( 'attachment_submitbox_metadata' ); + + if ( null === $expected ) { + $this->assertStringNotContainsString( 'misc-pub-filesize', $output, 'The file size should not have been displayed.' ); + } else { + $this->assertStringContainsString( size_format( $expected ), $output, 'The displayed file size did not match the normalized file size.' ); + } + } + + /** + * Data provider. + * + * @return array|null }> + */ + public function data_attachment_submitbox_metadata_filesize(): array { + return array( + 'an integer' => array( + 'filesize' => 12345, + 'expected' => 12345, + ), + 'a numeric string' => array( + 'filesize' => '12345', + 'expected' => 12345, + ), + 'a float' => array( + 'filesize' => 12345.6, + 'expected' => 12345, + ), + 'a float as a string' => array( + 'filesize' => '12345.6', + 'expected' => 12345, + ), + 'an exponential string' => array( + 'filesize' => '1e3', + 'expected' => 1000, + ), + 'a value smaller than a byte' => array( + 'filesize' => 0.5, + 'expected' => null, + ), + 'zero' => array( + 'filesize' => 0, + 'expected' => null, + ), + 'a negative integer' => array( + 'filesize' => -12345, + 'expected' => null, + ), + 'an empty string' => array( + 'filesize' => '', + 'expected' => null, + ), + 'a non-numeric string' => array( + 'filesize' => 'not-a-number', + 'expected' => null, + ), + 'an array' => array( + 'filesize' => array( 12345 ), + 'expected' => null, + ), + 'null' => array( + 'filesize' => null, + 'expected' => null, + ), + 'false' => array( + 'filesize' => false, + 'expected' => null, + ), + 'true' => array( + 'filesize' => true, + 'expected' => null, + ), + ); + } + + /** + * Tests that an unusable `filesize` in the attachment metadata falls back to the size of the file. + * + * @ticket 65686 + * + * @covers ::attachment_submitbox_metadata + * + * @dataProvider data_attachment_submitbox_metadata_filesize_falls_back_to_the_file + * + * @param mixed $filesize The `filesize` value stored in the attachment metadata. + */ + public function test_attachment_submitbox_metadata_filesize_falls_back_to_the_file( $filesize ) { + $id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' ); + $this->assertIsInt( $id ); + $file = get_attached_file( $id ); + $this->assertIsString( $file ); + + $meta = wp_get_attachment_metadata( $id ); + $this->assertIsArray( $meta ); + $meta['filesize'] = $filesize; + wp_update_attachment_metadata( $id, $meta ); + + $GLOBALS['post'] = get_post( $id ); + + $output = get_echo( 'attachment_submitbox_metadata' ); + + $filesize = wp_filesize( $file ); + $this->assertIsInt( $filesize ); + $this->assertStringContainsString( size_format( $filesize ), $output ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_attachment_submitbox_metadata_filesize_falls_back_to_the_file(): array { + return array( + 'a value smaller than a byte' => array( 'filesize' => 0.5 ), + 'zero' => array( 'filesize' => 0 ), + 'a negative integer' => array( 'filesize' => -12345 ), + 'an empty string' => array( 'filesize' => '' ), + 'a non-numeric string' => array( 'filesize' => 'not-a-number' ), + 'an array' => array( 'filesize' => array( 12345 ) ), + 'null' => array( 'filesize' => null ), + 'false' => array( 'filesize' => false ), + 'true' => array( 'filesize' => true ), + ); + } +} diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index 03fe3b4c02460..a492cf6da189f 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -667,6 +667,168 @@ public function test_wp_prepare_attachment_for_js_without_image_sizes() { $this->assertArrayHasKey( 'sizes', $prepped ); } + /** + * Tests that a `filesize` stored in the attachment metadata is normalized to a positive integer. + * + * When the stored value cannot be normalized, it should be treated as missing so that the + * filesystem fallback runs instead. + * + * @ticket 65686 + * + * @dataProvider data_wp_prepare_attachment_for_js_filesize + * + * @param mixed $filesize The `filesize` value stored in the attachment metadata. + * @param int<0, max>|null $expected The expected `filesizeInBytes` value, or null if it should not be set. + */ + public function test_wp_prepare_attachment_for_js_filesize( $filesize, ?int $expected ) { + $id = self::factory()->attachment->create_object( + array( + 'file' => 'test-image.jpg', + 'post_title' => 'Attachment Title', + 'post_parent' => 0, + 'post_mime_type' => 'image/jpeg', + ) + ); + $this->assertIsInt( $id ); + + wp_update_attachment_metadata( + $id, + array( + 'width' => 50, + 'height' => 50, + 'file' => 'test-image.jpg', + 'filesize' => $filesize, + ) + ); + + $post = get_post( $id ); + $this->assertInstanceOf( WP_Post::class, $post ); + $prepped = wp_prepare_attachment_for_js( $post ); + $this->assertIsArray( $prepped ); + + if ( null === $expected ) { + $this->assertArrayNotHasKey( 'filesizeInBytes', $prepped, 'The filesize should not have been set.' ); + $this->assertArrayNotHasKey( 'filesizeHumanReadable', $prepped, 'The human readable filesize should not have been set.' ); + } else { + $this->assertSame( $expected, $prepped['filesizeInBytes'], 'The filesize was not normalized to an integer.' ); + $this->assertSame( size_format( $expected ), $prepped['filesizeHumanReadable'], 'The human readable filesize did not match the normalized filesize.' ); + } + } + + /** + * Data provider. + * + * @return array|null }> + */ + public function data_wp_prepare_attachment_for_js_filesize(): array { + return array( + 'an integer' => array( + 'filesize' => 12345, + 'expected' => 12345, + ), + 'a numeric string' => array( + 'filesize' => '12345', + 'expected' => 12345, + ), + 'a float' => array( + 'filesize' => 12345.6, + 'expected' => 12345, + ), + 'a float as a string' => array( + 'filesize' => '12345.6', + 'expected' => 12345, + ), + 'an exponential string' => array( + 'filesize' => '1e3', + 'expected' => 1000, + ), + 'a value smaller than a byte' => array( + 'filesize' => 0.5, + 'expected' => null, + ), + 'zero' => array( + 'filesize' => 0, + 'expected' => null, + ), + 'a negative integer' => array( + 'filesize' => -12345, + 'expected' => null, + ), + 'an empty string' => array( + 'filesize' => '', + 'expected' => null, + ), + 'a non-numeric string' => array( + 'filesize' => 'not-a-number', + 'expected' => null, + ), + 'an array' => array( + 'filesize' => array( 12345 ), + 'expected' => null, + ), + 'null' => array( + 'filesize' => null, + 'expected' => null, + ), + 'false' => array( + 'filesize' => false, + 'expected' => null, + ), + 'true' => array( + 'filesize' => true, + 'expected' => null, + ), + ); + } + + /** + * Tests that an unusable `filesize` in the attachment metadata falls back to the size of the file. + * + * @ticket 65686 + * + * @dataProvider data_wp_prepare_attachment_for_js_filesize_falls_back_to_the_file + * + * @param mixed $filesize The `filesize` value stored in the attachment metadata. + */ + public function test_wp_prepare_attachment_for_js_filesize_falls_back_to_the_file( $filesize ) { + $id = self::factory()->attachment->create_upload_object( DIR_TESTDATA . '/images/canola.jpg' ); + $this->assertIsInt( $id ); + $post = get_post( $id ); + $this->assertInstanceOf( WP_Post::class, $post ); + $file = get_attached_file( $id ); + $this->assertIsString( $file ); + + $meta = wp_get_attachment_metadata( $id ); + $this->assertIsArray( $meta ); + $meta['filesize'] = $filesize; + wp_update_attachment_metadata( $id, $meta ); + + $prepped = wp_prepare_attachment_for_js( $post ); + $this->assertIsArray( $prepped ); + $this->assertArrayHasKey( 'filesizeInBytes', $prepped ); + + $this->assertSame( wp_filesize( $file ), $prepped['filesizeInBytes'] ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_wp_prepare_attachment_for_js_filesize_falls_back_to_the_file(): array { + return array( + 'a value smaller than a byte' => array( 'filesize' => 0.5 ), + 'zero' => array( 'filesize' => 0 ), + 'a negative integer' => array( 'filesize' => -12345 ), + 'an empty string' => array( 'filesize' => '' ), + 'a non-numeric string' => array( 'filesize' => 'not-a-number' ), + 'an array' => array( 'filesize' => array( 12345 ) ), + 'null' => array( 'filesize' => null ), + 'false' => array( 'filesize' => false ), + 'true' => array( 'filesize' => true ), + ); + } + /** * @ticket 19067 * @expectedDeprecated wp_convert_bytes_to_hr From 4af02ef896b2b7b75177a0406fd7b26379780506 Mon Sep 17 00:00:00 2001 From: Peter Wilson Date: Tue, 4 Aug 2026 01:51:49 +0000 Subject: [PATCH 105/138] Widgets: Revert On This Day dashboard widget. The On This Day dashboard widget has been bumped from the WordPress 7.1 release to the 7.2 release pending design and behavioural improvements. This reverts r62977, r62968, r62852, r62681. Props annezazu, matt, peterwilsoncc. Fixes #65801. git-svn-id: https://develop.svn.wordpress.org/trunk@63001 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/dashboard.css | 29 -- .../includes/dashboard-on-this-day.php | 223 -------- src/wp-admin/includes/dashboard.php | 7 - .../tests/admin/wpDashboardOnThisDay.php | 477 ------------------ 4 files changed, 736 deletions(-) delete mode 100644 src/wp-admin/includes/dashboard-on-this-day.php delete mode 100644 tests/phpunit/tests/admin/wpDashboardOnThisDay.php diff --git a/src/wp-admin/css/dashboard.css b/src/wp-admin/css/dashboard.css index 860fe9696b873..17a9e312b85c6 100644 --- a/src/wp-admin/css/dashboard.css +++ b/src/wp-admin/css/dashboard.css @@ -1025,35 +1025,6 @@ body #dashboard-widgets .postbox form .submit { top: 0; } -/* On This Day dashboard widget */ - -#wp_dashboard_on_this_day h3 { - font-weight: 600; -} - -#wp_dashboard_on_this_day li { - margin: 0; - padding: 0; -} - -#wp_dashboard_on_this_day ul ul { - margin: 0 0 0 18px; - padding: 0; - list-style: disc; -} - -#wp_dashboard_on_this_day ul ul li + li { - margin-top: 6px; -} - -#wp_dashboard_on_this_day .wp-on-this-day-widget > ul > li + li { - margin-top: 16px; -} - -#wp_dashboard_on_this_day .wp-on-this-day-post-author { - color: #646970; -} - /* Browse happy box */ #dashboard-widgets #dashboard_browser_nag.postbox .inside { diff --git a/src/wp-admin/includes/dashboard-on-this-day.php b/src/wp-admin/includes/dashboard-on-this-day.php deleted file mode 100644 index 948e128f72c59..0000000000000 --- a/src/wp-admin/includes/dashboard-on-this-day.php +++ /dev/null @@ -1,223 +0,0 @@ -'; - - if ( current_user_can( 'edit_posts' ) ) { - printf( - /* translators: %s: URL to the new post screen. */ - __( 'No posts were published on this day in previous years. Write one today, and be reminded about it next year.' ), - esc_url( admin_url( 'post-new.php' ) ) - ); - } else { - echo esc_html__( 'No posts were published on this day in previous years.' ); - } - - echo '

      '; - return; - } - - $posts_by_year = array(); - $post_count = count( $posts ); - - foreach ( $posts as $post ) { - $year = get_the_date( 'Y', $post ); - - if ( ! isset( $posts_by_year[ $year ] ) ) { - $posts_by_year[ $year ] = array(); - } - - $posts_by_year[ $year ][] = $post; - } - - /* translators: Date format for the On This Day widget date, without year. See https://www.php.net/manual/datetime.format.php */ - $date = '' . esc_html( wp_date( _x( 'F jS', 'on this day date format' ) ) ) . ''; - ?> -
      -

      - -

      -
        - $year_posts ) : ?> -
      • -

        -
          - - ID ) && ! post_password_required( $year_post ) ) { - $excerpt = get_the_excerpt( $year_post ); - - if ( is_string( $excerpt ) && '' !== $excerpt ) { - $no_title_excerpt = wp_trim_words( $excerpt, 15 ); - } - } - } - - $author_id = (int) $year_post->post_author; - $author_name = $author_id > 0 ? (string) get_the_author_meta( 'display_name', $author_id ) : ''; - $show_author = '' !== trim( $author_name ) && get_current_user_id() !== $author_id; - ?> -
        • - - - - - - ' . esc_html( - sprintf( - /* translators: %s: Post author's display name. */ - __( 'by %s' ), - $author_name - ) - ) . ''; - ?> - -
        • - -
        -
      • - -
      -
      - format( 'Y' ); - $date_query = array( - 'relation' => 'AND', - array( - 'before' => array( 'year' => $year ), - ), - _wp_dashboard_on_this_day_date_query_clause( $today ), - ); - - $args = array( - 'post_type' => 'post', - 'post_status' => array( 'publish' ), - 'posts_per_page' => 10, - 'ignore_sticky_posts' => true, - 'orderby' => 'date', - 'order' => 'DESC', - 'no_found_rows' => true, - 'update_post_term_cache' => false, - 'update_post_meta_cache' => false, - 'date_query' => $date_query, - ); - - /** - * Filters the arguments used to query posts for the On This Day dashboard widget. - * - * @since 7.1.0 - * - * @param array $args WP_Query arguments. - */ - $args = apply_filters( 'wp_dashboard_on_this_day_query_args', $args ); - - $query = new WP_Query( $args ); - - return $query->posts; -} - -/** - * Builds the date query clause for today's anniversary date. - * - * On February 28 in a non-leap year, February 29 posts are included so - * leap-day anniversaries still appear. - * - * @since 7.1.0 - * @access private - * - * @param DateTimeInterface $date Date to build the clause for. - * @return array Date query clause. - */ -function _wp_dashboard_on_this_day_date_query_clause( $date ) { - $month = (int) $date->format( 'm' ); - $day = (int) $date->format( 'd' ); - $clause = array( - 'month' => $month, - 'day' => $day, - ); - - // Display leap day posts on Feb 28 in non leap years. - if ( - 28 === $day - && 2 === $month - && false === (bool) $date->format( 'L' ) - ) { - $clause = array( - 'relation' => 'OR', - $clause, - array( - 'month' => 2, - 'day' => 29, - ), - ); - } - - return $clause; -} diff --git a/src/wp-admin/includes/dashboard.php b/src/wp-admin/includes/dashboard.php index a0c2a23189644..0fe5c62064b64 100644 --- a/src/wp-admin/includes/dashboard.php +++ b/src/wp-admin/includes/dashboard.php @@ -88,13 +88,6 @@ function wp_dashboard_setup() { wp_add_dashboard_widget( 'dashboard_quick_press', $quick_draft_title, 'wp_dashboard_quick_press' ); } - // On This Day. - if ( ! function_exists( 'wp_dashboard_on_this_day' ) ) { - require_once ABSPATH . 'wp-admin/includes/dashboard-on-this-day.php'; - } - - wp_add_dashboard_widget( 'wp_dashboard_on_this_day', __( 'On This Day' ), 'wp_dashboard_on_this_day' ); - // WordPress Events and News. wp_add_dashboard_widget( 'dashboard_primary', __( 'WordPress Events and News' ), 'wp_dashboard_events_news' ); diff --git a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php b/tests/phpunit/tests/admin/wpDashboardOnThisDay.php deleted file mode 100644 index 728b9bcef64d0..0000000000000 --- a/tests/phpunit/tests/admin/wpDashboardOnThisDay.php +++ /dev/null @@ -1,477 +0,0 @@ -user->create( - array( - 'display_name' => 'Current Writer', - 'role' => 'author', - ) - ); - self::$other_user_id = $factory->user->create( - array( - 'display_name' => 'Guest Writer', - 'role' => 'author', - ) - ); - self::$subscriber_id = $factory->user->create( - array( - 'display_name' => 'Reader', - 'role' => 'subscriber', - ) - ); - } - - public static function wpTearDownAfterClass() { - self::delete_user( self::$user_id ); - self::delete_user( self::$other_user_id ); - self::delete_user( self::$subscriber_id ); - } - - public function set_up() { - parent::set_up(); - - set_current_screen( 'dashboard' ); - } - - /** - * Creates a published post on the widget's prior-year calendar day. - * - * @param int $author_id Author ID. - * @param string $title Post title. - * @param int $years_ago Number of years before today. - * @param string $time Post time. - * @param array $post_args Additional post arguments. - * @return int Post ID. - */ - private function create_matching_post( - int $author_id, - string $title = 'A memory from last year', - int $years_ago = 1, - string $time = '12:00:00', - array $post_args = array() - ): int { - $post_date = current_datetime()->modify( '-' . $years_ago . ' years' )->format( 'Y-m-d' ) . ' ' . $time; - - return self::factory()->post->create( - array_merge( - array( - 'post_author' => $author_id, - 'post_date' => $post_date, - 'post_date_gmt' => get_gmt_from_date( $post_date ), - 'post_status' => 'publish', - 'post_title' => $title, - ), - $post_args - ) - ); - } - - /** - * Creates a published post near, but not on, today's prior-year calendar day. - * - * @param int $author_id Author ID. - * @param string $title Post title. - * @param int $day_offset Number of days from today's prior-year calendar day. - * @return int Post ID. - */ - private function create_nearby_post( int $author_id, string $title = 'Almost a memory', int $day_offset = 1 ): int { - $post_date = current_datetime() - ->modify( '-1 year' ) - ->modify( ( $day_offset >= 0 ? '+' : '' ) . $day_offset . ' days' ) - ->format( 'Y-m-d' ) . ' 12:00:00'; - - return self::factory()->post->create( - array( - 'post_author' => $author_id, - 'post_date' => $post_date, - 'post_date_gmt' => get_gmt_from_date( $post_date ), - 'post_status' => 'publish', - 'post_title' => $title, - ) - ); - } - - /** - * Invokes _wp_dashboard_on_this_day_date_query_clause(). - * - * @param string $date Date string. - * @return array Date query clause. - */ - private static function get_date_query_clause( string $date ): array { - return _wp_dashboard_on_this_day_date_query_clause( new DateTimeImmutable( $date, wp_timezone() ) ); - } - - /** - * @ticket 65116 - * - * @covers ::_wp_dashboard_on_this_day_date_query_clause - */ - public function test_get_date_query_clause_includes_february_29_on_february_28_in_non_leap_year() { - $clause = self::get_date_query_clause( '2023-02-28 12:00:00' ); - - $this->assertSame( - array( - 'relation' => 'OR', - array( - 'month' => 2, - 'day' => 28, - ), - array( - 'month' => 2, - 'day' => 29, - ), - ), - $clause - ); - } - - /** - * @ticket 65116 - * - * @covers ::_wp_dashboard_on_this_day_date_query_clause - */ - public function test_get_date_query_clause_does_not_include_february_29_on_february_28_in_leap_year() { - $clause = self::get_date_query_clause( '2024-02-28 12:00:00' ); - - $this->assertSame( - array( - 'month' => 2, - 'day' => 28, - ), - $clause - ); - } - - /** - * @ticket 65116 - * - * @covers ::_wp_dashboard_on_this_day_date_query_clause - */ - public function test_get_date_query_clause_matches_february_29_on_leap_day() { - $clause = self::get_date_query_clause( '2024-02-29 12:00:00' ); - - $this->assertSame( - array( - 'month' => 2, - 'day' => 29, - ), - $clause - ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_outputs_placeholder_without_matching_posts() { - wp_set_current_user( self::$user_id ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output ); - $this->assertStringContainsString( 'Write one today', $output ); - $this->assertStringContainsString( admin_url( 'post-new.php' ), $output ); - $this->assertStringNotContainsString( '
        ', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_placeholder_omits_link_without_edit_posts_capability() { - wp_set_current_user( self::$subscriber_id ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output ); - $this->assertStringNotContainsString( 'Write one today', $output ); - $this->assertStringNotContainsString( admin_url( 'post-new.php' ), $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_ignores_nearby_prior_year_posts() { - wp_set_current_user( self::$user_id ); - $this->create_nearby_post( self::$user_id ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringNotContainsString( 'Almost a memory', $output ); - $this->assertStringContainsString( 'No posts were published on this day in previous years.', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_uses_singular_copy_for_a_single_post() { - wp_set_current_user( self::$user_id ); - $this->create_matching_post( self::$user_id ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( 'One post has been published on ' . wp_date( 'F jS' ) . ':', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_labels_posts_from_other_authors() { - wp_set_current_user( self::$user_id ); - - $this->create_matching_post( self::$user_id, 'A note from me' ); - $this->create_matching_post( self::$other_user_id, 'A note from someone else' ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( 'A note from me', $output ); - $this->assertStringNotContainsString( 'by Current Writer', $output ); - $this->assertStringContainsString( 'A note from someone else', $output ); - $this->assertStringContainsString( 'by Guest Writer', $output ); - $this->assertStringContainsString( '', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_groups_posts_by_year() { - wp_set_current_user( self::$user_id ); - - $this->create_matching_post( self::$user_id, 'Pretending to meditate', 1, '12:00:00' ); - $this->create_matching_post( self::$user_id, 'Slow internet and good books', 1, '11:00:00' ); - $this->create_matching_post( self::$user_id, 'Late-night shipping log', 2, '12:00:00' ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $last_year = current_datetime()->modify( '-1 year' )->format( 'Y' ); - $two_years_ago = current_datetime()->modify( '-2 years' )->format( 'Y' ); - - $this->assertStringContainsString( '3 posts have been published on ' . wp_date( 'F jS' ) . ':', $output ); - $this->assertStringContainsString( '

        ' . $last_year . '

        ', $output ); - $this->assertStringContainsString( '

        ' . $two_years_ago . '

        ', $output ); - $this->assertStringContainsString( 'Pretending to meditate', $output ); - $this->assertStringContainsString( 'Slow internet and good books', $output ); - $this->assertStringContainsString( 'Late-night shipping log', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_includes_trimmed_excerpt_for_untitled_posts() { - wp_set_current_user( self::$user_id ); - - $words = array(); - for ( $n = 1; $n <= 20; $n++ ) { - $words[] = 'word' . $n; - } - - $this->create_matching_post( - self::$user_id, - '', - 1, - '12:00:00', - array( - 'post_excerpt' => implode( ' ', $words ), - ) - ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( '(no title)', $output ); - $this->assertStringContainsString( 'word15', $output, 'The 15th word should be present.' ); - $this->assertStringNotContainsString( 'word16', $output, 'The 16th word should be trimmed.' ); - $this->assertStringContainsString( '…', $output, 'The excerpt should end with an ellipsis.' ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_does_not_append_excerpt_to_titled_posts() { - wp_set_current_user( self::$user_id ); - - $this->create_matching_post( - self::$user_id, - 'A titled anniversary memory', - 1, - '12:00:00', - array( - 'post_excerpt' => 'This excerpt should not be shown.', - ) - ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( 'A titled anniversary memory', $output ); - $this->assertStringNotContainsString( 'This excerpt should not be shown.', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_includes_trimmed_excerpt_for_untitled_private_posts_authored_by_current_user() { - wp_set_current_user( self::$user_id ); - - $this->create_matching_post( - self::$user_id, - '', - 1, - '12:00:00', - array( - 'post_excerpt' => 'Readable private anniversary memory.', - 'post_status' => 'private', - ) - ); - - add_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); - - ob_start(); - try { - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - } finally { - remove_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); - } - - $this->assertStringContainsString( '(no title)', $output ); - $this->assertStringContainsString( 'Readable private anniversary memory.', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_hides_untitled_post_excerpt_for_unreadable_posts() { - wp_set_current_user( self::$user_id ); - - $post_id = $this->create_matching_post( - self::$other_user_id, - '', - 1, - '12:00:00', - array( - 'post_excerpt' => 'Unreadable private anniversary memory.', - 'post_status' => 'private', - ) - ); - - add_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); - - ob_start(); - try { - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - } finally { - remove_filter( 'wp_dashboard_on_this_day_query_args', array( $this, 'filter_on_this_day_query_private_posts' ) ); - } - - $this->assertFalse( current_user_can( 'read_post', $post_id ) ); - $this->assertStringContainsString( '(no title)', $output ); - $this->assertStringNotContainsString( 'Unreadable private anniversary memory.', $output ); - } - - /** - * @ticket 65116 - * - * @covers ::wp_dashboard_on_this_day - */ - public function test_widget_hides_untitled_post_excerpt_for_password_protected_posts() { - wp_set_current_user( self::$user_id ); - - $this->create_matching_post( - self::$user_id, - '', - 1, - '12:00:00', - array( - 'post_excerpt' => 'Private anniversary memory.', - 'post_password' => 'secret', - ) - ); - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringNotContainsString( 'Private anniversary memory.', $output ); - } - - /** - * @covers ::wp_dashboard_on_this_day - * @covers ::wp_dashboard_on_this_day_get_posts - */ - public function test_widget_limits_posts_to_ten() { - wp_set_current_user( self::$user_id ); - - for ( $years_ago = 1; $years_ago <= 11; $years_ago++ ) { - $this->create_matching_post( self::$user_id, 'Anniversary post ' . $years_ago, $years_ago ); - } - - ob_start(); - wp_dashboard_on_this_day(); - $output = ob_get_clean(); - - $this->assertStringContainsString( '10 posts have been published on ' . wp_date( 'F jS' ) . ':', $output ); - $this->assertMatchesRegularExpression( '/>\s*Anniversary post 1\s*<\/a>/', $output ); - $this->assertMatchesRegularExpression( '/>\s*Anniversary post 10\s*<\/a>/', $output ); - $this->assertStringNotContainsString( 'Anniversary post 11', $output ); - } - - /** - * Filters the On This Day query to include private posts. - * - * @param array $args WP_Query arguments. - * @return array Filtered query arguments. - */ - public function filter_on_this_day_query_private_posts( $args ) { - $args['post_status'] = array( 'private' ); - - return $args; - } -} From c0155cd2bea0722270b5f15b2a9ce78b2d78e375 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 4 Aug 2026 01:56:04 +0000 Subject: [PATCH 106/138] Media: Normalize unusable `sizes` attachment metadata. Attachment metadata is untyped, and the `sizes` key is not guaranteed to be present or to hold an array. Sub-size generation can leave it out entirely, and a plugin filtering `wp_get_attachment_metadata` can replace it with anything. `wp_save_image()` validated only that the metadata itself was an array before passing `$meta['sizes']` to `array_merge()`, so an absent or scalar value raised a `TypeError` and the image editor returned an HTTP 500 mid-save. `wp_restore_image()` had the same gap at `$meta['sizes'][ $default_size ] = $data`, where a string raises "Cannot use a scalar value as an array" and `false` is deprecated as of PHP 8.1 and an error as of PHP 9. `wp_get_attachment_metadata()` now returns `false` whenever the metadata is not an array, on the `$unfiltered` path as well as after the filter, matching the documented `array|false` return. A `sizes` key holding a non-array is replaced with an empty array, so every caller can rely on the key being an array whenever it is present. The key is not invented when it is absent: audio, video and document attachments legitimately store metadata without it, and callers such as `wp-admin/post.php` read the metadata unfiltered in order to modify it and write it back, so normalizing there would persist into the database. The image editor entry points fill in the missing key themselves, and `wp_prepare_attachment_for_js()` now checks the dimensions of the `full` entry alongside its filename before reading them, removing the "Undefined array key" warnings raised for a `sizes` array that carries no usable `full` size. PHPUnit coverage is added for all three functions. Developed in https://github.com/WordPress/wordpress-develop/pull/12744. Follow-up to r11965, r23873, r38949, r49084, r62978. Props josephscott, westonruter, mukesh27, irozum, ugyensupport, nazmulasif. See #65686, #64898. Fixes #65748. git-svn-id: https://develop.svn.wordpress.org/trunk@63002 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/image-edit.php | 6 +- src/wp-includes/media.php | 5 +- src/wp-includes/post.php | 16 +- .../phpunit/tests/ajax/wpAjaxImageEditor.php | 132 ++++++++ tests/phpunit/tests/media.php | 150 ++++++++++ .../tests/post/wpGetAttachmentMetadata.php | 281 ++++++++++++++++++ 6 files changed, 586 insertions(+), 4 deletions(-) create mode 100644 tests/phpunit/tests/post/wpGetAttachmentMetadata.php diff --git a/src/wp-admin/includes/image-edit.php b/src/wp-admin/includes/image-edit.php index a192ef0000c17..2f6bc25740e2d 100644 --- a/src/wp-admin/includes/image-edit.php +++ b/src/wp-admin/includes/image-edit.php @@ -820,11 +820,13 @@ function wp_restore_image( $post_id ) { $restored = false; $msg = new stdClass(); - if ( ! is_array( $backup_sizes ) ) { + if ( ! is_array( $meta ) || ! is_array( $backup_sizes ) ) { $msg->error = __( 'Cannot load image metadata.' ); return $msg; } + $meta['sizes'] ??= array(); + $parts = pathinfo( $file ); $suffix = time() . rand( 100, 999 ); $default_sizes = get_intermediate_image_sizes(); @@ -983,6 +985,8 @@ function wp_save_image( $post_id ) { return $return; } + $meta['sizes'] ??= array(); + if ( ! is_array( $backup_sizes ) ) { $backup_sizes = array(); } diff --git a/src/wp-includes/media.php b/src/wp-includes/media.php index 9f98538d2757f..a31e77b00e26c 100644 --- a/src/wp-includes/media.php +++ b/src/wp-includes/media.php @@ -4814,7 +4814,10 @@ function wp_prepare_attachment_for_js( $attachment ) { } $response = array_merge( $response, $sizes['full'] ); - } elseif ( $meta['sizes']['full']['file'] ) { + } elseif ( + ! empty( $meta['sizes']['full']['file'] ) && + isset( $meta['sizes']['full']['width'], $meta['sizes']['full']['height'] ) + ) { $sizes['full'] = array( 'url' => esc_url_raw( $base_url . $meta['sizes']['full']['file'] ), 'height' => $meta['sizes']['full']['height'], diff --git a/src/wp-includes/post.php b/src/wp-includes/post.php index da3abfbd7d61c..2db73e9a20476 100644 --- a/src/wp-includes/post.php +++ b/src/wp-includes/post.php @@ -7048,6 +7048,8 @@ function wp_delete_attachment_files( $post_id, $meta, $backup_sizes, $file ) { * * @since 2.1.0 * @since 6.0.0 The `$filesize` value was added to the returned array. + * @since 7.1.0 `false` is now returned if the metadata is not an array, and when the result is + * filtered the `sizes` key is always an array when present. * * @param int $attachment_id Attachment post ID. Defaults to global $post. * @param bool $unfiltered Optional. If true, filters are not run. Default false. @@ -7111,7 +7113,7 @@ function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) { $data = get_post_meta( $attachment_id, '_wp_attachment_metadata', true ); - if ( ! $data ) { + if ( ! is_array( $data ) || ! $data ) { return false; } @@ -7127,7 +7129,17 @@ function wp_get_attachment_metadata( $attachment_id = 0, $unfiltered = false ) { * @param array $data Array of meta data for the given attachment. * @param int $attachment_id Attachment post ID. */ - return apply_filters( 'wp_get_attachment_metadata', $data, $attachment_id ); + $data = apply_filters( 'wp_get_attachment_metadata', $data, $attachment_id ); + + if ( ! is_array( $data ) ) { + return false; + } + + if ( array_key_exists( 'sizes', $data ) && ! is_array( $data['sizes'] ) ) { + $data['sizes'] = array(); + } + + return $data; } /** diff --git a/tests/phpunit/tests/ajax/wpAjaxImageEditor.php b/tests/phpunit/tests/ajax/wpAjaxImageEditor.php index 205f61636149c..03f14f6dd8fa8 100644 --- a/tests/phpunit/tests/ajax/wpAjaxImageEditor.php +++ b/tests/phpunit/tests/ajax/wpAjaxImageEditor.php @@ -194,4 +194,136 @@ public function test_filesize_restored_after_restoring_original_image() { $this->assertSameSetsWithIndex( $pre_file_sizes, $post_restore_file_sizes, 'Filesize should have restored after restoring the original image.' ); } + + /** + * Ensure editing an image does not fatal when the attachment metadata has no usable `sizes` data. + * + * Attachment metadata is not guaranteed to contain a `sizes` array. It can be missing when + * sub-size generation never ran or failed (for example `wp_create_image_subsizes()` returns an + * empty array when the file cannot be parsed), or when it is removed by a plugin filtering + * `wp_get_attachment_metadata`. `wp_save_image()` only validates that the metadata itself is an + * array, then passes `$meta['sizes']` straight to `array_merge()`. + * + * @ticket 65748 + * + * @covers ::wp_save_image + * + * @dataProvider data_save_image_with_unusable_sizes_metadata + * + * @param array{ sizes?: mixed } $meta Attachment metadata to store before editing, minus the file-specific keys. + */ + public function test_save_image_with_unusable_sizes_metadata( array $meta ) { + require_once ABSPATH . 'wp-admin/includes/image-edit.php'; + + $filename = DIR_TESTDATA . '/images/canola.jpg'; + $contents = file_get_contents( $filename ); + $this->assertIsString( $contents ); + + $upload = wp_upload_bits( wp_basename( $filename ), null, $contents ); + $id = $this->_make_attachment( $upload ); + $this->assertIsInt( $id ); + + $original_meta = wp_get_attachment_metadata( $id ); + $this->assertIsArray( $original_meta ); + + // Keep the real file/dimension data, only make `sizes` unusable. + $meta = array_merge( + wp_array_slice_assoc( $original_meta, array( 'width', 'height', 'file', 'filesize' ) ), + $meta + ); + + wp_update_attachment_metadata( $id, $meta ); + + $_REQUEST['action'] = 'image-editor'; + $_REQUEST['context'] = 'edit-attachment'; + $_REQUEST['postid'] = $id; + $_REQUEST['target'] = 'all'; + $_REQUEST['do'] = 'save'; + $_REQUEST['history'] = '[{"c":{"x":5,"y":8,"w":289,"h":322}}]'; + + $ret = wp_save_image( $id ); + + $this->assertObjectNotHasProperty( 'error', $ret, 'Saving the image should not have returned an error.' ); + + $saved_meta = wp_get_attachment_metadata( $id ); + + $this->assertIsArray( $saved_meta, 'The saved attachment metadata should be an array.' ); + $this->assertArrayHasKey( 'sizes', $saved_meta ); + $this->assertIsArray( $saved_meta['sizes'], 'The saved attachment metadata should contain a `sizes` array.' ); + $this->assertArrayHasKey( 'thumbnail', $saved_meta['sizes'], 'The edited image should have regenerated the thumbnail size.' ); + } + + /** + * Ensure restoring an image does not fatal when the attachment metadata has no usable `sizes` data. + * + * `wp_restore_image()` writes each backed up size with `$meta['sizes'][ $default_size ] = $data` + * without ever checking that `$meta['sizes']` is an array. A scalar value raises + * "Cannot use a scalar value as an array", and `false` is deprecated as of PHP 8.1 and + * an error as of PHP 9. The same metadata that fatals `wp_save_image()` reaches this code. + * + * @ticket 65748 + * + * @covers ::wp_restore_image + * + * @dataProvider data_save_image_with_unusable_sizes_metadata + * + * @param array{ sizes?: mixed } $meta Replacement `sizes` metadata to store before restoring. + */ + public function test_restore_image_with_unusable_sizes_metadata( array $meta ) { + require_once ABSPATH . 'wp-admin/includes/image-edit.php'; + + $filename = DIR_TESTDATA . '/images/canola.jpg'; + $contents = file_get_contents( $filename ); + $this->assertIsString( $contents ); + + $upload = wp_upload_bits( wp_basename( $filename ), null, $contents ); + $id = $this->_make_attachment( $upload ); + $this->assertIsInt( $id ); + + $_REQUEST['action'] = 'image-editor'; + $_REQUEST['context'] = 'edit-attachment'; + $_REQUEST['postid'] = $id; + $_REQUEST['target'] = 'all'; + $_REQUEST['do'] = 'save'; + $_REQUEST['history'] = '[{"c":{"x":5,"y":8,"w":289,"h":322}}]'; + + // Edit the image first so that `_wp_attachment_backup_sizes` holds the original sizes. + wp_save_image( $id ); + + $this->assertNotEmpty( + get_post_meta( $id, '_wp_attachment_backup_sizes', true ), + 'The image edit should have stored backup sizes to restore from.' + ); + + // Keep the metadata written by the edit, only make `sizes` unusable. + $edited_meta = wp_get_attachment_metadata( $id ); + $this->assertIsArray( $edited_meta ); + unset( $edited_meta['sizes'] ); + + wp_update_attachment_metadata( $id, array_merge( $edited_meta, $meta ) ); + + wp_restore_image( $id ); + + $restored_meta = wp_get_attachment_metadata( $id ); + $this->assertIsArray( $restored_meta ); + + $this->assertArrayHasKey( 'sizes', $restored_meta ); + $this->assertIsArray( $restored_meta['sizes'], 'The restored attachment metadata should contain a `sizes` array.' ); + $this->assertArrayHasKey( 'thumbnail', $restored_meta['sizes'], 'The restored image should have the thumbnail size restored from the backup sizes.' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_save_image_with_unusable_sizes_metadata(): array { + return array( + 'no sizes key' => array( array() ), + 'null sizes' => array( array( 'sizes' => null ) ), + 'empty string' => array( array( 'sizes' => '' ) ), + 'string sizes' => array( array( 'sizes' => 'not-an-array' ) ), + 'boolean sizes' => array( array( 'sizes' => false ) ), + ); + } } diff --git a/tests/phpunit/tests/media.php b/tests/phpunit/tests/media.php index a492cf6da189f..5aee3f8b6955f 100644 --- a/tests/phpunit/tests/media.php +++ b/tests/phpunit/tests/media.php @@ -667,6 +667,153 @@ public function test_wp_prepare_attachment_for_js_without_image_sizes() { $this->assertArrayHasKey( 'sizes', $prepped ); } + /** + * Tests that an unusable `full` entry in the `sizes` metadata is skipped. + * + * Attachments that are not images, such as PDFs, are handled by a separate branch that reads + * the `full` entry of the `sizes` metadata directly. That entry is not guaranteed to be there, + * nor to carry dimensions when it is, and reading it unconditionally raises "Undefined array + * key" warnings. + * + * @ticket 65748 + * + * @dataProvider data_wp_prepare_attachment_for_js_unusable_full_size + * + * @covers ::wp_prepare_attachment_for_js + * + * @param array $sizes Value to store as the `sizes` metadata. + */ + public function test_wp_prepare_attachment_for_js_with_an_unusable_full_size( array $sizes ) { + $id = $this->create_pdf_attachment( $sizes ); + + $prepped = wp_prepare_attachment_for_js( $id ); + + $this->assertIsArray( $prepped ); + $this->assertArrayHasKey( 'sizes', $prepped ); + + $sizes = $prepped['sizes']; + + $this->assertIsArray( $sizes ); + $this->assertArrayNotHasKey( 'full', $sizes, 'An unusable `full` size should not have been exposed.' ); + } + + /** + * Tests that a usable `full` entry in the `sizes` metadata is still exposed. + * + * @ticket 65748 + * + * @covers ::wp_prepare_attachment_for_js + */ + public function test_wp_prepare_attachment_for_js_with_a_usable_full_size() { + $id = $this->create_pdf_attachment( + array( + 'full' => array( + 'file' => 'test-document-pdf.jpg', + 'width' => 232, + 'height' => 300, + 'mime-type' => 'image/jpeg', + ), + ) + ); + + $prepped = wp_prepare_attachment_for_js( $id ); + + $this->assertIsArray( $prepped ); + $this->assertArrayHasKey( 'sizes', $prepped ); + + $sizes = $prepped['sizes']; + + $this->assertIsArray( $sizes ); + $this->assertArrayHasKey( 'full', $sizes, 'A usable `full` size should have been exposed.' ); + + $full = $sizes['full']; + + $this->assertIsArray( $full ); + $this->assertSame( 232, $full['width'] ); + $this->assertSame( 300, $full['height'] ); + $this->assertSame( 'portrait', $full['orientation'] ); + $this->assertIsString( $full['url'] ); + $this->assertStringEndsWith( '/test-document-pdf.jpg', $full['url'] ); + } + + /** + * Data provider. + * + * @return array }> + */ + public function data_wp_prepare_attachment_for_js_unusable_full_size(): array { + return array( + 'no full size' => array( + array( + 'thumbnail' => array( + 'file' => 'test-document-pdf-116x150.jpg', + 'width' => 116, + 'height' => 150, + 'mime-type' => 'image/jpeg', + ), + ), + ), + 'full without dimensions' => array( + array( + 'full' => array( + 'file' => 'test-document-pdf.jpg', + 'mime-type' => 'image/jpeg', + ), + ), + ), + 'full without a height' => array( + array( + 'full' => array( + 'file' => 'test-document-pdf.jpg', + 'width' => 232, + 'mime-type' => 'image/jpeg', + ), + ), + ), + 'full with an empty file' => array( + array( + 'full' => array( + 'file' => '', + 'width' => 232, + 'height' => 300, + 'mime-type' => 'image/jpeg', + ), + ), + ), + ); + } + + /** + * Creates a PDF attachment carrying the given `sizes` metadata. + * + * A PDF is used so that wp_prepare_attachment_for_js() takes the branch for attachments that + * are not images, which is the one that reads the `full` entry of the `sizes` metadata. + * + * @param array $sizes Value to store as the `sizes` metadata. + * @return int Attachment ID. + */ + private function create_pdf_attachment( array $sizes ): int { + $id = wp_insert_attachment( + array( + 'post_title' => 'Attachment Title', + 'post_type' => 'attachment', + 'post_parent' => 0, + 'post_mime_type' => 'application/pdf', + 'guid' => home_url( '/wp-content/uploads/test-document.pdf' ), + ) + ); + + wp_update_attachment_metadata( + $id, + array( + 'file' => 'test-document.pdf', + 'sizes' => $sizes, + ) + ); + + return $id; + } + /** * Tests that a `filesize` stored in the attachment metadata is normalized to a positive integer. * @@ -3178,6 +3325,9 @@ public function test_get_image_send_to_editor_defaults_no_caption_no_rel() { * * @ticket 36246 * @requires function imagejpeg + * + * @covers ::wp_get_attachment_image + * @covers ::wp_get_attachment_metadata */ public function test_wp_get_attachment_image_should_use_wp_get_attachment_metadata() { add_filter( 'wp_get_attachment_metadata', array( $this, 'filter_36246' ), 10, 2 ); diff --git a/tests/phpunit/tests/post/wpGetAttachmentMetadata.php b/tests/phpunit/tests/post/wpGetAttachmentMetadata.php new file mode 100644 index 0000000000000..028356a04168d --- /dev/null +++ b/tests/phpunit/tests/post/wpGetAttachmentMetadata.php @@ -0,0 +1,281 @@ +create_attachment(); + + $this->assertFalse( wp_get_attachment_metadata( $attachment_id ) ); + } + + /** + * Ensure stored metadata that is not an array is reported as a failure. + * + * The documented return of `array|false` has to hold on the `$unfiltered` path too, since + * callers such as wp-admin/post.php read the metadata that way in order to modify it and + * pass it back to wp_update_attachment_metadata(). + * + * @ticket 65748 + * + * @dataProvider data_non_array_stored_metadata_values + * + * @param mixed $metadata Value to store as `_wp_attachment_metadata`. + */ + public function test_should_return_false_when_the_stored_metadata_is_not_an_array( $metadata ) { + $attachment_id = $this->create_attachment(); + + update_post_meta( $attachment_id, '_wp_attachment_metadata', $metadata ); + + $this->assertFalse( wp_get_attachment_metadata( $attachment_id ), 'The filtered metadata should have been reported as missing.' ); + $this->assertFalse( wp_get_attachment_metadata( $attachment_id, true ), 'The unfiltered metadata should have been reported as missing.' ); + } + + /** + * Ensure the `sizes` key is not invented for attachments that have no sub-sizes. + * + * An attachment is not necessarily an image. Audio, video and document attachments + * legitimately store metadata without a `sizes` key, and fabricating one would both + * blur that distinction and pollute the stored metadata for any caller that reads + * the metadata, modifies it, and passes it back to wp_update_attachment_metadata(). + * + * @ticket 65748 + */ + public function test_should_not_add_a_sizes_key_when_the_metadata_has_none() { + $metadata = array( + 'bitrate' => 128000, + 'length' => 191, + 'fileformat' => 'mp3', + ); + + $attachment_id = $this->create_attachment( $metadata ); + + $this->assertSame( $metadata, wp_get_attachment_metadata( $attachment_id ) ); + } + + /** + * Ensure a usable `sizes` array is passed through untouched. + * + * @ticket 65748 + */ + public function test_should_preserve_a_usable_sizes_array() { + $metadata = array( + 'file' => '2026/08/image.jpg', + 'sizes' => array( + 'thumbnail' => array( + 'file' => 'image-150x150.jpg', + 'width' => 150, + 'height' => 150, + 'mime-type' => 'image/jpeg', + ), + ), + ); + + $attachment_id = $this->create_attachment( $metadata ); + + $this->assertSame( $metadata, wp_get_attachment_metadata( $attachment_id ) ); + } + + /** + * Ensure a `sizes` key holding something other than an array is replaced with an empty array. + * + * Callers such as wp_save_image() pass `$meta['sizes']` straight to array_merge(), which + * is a fatal error for a scalar. Guarding the value here means every caller can rely on + * `sizes` being an array whenever the key is present. + * + * @ticket 65748 + * + * @dataProvider data_non_array_sizes_values + * + * @param mixed $sizes Value to store under the `sizes` key. + */ + public function test_should_replace_a_non_array_sizes_value_with_an_empty_array( $sizes ) { + $attachment_id = $this->create_attachment( + array( + 'file' => '2026/08/image.jpg', + 'sizes' => $sizes, + ) + ); + + $metadata = wp_get_attachment_metadata( $attachment_id ); + + $this->assertIsArray( $metadata, 'The metadata should have been returned as an array.' ); + $this->assertArrayHasKey( 'sizes', $metadata, 'The `sizes` key should still be present.' ); + $this->assertSame( array(), $metadata['sizes'], 'The unusable `sizes` value should have been replaced.' ); + } + + /** + * Ensure the stored metadata is returned verbatim when filters are skipped. + * + * Passing `$unfiltered` as true is documented as skipping the filters, and callers such as + * wp-admin/post.php read the metadata this way in order to modify and re-save it. Normalizing + * the value here would write the normalization back into the database. + * + * @ticket 65748 + * + * @dataProvider data_non_array_sizes_values + * + * @param mixed $sizes Value to store under the `sizes` key. + */ + public function test_should_not_replace_a_non_array_sizes_value_when_unfiltered( $sizes ) { + $metadata = array( + 'file' => '2026/08/image.jpg', + 'sizes' => $sizes, + ); + + $attachment_id = $this->create_attachment( $metadata ); + + $this->assertSame( $metadata, wp_get_attachment_metadata( $attachment_id, true ) ); + } + + /** + * Ensure a filtered value that is not an array is reported as a failure. + * + * The function documents a return of `array|false`, so a filter returning something else + * should surface as a failure rather than being handed to callers that expect an array. + * + * @ticket 65748 + * + * @dataProvider data_non_array_filter_return_values + * + * @param mixed $value Value for the filter to return. + */ + public function test_should_return_false_when_the_filter_returns_a_non_array( $value ) { + $attachment_id = $this->create_attachment( array( 'file' => '2026/08/image.jpg' ) ); + + add_filter( + 'wp_get_attachment_metadata', + static function () use ( $value ) { + return $value; + } + ); + + $this->assertFalse( wp_get_attachment_metadata( $attachment_id ) ); + } + + /** + * Ensure the `sizes` value is normalized after the filter has run, not before. + * + * @ticket 65748 + */ + public function test_should_normalize_a_sizes_value_introduced_by_the_filter() { + // Stored without a `sizes` key, so the key can only come from the filter. + $attachment_id = $this->create_attachment( array( 'file' => '2026/08/image.jpg' ) ); + + add_filter( + 'wp_get_attachment_metadata', + static function ( array $data ): array { + $data['sizes'] = 'not-an-array'; + return $data; + } + ); + + $metadata = wp_get_attachment_metadata( $attachment_id ); + + $this->assertIsArray( $metadata, 'The metadata should have been returned as an array.' ); + $this->assertArrayHasKey( 'sizes', $metadata, 'The `sizes` key should still be present.' ); + $this->assertSame( array(), $metadata['sizes'], 'The value set by the filter should have been replaced.' ); + } + + /** + * Ensure the filter is not applied when filters are skipped. + */ + public function test_should_not_apply_the_filter_when_unfiltered() { + $metadata = array( 'file' => '2026/08/image.jpg' ); + + $attachment_id = $this->create_attachment( $metadata ); + + add_filter( 'wp_get_attachment_metadata', '__return_empty_array' ); + + $this->assertSame( $metadata, wp_get_attachment_metadata( $attachment_id, true ) ); + } + + /** + * Data provider. + * + * Only values that survive a round trip through the meta table are listed. A value that + * comes back falsy, such as an empty string, was already treated as missing metadata. + * + * @return array + */ + public function data_non_array_stored_metadata_values(): array { + return array( + 'string' => array( 'not-an-array' ), + 'integer' => array( 1 ), + 'float' => array( 1.5 ), + 'object' => array( new stdClass() ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_non_array_sizes_values(): array { + return array( + 'null' => array( null ), + 'empty string' => array( '' ), + 'string' => array( 'not-an-array' ), + 'boolean false' => array( false ), + 'integer' => array( 0 ), + ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_non_array_filter_return_values(): array { + return array( + 'null' => array( null ), + 'empty string' => array( '' ), + 'string' => array( 'not-an-array' ), + 'boolean false' => array( false ), + 'boolean true' => array( true ), + 'integer' => array( 1 ), + 'float' => array( 1.5 ), + 'object' => array( new stdClass() ), + ); + } + + /** + * Creates an attachment, optionally storing metadata for it. + * + * The metadata is stored with update_post_meta() rather than wp_update_attachment_metadata() + * so that it reaches the database without passing through the update filter, leaving the + * stored value entirely under the control of the test. + * + * @param array|null $metadata Optional. Metadata to store as + * `_wp_attachment_metadata`. Default null, meaning + * no metadata is stored at all. + * @return int Attachment ID. + */ + private function create_attachment( ?array $metadata = null ): int { + $attachment_id = self::factory()->attachment->create_object( + array( + 'file' => '2026/08/image.jpg', + 'post_mime_type' => 'image/jpeg', + ) + ); + + $this->assertIsInt( $attachment_id, 'Failed to create the attachment fixture.' ); + + if ( null !== $metadata ) { + update_post_meta( $attachment_id, '_wp_attachment_metadata', $metadata ); + } + + return $attachment_id; + } +} From 275a37a6b1663031f01ff4481acf0aec5bb4bc0c Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Tue, 4 Aug 2026 02:03:30 +0000 Subject: [PATCH 107/138] Build/Test Tools: Further refine runner override variable name. This changes `RUNNER_GROUP` to `RUNNERS_NAME` to avoid confusion with the `runs-on.group` setting, which is configured in a completely different way. Props lancewillet. See #65749. git-svn-id: https://develop.svn.wordpress.org/trunk@63003 602fd350-edb4-49c9-b593-d223f7449a82 --- .github/workflows/reusable-phpunit-tests-v3.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/reusable-phpunit-tests-v3.yml b/.github/workflows/reusable-phpunit-tests-v3.yml index abe472e03b6d1..6a7f49fba468c 100644 --- a/.github/workflows/reusable-phpunit-tests-v3.yml +++ b/.github/workflows/reusable-phpunit-tests-v3.yml @@ -129,7 +129,7 @@ jobs: # - Submit the test results to the WordPress.org host test results. phpunit-tests: name: ${{ ( inputs.phpunit-test-groups || inputs.coverage-report ) && format( 'PHP {0} with ', inputs.php ) || '' }} ${{ 'mariadb' == inputs.db-type && 'MariaDB' || 'MySQL' }} ${{ inputs.db-version }}${{ inputs.multisite && ' multisite' || '' }}${{ inputs.db-innovation && ' (innovation release)' || '' }}${{ inputs.memcached && ' with memcached' || '' }}${{ inputs.report && ' (test reporting enabled)' || '' }} ${{ 'example.org' != inputs.tests-domain && inputs.tests-domain || '' }} - runs-on: ${{ vars.RUNNER_GROUP || inputs.os }} + runs-on: ${{ vars.RUNNERS_NAME || inputs.os }} timeout-minutes: ${{ inputs.coverage-report && 120 || inputs.php == '8.4' && 30 || 20 }} permissions: contents: read From 8c3c976c251d4fd2225b6eaa788b0678c1927206 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 4 Aug 2026 02:50:15 +0000 Subject: [PATCH 108/138] Build/Test Tools: Expand suggested extensions in `composer.json`. The `suggest` section had accumulated only four extensions, added ad hoc as individual changes happened to need them. It now lists every extension that the Hosting handbook's server environment page [https://make.wordpress.org/hosting/handbook/server-environment/#required-extensions identifies] as required, highly recommended, or suggested. This lets development environments be provisioned to match what core actually expects, and gives IDEs an accurate picture of which functions are available. The `require` section is deliberately left unchanged: the `mysqli` extension stays a suggestion rather than a requirement since a `db.php` drop-in can supply the database layer without it. Developed in https://github.com/WordPress/wordpress-develop/pull/12384. Follow-up to r56687, r62529, r62637. Fixes #65571. git-svn-id: https://develop.svn.wordpress.org/trunk@63004 602fd350-edb4-49c9-b593-d223f7449a82 --- composer.json | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 5505c9136c263..1bff1b4d62dd7 100644 --- a/composer.json +++ b/composer.json @@ -16,10 +16,35 @@ "php": ">=7.4" }, "suggest": { + "ext-apcu": "*", + "ext-bc": "*", + "ext-curl": "*", "ext-dom": "*", + "ext-exif": "*", + "ext-fileinfo": "*", + "ext-filter": "*", "ext-ftp": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-igbinary": "*", + "ext-imagick": "*", + "ext-intl": "*", + "ext-mbstring": "*", + "ext-memcached": "*", "ext-mysqli": "*", - "ext-ssh2": "*" + "ext-opcache": "*", + "ext-openssl": "*", + "ext-redis": "*", + "ext-shmop": "*", + "ext-simplexml": "*", + "ext-sockets": "*", + "ext-sodium": "*", + "ext-ssh2": "*", + "ext-timezonedb": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-zip": "*", + "ext-zlib": "*" }, "require-dev": { "composer/ca-bundle": "1.5.13", From 0040ded7216de5597637f81b3117d119b736160b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 4 Aug 2026 05:13:18 +0000 Subject: [PATCH 109/138] Build/Test Tools: Add `@phpstan-assert` on `assertIXRError` and `assertNotIXRError`. See #64898. git-svn-id: https://develop.svn.wordpress.org/trunk@63005 602fd350-edb4-49c9-b593-d223f7449a82 --- tests/phpunit/includes/abstract-testcase.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/phpunit/includes/abstract-testcase.php b/tests/phpunit/includes/abstract-testcase.php index 55a9924fb23c3..98b3456935716 100644 --- a/tests/phpunit/includes/abstract-testcase.php +++ b/tests/phpunit/includes/abstract-testcase.php @@ -898,6 +898,8 @@ public function assertNotWPError( $actual, $message = '' ) { * * @param mixed $actual The value to check. * @param string $message Optional. Message to display when the assertion fails. + * + * @phpstan-assert IXR_Error $actual */ public function assertIXRError( $actual, $message = '' ) { $this->assertInstanceOf( 'IXR_Error', $actual, $message ); @@ -908,6 +910,8 @@ public function assertIXRError( $actual, $message = '' ) { * * @param mixed $actual The value to check. * @param string $message Optional. Message to display when the assertion fails. + * + * @phpstan-assert !IXR_Error $actual */ public function assertNotIXRError( $actual, $message = '' ) { if ( $actual instanceof IXR_Error ) { From 1ef9d70aea32f272b3680408d7c4761c8ca32445 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Tue, 4 Aug 2026 07:25:22 +0000 Subject: [PATCH 110/138] XML-RPC: Validate the attachment data in `mw_newMediaObject()`. Passing anything other than a struct as the fourth argument caused a fatal error, and because the struct was read before the login was attempted, an unauthenticated request was enough to trigger it. Read and validate the struct only once the request is authenticated and the `upload_files` capability is confirmed, as every other method on the server does, and reject a call with too few arguments using `minimum_args()`. The `name`, `type` and `bits` members must all be strings: a struct sent for `bits` reached `fwrite()` by way of `wp_upload_bits()` and threw a `TypeError`, while one sent for `type` survived `sanitize_mime_type()` to reach the database as the attachment's post MIME type. A `name` left empty by `sanitize_file_name()` is now reported as a malformed request too, rather than as the server failure `wp_upload_bits()` produced for it. The fourth argument is expanded into a nested hash in the documentation, covering the previously undocumented `post_id` member. Tests cover each rejected shape, the optional members that remain tolerated when absent, and the ordering of the login and capability checks ahead of the validation. Developed in https://github.com/WordPress/wordpress-develop/pull/12482. Follow-up to r32579, r53881. Props josephscott, westonruter, mukesh27. See #65600. Fixes #65611. git-svn-id: https://develop.svn.wordpress.org/trunk@63006 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/class-wp-xmlrpc-server.php | 40 ++- tests/phpunit/tests/xmlrpc/wp/uploadFile.php | 306 +++++++++++++++++++ 2 files changed, 340 insertions(+), 6 deletions(-) diff --git a/src/wp-includes/class-wp-xmlrpc-server.php b/src/wp-includes/class-wp-xmlrpc-server.php index 7d64d3f46c019..1061dbd1831d2 100644 --- a/src/wp-includes/class-wp-xmlrpc-server.php +++ b/src/wp-includes/class-wp-xmlrpc-server.php @@ -6440,24 +6440,33 @@ public function mw_getCategories( $args ) { * @since 1.5.0 * * @param array $args { - * Method arguments. Note: arguments must be ordered as documented. + * Method arguments. Note: top-level arguments must be ordered as documented. * * @type int $0 Blog ID (unused). * @type string $1 Username. * @type string $2 Password. - * @type array $3 Data. + * @type array $3 { + * Data for the file to upload. + * + * @type string $name File name. Sanitized with sanitize_file_name(). + * @type string $type Optional. File MIME type, stored as the attachment's + * post MIME type. Default empty string. + * @type string $bits Optional. File contents. Default empty string. + * @type int $post_id Optional. ID of the post to attach the file to. + * Default 0. + * } * } * @return array|IXR_Error */ public function mw_newMediaObject( $args ) { + if ( ! $this->minimum_args( $args, 4 ) ) { + return $this->error; + } + $username = $this->escape( $args[1] ); $password = $this->escape( $args[2] ); $data = $args[3]; - $name = sanitize_file_name( $data['name'] ); - $type = $data['type']; - $bits = $data['bits']; - $user = $this->login( $username, $password ); if ( ! $user ) { return $this->error; @@ -6471,6 +6480,25 @@ public function mw_newMediaObject( $args ) { return $this->error; } + if ( + ! is_array( $data ) || + ! is_string( $data['name'] ?? null ) || + ! is_string( $data['type'] ?? '' ) || + ! is_string( $data['bits'] ?? '' ) + ) { + return new IXR_Error( 400, __( 'Invalid attachment data.' ) ); + } + + $name = sanitize_file_name( $data['name'] ); + + // A name consisting only of characters the sanitizer strips leaves nothing to write to. + if ( '' === $name ) { + return new IXR_Error( 400, __( 'Invalid attachment data.' ) ); + } + + $type = $data['type'] ?? ''; + $bits = $data['bits'] ?? ''; + if ( is_multisite() && upload_is_user_over_quota( false ) ) { $this->error = new IXR_Error( 401, diff --git a/tests/phpunit/tests/xmlrpc/wp/uploadFile.php b/tests/phpunit/tests/xmlrpc/wp/uploadFile.php index 00cb601b28f3d..4dab3333fd8a0 100644 --- a/tests/phpunit/tests/xmlrpc/wp/uploadFile.php +++ b/tests/phpunit/tests/xmlrpc/wp/uploadFile.php @@ -34,4 +34,310 @@ public function test_valid_attachment() { $this->assertIsString( $result['url'] ); $this->assertIsString( $result['type'] ); } + + /** + * Tests that a non-array data argument returns an error instead of + * triggering a fatal error. + * + * The data argument (the fourth parameter) is expected to be a struct, + * which is passed to the method as an array. When it is any other type, + * the method must return an IXR_Error rather than attempting to access + * array offsets on a non-array value. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + */ + public function test_invalid_attachment_data_should_return_error() { + $this->make_user_by_role( 'editor' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'editor', 'editor', 'not-a-struct' ) ); + $this->assertIXRError( $result, 'A non-array data argument should return an IXR_Error.' ); + $this->assertSame( 400, $result->code, 'The error code should be 400.' ); + } + + /** + * Tests that an anonymous request with a non-array data argument returns + * the login error rather than triggering a fatal error. + * + * The reported fatal error was reached without credentials because the + * data struct was read before the login was attempted. The struct must + * only be read once the request is authenticated. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + */ + public function test_anonymous_request_with_invalid_attachment_data_should_return_login_error() { + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'not-a-user', 'not-a-password', 'not-a-struct' ) ); + $this->assertIXRError( $result, 'An anonymous request should return an IXR_Error.' ); + $this->assertSame( 403, $result->code, 'The error code should be the 403 returned for a failed login.' ); + } + + /** + * Tests that a user who cannot upload files is rejected before the data is + * read. + * + * The capability is checked ahead of the attachment data, so a user who is + * not allowed to upload is told that rather than being told the data is + * malformed. Sending unusable data must not change which error comes back. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + */ + public function test_incapable_user() { + $this->make_user_by_role( 'subscriber' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'subscriber', 'subscriber', 'not-a-struct' ) ); + $this->assertIXRError( $result, 'A user who cannot upload files should return an IXR_Error.' ); + $this->assertSame( 401, $result->code, 'The error code should be the 401 returned for a missing capability.' ); + } + + /** + * Tests that too few arguments return an error instead of emitting a PHP + * notice for the undefined arguments. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + * + * @dataProvider data_insufficient_arguments + * + * @param list $args The arguments to pass to the method. + */ + public function test_insufficient_arguments_should_return_error( array $args ) { + $this->make_user_by_role( 'editor' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( $args ); + $this->assertIXRError( $result, 'Insufficient arguments should return an IXR_Error.' ); + $this->assertSame( 400, $result->code, 'The error code should be 400.' ); + } + + /** + * Data provider. + * + * @return array}> + */ + public function data_insufficient_arguments(): array { + return array( + 'no arguments' => array( + 'args' => array(), + ), + 'only the blog ID' => array( + 'args' => array( 0 ), + ), + 'missing the data' => array( + 'args' => array( 0, 'editor', 'editor' ), + ), + ); + } + + /** + * Tests that a data struct without a usable file name returns an error + * instead of emitting a PHP notice for the undefined array key. + * + * A file name is required to write the upload, so the request cannot + * succeed. It must fail with an IXR_Error rather than by reading an + * undefined array offset. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + * + * @dataProvider data_attachment_data_without_name + * + * @param array $data The data argument to pass to the method. + */ + public function test_attachment_data_without_name_should_return_error( array $data ) { + $this->make_user_by_role( 'editor' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'editor', 'editor', $data ) ); + $this->assertIXRError( $result, 'A data argument without a name should return an IXR_Error.' ); + $this->assertSame( 400, $result->code, 'The error code should be 400.' ); + } + + /** + * Data provider. + * + * @return array}> + */ + public function data_attachment_data_without_name(): array { + return array( + 'empty struct' => array( + 'data' => array(), + ), + 'only type and bits' => array( + 'data' => array( + 'type' => 'image/jpeg', + 'bits' => 'contents', + ), + ), + 'non-string name' => array( + 'data' => array( + 'name' => array( 'a2-small.jpg' ), + 'type' => 'image/jpeg', + 'bits' => 'contents', + ), + ), + ); + } + + /** + * Tests that a file name left empty by sanitization returns the same error + * as an absent one. + * + * sanitize_file_name() strips special characters and then trims the + * remaining leading and trailing '.', '-' and '_' characters, so a name + * built only from those is reduced to an empty string. That leaves nothing + * to write, which is a malformed request rather than a server failure, so + * it must be reported as a 400 like any other unusable name instead of + * reaching wp_upload_bits() and surfacing as a 500. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + * + * @dataProvider data_attachment_data_with_unusable_name + * + * @param string $name The file name to pass to the method. + */ + public function test_attachment_data_with_unusable_name_should_return_error( string $name ) { + $this->make_user_by_role( 'editor' ); + + $data = array( + 'name' => $name, + 'type' => 'image/jpeg', + 'bits' => 'contents', + ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'editor', 'editor', $data ) ); + $this->assertIXRError( $result, 'A name left empty by sanitization should return an IXR_Error.' ); + $this->assertSame( 400, $result->code, 'The error code should be 400.' ); + } + + /** + * Data provider. + * + * @return array + */ + public function data_attachment_data_with_unusable_name(): array { + return array( + 'empty name' => array( + 'name' => '', + ), + 'only dots' => array( + 'name' => '...', + ), + 'only dashes' => array( + 'name' => '---', + ), + 'only underscores' => array( + 'name' => '___', + ), + 'only a space' => array( + 'name' => ' ', + ), + 'only special chars' => array( + 'name' => '///', + ), + 'only a question mark' => array( + 'name' => '?', + ), + ); + } + + /** + * Tests that a data struct with a non-string type or bits member returns an + * error instead of triggering a fatal error. + * + * A struct sent for either member arrives as an array. An array reaches + * fwrite() by way of wp_upload_bits(), which throws a TypeError, and it + * survives sanitize_mime_type() to reach the database as the attachment's + * post MIME type. Both members must be rejected before that point. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + * + * @dataProvider data_attachment_data_with_invalid_members + * + * @param array $data The data argument to pass to the method. + */ + public function test_attachment_data_with_invalid_members_should_return_error( array $data ) { + $this->make_user_by_role( 'editor' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'editor', 'editor', $data ) ); + $this->assertIXRError( $result, 'A data argument with a non-string member should return an IXR_Error.' ); + $this->assertSame( 400, $result->code, 'The error code should be 400.' ); + } + + /** + * Data provider. + * + * @return array}> + */ + public function data_attachment_data_with_invalid_members(): array { + return array( + 'non-string bits' => array( + 'data' => array( + 'name' => 'a2-small.jpg', + 'type' => 'image/jpeg', + 'bits' => array( 'contents' ), + ), + ), + 'non-string type' => array( + 'data' => array( + 'name' => 'a2-small.jpg', + 'type' => array( 'image/jpeg' ), + 'bits' => 'contents', + ), + ), + ); + } + + /** + * Tests that a data struct without the optional members is still accepted. + * + * Only the name is required. The type and bits members are tolerated when + * absent, and must not emit a PHP notice for the undefined array keys. + * + * @ticket 65611 + * + * @covers wp_xmlrpc_server::mw_newMediaObject + * + * @dataProvider data_attachment_data_with_optional_members_omitted + * + * @param array $data The data argument to pass to the method. + */ + public function test_attachment_data_with_optional_members_omitted_should_be_accepted( array $data ) { + $this->make_user_by_role( 'editor' ); + + $result = $this->myxmlrpcserver->mw_newMediaObject( array( 0, 'editor', 'editor', $data ) ); + $this->assertNotIXRError( $result ); + $this->assertIsString( $result['id'] ); + $this->assertStringMatchesFormat( '%d', $result['id'] ); + } + + /** + * Data provider. + * + * @return array}> + */ + public function data_attachment_data_with_optional_members_omitted(): array { + return array( + 'missing type' => array( + 'data' => array( + 'name' => 'a2-small.jpg', + 'bits' => file_get_contents( DIR_TESTDATA . '/images/a2-small.jpg' ), + ), + ), + 'missing bits' => array( + 'data' => array( + 'name' => 'a2-small.jpg', + 'type' => 'image/jpeg', + ), + ), + ); + } } From 03b7c8a5b879d79c3322d7127e7533f43fef5ec9 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Tue, 4 Aug 2026 11:03:49 +0000 Subject: [PATCH 111/138] Media: Register the `wp-media-utils` style handle. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The media editor modal rendered without its intended styles, because the stylesheet it relies on was never registered in core. Registering the handle makes the modal display as intended. Developed in https://github.com/WordPress/wordpress-develop/pull/12813 Props afercia, andrewserong, gulamdastgir04, mdridipu, ramonopoly, softglaze, wildworks. Fixes #65794. git-svn-id: https://develop.svn.wordpress.org/trunk@63007 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/script-loader.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index fd1f24a08968d..b5df9291ef354 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -1781,9 +1781,11 @@ function wp_default_styles( $styles ) { 'wp-reusable-blocks', 'wp-patterns', 'wp-preferences', + 'wp-media-utils', ), 'format-library' => array(), 'list-reusable-blocks' => array( 'wp-components' ), + 'media-utils' => array( 'wp-components' ), 'reusable-blocks' => array( 'wp-components' ), 'patterns' => array( 'wp-components' ), 'preferences' => array( 'wp-components' ), @@ -1892,6 +1894,7 @@ function wp_default_styles( $styles ) { 'wp-editor', 'wp-format-library', 'wp-list-reusable-blocks', + 'wp-media-utils', 'wp-reusable-blocks', 'wp-patterns', 'wp-nux', From 815b17e10fc7cd2bebc691573239747f1f9047b2 Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Tue, 4 Aug 2026 12:30:16 +0000 Subject: [PATCH 112/138] Networks and Sites: Correct capitalization in Upgrade Network admin notice. Follow-up to [https://mu.trac.wordpress.org/changeset/1968 mu:1968], [https://mu.trac.wordpress.org/changeset/2005 mu:2005], [13590]. Props bor0, realloc. Fixes #65792. git-svn-id: https://develop.svn.wordpress.org/trunk@63008 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/ms.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-admin/includes/ms.php b/src/wp-admin/includes/ms.php index 669c198fe9528..56e17113653d2 100644 --- a/src/wp-admin/includes/ms.php +++ b/src/wp-admin/includes/ms.php @@ -692,7 +692,7 @@ function site_admin_notice() { if ( (int) get_site_option( 'wpmu_upgrade_site' ) !== $wp_db_version ) { $upgrade_network_message = sprintf( /* translators: %s: URL to Upgrade Network screen. */ - __( 'Thank you for Updating! Please visit the Upgrade Network page to update all your sites.' ), + __( 'Thank you for updating! Please visit the Upgrade Network page to update all your sites.' ), esc_url( network_admin_url( 'upgrade.php' ) ) ); From c60dba3572080207fa4423bbf5b0a9429a1030b4 Mon Sep 17 00:00:00 2001 From: Andrea Fercia Date: Tue, 4 Aug 2026 17:28:48 +0000 Subject: [PATCH 113/138] Toolbar: Improve the focus style indication. - Updates the toolbar items styling by adding a more prominent focus indicator. - Adjusts label and icon coloring selectors (including mobile-specific focus states). - Refines the 'Howdy menu' dropdown layout and focus styles. - Tweaks the responsive menu toggle item sizing. Props afercia, joedolson, sabernhardt, khokansardar, jns141191, iamraju, sukhendu2002, shamimmoeen, ugyensupport. Fixes #65445. Fixes #65765. git-svn-id: https://develop.svn.wordpress.org/trunk@63009 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/admin-menu.css | 17 ++++-------- src/wp-admin/css/colors/_admin.scss | 32 ++++++++++++----------- src/wp-includes/css/admin-bar.css | 40 ++++++++++++----------------- 3 files changed, 39 insertions(+), 50 deletions(-) diff --git a/src/wp-admin/css/admin-menu.css b/src/wp-admin/css/admin-menu.css index 3747613282be1..aa6a8bc1414aa 100644 --- a/src/wp-admin/css/admin-menu.css +++ b/src/wp-admin/css/admin-menu.css @@ -800,12 +800,10 @@ li#wp-admin-bar-menu-toggle { display: block; padding: 0; overflow: hidden; - outline: none; text-decoration: none; - border: 1px solid transparent; background: none; - height: 44px; - margin-left: -1px; + height: 46px; + box-sizing: border-box; } .wp-responsive-open #wpadminbar #wp-admin-bar-menu-toggle a { @@ -816,22 +814,17 @@ li#wp-admin-bar-menu-toggle { display: block; } - #wpadminbar #wp-admin-bar-menu-toggle a:hover { - border: 1px solid transparent; - } - #wpadminbar #wp-admin-bar-menu-toggle .ab-icon:before { content: "\f228"; display: inline-block; float: left; - font: normal 40px/45px dashicons; + font: normal 40px/46px dashicons; vertical-align: middle; - outline: none; margin: 0; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; - height: 44px; - width: 50px; + height: 46px; + width: 52px; padding: 0; border: none; text-align: center; diff --git a/src/wp-admin/css/colors/_admin.scss b/src/wp-admin/css/colors/_admin.scss index 366f1b86b4f16..91d6a4b66bc8c 100644 --- a/src/wp-admin/css/colors/_admin.scss +++ b/src/wp-admin/css/colors/_admin.scss @@ -416,9 +416,11 @@ ul#adminmenu > li.current > a.current:after { background: variables.$menu-submenu-background; } -#wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label, -#wpadminbar:not(.mobile) > #wp-toolbar li.hover span.ab-label, -#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label { +#wpadminbar > #wp-toolbar li:hover span.ab-label, +#wpadminbar > #wp-toolbar li.hover span.ab-label, +/* The adminbar menu may output either links or focusable div elements. */ +/* As such, we target the focus state without specifying the element type. */ +#wpadminbar > #wp-toolbar :focus span.ab-label { color: variables.$menu-submenu-focus-text; } @@ -449,7 +451,9 @@ ul#adminmenu > li.current > a.current:after { } #wpadminbar .quicklinks li .blavatar, -#wpadminbar .menupop .menupop > .ab-item:before { +#wpadminbar .menupop .menupop > .ab-item:before, +#wpadminbar.mobile .quicklinks .ab-icon:before, +#wpadminbar.mobile .quicklinks .ab-item:before { color: variables.$menu-icon; } @@ -474,21 +478,17 @@ ul#adminmenu > li.current > a.current:after { color: variables.$menu-submenu-focus-text; } +// Note that the icon of the site-name item is not wrapped within a span with class ab-icon like other items. #wpadminbar .quicklinks li a:hover .blavatar, #wpadminbar .quicklinks li a:focus .blavatar, #wpadminbar .quicklinks .ab-sub-wrapper .menupop.hover > a .blavatar, #wpadminbar .menupop .menupop > .ab-item:hover:before, #wpadminbar.mobile .quicklinks .hover .ab-icon:before, -#wpadminbar.mobile .quicklinks .hover .ab-item:before { +#wpadminbar.mobile .quicklinks .hover .ab-item:before, +#wpadminbar.mobile .quicklinks .ab-item:focus:before { color: variables.$menu-submenu-focus-text; } -#wpadminbar.mobile .quicklinks .ab-icon:before, -#wpadminbar.mobile .quicklinks .ab-item:before { - color: variables.$menu-icon; -} - - /* Admin Bar: search */ #wpadminbar #adminbarsearch:before { @@ -531,14 +531,16 @@ ul#adminmenu > li.current > a.current:after { color: variables.$menu-text; } -#wpadminbar #wp-admin-bar-user-info a:hover .display-name { - color: variables.$menu-submenu-focus-text; -} - #wpadminbar #wp-admin-bar-user-info .username { color: variables.$menu-submenu-text; } +#wpadminbar #wp-admin-bar-user-info a:hover .display-name, +#wpadminbar #wp-admin-bar-user-info a:focus .display-name, +#wpadminbar #wp-admin-bar-user-info a:hover .username, +#wpadminbar #wp-admin-bar-user-info a:focus .username { + color: variables.$menu-submenu-focus-text; +} /* Pointers */ diff --git a/src/wp-includes/css/admin-bar.css b/src/wp-includes/css/admin-bar.css index 77e196525657a..f50c67dd71689 100644 --- a/src/wp-includes/css/admin-bar.css +++ b/src/wp-includes/css/admin-bar.css @@ -77,10 +77,18 @@ html:lang(he-il) .rtl #wpadminbar * { box-shadow: none; } -#wpadminbar a:focus { - outline-offset: -1px; +#wpadminbar a:focus, +#wpadminbar .ab-item[tabindex="0"]:focus { + outline-offset: -2px; /* Only visible in Windows High Contrast mode */ outline: 2px solid transparent; + box-shadow: inset 0 -4px 0 0 currentColor; + transition: box-shadow 0.1s linear; +} + +#wpadminbar .ab-submenu a:focus, +#wpadminbar .ab-submenu .ab-item[tabindex="0"]:focus { + box-shadow: inset 4px 0 0 0 currentColor; } #wpadminbar { @@ -225,7 +233,9 @@ html:lang(he-il) .rtl #wpadminbar * { #wpadminbar:not(.mobile) > #wp-toolbar li:hover span.ab-label, #wpadminbar > #wp-toolbar li.hover span.ab-label, -#wpadminbar:not(.mobile) > #wp-toolbar a:focus span.ab-label { +/* The adminbar menu may output either links or focusable div elements. */ +/* As such, we target the focus state without specifying the element type. */ +#wpadminbar > #wp-toolbar :focus span.ab-label { color: #72aee6; } @@ -294,7 +304,8 @@ html:lang(he-il) .rtl #wpadminbar * { #wpadminbar li.hover .ab-icon:before, #wpadminbar li.hover .ab-item:before, #wpadminbar li:hover #adminbarsearch:before, -#wpadminbar li #adminbarsearch.adminbar-focused:before { +#wpadminbar li #adminbarsearch.adminbar-focused:before, +#wpadminbar.mobile .quicklinks .ab-item:focus:before { color: #72aee6; } @@ -379,11 +390,6 @@ html:lang(he-il) .rtl #wpadminbar * { float: right; } -#wpadminbar ul li:last-child, -#wpadminbar ul li:last-child .ab-item { - box-shadow: none; -} - /** * Recovery Mode */ @@ -452,7 +458,7 @@ html:lang(he-il) .rtl #wpadminbar * { #wp-admin-bar-user-info .avatar { position: absolute; left: -72px; - top: 4px; + top: 0; width: 64px; height: 64px; border-radius: 50%; @@ -466,7 +472,7 @@ html:lang(he-il) .rtl #wpadminbar * { #wpadminbar #wp-admin-bar-user-info span { background: none; padding: 0; - height: 18px; + line-height: 1.38461538; } #wpadminbar #wp-admin-bar-user-info .display-name, @@ -475,7 +481,6 @@ html:lang(he-il) .rtl #wpadminbar * { } #wpadminbar #wp-admin-bar-user-info .username { - color: #a7aaad; font-size: 11px; } @@ -911,7 +916,6 @@ html:lang(he-il) .rtl #wpadminbar * { overflow: hidden; width: 52px; padding: 0; - color: #a7aaad; /* @todo not needed? this text is hidden */ position: relative; } @@ -1031,16 +1035,6 @@ html:lang(he-il) .rtl #wpadminbar * { height: auto; font-size: 16px; line-height: 1.5; - color: #f0f0f1; - } - - #wpadminbar #wp-admin-bar-user-info a { - padding-top: 4px; - } - - #wpadminbar #wp-admin-bar-user-info .username { - line-height: 0.8 !important; - margin-bottom: -2px; } /* Show only default top level items */ From 71a2a03b81b698a7f4d19f6d390e6e27bcc85536 Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Tue, 4 Aug 2026 18:36:23 +0000 Subject: [PATCH 114/138] Privacy: Fix checkbox alignment and highlight color. Adjust styling on privacy export and erasure tables for compatibility with the list table column changes in [62839]. Update the colors used to highlight confirmed or failed privacy requests following the admin color scheme changes in WordPress 7.0. Developed in https://github.com/WordPress/wordpress-develop/pull/12803 Props r1k0, joedolson, masteradhoc, shailu25. Fixes #65787. git-svn-id: https://develop.svn.wordpress.org/trunk@63010 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/forms.css | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css index 3747fb5028484..bf14d3197401d 100644 --- a/src/wp-admin/css/forms.css +++ b/src/wp-admin/css/forms.css @@ -1493,7 +1493,7 @@ table.form-table td .updated p { border-left: 4px solid #fff; } -.privacy_requests tbody th { +.privacy_requests tbody td.check-column { border-left: 4px solid #fff; background: #fff; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1); @@ -1515,7 +1515,8 @@ table.form-table td .updated p { margin: 0 0 5px; } -.privacy_requests tbody td { +.privacy_requests tbody td:not(.check-column), +.privacy_requests tbody th { background: #fff; box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1); } @@ -1529,16 +1530,14 @@ table.form-table td .updated p { white-space: normal; } -.privacy_requests .status-request-confirmed th, -.privacy_requests .status-request-confirmed td { +.privacy_requests tr.status-request-confirmed td.check-column { background-color: #fff; - border-left-color: #72aee6; + border-left-color: #3858e9; } -.privacy_requests .status-request-failed th, -.privacy_requests .status-request-failed td { +.privacy_requests tr.status-request-failed td.check-column { background-color: #f6f7f7; - border-left-color: #d63638; + border-left-color: #cc1818; } .privacy_requests .export_personal_data_failed a { @@ -1973,11 +1972,6 @@ table.form-table td .updated p { display: table-cell; } - .wp-list-table.privacy_requests.widefat th input, - .wp-list-table.privacy_requests.widefat thead td input { - margin-left: 5px; - } - .wp-privacy-request-form-field input[type="text"] { width: 100%; margin-bottom: 10px; From a105958a2052fe87f2374cf71178d92d4cde567a Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Tue, 4 Aug 2026 19:07:33 +0000 Subject: [PATCH 115/138] Privacy: Fix checkbox alignment in request form. The margins were set to `0` for all inputs in the request form, breaking the alignment for the checkbox. Limit margin resetting to inputs of type text. Change labeling from implicit to explicit labelling, to better support voice control users. Developed in https://github.com/WordPress/wordpress-develop/pull/11841 Props soyebsalar01, suryakantupadhyay, deepakprajapati, audrasjb, joedolson, adrianduffell, mukesh27, wildworks, masteradhoc. Fixes #65246. git-svn-id: https://develop.svn.wordpress.org/trunk@63011 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/css/forms.css | 2 +- src/wp-admin/erase-personal-data.php | 4 ++-- src/wp-admin/export-personal-data.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/wp-admin/css/forms.css b/src/wp-admin/css/forms.css index bf14d3197401d..f7e6accfce0fd 100644 --- a/src/wp-admin/css/forms.css +++ b/src/wp-admin/css/forms.css @@ -1572,7 +1572,7 @@ table.form-table td .updated p { margin: 1.5em 0; } -.wp-privacy-request-form input { +.wp-privacy-request-form input[type="text"] { margin: 0; } diff --git a/src/wp-admin/erase-personal-data.php b/src/wp-admin/erase-personal-data.php index c96d80a9b5e06..a1472e7e7fd24 100644 --- a/src/wp-admin/erase-personal-data.php +++ b/src/wp-admin/erase-personal-data.php @@ -126,9 +126,9 @@ - + + diff --git a/src/wp-admin/export-personal-data.php b/src/wp-admin/export-personal-data.php index 64b9653c3c1ba..e9ccedc491c14 100644 --- a/src/wp-admin/export-personal-data.php +++ b/src/wp-admin/export-personal-data.php @@ -127,8 +127,8 @@ + From 439615d4b8b1736d421d512ca97d7a62d1d6ec87 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 4 Aug 2026 21:30:53 +0000 Subject: [PATCH 116/138] Comments: Notify users mentioned in a note. Introduce `wp_notify_note_mentions()` on `rest_insert_comment`, alongside the existing post author notification, which parses those IDs out of the saved note and emails each mentioned user in their own locale with a link back to the post editor. Recipients are limited to users who can `edit_comment` the note, matching `WP_REST_Comments_Controller::check_read_permission()`, so an email cannot carry note content to someone who cannot see the note in the editor. The note's own author is skipped, as is the post author, who `wp_new_comment_via_rest_notify_postauthor()` already notifies about every note. Only note creation notifies, and the existing `wp_notes_notify` option turns the whole path off. See related Gutenberg pull request: https://github.com/WordPress/gutenberg/pull/79606. Follow-up to [62832]. Props westonruter, mamaduka. Fixes #65639. git-svn-id: https://develop.svn.wordpress.org/trunk@63012 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/comment.php | 187 +++++++ src/wp-includes/default-filters.php | 1 + .../tests/comment/wpNotifyNoteMentions.php | 455 ++++++++++++++++++ 3 files changed, 643 insertions(+) create mode 100644 tests/phpunit/tests/comment/wpNotifyNoteMentions.php diff --git a/src/wp-includes/comment.php b/src/wp-includes/comment.php index ed7478f5ed104..96a26fcf558a1 100644 --- a/src/wp-includes/comment.php +++ b/src/wp-includes/comment.php @@ -2556,6 +2556,193 @@ function wp_new_comment_via_rest_notify_postauthor( $comment ) { } } +/** + * Extracts the mentioned user IDs from note content. + * + * Mentions are stored as chips carrying the `wp-note-mention` class plus a + * `user-N` class token holding the mentioned user's ID: + * `@Name`. Only elements that + * carry both classes are treated as mentions. + * + * @since 7.1.0 + * + * @param string $content Note (comment) content, as stored. + * @return int[] Unique, positive mentioned user IDs. + * @phpstan-return list + */ +function wp_get_note_mentioned_user_ids( string $content ): array { + if ( ! str_contains( $content, 'wp-note-mention' ) ) { + return array(); + } + + $user_ids = array(); + $processor = new WP_HTML_Tag_Processor( $content ); + while ( + $processor->next_tag( + array( + 'tag_name' => 'SPAN', + 'class_name' => 'wp-note-mention', + ) + ) + ) { + foreach ( $processor->class_list() as $class_name ) { + if ( 1 === preg_match( '/^user-(\d+)$/', $class_name, $matches ) ) { + $user_id = (int) $matches[1]; + if ( $user_id > 0 ) { + $user_ids[] = $user_id; + } + break; + } + } + } + + return array_values( array_unique( $user_ids, SORT_NUMERIC ) ); +} + +/** + * Notifies mentioned users about a new note. + * + * Runs on {@see 'rest_insert_comment'} alongside the post author notification. + * The recipient set is the users mentioned in this note, minus the note's own + * author (a user is not notified about their own note) and the post author, + * who is already notified about every note by + * {@see wp_new_comment_via_rest_notify_postauthor()}. + * + * Only fires when a note is created, not when an existing one is edited, so + * correcting a note does not re-notify everyone who already received it. + * + * @since 7.1.0 + * + * @param WP_Comment|null $comment The note that was just inserted. (May only be null as an edge case.) + * @param mixed $request The REST request. Unused. + * @param bool $creating Whether this is a create (true) or update (false). + */ +function wp_notify_note_mentions( ?WP_Comment $comment, $request = null, bool $creating = true ): void { + if ( ! $creating || ! $comment ) { + return; + } + + if ( 'note' !== $comment->comment_type ) { + return; + } + + // Share the single user-facing notes notification preference. + if ( ! get_option( 'wp_notes_notify', 1 ) ) { + return; + } + + $mentioned = wp_get_note_mentioned_user_ids( $comment->comment_content ); + + $author_id = (int) $comment->user_id; + $comment_post_id = (int) $comment->comment_post_ID; + $post = $comment_post_id ? get_post( $comment_post_id ) : null; + $post_author_id = $post ? (int) $post->post_author : 0; + + /* + * The recipient set is bounded and small (one note's mentions), so emails + * are sent synchronously here. If notification volume ever warrants it, + * the right fix is to offload delivery to a background queue rather than + * throttle within the request. + */ + foreach ( $mentioned as $user_id ) { + // Never notify the author about their own note. + if ( $user_id === $author_id ) { + continue; + } + + // The post author is already notified of every note. + if ( $user_id === $post_author_id ) { + continue; + } + + $user = get_userdata( $user_id ); + if ( ! $user || empty( $user->user_email ) ) { + continue; + } + + /* + * Only notify users who can actually read the note. Notes are + * internal: WP_REST_Comments_Controller::check_read_permission() + * only exposes a note to its author or to users who can edit it, so + * the email audience is held to the same bar. A plain read_post + * check would leak note content to, for example, subscribers on a + * public post, who cannot see the note in the editor. + */ + if ( ! user_can( $user_id, 'edit_comment', $comment->comment_ID ) ) { + continue; + } + + wp_send_note_notification( $user, $comment, $post ); + } +} + +/** + * Sends a single note mention notification email. + * + * The email is composed in the recipient's locale, matching how other + * user-directed notifications are composed, and links to the post editor the + * same way the post author's note notification does. + * + * @since 7.1.0 + * + * @param WP_User $user The recipient. + * @param WP_Comment $comment The note that triggered the notification. + * @param WP_Post|null $post The post the note belongs to. + * @return bool Whether the email was accepted for delivery by {@see wp_mail()}. + */ +function wp_send_note_notification( WP_User $user, WP_Comment $comment, ?WP_Post $post ): bool { + $switched_locale = switch_to_user_locale( $user->ID ); + + /* + * The site title and the post title are escaped on the way into the database, + * and note content is stored as HTML. Both are reversed once here for the + * plain text arena of emails. Decoding a second time would go too far and + * resolve entities the author meant to be read literally. + */ + $blogname = wp_specialchars_decode( get_bloginfo( 'name', 'display' ), ENT_QUOTES ); + $post_title = $post ? wp_specialchars_decode( get_the_title( $post ), ENT_QUOTES ) : ''; + $author_name = $comment->comment_author ? $comment->comment_author : __( 'Someone' ); + $content = wp_specialchars_decode( wp_strip_all_tags( $comment->comment_content ) ); + + /* + * The rest of the message is composed for the recipient, and so is the editor + * link: get_edit_post_link() answers for whoever is current, which here is the + * note's author over REST and nobody at all under WP-Cron. + */ + $edit_link = ''; + if ( $post ) { + $previous_user_id = get_current_user_id(); + wp_set_current_user( $user->ID ); + $edit_link = (string) get_edit_post_link( $post->ID, 'url' ); + wp_set_current_user( $previous_user_id ); + } + + /* translators: 1: Note author's name, 2: Post title. */ + $message = sprintf( __( '%1$s mentioned you in a note on "%2$s".' ), $author_name, $post_title ); + /* translators: Note mention notification email subject. 1: Site title, 2: Post title. */ + $subject = sprintf( __( '[%1$s] You were mentioned in a note on "%2$s"' ), $blogname, $post_title ); + + $lines = array( $message, '' ); + if ( '' !== $content ) { + $lines[] = $content; + } + if ( $edit_link ) { + $lines[] = ''; + $lines[] = __( 'Edit This' ) . ': ' . $edit_link; + } + + // Declared explicitly so a filtered default cannot turn the message into HTML. + $headers = 'Content-Type: text/plain; charset="' . get_option( 'blog_charset' ) . '"'; + + $sent = wp_mail( $user->user_email, $subject, implode( "\n", $lines ), $headers ); + + if ( $switched_locale ) { + restore_previous_locale(); + } + + return $sent; +} + /** * Sets the status of a comment. * diff --git a/src/wp-includes/default-filters.php b/src/wp-includes/default-filters.php index ea6fee0dab3ad..12ca0045b98b4 100644 --- a/src/wp-includes/default-filters.php +++ b/src/wp-includes/default-filters.php @@ -536,6 +536,7 @@ add_action( 'comment_post', 'wp_new_comment_notify_moderator' ); add_action( 'comment_post', 'wp_new_comment_notify_postauthor' ); add_action( 'rest_insert_comment', 'wp_new_comment_via_rest_notify_postauthor' ); +add_action( 'rest_insert_comment', 'wp_notify_note_mentions', 10, 3 ); add_action( 'after_password_reset', 'wp_password_change_notification' ); add_action( 'register_new_user', 'wp_send_new_user_notifications' ); add_action( 'edit_user_created_user', 'wp_send_new_user_notifications', 10, 2 ); diff --git a/tests/phpunit/tests/comment/wpNotifyNoteMentions.php b/tests/phpunit/tests/comment/wpNotifyNoteMentions.php new file mode 100644 index 0000000000000..f8e1eddc75293 --- /dev/null +++ b/tests/phpunit/tests/comment/wpNotifyNoteMentions.php @@ -0,0 +1,455 @@ +, + * subject: string, + * message: string, + * headers: list, + * }> + */ + private array $sent = array(); + + /** + * Captured wp_mail() recipients for the current test. + * + * @var list + */ + private array $sent_to = array(); + + /** + * Sets up shared fixtures. + * + * @param WP_UnitTest_Factory $factory Factory. + */ + public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) { + self::$post_author = $factory->user->create_and_get( array( 'role' => 'editor' ) ); + self::$commenter = $factory->user->create_and_get( array( 'role' => 'editor' ) ); + self::$mentioned = $factory->user->create_and_get( array( 'role' => 'editor' ) ); + + self::$post = $factory->post->create_and_get( array( 'post_author' => self::$post_author->ID ) ); + } + + public function set_up() { + parent::set_up(); + $this->sent = array(); + $this->sent_to = array(); + // Short-circuit wp_mail() and record what would have been sent. + add_filter( 'pre_wp_mail', array( $this, 'capture_mail' ), 10, 2 ); + } + + /** + * Records wp_mail() calls and short-circuits delivery. + * + * @param null $short_circuit Short-circuit value. + * @param array $atts wp_mail() arguments. + * @return bool Always true to indicate a "sent" message. + * + * @phpstan-param array{ + * to: non-falsy-string|list, + * subject: string, + * message: string, + * headers: string|list, + * ... + * } $atts + * @phpstan-return true + */ + public function capture_mail( $short_circuit, array $atts ): bool { + $to = (array) $atts['to']; + + $this->sent[] = array( + 'to' => $to, + 'subject' => $atts['subject'], + 'message' => $atts['message'], + 'headers' => (array) $atts['headers'], + ); + + foreach ( $to as $recipient ) { + $this->sent_to[] = $recipient; + } + + return true; + } + + /** + * Builds a note comment for the shared post. + * + * @param string $content Note content. + * @param int $user_id Author user ID. + * @param int $parent_id Parent note ID (0 for a top-level note). + * @return WP_Comment The inserted note. + */ + private function insert_note( string $content, int $user_id, int $parent_id = 0 ): WP_Comment { + $comment = self::factory()->comment->create_and_get( + array( + 'comment_post_ID' => self::$post->ID, + 'comment_type' => 'note', + 'comment_content' => $content, + 'comment_parent' => $parent_id, + 'user_id' => $user_id, + ) + ); + assert( $comment instanceof WP_Comment ); + return $comment; + } + + /** + * Builds the stored markup for a mention of the given user. + * + * @param int $user_id User ID to mention. + * @param string $label Optional. The mention's visible text. + * @return string The mention chip markup. + */ + private function get_mention_markup( int $user_id, string $label = '@Mentioned' ): string { + return sprintf( '%s', $user_id, $label ); + } + + /** + * @ticket 65639 + * + * @covers ::wp_get_note_mentioned_user_ids + */ + public function test_parses_mentioned_user_ids() { + $content = '

        Hi @Jane and ' + . '@Bob.

        '; + + $this->assertSame( array( 5, 9 ), wp_get_note_mentioned_user_ids( $content ) ); + } + + /** + * @ticket 65639 + * + * @covers ::wp_get_note_mentioned_user_ids + */ + public function test_ignores_non_mentions_and_deduplicates() { + $content = '

        not a mention ' + . 'an anchor, not a chip ' + . '@Jane ' + . '@Jane again ' + . 'no user class

        '; + + $this->assertSame( array( 5 ), wp_get_note_mentioned_user_ids( $content ) ); + } + + /** + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_mentioned_user_is_emailed() { + $note = $this->insert_note( + 'Ping ' . $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertContains( self::$mentioned->user_email, $this->sent_to ); + } + + /** + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_email_contains_context_and_editor_link() { + /* + * The editor link comes from get_edit_post_link(), which is scoped to + * the current user; in the REST flow that is the note's author. + */ + wp_set_current_user( self::$commenter->ID ); + + $note = $this->insert_note( + '

        Please review ' . $this->get_mention_markup( self::$mentioned->ID, '@Reviewer' ) . '

        ', + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertCount( 1, $this->sent ); + $email = $this->sent[0]; + + $this->assertStringContainsString( 'You were mentioned in a note', $email['subject'] ); + // The note text is included, stripped of markup. + $this->assertStringContainsString( 'Please review @Reviewer', $email['message'] ); + $this->assertStringNotContainsString( 'ID, 'url' ); + $this->assertIsString( $edit_link ); + $this->assertStringContainsString( + $edit_link, + $email['message'] + ); + } + + /** + * The editor link is composed for the recipient, not for whoever happens to + * be current, so it survives contexts with no logged-in user such as WP-Cron. + * + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_editor_link_is_built_for_the_recipient() { + wp_set_current_user( 0 ); + + $note = $this->insert_note( + $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertCount( 1, $this->sent ); + + // The switch is temporary; the caller's context is left as it was found. + $this->assertSame( 0, get_current_user_id() ); + + wp_set_current_user( self::$mentioned->ID ); + $edit_link = get_edit_post_link( self::$post->ID, 'url' ); + $this->assertIsString( $edit_link ); + $this->assertStringContainsString( $edit_link, $this->sent[0]['message'] ); + } + + /** + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_email_is_sent_as_plain_text() { + $note = $this->insert_note( + $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertCount( 1, $this->sent ); + $this->assertStringContainsString( 'Content-Type: text/plain', implode( "\n", $this->sent[0]['headers'] ) ); + } + + /** + * The post title is escaped on the way into the database, so it is decoded + * exactly once for the plain text email. Decoding twice resolves entities + * the author meant to be read literally. + * + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_email_subject_decodes_the_post_title_once() { + // Stored form of the literal title "Tom & Jerry". + add_filter( + 'the_title', + static function () { + return 'Tom &amp; Jerry'; + } + ); + + $note = $this->insert_note( + $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertCount( 1, $this->sent ); + $this->assertStringContainsString( 'Tom & Jerry', $this->sent[0]['subject'] ); + $this->assertStringNotContainsString( 'Tom & Jerry', $this->sent[0]['subject'] ); + } + + /** + * Note content is stored as HTML, so markup is stripped before entities are + * decoded. Decoding first would turn escaped text into tags and strip it. + * + * @ticket 65639 + * + * @covers ::wp_send_note_notification + */ + public function test_email_keeps_escaped_markup_in_the_note_text() { + $note = $this->insert_note( + '

        Use <code> tags ' . $this->get_mention_markup( self::$mentioned->ID ) . '

        ', + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertCount( 1, $this->sent ); + $this->assertStringContainsString( 'Use tags', $this->sent[0]['message'] ); + } + + /** + * @ticket 65639 + */ + public function test_author_is_not_notified_about_their_own_note() { + $note = $this->insert_note( + 'Note to ' . $this->get_mention_markup( self::$commenter->ID, '@Me' ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertNotContains( self::$commenter->user_email, $this->sent_to ); + } + + /** + * @ticket 65639 + */ + public function test_post_author_is_left_to_the_postauthor_notification() { + $note = $this->insert_note( + 'Hey ' . $this->get_mention_markup( self::$post_author->ID, '@Author' ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + /* + * wp_new_comment_via_rest_notify_postauthor() notifies the post author + * of every note; the mention path must not also email them or they + * would receive a duplicate. + */ + $this->assertNotContains( self::$post_author->user_email, $this->sent_to ); + } + + /** + * @ticket 65639 + */ + public function test_mentioned_user_without_note_access_is_not_emailed() { + $subscriber = self::factory()->user->create_and_get( array( 'role' => 'subscriber' ) ); + $this->assertInstanceOf( WP_User::class, $subscriber ); + + $note = $this->insert_note( + 'Ping ' . $this->get_mention_markup( $subscriber->ID, '@Subscriber' ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + /* + * Notes are only readable by users who can edit them; a subscriber + * cannot, so emailing them would leak content they cannot see. + */ + $this->assertNotContains( $subscriber->user_email, $this->sent_to ); + } + + /** + * @ticket 65639 + */ + public function test_mentioning_a_nonexistent_user_sends_nothing() { + $note = $this->insert_note( + 'Ghost ' . $this->get_mention_markup( 999999, '@Ghost' ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertEmpty( $this->sent_to ); + } + + /** + * @ticket 65639 + */ + public function test_no_notifications_when_disabled() { + update_option( 'wp_notes_notify', 0 ); + + $note = $this->insert_note( + 'Ping ' . $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_notify_note_mentions( $note ); + + $this->assertEmpty( $this->sent_to ); + } + + /** + * @ticket 65639 + */ + public function test_editing_a_note_does_not_renotify() { + $note = $this->insert_note( + 'Ping ' . $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + // Simulate the update path of rest_insert_comment ( $creating false ). + wp_notify_note_mentions( $note, null, false ); + + $this->assertEmpty( $this->sent_to ); + } + + /** + * Creating a note through the REST endpoint must trigger the mention email. + * + * This exercises the `rest_insert_comment` wiring (hook name, priority and + * argument count), which the direct calls above bypass. + * + * @ticket 65639 + */ + public function test_rest_note_creation_triggers_mention_email() { + wp_set_current_user( self::$commenter->ID ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/comments' ); + $request->set_param( 'post', self::$post->ID ); + $request->set_param( 'type', 'note' ); + $request->set_param( 'content', 'Ping ' . $this->get_mention_markup( self::$mentioned->ID ) ); + + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 201, $response->get_status() ); + $this->assertContains( self::$mentioned->user_email, $this->sent_to ); + } + + /** + * Updating a note through the REST endpoint must not re-notify. + * + * @ticket 65639 + */ + public function test_rest_note_update_does_not_renotify() { + $note = $this->insert_note( + 'Ping ' . $this->get_mention_markup( self::$mentioned->ID ), + self::$commenter->ID + ); + + wp_set_current_user( self::$commenter->ID ); + + $request = new WP_REST_Request( 'PUT', '/wp/v2/comments/' . $note->comment_ID ); + $request->set_param( 'content', 'Edited ping ' . $this->get_mention_markup( self::$mentioned->ID ) ); + + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 200, $response->get_status() ); + $this->assertNotContains( self::$mentioned->user_email, $this->sent_to ); + } +} From 5bb4b68daf55e37f2582b10d33b74efa8601dbcd Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 4 Aug 2026 22:03:47 +0000 Subject: [PATCH 117/138] Media: Correct the HEIC upload error message. When a HEIC upload fails, the Media Library reported that "This image cannot be displayed in a web browser." That has not been accurate since [48288] introduced the string: Safari and other browsers render HEIC fine, and because the same message is sent to every browser it cannot describe what the visitor's own browser supports. The upload fails because the server's image editor cannot process the `image/heic` mime type, so the file is never converted to a web safe format - servers that do support HEIC convert it to JPEG, as of [58849]. Reword the message to name that cause and keep the existing suggestion to convert to JPEG. The `unsupported_image` string is only shown for queued HEIC files, so naming the format explicitly does not affect other uploads; WebP and AVIF continue to use `noneditable_image`. See related Gutenberg issue: https://github.com/WordPress/gutenberg/issues/81123. Follow-up to [48288]. Props khokansardar, annezazu. Fixes #65800. git-svn-id: https://develop.svn.wordpress.org/trunk@63013 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/script-loader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index b5df9291ef354..a364439f0abbb 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -1038,7 +1038,7 @@ function wp_default_scripts( $scripts ) { 'deleted' => __( 'moved to the Trash.' ), /* translators: %s: File name. */ 'error_uploading' => __( '“%s” has failed to upload.' ), - 'unsupported_image' => __( 'This image cannot be displayed in a web browser. For best results convert it to JPEG before uploading.' ), + 'unsupported_image' => __( 'The server cannot process HEIC images. Convert it to JPEG before uploading.' ), 'noneditable_image' => __( 'The web server cannot generate responsive image sizes for this image. Convert it to JPEG or PNG before uploading.' ), 'file_url_copied' => __( 'The file URL has been copied to your clipboard' ), ); From 7e5d241a2a5a68c739dbff722ea544ad0f665eb6 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 4 Aug 2026 22:56:49 +0000 Subject: [PATCH 118/138] Media: Skip server-side image scaling during client-side media processing. Disable the `big_image_size_threshold` filter alongside the existing client-side processing filters so the upload is stored untouched. The client's scaled sideload then keeps the plain `-scaled` name and records the untouched upload as `original_image`. Uploads that leave `generate_sub_sizes` enabled are unaffected. Props khokansardar, ianmjones. Fixes #65708. git-svn-id: https://develop.svn.wordpress.org/trunk@63014 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-attachments-controller.php | 5 + .../rest-api/rest-attachments-controller.php | 169 ++++++++++++++++++ 2 files changed, 174 insertions(+) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 6e06f1563c50c..78225e87e23da 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -459,6 +459,10 @@ public function create_item( $request ) { // Disable server-side EXIF rotation so the client can handle it. // This preserves the original orientation value in the metadata. add_filter( 'wp_image_maybe_exif_rotate', '__return_false', 100 ); + // Disable server-side "big image" downscaling; the client supplies its + // own scaled version via the sideload endpoint. Scaling here would + // create a conflicting "-scaled" file and orphan the full-size upload. + add_filter( 'big_image_size_threshold', '__return_false', 100 ); } // Handle convert_format parameter. @@ -691,6 +695,7 @@ private function remove_client_side_media_processing_filters(): void { remove_filter( 'fallback_intermediate_image_sizes', '__return_empty_array', 100 ); remove_filter( 'wp_image_maybe_exif_rotate', '__return_false', 100 ); remove_filter( 'image_editor_output_format', '__return_empty_array', 100 ); + remove_filter( 'big_image_size_threshold', '__return_false', 100 ); } /** diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 90899df850d47..72bb483d087be 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -3875,6 +3875,175 @@ public function test_sideload_scaled_image() { $this->assertGreaterThan( 0, $metadata['filesize'], 'Filesize should be positive.' ); } + /** + * When the client generates sub-sizes (generate_sub_sizes is false), the + * server must not perform its own "big image" downscaling on upload. + * + * Otherwise the server creates a `-scaled` file and records the upload as + * `original_image`. The client's subsequent scaled sideload then collides + * with that `-scaled` file and is renamed `-scaled-1`, the thumbnails + * inherit the numbered name, and the server-generated full-size file is + * left orphaned on disk. + * + * @ticket 65708 + * @requires function imagejpeg + */ + public function test_create_item_skips_big_image_scaling_when_client_generates_sub_sizes() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$author_id ); + + // Force the threshold below the image's dimensions so scaling would be + // triggered were it not suppressed for client-side processing. + add_filter( + 'big_image_size_threshold', + static function () { + return 1000; + } + ); + + // Upload a large image with the client handling sub-size generation. + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_header( 'Content-Type', 'image/jpeg' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=33772.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + $request->set_body( file_get_contents( DIR_TESTDATA . '/images/33772.jpg' ) ); + $response = rest_get_server()->dispatch( $request ); + $data = $response->get_data(); + $attachment_id = $data['id']; + + $this->assertSame( 201, $response->get_status(), 'Uploading the image should succeed.' ); + + // The uploaded full-size image should be stored untouched: no + // server-side "-scaled" file and no original_image swap. + $original_file = get_attached_file( $attachment_id, true ); + $original_basename = wp_basename( $original_file ); + $original_name_stem = pathinfo( $original_basename, PATHINFO_FILENAME ); + $this->assertStringNotContainsString( '-scaled', $original_basename, 'The server should not create a -scaled file when the client generates sub-sizes.' ); + + $metadata = wp_get_attachment_metadata( $attachment_id ); + $this->assertArrayNotHasKey( 'original_image', $metadata, 'The server should not record an original_image when it does not scale the upload.' ); + + // The client's scaled sideload should now record the untouched upload as + // original_image and keep the -scaled name without a numeric suffix. + $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" ); + $request->set_header( 'Content-Type', 'image/jpeg' ); + $request->set_header( 'Content-Disposition', "attachment; filename={$original_name_stem}-scaled.jpg" ); + $request->set_param( 'image_size', 'scaled' ); + $request->set_body( file_get_contents( DIR_TESTDATA . '/images/33772.jpg' ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 200, $response->get_status(), 'Sideloading the scaled image should succeed.' ); + + $sub_size = $response->get_data(); + $this->assertSame( $original_basename, $sub_size['original_image'], 'The untouched upload should be recorded as original_image.' ); + $this->assertSame( "{$original_name_stem}-scaled.jpg", wp_basename( $sub_size['file'] ), 'The scaled sideload should keep the -scaled name without a numeric collision suffix.' ); + } + + /** + * The complete client-side flow for an image over the "big image" threshold + * should write only files that the metadata tracks, so that deleting the + * attachment removes all of them. + * + * When the server scales the upload as well, its own full-size file is + * never referenced by the metadata and survives "Delete Permanently", the + * client's scaled sideload collides with the server's "-scaled" file and is + * stored as "-scaled-1", and the sub-sizes inherit the numbered name. + * + * @ticket 65708 + * @covers WP_REST_Attachments_Controller::create_item + * @covers WP_REST_Attachments_Controller::sideload_item + * @covers WP_REST_Attachments_Controller::finalize_item + * @requires function imagejpeg + */ + public function test_client_side_big_image_flow_leaves_no_orphaned_files() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$author_id ); + + // Force the threshold below the uploaded image's dimensions so scaling + // would be triggered were it not suppressed for client-side processing. + add_filter( + 'big_image_size_threshold', + static function () { + return 1000; + } + ); + + $upload_dir = wp_upload_dir(); + $files_before = (array) glob( $upload_dir['path'] . '/*' ); + + // 1. Upload the full-size image; the client owns all the derivatives. + // 33772.jpg is 1920x1080, so it exceeds the threshold above. + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_header( 'Content-Type', 'image/jpeg' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=big-photo.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + $request->set_body( file_get_contents( DIR_TESTDATA . '/images/33772.jpg' ) ); + $response = rest_get_server()->dispatch( $request ); + $attachment_id = $response->get_data()['id']; + + $this->assertSame( 201, $response->get_status(), 'Uploading the image should succeed.' ); + + /* + * 2. Sideload a thumbnail, as the client does for each sub-size. The + * client names it after the file it uploaded, so a server-side + * rename of that file is what pushes this into a collision. + * test-image.jpg is 50x50, within the registered thumbnail maximum. + */ + $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" ); + $request->set_header( 'Content-Type', 'image/jpeg' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=big-photo-150x150.jpg' ); + $request->set_param( 'image_size', 'thumbnail' ); + $request->set_body( file_get_contents( DIR_TESTDATA . '/images/test-image.jpg' ) ); + $response = rest_get_server()->dispatch( $request ); + $thumbnail_data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Sideloading the thumbnail should succeed.' ); + $this->assertSame( 'big-photo-150x150.jpg', wp_basename( $thumbnail_data['file'] ), 'The thumbnail should not inherit a numeric collision suffix.' ); + + // 3. Sideload the scaled full-size image. canola.jpg is 640x480, the + // size the client would have downscaled the upload to. + $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/sideload" ); + $request->set_header( 'Content-Type', 'image/jpeg' ); + $request->set_header( 'Content-Disposition', 'attachment; filename=big-photo-scaled.jpg' ); + $request->set_param( 'image_size', 'scaled' ); + $request->set_body( file_get_contents( self::$test_file ) ); + $response = rest_get_server()->dispatch( $request ); + $scaled_data = $response->get_data(); + + $this->assertSame( 200, $response->get_status(), 'Sideloading the scaled image should succeed.' ); + + // 4. Finalize, which writes the collected sub-size metadata in one pass. + $request = new WP_REST_Request( 'POST', "/wp/v2/media/{$attachment_id}/finalize" ); + $request->set_param( 'sub_sizes', array( $thumbnail_data, $scaled_data ) ); + $response = rest_get_server()->dispatch( $request ); + + $this->assertSame( 200, $response->get_status(), 'Finalize should succeed.' ); + + $metadata = wp_get_attachment_metadata( $attachment_id ); + + $this->assertSame( 'big-photo.jpg', $metadata['original_image'], 'The untouched upload should be recorded as original_image.' ); + $this->assertSame( 'big-photo-scaled.jpg', wp_basename( $metadata['file'] ), 'The client-supplied scaled image should become the attached file.' ); + $this->assertSame( 'big-photo-150x150.jpg', $metadata['sizes']['thumbnail']['file'], 'The thumbnail should keep its dimension-based name.' ); + + // Every file written for this attachment must be reachable from the + // metadata, otherwise it is orphaned on disk. + $written = array_map( 'wp_basename', array_diff( (array) glob( $upload_dir['path'] . '/*' ), $files_before ) ); + sort( $written ); + $this->assertSame( + array( 'big-photo-150x150.jpg', 'big-photo-scaled.jpg', 'big-photo.jpg' ), + $written, + 'The flow should write only the full-size upload, its scaled copy, and the sub-sizes.' + ); + + // Deleting the attachment should therefore clean all of them up. + wp_delete_attachment( $attachment_id, true ); + + $remaining = array_diff( (array) glob( $upload_dir['path'] . '/*' ), $files_before ); + $this->assertSame( array(), array_values( $remaining ), 'Deleting the attachment should leave no files behind.' ); + } + /** * Tests that sideloading scaled image requires authentication. * From 5f5d96bd4b0ad25b803dc507c08b5336fff926ed Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Tue, 4 Aug 2026 23:49:35 +0000 Subject: [PATCH 119/138] REST API: Bound the size of media sideloaded from a URL. Ensure upload limits are honored when fetching sideloaded image from URL. `WP_REST_Attachments_Controller::create_item_from_url()` only ran `check_upload_size()`, which returns early when `! is_multisite()`, so a single site had no ceiling at all on this path: `upload_max_filesize` and `post_max_size` bound a request body, not a fetch the server makes itself. Apply `wp_max_upload_size()` to the download, so a URL cannot bring in a file larger than the same site would accept as a direct upload, and pass that limit to the request as `limit_response_size` so an oversized file is not written to disk in full before being rejected. The multisite checks are unchanged and still run first, and no ceiling is applied when `wp_max_upload_size()` returns 0. Follow-up to [62659], [62841]. Props andrewserong, courane01. See #65517. git-svn-id: https://develop.svn.wordpress.org/trunk@63015 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-attachments-controller.php | 42 +++++++++ .../rest-api/rest-attachments-controller.php | 92 +++++++++++++++++++ 2 files changed, 134 insertions(+) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 78225e87e23da..9a7dabc7b3cf1 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -630,12 +630,41 @@ protected function create_item_from_url( $request ) { ); } + /* + * Cap the download at the same size the site would accept as a direct + * upload. check_upload_size() only applies on multisite, so without a + * ceiling here a single site has no limit at all on this path: the + * `upload_max_filesize` and `post_max_size` directives bound a request + * body, not a fetch the server makes itself. + * + * When `wp_max_upload_size` returns 0, no ceiling is applied. + */ + $max_size = (int) wp_max_upload_size(); + /* * Download the remote file with WordPress's HTTP API, which validates * the host and blocks requests to private or local addresses. This is * the same primitive core's media_sideload_image() relies on. + * + * `limit_response_size` stops the transfer once the limit is passed, + * so an oversized remote file is never written to disk in full. One + * byte over the ceiling is enough to fail the size check below. */ + $limit_response_size = static function ( $args ) use ( $max_size ) { + $args['limit_response_size'] = $max_size + 1; + return $args; + }; + + if ( $max_size > 0 ) { + add_filter( 'http_request_args', $limit_response_size ); + } + $tmp_file = download_url( $url ); + + if ( $max_size > 0 ) { + remove_filter( 'http_request_args', $limit_response_size ); + } + if ( is_wp_error( $tmp_file ) ) { return $tmp_file; } @@ -653,6 +682,19 @@ protected function create_item_from_url( $request ) { return $size_check; } + if ( $max_size > 0 && wp_filesize( $tmp_file ) > $max_size ) { + if ( file_exists( $tmp_file ) ) { + wp_delete_file( $tmp_file ); + } + + return new WP_Error( + 'rest_upload_file_too_big', + /* translators: %s: Maximum allowed file size in kilobytes. */ + sprintf( __( 'This file is too big. Files must be less than %s KB in size.' ), number_format( $max_size / KB_IN_BYTES ) ), + array( 'status' => 400 ) + ); + } + $attachment_id = media_handle_sideload( $file_array, $post_id ); if ( is_wp_error( $attachment_id ) ) { diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 72bb483d087be..1efa090efb05c 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -5563,6 +5563,98 @@ public function test_create_item_from_url_exceeds_multisite_site_upload_space() $this->assertErrorResponse( 'rest_upload_limited_space', $response, 400 ); } + /** + * Verifies that the URL sideload path enforces the site's maximum upload + * size on single site as well as multisite. + * + * check_upload_size() returns early when ! is_multisite(), so before this + * check a single site had no ceiling at all on this path. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::create_item_from_url + */ + public function test_create_item_from_url_exceeds_max_upload_size() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + + // The fixture the download is mocked with is comfortably larger than this. + add_filter( 'upload_size_limit', array( $this, 'filter_small_upload_size_limit' ), 20 ); + add_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/too-big.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + + $response = rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10 ); + + $this->assertErrorResponse( 'rest_upload_file_too_big', $response, 400 ); + } + + /** + * Verifies that the download itself is bounded, so an oversized remote file + * is not written to disk in full before the size check rejects it. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::create_item_from_url + */ + public function test_create_item_from_url_limits_the_download_size() { + $this->enable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + + $request_args = null; + + $capture_args = static function ( $response, $args, $url ) use ( &$request_args ) { + $request_args = $args; + + if ( ! empty( $args['filename'] ) ) { + copy( DIR_TESTDATA . '/images/canola.jpg', $args['filename'] ); + } + + return array( + 'response' => array( + 'code' => 200, + 'message' => 'OK', + ), + 'headers' => array(), + 'cookies' => array(), + 'body' => '', + ); + }; + + add_filter( 'pre_http_request', $capture_args, 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/photo.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + + rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', $capture_args, 10 ); + + $this->assertIsArray( $request_args, 'The download request should have been made.' ); + $this->assertSame( + (int) wp_max_upload_size() + 1, + $request_args['limit_response_size'], + 'The download should be capped one byte past the maximum upload size.' + ); + } + + /** + * Filters the maximum upload size down to a value smaller than the image + * fixture used to mock the download. + * + * @return int A deliberately small upload size limit, in bytes. + */ + public function filter_small_upload_size_limit() { + return 1024; + } + /** * Verifies that a URL with no usable path bails with a 400 before any * download is attempted, rather than handing an empty filename to the From 7f81cb2d0df5e3252ddc7c9aba65e23b6f965e82 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 01:33:06 +0000 Subject: [PATCH 120/138] Networks and Sites: Improve user autocomplete search term handling. In `wp_ajax_autocomplete_user()`, unslash and sanitize the `term` request parameter before it is passed to `get_users()`. Unslashing fixes searching for an email address containing an apostrophe (valid per `is_email()`), which could previously never match because `wp_magic_quotes()` added a slash which `wpdb::esc_like()` then escaped as a literal. Note that the raw term was already safely handled in the user query, since `WP_User_Query` passes the search term through `wpdb::prepare()`, so this is a hardening and correctness fix rather than a security fix. Additionally, a missing, non-string, or empty term now short-circuits with a `0` response instead of returning an empty array, avoiding a PHP warning and needless user queries. Asterisks are also trimmed from the term given that wildcards are appended to it; a term consisting only of asterisks previously resulted in an empty search which matched all users on the network. Also introduce the `Tests_Ajax_wpAjaxAutocompleteUser` test class covering the Ajax action's search behavior, input handling, and capability checks. Developed in https://github.com/WordPress/wordpress-develop/pull/11530. Follow-up to r19897, r20279. Props rajeshcp, wildworks, westonruter, liaison, gaurangsondagar, vgnavada, saadtajik. Fixes #65051. git-svn-id: https://develop.svn.wordpress.org/trunk@63016 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/ajax-actions.php | 20 +- .../tests/ajax/wpAjaxAutocompleteUser.php | 412 ++++++++++++++++++ 2 files changed, 431 insertions(+), 1 deletion(-) create mode 100644 tests/phpunit/tests/ajax/wpAjaxAutocompleteUser.php diff --git a/src/wp-admin/includes/ajax-actions.php b/src/wp-admin/includes/ajax-actions.php index 3cda30f0d523f..c51751940a976 100644 --- a/src/wp-admin/includes/ajax-actions.php +++ b/src/wp-admin/includes/ajax-actions.php @@ -285,6 +285,10 @@ function wp_ajax_oembed_cache() { * Handles user autocomplete via AJAX. * * @since 3.4.0 + * @since 7.1.0 The search term is now sanitized, and a missing, non-string, + * or empty term results in a `0` response instead of an empty array. + * + * @return never */ function wp_ajax_autocomplete_user() { if ( ! is_multisite() || ! current_user_can( 'promote_users' ) || wp_is_large_network( 'users' ) ) { @@ -298,6 +302,20 @@ function wp_ajax_autocomplete_user() { $return = array(); + // Obtain the search term, and short-circuit missing/invalid search term. + if ( ! isset( $_REQUEST['term'] ) || ! is_string( $_REQUEST['term'] ) ) { + wp_die( 0 ); + } + /* + * Asterisks are trimmed since wildcards are appended below. Without this, a + * term consisting only of asterisks would result in an empty search that + * matches all users. + */ + $term = trim( sanitize_text_field( wp_unslash( $_REQUEST['term'] ) ), '*' ); + if ( '' === $term ) { + wp_die( 0 ); + } + /* * Check the type of request. * Current allowed values are `add` and `search`. @@ -342,7 +360,7 @@ function wp_ajax_autocomplete_user() { $users = get_users( array( 'blog_id' => false, - 'search' => '*' . $_REQUEST['term'] . '*', + 'search' => '*' . $term . '*', 'include' => $include_blog_users, 'exclude' => $exclude_blog_users, 'search_columns' => array( 'user_login', 'user_nicename', 'user_email' ), diff --git a/tests/phpunit/tests/ajax/wpAjaxAutocompleteUser.php b/tests/phpunit/tests/ajax/wpAjaxAutocompleteUser.php new file mode 100644 index 0000000000000..3d1eecf2f0fa3 --- /dev/null +++ b/tests/phpunit/tests/ajax/wpAjaxAutocompleteUser.php @@ -0,0 +1,412 @@ +user->create( array( 'role' => 'administrator' ) ); + self::$site_admin_id = $factory->user->create( array( 'role' => 'administrator' ) ); + self::$subscriber_id = $factory->user->create( array( 'role' => 'subscriber' ) ); + self::$target_user_id = $factory->user->create( + array( + 'role' => 'subscriber', + 'user_login' => 'autocompleteuser', + 'user_email' => 'autocompleteuser+bat\'leth@klingon.example.org', + ) + ); + + if ( is_multisite() ) { + grant_super_admin( self::$super_admin_id ); + } + } + + /** + * Runs the Ajax handler and returns the response passed to wp_die(). + * + * The handler never echoes anything, so the response is only available + * through the exception thrown by the die handler. + * + * @return string The raw response. + */ + protected function handle_autocomplete_user(): string { + try { + $this->_handleAjax( 'autocomplete-user' ); + } catch ( WPAjaxDieStopException $e ) { + return $e->getMessage(); + } + + $this->fail( 'wp_ajax_autocomplete_user() did not stop execution.' ); + } + + /** + * Tests that users of the current site are returned when searching them. + * + * @ticket 65051 + */ + public function test_should_return_users_matching_the_search_term() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => 'autocompleteuser', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + $this->assertCount( 1, $response, 'Only the matching user should be returned.' ); + $result = array_first( $response ); + $this->assertIsArray( $result ); + $this->assertSame( 'autocompleteuser', $result['value'], 'The user login should be returned as the value.' ); + $this->assertIsString( $result['label'] ); + $this->assertStringContainsString( 'autocompleteuser+bat\'leth@klingon.example.org', $result['label'], 'The label should contain the email address.' ); + } + + /** + * Tests that the email address is returned when it is the requested field. + * + * @ticket 65051 + */ + public function test_should_return_the_email_address_as_the_value_when_requested() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'autocomplete_field' => 'user_email', + 'term' => 'autocompleteuser', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + $this->assertCount( 1, $response, 'Only the matching user should be returned.' ); + $result = array_first( $response ); + $this->assertIsArray( $result ); + $this->assertSame( 'autocompleteuser+bat\'leth@klingon.example.org', $result['value'], 'The email address should be returned as the value.' ); + } + + /** + * Tests that users of the current site are excluded when adding a user to it. + * + * @ticket 65051 + */ + public function test_should_exclude_users_of_the_current_site_when_adding() { + wp_set_current_user( self::$super_admin_id ); + + // The default autocomplete type is 'add', which excludes existing users of the site. + $_GET = wp_slash( + array( + 'term' => 'autocompleteuser', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertSame( array(), $response, 'A user of the current site should not be suggested.' ); + } + + /** + * Tests that HTML tags are removed from the search term. + * + * @ticket 65051 + * + * @dataProvider data_terms_containing_tags + * + * @param string $term Term containing HTML tags. + */ + public function test_should_strip_tags_from_the_search_term( string $term ) { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => $term, + ) + ); + + $search = null; + add_action( + 'pre_get_users', + static function ( WP_User_Query $query ) use ( &$search ) { + $search = $query->get( 'search' ); + } + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + + $this->assertSame( '*autocompleteuser*', $search, 'The search term should be sanitized before it is passed to get_users().' ); + $this->assertCount( 1, $response, 'The sanitized term should still match the user.' ); + } + + /** + * Data provider. + * + * Note that `wp_strip_all_tags()` removes script and style elements along + * with their contents, while for other tags only the tags themselves are + * removed. + * + * @return array + */ + public static function data_terms_containing_tags(): array { + return array( + 'script element after the term' => array( 'autocompleteuser' ), + 'tags wrapping the term' => array( 'autocompleteuser' ), + ); + } + + /** + * Tests that searching for an email address with apostrophes is successful. + * + * @ticket 65051 + */ + public function test_search_email_address_with_apostrophe() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'autocomplete_field' => 'user_email', + 'term' => 'autocompleteuser+bat\'leth@klingon.example.org', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + $this->assertCount( 1, $response, 'Only the matching user should be returned.' ); + $result = array_first( $response ); + $this->assertIsArray( $result ); + $this->assertSame( 'autocompleteuser+bat\'leth@klingon.example.org', $result['value'], 'The email address should be returned as the value.' ); + } + + /** + * Tests that a missing search term does not return results. + * + * @ticket 65051 + */ + public function test_missing_term_does_not_return_results() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + ) + ); + + $this->assertSame( '0', $this->handle_autocomplete_user() ); + } + + /** + * Tests that an empty search term does not return results. + * + * @ticket 65051 + * + * @dataProvider data_empty_terms + * + * @param string $term Empty or whitespace-only term. + */ + public function test_empty_term_does_not_return_results( string $term ) { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => $term, + ) + ); + + $this->assertSame( '0', $this->handle_autocomplete_user() ); + } + + /** + * Data provider. + * + * @return array + */ + public static function data_empty_terms(): array { + return array( + 'empty string' => array( '' ), + 'whitespace only' => array( ' ' ), + ); + } + + /** + * Tests that a non-string search term does not return results. + * + * @ticket 65051 + */ + public function test_non_string_term_does_not_return_results() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => array( 'autocompleteuser' ), + ) + ); + + $this->assertSame( '0', $this->handle_autocomplete_user() ); + } + + /** + * Tests that a term consisting only of asterisks does not match all users. + * + * @ticket 65051 + */ + public function test_asterisk_only_term_does_not_return_results() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => '**', + ) + ); + + $this->assertSame( '0', $this->handle_autocomplete_user() ); + } + + /** + * Tests that a term wrapped in asterisks still matches. + * + * @ticket 65051 + */ + public function test_asterisk_wrapped_term_returns_results() { + wp_set_current_user( self::$super_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => '*autocompleteuser*', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + $this->assertCount( 1, $response, 'The matching user should be returned.' ); + } + + /** + * Tests that users without the 'promote_users' capability are denied. + * + * @ticket 65051 + */ + public function test_should_deny_users_without_the_promote_users_capability() { + wp_set_current_user( self::$subscriber_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => 'autocompleteuser', + ) + ); + + $this->assertSame( '-1', $this->handle_autocomplete_user() ); + } + + /** + * Tests that site administrators are denied unless the filter allows them. + * + * @ticket 65051 + */ + public function test_should_deny_site_administrators_by_default() { + wp_set_current_user( self::$site_admin_id ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => 'autocompleteuser', + ) + ); + + $this->assertSame( '-1', $this->handle_autocomplete_user() ); + } + + /** + * Tests that site administrators are allowed by the + * 'autocomplete_users_for_site_admins' filter. + * + * @ticket 65051 + */ + public function test_should_allow_site_administrators_when_filtered() { + wp_set_current_user( self::$site_admin_id ); + + add_filter( 'autocomplete_users_for_site_admins', '__return_true' ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => 'autocompleteuser', + ) + ); + + $response = json_decode( $this->handle_autocomplete_user(), true ); + + $this->assertIsArray( $response, 'The response should be a JSON encoded array.' ); + $this->assertCount( 1, $response, 'The matching user should be returned.' ); + } + + /** + * Tests that no autocompletion happens on large networks. + * + * @ticket 65051 + */ + public function test_should_deny_the_request_on_a_large_network() { + wp_set_current_user( self::$super_admin_id ); + + add_filter( 'wp_is_large_network', '__return_true' ); + + $_GET = wp_slash( + array( + 'autocomplete_type' => 'search', + 'term' => 'autocompleteuser', + ) + ); + + $this->assertSame( '-1', $this->handle_autocomplete_user() ); + } +} From 3a20e599baf75e8d568f0bfd029be4f8ef4094a4 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 5 Aug 2026 06:16:54 +0000 Subject: [PATCH 121/138] Media: Normalize the order property in media models. The Media Library grid view renders attachments in the reverse of the order the server returned whenever the `order` query var is present but not uppercase, most commonly after sorting in list view and then clicking the grid view toggle, which carries `order=desc` over in the URL. `WP_Query` normalizes and defaults `order` server side, but the media models compare against the literal strings `'ASC'` and `'DESC'`, so a lowercase or invalid value flips the display. `wp.media.model.Query.get()` already normalized `order`, but `wp.media.model.Attachments.initialize()` did not, so a `Query` and the plain `Attachments` collection mirroring it could disagree about the sort direction. Normalizing at initialization instead gives every attachment collection a consistent `order` regardless of how it was constructed. Props trivedikavit, sabernhardt, mukesh27, shailu25, soyebsalar01, ozgursar, darshitrajyaguru97. Fixes #64467. git-svn-id: https://develop.svn.wordpress.org/trunk@63017 602fd350-edb4-49c9-b593-d223f7449a82 --- src/js/media/models/attachments.js | 16 +- src/js/media/models/query.js | 6 - tests/qunit/index.html | 1 + .../wp-includes/js/media/test-media-models.js | 254 ++++++++++++++++++ 4 files changed, 270 insertions(+), 7 deletions(-) create mode 100644 tests/qunit/wp-includes/js/media/test-media-models.js diff --git a/src/js/media/models/attachments.js b/src/js/media/models/attachments.js index 1683494388283..fb31ba09ab9d6 100644 --- a/src/js/media/models/attachments.js +++ b/src/js/media/models/attachments.js @@ -32,6 +32,8 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen * @param {Object} [options={}] */ initialize: function( models, options ) { + var normalizedOrder; + options = options || {}; this.props = new Backbone.Model(); @@ -44,7 +46,19 @@ var Attachments = Backbone.Collection.extend(/** @lends wp.media.model.Attachmen this.props.on( 'change:orderby', this._changeOrderby, this ); this.props.on( 'change:query', this._changeQuery, this ); - this.props.set( _.defaults( options.props || {} ) ); + options.props = options.props || {}; + + /* + * Normalize the order, if one is set. `Attachments.comparator()` and the + * `order` filter in `wp.media.model.Query` both test for the literal + * strings 'ASC' and 'DESC', so anything else has to fall back to 'DESC'. + */ + if ( ! _.isUndefined( options.props.order ) && ! _.isNull( options.props.order ) ) { + normalizedOrder = String( options.props.order ).toUpperCase(); + options.props.order = ( 'ASC' === normalizedOrder || 'DESC' === normalizedOrder ) ? normalizedOrder : 'DESC'; + } + + this.props.set( options.props ); if ( options.observe ) { this.observe( options.observe ); diff --git a/src/js/media/models/query.js b/src/js/media/models/query.js index b3f62018f5cd4..3c47215c39833 100644 --- a/src/js/media/models/query.js +++ b/src/js/media/models/query.js @@ -251,12 +251,6 @@ Query = Attachments.extend(/** @lends wp.media.model.Query.prototype */{ // Fill default args. _.defaults( props, defaults ); - // Normalize the order. - props.order = props.order.toUpperCase(); - if ( 'DESC' !== props.order && 'ASC' !== props.order ) { - props.order = defaults.order.toUpperCase(); - } - // Ensure we have a valid orderby value. if ( ! _.contains( orderby.allowed, props.orderby ) ) { props.orderby = defaults.orderby; diff --git a/tests/qunit/index.html b/tests/qunit/index.html index a6b6177014586..d0e81acedb502 100644 --- a/tests/qunit/index.html +++ b/tests/qunit/index.html @@ -152,6 +152,7 @@ + diff --git a/tests/qunit/wp-includes/js/media/test-media-models.js b/tests/qunit/wp-includes/js/media/test-media-models.js new file mode 100644 index 0000000000000..b6d5563f584b6 --- /dev/null +++ b/tests/qunit/wp-includes/js/media/test-media-models.js @@ -0,0 +1,254 @@ +/* globals wp */ +/* jshint qunit: true */ +/* eslint-env qunit */ +/* eslint-disable no-magic-numbers */ + +( function() { + 'use strict'; + + QUnit.module( 'Media Models - Order Normalization' ); + + // Test valid uppercase values + QUnit.test( 'Attachments should accept uppercase "ASC" order', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'ASC' + } + }); + + assert.strictEqual( collection.props.get('order'), 'ASC', + 'Order should remain ASC when passed as uppercase' ); + }); + + QUnit.test( 'Attachments should accept uppercase "DESC" order', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'DESC' + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Order should remain DESC when passed as uppercase' ); + }); + + // Test lowercase normalization + QUnit.test( 'Attachments should normalize lowercase "asc" to uppercase', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'asc' + } + }); + + assert.strictEqual( collection.props.get('order'), 'ASC', + 'Order should be converted from lowercase asc to uppercase ASC' ); + }); + + QUnit.test( 'Attachments should normalize lowercase "desc" to uppercase', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'desc' + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Order should be converted from lowercase desc to uppercase DESC' ); + }); + + // Test mixed case normalization + QUnit.test( 'Attachments should normalize mixed case "AsC" to uppercase', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'AsC' + } + }); + + assert.strictEqual( collection.props.get('order'), 'ASC', + 'Order should be converted from mixed case AsC to uppercase ASC' ); + }); + + QUnit.test( 'Attachments should normalize mixed case "DeSc" to uppercase', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'DeSc' + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Order should be converted from mixed case DeSc to uppercase DESC' ); + }); + + // Test invalid string values + QUnit.test( 'Attachments should default invalid string order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'invalid' + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Invalid string order should default to DESC' ); + }); + + QUnit.test( 'Attachments should default empty string order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: '' + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Empty string order should default to DESC' ); + }); + + /* + * An unset order is left alone so the existing 'DESC' fallbacks in + * Attachments.comparator() still apply. Any value that *is* set gets + * normalized, otherwise a truthy non-string would sort ascending. + */ + QUnit.test( 'Attachments should leave a null order value unset', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: null + } + }); + + assert.strictEqual( collection.props.get('order'), null, + 'Null order should remain null' ); + }); + + QUnit.test( 'Attachments should leave an undefined order value unset', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: undefined + } + }); + + assert.strictEqual( collection.props.get('order'), undefined, + 'Undefined order should remain undefined' ); + }); + + QUnit.test( 'Attachments should default a numeric order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 123 + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Numeric order should default to DESC' ); + }); + + QUnit.test( 'Attachments should default a boolean true order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: true + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Boolean true order should default to DESC' ); + }); + + QUnit.test( 'Attachments should default a boolean false order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: false + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Boolean false order should default to DESC' ); + }); + + QUnit.test( 'Attachments should default an object order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: { value: 'ASC' } + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Object order should default to DESC' ); + }); + + QUnit.test( 'Attachments should default an array order to "DESC"', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: ['ASC', 'DESC'] + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Array order should default to DESC' ); + }); + + // Test when no order property is provided + QUnit.test( 'Attachments should work when no order property is provided', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + orderby: 'date' + } + }); + + assert.strictEqual( collection.props.get('order'), undefined, + 'Order should be undefined when not provided' ); + }); + + /* + * Query no longer normalizes the order itself, it relies on inheriting the + * normalization above. Note these pass `args` rather than `props.query`: + * setting `query` would kick off a server request via `_requery()`. + */ + QUnit.test( 'Query should inherit order normalization from Attachments', function( assert ) { + var query = new wp.media.model.Query( [], { + props: { + order: 'asc' + }, + args: {} + }); + + assert.strictEqual( query.props.get('order'), 'ASC', + 'Query model should normalize order through inheritance from Attachments' ); + assert.ok( query instanceof wp.media.model.Attachments, + 'Query should be instance of Attachments' ); + }); + + QUnit.test( 'Query should default invalid order to "DESC"', function( assert ) { + var query = new wp.media.model.Query( [], { + props: { + order: 'random' + }, + args: {} + }); + + assert.strictEqual( query.props.get('order'), 'DESC', + 'Query model should default invalid order to DESC' ); + }); + + // Test whitespace handling + QUnit.test( 'Attachments should handle order with whitespace', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: ' asc ' + } + }); + + assert.notStrictEqual( collection.props.get('order'), 'ASC', + 'Order with whitespace should not match ASC exactly' ); + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Order with whitespace should default to DESC as it does not match ASC/DESC after toUpperCase' ); + }); + + // Test unicode characters + QUnit.test( 'Attachments should handle order with unicode characters', function( assert ) { + var collection = new wp.media.model.Attachments( [], { + props: { + order: 'asc\u200B' // Zero-width space + } + }); + + assert.strictEqual( collection.props.get('order'), 'DESC', + 'Order with unicode characters should default to DESC' ); + }); + +})(); From 6904e896b870e1ddd4e706edcd990b794977fec1 Mon Sep 17 00:00:00 2001 From: Adam Silverstein Date: Wed, 5 Aug 2026 06:40:32 +0000 Subject: [PATCH 122/138] REST API: Always register the media creation arguments. The `url`, `generate_sub_sizes`, and `convert_format` arguments for `POST /wp/v2/media` were only registered when client side media processing is enabled, but `create_item()` and `create_item_permissions_check()` honored all three either way. Since an unregistered argument skips the validation and sanitization its registration carries, an unsafe sideload `url` failed with a bare `http_request_failed` instead of a 400. Gating registration also made the schema depend on request context rather than site configuration, since `wp_is_client_side_media_processing_enabled()` is derived from `is_ssl()` and the host, so the same site could advertise different arguments depending on how it was reached. All three arguments are now registered unconditionally. None of them require the feature: sideloading from a URL works around a cross-origin fetch the browser cannot make, and skipping sub-size generation or format conversion is something the server can do on its own. One condition is kept: `generate_sub_sizes` of `false` no longer relaxes the unsupported image type check in `create_item_permissions_check()` unless client side media processing is enabled, since that check exists because the server cannot process the image and should only be relaxed when the client can. Behavior with client side media processing enabled is unchanged. Follow-up to [62659], [62841]. Props andrewserong, jeremyfelt. Fixes #65808. See #65517. git-svn-id: https://develop.svn.wordpress.org/trunk@63018 602fd350-edb4-49c9-b593-d223f7449a82 --- .../class-wp-rest-attachments-controller.php | 100 +++++----- .../rest-api/rest-attachments-controller.php | 179 ++++++++++++++++++ 2 files changed, 234 insertions(+), 45 deletions(-) diff --git a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php index 9a7dabc7b3cf1..f336f321a9ea2 100644 --- a/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php +++ b/src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php @@ -237,50 +237,54 @@ public function register_routes() { public function get_endpoint_args_for_item_schema( $method = WP_REST_Server::CREATABLE ) { $args = parent::get_endpoint_args_for_item_schema( $method ); - if ( WP_REST_Server::CREATABLE === $method && wp_is_client_side_media_processing_enabled() ) { - $args['generate_sub_sizes'] = array( - 'type' => 'boolean', - 'default' => true, - 'description' => __( 'Whether to generate image sub sizes.' ), - ); - $args['convert_format'] = array( - 'type' => 'boolean', - 'default' => true, - 'description' => __( 'Whether to convert image formats.' ), - ); - $args['url'] = array( - 'type' => 'string', - 'format' => 'uri', - 'description' => __( 'URL of an external image to sideload into the media library, instead of uploading a file.' ), - 'sanitize_callback' => 'sanitize_url', - 'validate_callback' => static function ( $url, $request, $param ) { - /* - * A custom validate_callback replaces the default - * rest_validate_request_arg(), so re-apply it first to keep - * the schema checks (string type, uri format) enforced. - */ - $valid = rest_validate_request_arg( $url, $request, $param ); - if ( is_wp_error( $valid ) ) { - return $valid; - } + if ( WP_REST_Server::CREATABLE !== $method ) { + return $args; + } - /* - * Reject URLs that are not safe to request server-side. wp_http_validate_url() - * enforces an HTTP(S) scheme and blocks private, local, and otherwise - * disallowed hosts, guarding the sideload against SSRF. - */ - if ( false === wp_http_validate_url( $url ) ) { - return new WP_Error( - 'rest_invalid_url', - __( 'Invalid URL. Provide a valid, publicly reachable HTTP or HTTPS image URL.' ), - array( 'status' => 400 ) - ); - } + $args['generate_sub_sizes'] = array( + 'type' => 'boolean', + 'default' => true, + 'description' => __( 'Whether to generate image sub sizes.' ), + ); - return true; - }, - ); - } + $args['convert_format'] = array( + 'type' => 'boolean', + 'default' => true, + 'description' => __( 'Whether to convert image formats.' ), + ); + + $args['url'] = array( + 'type' => 'string', + 'format' => 'uri', + 'description' => __( 'URL of an external image to sideload into the media library, instead of uploading a file.' ), + 'sanitize_callback' => 'sanitize_url', + 'validate_callback' => static function ( $url, $request, $param ) { + /* + * A custom validate_callback replaces the default + * rest_validate_request_arg(), so re-apply it first to keep + * the schema checks (string type, uri format) enforced. + */ + $valid = rest_validate_request_arg( $url, $request, $param ); + if ( is_wp_error( $valid ) ) { + return $valid; + } + + /* + * Reject URLs that are not safe to request server-side. wp_http_validate_url() + * enforces an HTTP(S) scheme and blocks private, local, and otherwise + * disallowed hosts, guarding the sideload against SSRF. + */ + if ( false === wp_http_validate_url( $url ) ) { + return new WP_Error( + 'rest_invalid_url', + __( 'Invalid URL. Provide a valid, publicly reachable HTTP or HTTPS image URL.' ), + array( 'status' => 400 ) + ); + } + + return true; + }, + ); return $args; } @@ -381,9 +385,15 @@ public function create_item_permissions_check( $request ) { */ $prevent_unsupported_uploads = apply_filters( 'wp_prevent_unsupported_mime_type_uploads', true, $files['file']['type'] ?? null ); - // When the client handles image processing (generate_sub_sizes is false), - // skip the server-side image editor support check. - if ( false === $request['generate_sub_sizes'] ) { + /* + * When the client handles image processing (generate_sub_sizes is false), + * skip the server-side image editor support check. This check exists + * because the server cannot process the image, so it is only relaxed when + * client side media processing is enabled and something else can. Asking + * to skip sub sizes on a site without it does not make an unsupported + * image type any more usable. + */ + if ( wp_is_client_side_media_processing_enabled() && false === $request['generate_sub_sizes'] ) { $prevent_unsupported_uploads = false; } diff --git a/tests/phpunit/tests/rest-api/rest-attachments-controller.php b/tests/phpunit/tests/rest-api/rest-attachments-controller.php index 1efa090efb05c..7f4dcd06c2f71 100644 --- a/tests/phpunit/tests/rest-api/rest-attachments-controller.php +++ b/tests/phpunit/tests/rest-api/rest-attachments-controller.php @@ -207,6 +207,18 @@ private function enable_client_side_media_processing(): void { do_action( 'rest_api_init', $wp_rest_server ); } + /** + * Turns client-side media processing off and rebuilds the REST server so the + * routes are registered with the feature disabled. + */ + private function disable_client_side_media_processing(): void { + add_filter( 'wp_client_side_media_processing_enabled', '__return_false' ); + + global $wp_rest_server; + $wp_rest_server = new Spy_REST_Server(); + do_action( 'rest_api_init', $wp_rest_server ); + } + public function test_register_routes() { $routes = rest_get_server()->get_routes(); $this->assertArrayHasKey( '/wp/v2/media', $routes ); @@ -3412,9 +3424,16 @@ public function test_upload_unsupported_image_type_with_filter() { * Tests the permissions check directly with file params set, since the core * check uses get_file_params() which is only populated for multipart uploads. * + * The check is only relaxed when client-side media processing is enabled, + * since that is what makes the client able to handle the image, so the + * feature is enabled here. + * * @ticket 64836 + * @ticket 65517 */ public function test_upload_unsupported_image_type_skipped_when_not_generating_sub_sizes() { + $this->enable_client_side_media_processing(); + wp_set_current_user( self::$author_id ); add_filter( 'wp_image_editors', '__return_empty_array' ); @@ -5830,6 +5849,166 @@ public function test_url_registered_as_creatable_arg() { $this->assertSame( 'uri', $creatable['args']['url']['format'] ); } + /** + * Verifies that the media creation arguments are registered even when + * client-side media processing is disabled. + * + * The feature is determined per request, from the scheme and host, so gating + * the schema on it would advertise different arguments for the same site + * depending on how it was reached. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::get_endpoint_args_for_item_schema + */ + public function test_creatable_args_registered_without_client_side_media_processing() { + $this->disable_client_side_media_processing(); + + $routes = rest_get_server()->get_routes(); + $creatable = null; + foreach ( $routes['/wp/v2/media'] as $route ) { + if ( ! empty( $route['methods'][ WP_REST_Server::CREATABLE ] ) ) { + $creatable = $route; + break; + } + } + + $this->assertNotNull( $creatable, 'The media route should register a CREATABLE handler.' ); + $this->assertArrayHasKey( 'url', $creatable['args'] ); + $this->assertArrayHasKey( 'generate_sub_sizes', $creatable['args'] ); + $this->assertArrayHasKey( 'convert_format', $creatable['args'] ); + } + + /** + * Verifies that sideloading an external image works when client-side media + * processing is disabled. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::create_item + * @covers WP_REST_Attachments_Controller::create_item_from_url + */ + public function test_create_item_from_url_without_client_side_media_processing() { + $this->disable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + + add_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/photo.jpg' ); + + $response = rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10 ); + + $data = $response->get_data(); + + $this->assertSame( 201, $response->get_status() ); + $this->assertSame( 'image', $data['media_type'] ); + $this->assertSame( 'https://example.com/photo.jpg', $this->last_download_url ); + } + + /** + * Verifies that the `url` argument's validation runs when client-side media + * processing is disabled, so an unsafe URL is rejected with a 400 rather than + * reaching the download. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::get_endpoint_args_for_item_schema + */ + public function test_url_arg_rejects_unsafe_urls_without_client_side_media_processing() { + $this->disable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'http://127.0.0.1/private.jpg' ); + + $response = rest_get_server()->dispatch( $request ); + + $this->assertErrorResponse( 'rest_invalid_param', $response, 400 ); + } + + /** + * Verifies that `generate_sub_sizes` is honored when client-side media + * processing is disabled. + * + * Skipping sub-size generation is a request the server can carry out on its + * own, so it does not depend on the feature. Sub-sizes can still be added + * later with wp_update_image_subsizes(). + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::create_item + */ + public function test_generate_sub_sizes_honored_without_client_side_media_processing() { + $this->disable_client_side_media_processing(); + + wp_set_current_user( self::$superadmin_id ); + + add_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10, 3 ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_param( 'url', 'https://example.com/photo.jpg' ); + $request->set_param( 'generate_sub_sizes', false ); + + $response = rest_get_server()->dispatch( $request ); + + remove_filter( 'pre_http_request', array( $this, 'mock_image_download' ), 10 ); + + $data = $response->get_data(); + + $this->assertSame( 201, $response->get_status() ); + + $metadata = wp_get_attachment_metadata( $data['id'], true ); + $this->assertEmpty( + $metadata['sizes'] ?? array(), + 'Sub-sizes should not be generated when generate_sub_sizes is false.' + ); + } + + /** + * Verifies that `generate_sub_sizes` does not relax the unsupported image + * type check when client-side media processing is disabled. + * + * That check exists because the server cannot process the image, so it should + * only be relaxed when the client can process it instead. Otherwise the + * upload is stored unprocessable. + * + * @ticket 65517 + * + * @covers WP_REST_Attachments_Controller::create_item_permissions_check + */ + public function test_unsupported_image_type_still_checked_without_client_side_media_processing() { + $this->disable_client_side_media_processing(); + + wp_set_current_user( self::$author_id ); + + add_filter( 'wp_image_editors', '__return_empty_array' ); + + $request = new WP_REST_Request( 'POST', '/wp/v2/media' ); + $request->set_file_params( + array( + 'file' => array( + 'name' => 'avif-lossy.avif', + 'type' => 'image/avif', + 'tmp_name' => self::$test_avif_file, + 'error' => 0, + 'size' => filesize( self::$test_avif_file ), + ), + ) + ); + $request->set_param( 'generate_sub_sizes', false ); + + $controller = new WP_REST_Attachments_Controller( 'attachment' ); + $result = $controller->create_item_permissions_check( $request ); + + $this->assertWPError( $result ); + $this->assertSame( 'rest_upload_image_type_not_supported', $result->get_error_code() ); + } + /** * Verifies that the `url` argument rejects values that are not safe to * request server-side, guarding the sideload against SSRF. From e9e0be1c75b3bb2ce472d4c7891f3d7906f227d3 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 07:16:57 +0000 Subject: [PATCH 123/138] Build/Test Tools: Raise the PHPStan rule level to 1. Level 1 adds detection of possibly undefined variables, and of unknown magic methods and properties on classes with `__call` and `__get`. The 494 errors this surfaces in existing code are recorded in baselines rather than being fixed here, so that new code is held to level 1 straight away while the existing reports are worked through separately. No files under `src` are changed. The `tests/phpstan/baseline.php` file is replaced by one baseline per error identifier under `tests/phpstan/baselines`, so that the remaining work on each kind of error is visible as a single file that should shrink to nothing and then be deleted. Every entry is scoped to the file which the error occurs in and carries an exact occurrence count, so that a new occurrence of an already baselined error is reported rather than absorbed. The consequence is that fixing a baselined error means regenerating its baseline in the same change, because the count no longer matches. PHPStan's own `--generate-baseline` captures every error a run reports, with no way to restrict it to one identifier, so `tests/phpstan/generate-baselines.php` is added to write the files instead, exposed as `composer phpstan:baselines` and as `npm run typecheck:php:baselines`. A run also deletes any baseline whose identifier no longer reports anything, and rewrites the list of baselines in `phpstan.neon.dist`. The `ignoreErrors` in that file now has a comment explaining how it is distinct from a baseline: an entry there is a decision that the code is right as written, whereas a baseline entry is work still to be done. The constants that `add_theme_support()` defines are declared in the configuration so that the errors around them are resolved rather than recorded, and `tests/phpstan/README.md` is updated throughout. Three problems in the static analysis GHA workflow are fixed as well. Fixing a baselined error makes PHPStan report an unmatched ignore, which surfaced only as an annotation reading like a complaint about a correct fix; the job now detects any `ignore.*` report and fails with an explanation of what to run. An analysis that did not finish passed as a green run, because the status of the pipeline was that of `cs2pr` rather than of PHPStan; that status is now recovered and a run that did not finish fails. The path filter deciding whether the workflow runs named only the old baseline file, so a pull request that merely regenerated the baselines would not have run the analysis that checks them. Developed in https://github.com/WordPress/wordpress-develop/pull/11151. Follow-up to r61699. Props westonruter, sabernhardt, apermo, johnjamesjacoby, adamsilverstein, justlevine. See #61175. Fixes #64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63019 602fd350-edb4-49c9-b593-d223f7449a82 --- .github/workflows/phpstan-static-analysis.yml | 2 +- .../reusable-phpstan-static-analysis-v1.yml | 95 +- composer.json | 1 + package.json | 3 +- phpstan.neon.dist | 27 +- tests/phpstan/README.md | 68 +- tests/phpstan/base.neon | 7 + tests/phpstan/baseline.php | 3 - tests/phpstan/baselines/empty.variable.neon | 65 ++ tests/phpstan/baselines/isset.variable.neon | 50 + .../phpstan/baselines/variable.undefined.neon | 995 ++++++++++++++++++ tests/phpstan/bootstrap.php | 9 + tests/phpstan/generate-baselines.php | 662 ++++++++++++ 13 files changed, 1970 insertions(+), 17 deletions(-) delete mode 100644 tests/phpstan/baseline.php create mode 100644 tests/phpstan/baselines/empty.variable.neon create mode 100644 tests/phpstan/baselines/isset.variable.neon create mode 100644 tests/phpstan/baselines/variable.undefined.neon create mode 100644 tests/phpstan/generate-baselines.php diff --git a/.github/workflows/phpstan-static-analysis.yml b/.github/workflows/phpstan-static-analysis.yml index 62061a83a2688..7d7043ac0c1ec 100644 --- a/.github/workflows/phpstan-static-analysis.yml +++ b/.github/workflows/phpstan-static-analysis.yml @@ -18,7 +18,7 @@ on: # These files configure PHPStan. Changes could affect the outcome. - 'phpstan.neon.dist' - 'tests/phpstan/base.neon' - - 'tests/phpstan/baseline.php' + - 'tests/phpstan/baselines/**' # Confirm any changes to relevant workflow files. - '.github/workflows/phpstan-static-analysis.yml' - '.github/workflows/reusable-phpstan-static-analysis-v1.yml' diff --git a/.github/workflows/reusable-phpstan-static-analysis-v1.yml b/.github/workflows/reusable-phpstan-static-analysis-v1.yml index a69b3b46fdea4..26a14ba8d890f 100644 --- a/.github/workflows/reusable-phpstan-static-analysis-v1.yml +++ b/.github/workflows/reusable-phpstan-static-analysis-v1.yml @@ -32,6 +32,7 @@ jobs: # - Builds WordPress. # - Configures caching for PHPStan static analysis scans. # - Runs PHPStan static analysis (with Pull Request annotations). + # - Checks whether the baselines need regenerating. # - Saves the PHPStan result cache. # - Ensures version-controlled files are not modified or deleted. phpstan: @@ -93,7 +94,99 @@ jobs: - name: Run PHP static analysis tests id: phpstan - run: composer run phpstan -- -vvv --error-format=checkstyle | cs2pr --errors-as-warnings --graceful-warnings + run: | + # The report is written to a file as well as piped to cs2pr, so that the step below + # can look at it. + # + # cs2pr exits successfully so that reported errors annotate the pull request without + # failing the run. A pipeline reports only the status of its last command, so that + # also discards the status of the analysis itself. Recover it from PIPESTATUS. + composer run phpstan -- -vvv --error-format=checkstyle | tee "${RUNNER_TEMP}/phpstan-report.xml" | cs2pr --errors-as-warnings --graceful-warnings + status="${PIPESTATUS[0]}" + + # PHPStan exits 1 when it has errors to report, which is the expected case here and + # is what the annotations are for. Anything higher means it did not finish at all, + # which would otherwise pass silently, since the discarded status was the only sign. + if [ "${status}" -gt 1 ]; then + echo "::error title=PHPStan did not complete::The analysis exited with status ${status}, so the code was not fully checked. This is a failure of the run itself rather than a problem found in the code." + exit "${status}" + fi + + # An ignored error that no longer occurs, or occurs a different number of times, is + # reported under an `ignore.*` identifier. That is not something to fix in the code: the + # usual cause is that the error *was* fixed, leaving a baseline describing a state that + # no longer exists. PHPStan does not allow those reports to be ignored or baselined. + # + # The analysis above is reported as warnings, so this would otherwise surface as a + # passing run carrying an annotation that reads like a complaint about a fix. Call it + # out on its own, and say what to do about it. + # + # Detection is on the identifier rather than the message, which is prose and may be + # reworded in any release. The checkstyle format carries it in the `source` attribute. + - name: Check whether the baselines need regenerating + if: ${{ !cancelled() }} + env: + BASELINES_URL: ${{ github.server_url }}/${{ github.repository }}/tree/${{ github.sha }}/tests/phpstan/baselines + README_URL: ${{ github.server_url }}/${{ github.repository }}/blob/${{ github.sha }}/tests/phpstan/README.md + run: | + # This step runs even when the analysis above it failed, in which case the report may + # never have been written. That failure is reported there, so there is nothing to add + # here beyond staying quiet about a file that was never going to exist. + if [ ! -f "${RUNNER_TEMP}/phpstan-report.xml" ]; then + exit 0 + fi + + # Leave the run alone unless PHPStan reported an ignore error, because everything + # below concerns an ignore configuration that no longer describes the code, and + # nothing else. Those errors are `ignore.unmatched`, where a pattern matched nothing + # at all, and `ignore.count`, where it matched a different number of times than the + # entry records. The `ignore.` prefix is matched rather than those two names so that + # any later addition to the group is caught as well. + if ! grep -q 'source="ignore\.' "${RUNNER_TEMP}/phpstan-report.xml"; then + exit 0 + fi + + # The summary is Markdown, and its code spans and fences are written literally, so the + # heredoc is quoted to keep the backticks out of the shell's hands. The links are + # written in reference style for the same reason: the URLs are the only part needing + # a variable, so defining them afterwards keeps the whole of the prose in here. + # + # A newline renders as a line break rather than a space, so each paragraph is one + # line however long that makes it, and the rendered summary wraps to its own width. + cat >> "${GITHUB_STEP_SUMMARY}" <<'SUMMARY' + ## PHPStan baselines are out of date + + An ignored error no longer occurs, or occurs a different number of times, so PHPStan reported it under an `ignore.unmatched` or `ignore.count` identifier. + + **If you fixed the error, this is expected.** Each baseline entry records an exact count for a specific file, so that a new occurrence of an already baselined error is reported rather than absorbed. That same exactness means fixing one leaves the baseline describing a state that no longer exists. There is nothing to fix in the code; the baselines just need to catch up. + + Regenerate them and commit the result: + + ```bash + npm run typecheck:php:baselines + ``` + + or, outside the Docker environment: + + ```bash + composer phpstan:baselines + ``` + + That rewrites the files under [`tests/phpstan/baselines`][baselines], deletes any whose errors are now all fixed, and updates the list of them in `phpstan.neon.dist`. + + Where the report names an `@phpstan-ignore` annotation in the code rather than a baseline entry, remove that annotation instead; regenerating will not clear it. + + See [`tests/phpstan/README.md`][readme] for details. + + SUMMARY + + { + echo "[baselines]: ${BASELINES_URL}" + echo "[readme]: ${README_URL}" + } >> "${GITHUB_STEP_SUMMARY}" + + echo "::error title=PHPStan baselines are out of date::An ignored error no longer occurs, or occurs a different number of times. If you fixed it, that is expected: run \`npm run typecheck:php:baselines\` or \`composer phpstan:baselines\` and commit the updated baselines. See ${README_URL}" + exit 1 - name: "Save result cache" uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 diff --git a/composer.json b/composer.json index 1bff1b4d62dd7..a04cdedd18d84 100644 --- a/composer.json +++ b/composer.json @@ -68,6 +68,7 @@ }, "scripts": { "phpstan": "@php ./vendor/bin/phpstan analyse --memory-limit=2G", + "phpstan:baselines": [ "Composer\\Config::disableProcessTimeout", "@php ./tests/phpstan/generate-baselines.php" ], "compat": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --standard=phpcompat.xml.dist --report=summary,source", "format": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcbf --report=summary,source", "lint": "@php ./vendor/squizlabs/php_codesniffer/bin/phpcs --report=summary,source", diff --git a/package.json b/package.json index d854406d50d7e..5264d752b8e4e 100644 --- a/package.json +++ b/package.json @@ -141,7 +141,8 @@ "test:coverage": "npm run test:php -- --coverage-html ./coverage/html/ --coverage-php ./coverage/php/report.php --coverage-text=./coverage/text/report.txt", "test:e2e": "wp-scripts test-playwright --config tests/e2e/playwright.config.js", "test:visual": "wp-scripts test-playwright --config tests/visual-regression/playwright.config.js", - "typecheck:php": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan", + "typecheck:php": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan --", + "typecheck:php:baselines": "node ./tools/local-env/scripts/docker.js run --rm php composer phpstan:baselines --", "gutenberg:copy": "node tools/gutenberg/copy.js", "gutenberg:verify": "node tools/gutenberg/utils.js", "gutenberg:download": "node tools/gutenberg/download.js && grunt build:gutenberg" diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 93e6c1f6653b3..778b24b78c465 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -14,15 +14,35 @@ includes: # new strict rules. - vendor/phpstan/phpstan-phpunit/extension.neon - # The baseline file includes preexisting errors in the codebase that should be ignored. + # Preexisting errors that should be ignored, one baseline per error identifier + # so that the remaining work on each is visible as a single shrinking file. + # Each is meant to reach zero and be deleted, taking its line below with it. # https://phpstan.org/user-guide/baseline - - tests/phpstan/baseline.php + # + # Regenerate with `composer phpstan:baselines`, which rewrites both the files + # and the list between the markers. Do not edit that list by hand. + # phpstan:baselines start + - tests/phpstan/baselines/empty.variable.neon + - tests/phpstan/baselines/isset.variable.neon + - tests/phpstan/baselines/variable.undefined.neon + # phpstan:baselines end parameters: # https://phpstan.org/user-guide/rule-levels - level: 0 + level: 1 reportUnmatchedIgnoredErrors: true + # The following ignored errors are not intended to be fixed, as distinct from the baselines + # included above. + # + # A baseline records work still to be done. Every entry in one is in scope to be fixed, and + # each file is meant to reach zero and then be deleted. An entry here is the opposite: a + # decision that the code is right as written and the report is not actionable, whether + # because PHPStan cannot see what makes the code safe, or because satisfying it would mean + # changing code that has no other reason to change. + # + # So prefer fixing an error, and baseline it when it cannot be fixed yet. Add it here only + # when it should never be fixed, and say why. ignoreErrors: # Level 0: - # Inner functions aren't supported by PHPStan. @@ -40,6 +60,7 @@ parameters: identifier: function.inner path: src/wp-includes/canonical.php count: 1 + # Level 2: # ValueError is PHP 8.0+; core throws it conditionally so the docblocks are correct for WP's 7.4+ range, # but bleedingEdge's version-aware check treats the class as non-existent against the PHP 7.4 floor. diff --git a/tests/phpstan/README.md b/tests/phpstan/README.md index 036f4b98432e3..edf96fefdc093 100644 --- a/tests/phpstan/README.md +++ b/tests/phpstan/README.md @@ -39,6 +39,8 @@ composer run phpstan -- src/wp-includes/template.php composer run phpstan -- -vvv --debug ``` +Note the `--` in each of those. Composer needs it in order to pass the flags on to PHPStan rather than reading them as its own, and without it they are discarded silently. The npm script supplies it, which is why only one is needed there. + For available flags, see https://phpstan.org/user-guide/command-line-usage. ## The PHPStan configuration @@ -91,20 +93,70 @@ PHPStan errors can be ignored in the following ways: - Adding the error pattern to the `ignoreErrors` section of the `phpstan.neon.dist` configuration file. This should be used to handle conflicts with WordPress Coding Standards or similar project decisions, or to allowlist legacy code that is not worth refactoring solely to satisfy the tests. -- Adding an error to the "tech debt" baseline. This should be used for code that needs to be addressed eventually - by fixing, refactoring, or ignoring via one of the above methods - but is not worth addressing right now. +- Adding an error to a "tech debt" baseline. This should be used for code that needs to be addressed eventually - by fixing, refactoring, or ignoring via one of the above methods - but is not worth addressing right now. Baselines are a useful triage tool for handling PHPStan errors in legacy code, as they allow us to enforce stricter code quality checks on new code, while gradually chipping away at the existing issues over time. **Avoid adding PHPStan errors from new code whenever possible, and use baselines as a last resort.** - The baseline file is located at `tests/phpstan/baseline.php` and generated by running PHPStan with the `--generate-baseline` flag: +### How the baselines are organized + +The baselines live in [`baselines/`](baselines), one file per error identifier, such as `variable.undefined.neon`. Splitting them this way keeps each kind of error visible as a single file that should shrink to nothing and then be deleted, rather than as part of one large file in which every kind is mixed together. + +Every entry is scoped to the file the error occurs in and carries an exact occurrence count: + +```neon +- + message: '#^Variable \$wpdb might not be defined\.$#' + identifier: variable.undefined + count: 4 + path: ../../../src/wp-trackback.php +``` + +Both the path and the count matter. A new occurrence of an already baselined error does not match the entry, even in a file that is already listed, and is reported as a new error. That is the point of recording them this way: the baselines describe exactly what exists today, so nothing new slips in behind them. + +The consequence is that **fixing a baselined error means regenerating its baseline as part of the same change**, because the count no longer matches. A count that no longer matches is reported as an `ignore.count` error, which PHPStan does not allow to be ignored or baselined. + +### Regenerating the baselines + +The baselines are generated, and should not be edited by hand. Regenerate them with: + +```bash +npm run typecheck:php:baselines +``` + +which will run the generator in the Docker container. + +As with the analysis itself, flags are passed by adding `--` followed by the flags themselves: + +```bash +# a single identifier: +npm run typecheck:php:baselines -- --identifier=variable.undefined + +# several, either comma separated or by repeating the option: +npm run typecheck:php:baselines -- --identifier=variable.undefined,isset.variable +npm run typecheck:php:baselines -- --identifier=isset.variable --identifier=empty.variable + +# print every error as one baseline, writing nothing: +npm run typecheck:php:baselines -- --combined + +# the remaining options: +npm run typecheck:php:baselines -- --help +``` + +If you are not using the Docker environment, you can run the generator via Composer directly: + +```bash +composer phpstan:baselines + +composer phpstan:baselines -- --identifier=variable.undefined +composer phpstan:baselines -- --combined +composer phpstan:baselines -- --help +``` - ```bash - npm run typecheck:php -- --generate-baseline=tests/phpstan/baseline.php +Note the `--` in each of those. Composer needs it in order to pass the flags on to the script rather than reading them as its own, and without it they are discarded silently, so `composer phpstan:baselines --identifier=variable.undefined` regenerates every baseline rather than that one. The npm script supplies it, which is why only one is needed there. - # or, with Composer directly: - composer run phpstan -- --generate-baseline=tests/phpstan/baseline.php - ``` +A run also deletes any baseline whose identifier no longer reports anything, and rewrites the list of them between the `# phpstan:baselines` markers in the `includes` of [`phpstan.neon.dist`](../../phpstan.neon.dist) to match. Adding a newly split out baseline, and retiring one that has reached zero, therefore need no edit of the configuration. - This will regenerate the baseline file with any new errors added to the existing ones. You can then commit the updated baseline file. +PHPStan's own `--generate-baseline` is deliberately not used directly. It captures every error a run reports, with no way to restrict it to one identifier, so it cannot refresh a single baseline without sweeping every other kind of error into it. ## Performance and troubleshooting diff --git a/tests/phpstan/base.neon b/tests/phpstan/base.neon index 71c0fa6ab6cdd..1c416cb3fe643 100644 --- a/tests/phpstan/base.neon +++ b/tests/phpstan/base.neon @@ -75,6 +75,8 @@ parameters: - ALLOW_SUBDIRECTORY_INSTALL - AUTH_SALT - AUTOMATIC_UPDATER_DISABLED + - BACKGROUND_COLOR + - BACKGROUND_IMAGE - COOKIEPATH - CUSTOM_TAGS - DISALLOW_FILE_EDIT @@ -82,8 +84,13 @@ parameters: - EMPTY_TRASH_DAYS - ENFORCE_GZIP - FORCE_SSL_LOGIN + - HEADER_IMAGE + - HEADER_IMAGE_HEIGHT + - HEADER_IMAGE_WIDTH + - HEADER_TEXTCOLOR - MEDIA_TRASH - MULTISITE + - NO_HEADER_TEXT - NOBLOGREDIRECT - SAVEQUERIES - SCRIPT_DEBUG diff --git a/tests/phpstan/baseline.php b/tests/phpstan/baseline.php deleted file mode 100644 index 646cbdbef630c..0000000000000 --- a/tests/phpstan/baseline.php +++ /dev/null @@ -1,3 +0,0 @@ - all-errors.neon + * + * @package WordPress + */ + +namespace WordPress\PHPStan; + +if ( 'cli' !== PHP_SAPI ) { + fwrite( STDERR, "This script must be run from the command line.\n" ); + exit( 1 ); +} + +$repo_root = dirname( __DIR__, 2 ); + +// $argv is only populated when register_argc_argv is on, so read it defensively. +$args = array(); +foreach ( (array) ( $_SERVER['argv'] ?? array() ) as $arg ) { + if ( is_string( $arg ) ) { + $args[] = $arg; + } +} +array_shift( $args ); + +$config_option = 'phpstan.neon.dist'; +$output_option = 'tests/phpstan/baselines'; +$memory_limit = '2G'; +$only_identifiers = array(); +$combined = false; + +foreach ( $args as $arg ) { + if ( '--help' === $arg || '-h' === $arg ) { + fwrite( STDOUT, get_usage() ); + exit( 0 ); + } + + if ( '--combined' === $arg ) { + $combined = true; + continue; + } + + if ( 1 === preg_match( '/^--identifier=(.+)$/', $arg, $matches ) ) { + foreach ( explode( ',', $matches[1] ) as $identifier ) { + $identifier = trim( $identifier ); + if ( '' !== $identifier ) { + $only_identifiers[] = $identifier; + } + } + continue; + } + + if ( 1 === preg_match( '/^--config=(.+)$/', $arg, $matches ) ) { + $config_option = $matches[1]; + continue; + } + + if ( 1 === preg_match( '/^--output-dir=(.+)$/', $arg, $matches ) ) { + $output_option = $matches[1]; + continue; + } + + if ( 1 === preg_match( '/^--memory-limit=(.+)$/', $arg, $matches ) ) { + $memory_limit = $matches[1]; + continue; + } + + fwrite( STDERR, "Unrecognized option: $arg\n\n" . get_usage() ); + exit( 1 ); +} + +$config_path = $repo_root . '/' . ltrim( $config_option, '/' ); +$output_dir = $repo_root . '/' . trim( $output_option, '/' ); + +if ( ! is_file( $config_path ) ) { + fwrite( STDERR, "Configuration not found: $config_option\n" ); + exit( 1 ); +} + +/* + * The temporary configuration has to sit beside the original, because a neon + * file's `includes` entries resolve relative to its own directory. + */ +/* + * Both temporary files sit beside the configuration, and so inside the + * repository, for two separate reasons. + * + * A neon file's `includes` resolve relative to its own directory, so the copy of + * the configuration has to live where the original did. + * + * PHPStan writes a PHP baseline's paths as __DIR__ followed by a relative chain, + * which it can only produce when the baseline shares an ancestry with the files + * it names. Generated somewhere else, the system temporary directory included, + * it emits `__DIR__ . '//absolute/path'` instead, and every path in it then + * resolves to somewhere under that directory rather than to the source file. + */ +$temp_config = dirname( $config_path ) . '/.phpstan-baselines-' . getmypid() . '.neon'; +$temp_baseline = dirname( $config_path ) . '/.phpstan-baselines-' . getmypid() . '.php'; + +register_shutdown_function( + static function () use ( $temp_config, $temp_baseline ): void { + foreach ( array( $temp_config, $temp_baseline ) as $file ) { + if ( is_file( $file ) ) { + unlink( $file ); + } + } + } +); + +file_put_contents( $temp_config, strip_baseline_includes( $config_path, $output_dir ) ); + +/* + * PHPStan reports on stdout, which --combined reserves for the baseline itself, + * so its output is sent to stderr. That keeps it visible on a terminal while + * leaving stdout parseable when it is redirected. + */ +$command = sprintf( + '%s analyse --configuration=%s --generate-baseline=%s --allow-empty-baseline --no-progress --memory-limit=%s 1>&2', + escapeshellarg( $repo_root . '/vendor/bin/phpstan' ), + escapeshellarg( $temp_config ), + escapeshellarg( $temp_baseline ), + escapeshellarg( $memory_limit ) +); + +fwrite( STDERR, "Analyzing with $config_option, existing baselines suppressed...\n" ); + +$exit_code = 0; +passthru( $command, $exit_code ); + +if ( 0 !== $exit_code || ! is_file( $temp_baseline ) ) { + fwrite( STDERR, "PHPStan failed, nothing written.\n" ); + exit( 1 ); +} + +/** + * The entries of each error, grouped by the identifier of the error it suppresses. + * + * @var array, path: non-empty-string}>> $grouped + */ +$grouped = array(); + +foreach ( read_baseline( $temp_baseline ) as $entry ) { + $grouped[ $entry['identifier'] ][] = $entry; +} +ksort( $grouped ); + +if ( $only_identifiers ) { + $grouped = array_intersect_key( $grouped, array_flip( $only_identifiers ) ); +} + +if ( $combined ) { + $all = array(); + foreach ( $grouped as $entries ) { + $all = array_merge( $all, $entries ); + } + echo build_baseline( $all, $output_dir, "# Every identifier, combined.\n" ); + exit( 0 ); +} + +if ( ! is_dir( $output_dir ) && ! mkdir( $output_dir, 0755, true ) ) { + fwrite( STDERR, "Could not create $output_option\n" ); + exit( 1 ); +} + +foreach ( $grouped as $identifier => $entries ) { + file_put_contents( + $output_dir . '/' . $identifier . '.neon', + build_baseline( $entries, $output_dir, build_baseline_header( $identifier, $config_option ) ) + ); + + printf( + "%s: %d entries, %d errors\n", + $output_option . '/' . $identifier . '.neon', + count( $entries ), + count_errors( $entries ) + ); +} + +/* + * An identifier that reports nothing has been driven to zero, so retire its file + * rather than leaving a stale one behind whose entries would then be reported as + * unmatched ignores. + * + * A run restricted to particular identifiers only knows about those, so it may + * only retire those. A full run has seen everything and may retire any file that + * no longer corresponds to a reported identifier. + */ +$retired = $only_identifiers; + +if ( ! $only_identifiers ) { + foreach ( find_baselines( $output_dir ) as $file ) { + $retired[] = basename( $file, '.neon' ); + } +} + +foreach ( $retired as $identifier ) { + if ( isset( $grouped[ $identifier ] ) ) { + continue; + } + + $file = $output_dir . '/' . $identifier . '.neon'; + if ( is_file( $file ) && unlink( $file ) ) { + printf( "%s: no errors remain, file deleted.\n", $output_option . '/' . $identifier . '.neon' ); + } else { + printf( "%s: no errors reported.\n", $identifier ); + } +} + +update_config_includes( $config_path, $config_option, $output_dir ); + +/** + * Returns the usage message. + * + * @return non-falsy-string Usage message. + */ +function get_usage(): string { + return <<<'TEXT' + Generates PHPStan baselines split by error identifier. + + Writes one baseline per identifier, retires any whose identifier no longer + reports anything, and rewrites the list of them between the + `# phpstan:baselines` markers in the configuration's `includes`, so that + neither addition nor removal has to be done by hand. + + Usage: + composer phpstan:baselines [-- ] + + Options: + --identifier= Only write the baseline for this identifier. Repeatable, + or comma separated. When an identifier is named and the + analysis reports none of it, its baseline file is deleted + rather than left behind empty. + Default: every identifier reported. + --config= Configuration to analyze with, relative to the repository + root. Default: phpstan.neon.dist + --output-dir= Where the per-identifier baselines are written, relative + to the repository root. Paths inside them are written + relative to this directory. + Default: tests/phpstan/baselines + --combined Print one combined baseline to stdout instead of writing + per-identifier files. Nothing is written to disk. + --memory-limit= Passed through to PHPStan. Default: 2G + -h, --help Show this message. + + Examples: + Refresh every baseline: + composer phpstan:baselines + + Refresh one: + composer phpstan:baselines -- --identifier=variable.undefined + + Refresh several, either comma separated or by repeating the option: + composer phpstan:baselines -- --identifier=variable.undefined,isset.variable + composer phpstan:baselines -- --identifier=isset.variable --identifier=empty.variable + + Inspect everything as one baseline without writing any files: + composer phpstan:baselines -- --combined + + TEXT; +} + +/** + * Reads a file, failing loudly rather than continuing with false. + * + * @param non-falsy-string $path Absolute path to the file. + * @return string File contents. + */ +function read_file( string $path ): string { + $contents = file_get_contents( $path ); + + if ( false === $contents ) { + fwrite( STDERR, "Could not read $path\n" ); + exit( 1 ); + } + + return $contents; +} + +/** + * Reads a baseline generated in PHPStan's PHP format. + * + * The file returns the entries as an array, so it is required rather than + * parsed. Its `path` values are built from __DIR__ and so arrive absolute. + * + * @param non-falsy-string $path Absolute path to the generated baseline. + * @return list, path: non-empty-string}> Baseline entries. + */ +function read_baseline( string $path ): array { + $data = require $path; + + $parameters = is_array( $data ) ? ( $data['parameters'] ?? null ) : null; + $ignore_errors = is_array( $parameters ) ? ( $parameters['ignoreErrors'] ?? null ) : null; + + if ( ! is_array( $ignore_errors ) ) { + fwrite( STDERR, "Unexpected baseline structure in $path\n" ); + exit( 1 ); + } + + $entries = array(); + + foreach ( $ignore_errors as $entry ) { + if ( ! is_array( $entry ) + || ! isset( $entry['message'], $entry['identifier'], $entry['count'], $entry['path'] ) + || ! is_string( $entry['message'] ) + || ! is_string( $entry['identifier'] ) + || ! is_int( $entry['count'] ) + || $entry['count'] < 0 + || ! is_string( $entry['path'] ) + || '' === $entry['path'] + ) { + fwrite( STDERR, "Unexpected baseline entry in $path.\n" ); + exit( 1 ); + } + + /* + * PHPStan attaches an identifier to every error it reports, so an entry + * without a usable one means this is not a baseline that can be split by + * identifier. Skipping it would quietly drop a suppression. + */ + if ( '' === $entry['identifier'] || '0' === $entry['identifier'] ) { + fwrite( STDERR, "Baseline entry in $path has no identifier.\n" ); + exit( 1 ); + } + + $entries[] = array( + 'message' => $entry['message'], + 'identifier' => $entry['identifier'], + 'count' => $entry['count'], + 'path' => $entry['path'], + ); + } + + return $entries; +} + +/** + * Returns the configuration with any `includes` of the baseline directory removed. + * + * Those files suppress the very errors being regenerated, so they have to be out + * of the way for the analysis to report anything. + * + * @param non-falsy-string $config_path Absolute path to the configuration file. + * @param non-falsy-string $output_dir Absolute path to the baseline directory. + * @return string Configuration contents. + */ +function strip_baseline_includes( string $config_path, string $output_dir ): string { + $config_dir = dirname( $config_path ); + $in_block = false; + $kept = array(); + + foreach ( explode( "\n", read_file( $config_path ) ) as $line ) { + if ( 1 === preg_match( '/^includes:/', $line ) ) { + $in_block = true; + $kept[] = $line; + continue; + } + + // A non-indented, non-blank line ends the block. + if ( $in_block && '' !== trim( $line ) && 1 !== preg_match( '/^\s/', $line ) ) { + $in_block = false; + } + + if ( $in_block && 1 === preg_match( '/^\s*-\s*(\S+)\s*$/', $line, $matches ) ) { + $included = $matches[1]; + $absolute = ( '/' === $included[0] ) ? $included : $config_dir . '/' . $included; + + if ( 0 === strpos( normalize_path( $absolute ), normalize_path( $output_dir ) . '/' ) ) { + continue; + } + } + + $kept[] = $line; + } + + return implode( "\n", $kept ); +} + +/** + * Lists the per-identifier baselines present on disk. + * + * @param non-empty-string $output_dir Absolute path to the baseline directory. + * @return list Absolute paths, sorted by name. + */ +function find_baselines( string $output_dir ): array { + $found = glob( $output_dir . '/*.neon' ); + + if ( false === $found ) { + return array(); + } + + sort( $found ); + + $files = array(); + foreach ( $found as $file ) { + if ( '' !== $file ) { + $files[] = $file; + } + } + + return $files; +} + +/** + * Rewrites the managed region of the configuration's `includes` list. + * + * The region is delimited by marker comments, so the hand written entries around + * it are never touched. Where the markers are absent they are appended to the end + * of the `includes` block, which is what happens the first time this is run + * against a configuration. + * + * @param non-falsy-string $config_path Absolute path to the configuration file. + * @param non-empty-string $config_option Configuration path, as passed on the command line. + * @param non-empty-string $output_dir Absolute path to the baseline directory. + */ +function update_config_includes( string $config_path, string $config_option, string $output_dir ): void { + $start_marker = '# phpstan:baselines start'; + $end_marker = '# phpstan:baselines end'; + + $before = read_file( $config_path ); + $lines = explode( "\n", $before ); + + $start = null; + $end = null; + foreach ( $lines as $i => $line ) { + if ( $start_marker === trim( $line ) ) { + $start = $i; + } + if ( $end_marker === trim( $line ) ) { + $end = $i; + } + } + + $region = array( "\t" . $start_marker ); + foreach ( find_baselines( $output_dir ) as $file ) { + $region[] = "\t- " . get_relative_path( dirname( $config_path ), $file ); + } + $region[] = "\t" . $end_marker; + + if ( null !== $start && null !== $end && $start < $end ) { + $updated = array_merge( + array_slice( $lines, 0, $start ), + $region, + array_slice( $lines, $end + 1 ) + ); + } else { + $insert = find_includes_end( $lines ); + + if ( null === $insert ) { + fwrite( STDERR, "No `includes` block found in $config_option, left untouched.\n" ); + return; + } + + $updated = array_merge( + array_slice( $lines, 0, $insert ), + array( '' ), + $region, + array_slice( $lines, $insert ) + ); + } + + $after = implode( "\n", $updated ); + + if ( $before === $after ) { + return; + } + + file_put_contents( $config_path, $after ); + printf( "%s: `includes` updated.\n", $config_option ); +} + +/** + * Finds where the `includes` block ends. + * + * @param list $lines Configuration lines. + * @return int|null Index of the first line after the block, or null when there is none. + */ +function find_includes_end( array $lines ): ?int { + $in_block = false; + $last = null; + + foreach ( $lines as $i => $line ) { + if ( 1 === preg_match( '/^includes:/', $line ) ) { + $in_block = true; + $last = $i; + continue; + } + + if ( ! $in_block || '' === trim( $line ) ) { + continue; + } + + // A non-indented line ends the block. + if ( 1 !== preg_match( '/^\s/', $line ) ) { + break; + } + + $last = $i; + } + + return null === $last ? null : $last + 1; +} + +/** + * Resolves ".." segments in a path without requiring it to exist. + * + * @param non-empty-string $path Path to normalize. + * @return non-falsy-string Normalized path, always absolute. + */ +function normalize_path( string $path ): string { + $parts = array(); + + foreach ( explode( '/', $path ) as $part ) { + if ( '' === $part || '.' === $part ) { + continue; + } + if ( '..' === $part ) { + array_pop( $parts ); + continue; + } + $parts[] = $part; + } + + return '/' . implode( '/', $parts ); +} + +/** + * Expresses one absolute path relative to a directory. + * + * A result of "0" is possible in principle, when the target is a single segment + * named "0" directly inside $from_dir, so this is non-empty rather than non-falsy. + * + * @param non-empty-string $from_dir Directory to express the path relative to. + * @param non-empty-string $to_path Path to express. + * @return non-empty-string Relative path, or "." when the two are the same. + */ +function get_relative_path( string $from_dir, string $to_path ): string { + $from = explode( '/', trim( normalize_path( $from_dir ), '/' ) ); + $to = explode( '/', trim( normalize_path( $to_path ), '/' ) ); + + while ( $from && $to && $from[0] === $to[0] ) { + array_shift( $from ); + array_shift( $to ); + } + + $relative = str_repeat( '../', count( $from ) ) . implode( '/', $to ); + + return '' === $relative ? '.' : $relative; +} + +/** + * Totals the `count` values across a set of entries. + * + * @param list, path: non-empty-string}> $entries Baseline entries. + * @return int<0, max> Total number of errors. + */ +function count_errors( array $entries ): int { + $total = 0; + + foreach ( $entries as $entry ) { + $total += $entry['count']; + } + + return $total; +} + +/** + * Builds a baseline file in PHPStan's NEON format. + * + * The entry layout matches what PHPStan itself writes, so a regenerated file can + * be diffed against one it produced. Paths are rewritten relative to the file's + * own directory, since that is what a NEON `path` resolves against. + * + * @param list, path: non-empty-string}> $entries Baseline entries. + * @param non-empty-string $output_dir Directory the file is written to. + * @param string $header Comment block, or an empty string. + * @return non-falsy-string Baseline file contents. + */ +function build_baseline( array $entries, string $output_dir, string $header ): string { + $contents = ( '' === $header ? '' : $header . "\n" ) . "parameters:\n\tignoreErrors:\n"; + + foreach ( $entries as $entry ) { + $contents .= "\t\t-\n" + . "\t\t\tmessage: " . quote_neon_value( $entry['message'] ) . "\n" + . "\t\t\tidentifier: " . $entry['identifier'] . "\n" + . "\t\t\tcount: " . $entry['count'] . "\n" + . "\t\t\tpath: " . get_relative_path( $output_dir, $entry['path'] ) . "\n"; + } + + return $contents; +} + +/** + * Quotes a value for NEON. + * + * A single quoted NEON string has no escape sequences other than a doubled + * quote, so the backslashes in a message pattern survive as written. This is the + * same quoting PHPStan applies when it generates a baseline itself. + * + * @param string $value Value to quote. + * @return non-falsy-string Quoted value. + */ +function quote_neon_value( string $value ): string { + return "'" . str_replace( "'", "''", $value ) . "'"; +} + +/** + * Builds the header comment for a per-identifier baseline. + * + * @param non-falsy-string $identifier Error identifier, a group followed by a code. + * @param non-empty-string $config Configuration path, as passed on the command line. + * @return non-falsy-string Comment block. + */ +function build_baseline_header( string $identifier, string $config ): string { + return << Date: Wed, 5 Aug 2026 07:45:41 +0000 Subject: [PATCH 124/138] Build/Test Tools: Raise the PHPStan rule level to 2. This rule level includes: > unknown methods checked on all expressions (not just `$this`), validating PHPDocs Baselines are regenerated for errors at this level. Developed in https://github.com/WordPress/wordpress-develop/pull/12852. Follow-up to r61699, r63019. Props westonruter, apermo. See #64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63020 602fd350-edb4-49c9-b593-d223f7449a82 --- phpstan.neon.dist | 21 +- tests/phpstan/baselines/arguments.count.neon | 50 +++ tests/phpstan/baselines/binaryOp.invalid.neon | 35 ++ tests/phpstan/baselines/class.nameCase.neon | 25 ++ tests/phpstan/baselines/class.notFound.neon | 90 +++++ .../encapsedStringPart.nonString.neon | 25 ++ tests/phpstan/baselines/greater.invalid.neon | 25 ++ tests/phpstan/baselines/method.nonObject.neon | 55 +++ tests/phpstan/baselines/method.notFound.neon | 45 +++ .../baselines/parameter.defaultValue.neon | 105 ++++++ .../phpstan/baselines/parameter.notFound.neon | 35 ++ .../baselines/parameter.phpDocType.neon | 25 ++ .../baselines/parameter.unresolvableType.neon | 25 ++ .../phpstan/baselines/property.nonObject.neon | 255 ++++++++++++++ .../phpstan/baselines/property.notFound.neon | 330 ++++++++++++++++++ tests/phpstan/baselines/property.private.neon | 60 ++++ .../phpstan/baselines/property.protected.neon | 60 ++++ tests/phpstan/baselines/return.missing.neon | 225 ++++++++++++ .../staticClassAccess.privateMethod.neon | 190 ++++++++++ .../phpstan/baselines/varTag.noVariable.neon | 60 ++++ 20 files changed, 1740 insertions(+), 1 deletion(-) create mode 100644 tests/phpstan/baselines/arguments.count.neon create mode 100644 tests/phpstan/baselines/binaryOp.invalid.neon create mode 100644 tests/phpstan/baselines/class.nameCase.neon create mode 100644 tests/phpstan/baselines/class.notFound.neon create mode 100644 tests/phpstan/baselines/encapsedStringPart.nonString.neon create mode 100644 tests/phpstan/baselines/greater.invalid.neon create mode 100644 tests/phpstan/baselines/method.nonObject.neon create mode 100644 tests/phpstan/baselines/method.notFound.neon create mode 100644 tests/phpstan/baselines/parameter.defaultValue.neon create mode 100644 tests/phpstan/baselines/parameter.notFound.neon create mode 100644 tests/phpstan/baselines/parameter.phpDocType.neon create mode 100644 tests/phpstan/baselines/parameter.unresolvableType.neon create mode 100644 tests/phpstan/baselines/property.nonObject.neon create mode 100644 tests/phpstan/baselines/property.notFound.neon create mode 100644 tests/phpstan/baselines/property.private.neon create mode 100644 tests/phpstan/baselines/property.protected.neon create mode 100644 tests/phpstan/baselines/return.missing.neon create mode 100644 tests/phpstan/baselines/staticClassAccess.privateMethod.neon create mode 100644 tests/phpstan/baselines/varTag.noVariable.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 778b24b78c465..e96b6cfd9ce20 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -22,14 +22,33 @@ includes: # Regenerate with `composer phpstan:baselines`, which rewrites both the files # and the list between the markers. Do not edit that list by hand. # phpstan:baselines start + - tests/phpstan/baselines/arguments.count.neon + - tests/phpstan/baselines/binaryOp.invalid.neon + - tests/phpstan/baselines/class.nameCase.neon + - tests/phpstan/baselines/class.notFound.neon - tests/phpstan/baselines/empty.variable.neon + - tests/phpstan/baselines/encapsedStringPart.nonString.neon + - tests/phpstan/baselines/greater.invalid.neon - tests/phpstan/baselines/isset.variable.neon + - tests/phpstan/baselines/method.nonObject.neon + - tests/phpstan/baselines/method.notFound.neon + - tests/phpstan/baselines/parameter.defaultValue.neon + - tests/phpstan/baselines/parameter.notFound.neon + - tests/phpstan/baselines/parameter.phpDocType.neon + - tests/phpstan/baselines/parameter.unresolvableType.neon + - tests/phpstan/baselines/property.nonObject.neon + - tests/phpstan/baselines/property.notFound.neon + - tests/phpstan/baselines/property.private.neon + - tests/phpstan/baselines/property.protected.neon + - tests/phpstan/baselines/return.missing.neon + - tests/phpstan/baselines/staticClassAccess.privateMethod.neon + - tests/phpstan/baselines/varTag.noVariable.neon - tests/phpstan/baselines/variable.undefined.neon # phpstan:baselines end parameters: # https://phpstan.org/user-guide/rule-levels - level: 1 + level: 2 reportUnmatchedIgnoredErrors: true # The following ignored errors are not intended to be fixed, as distinct from the baselines diff --git a/tests/phpstan/baselines/arguments.count.neon b/tests/phpstan/baselines/arguments.count.neon new file mode 100644 index 0000000000000..e3cab51b3621e --- /dev/null +++ b/tests/phpstan/baselines/arguments.count.neon @@ -0,0 +1,50 @@ +# PHPStan baseline for the `arguments.count` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/arguments.count +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=arguments.count +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Method WP_List_Table\:\:display_rows\(\) invoked with 2 parameters, 0 required\.$#' + identifier: arguments.count + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Method WP_List_Table\:\:single_row\(\) invoked with 2 parameters, 1 required\.$#' + identifier: arguments.count + count: 2 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Method WP_List_Table\:\:single_row\(\) invoked with 3 parameters, 1 required\.$#' + identifier: arguments.count + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Method WP_Upgrader_Skin\:\:before\(\) invoked with 1 parameter, 0 required\.$#' + identifier: arguments.count + count: 2 + path: ../../../src/wp-admin/includes/class-plugin-upgrader.php + - + message: '#^Method WP_Upgrader_Skin\:\:before\(\) invoked with 1 parameter, 0 required\.$#' + identifier: arguments.count + count: 2 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Method WP_List_Table\:\:display\(\) invoked with 1 parameter, 0 required\.$#' + identifier: arguments.count + count: 1 + path: ../../../src/wp-admin/includes/meta-boxes.php diff --git a/tests/phpstan/baselines/binaryOp.invalid.neon b/tests/phpstan/baselines/binaryOp.invalid.neon new file mode 100644 index 0000000000000..167f159cffb34 --- /dev/null +++ b/tests/phpstan/baselines/binaryOp.invalid.neon @@ -0,0 +1,35 @@ +# PHPStan baseline for the `binaryOp.invalid` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/binaryOp.invalid +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=binaryOp.invalid +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Binary operation "/" between string and 2 results in an error\.$#' + identifier: binaryOp.invalid + count: 2 + path: ../../../src/wp-content/themes/twentytwenty/functions.php + - + message: '#^Binary operation "\+" between array\\|WP_Comment\>\|int\<1, max\> and 1 results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Binary operation "\+" between string and int results in an error\.$#' + identifier: binaryOp.invalid + count: 1 + path: ../../../src/wp-includes/user.php diff --git a/tests/phpstan/baselines/class.nameCase.neon b/tests/phpstan/baselines/class.nameCase.neon new file mode 100644 index 0000000000000..dd88c5b677aa8 --- /dev/null +++ b/tests/phpstan/baselines/class.nameCase.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `class.nameCase` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/class.nameCase +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=class.nameCase +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Class MO referenced with incorrect case\: Mo\.$#' + identifier: class.nameCase + count: 1 + path: ../../../src/wp-includes/class-wp-locale-switcher.php diff --git a/tests/phpstan/baselines/class.notFound.neon b/tests/phpstan/baselines/class.notFound.neon new file mode 100644 index 0000000000000..560ceafb56573 --- /dev/null +++ b/tests/phpstan/baselines/class.notFound.neon @@ -0,0 +1,90 @@ +# PHPStan baseline for the `class.notFound` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/class.notFound +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=class.notFound +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_Filesystem_FTPext\:\:\$link has unknown class FTP\\Connection as its type\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-filesystem-ftpext.php + - + message: '#^Function _crop_image_resource\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Function _flip_image_resource\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Function _rotate_image_resource\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \$img of function _crop_image_resource\(\) has invalid type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \$img of function _flip_image_resource\(\) has invalid type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \$img of function _rotate_image_resource\(\) has invalid type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Function load_image_to_edit\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/includes/image.php + - + message: '#^Call to method html\(\) on an unknown class WP_Press_This_Plugin\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-admin/press-this.php + - + message: '#^Method WP_Image_Editor_GD\:\:_resize\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-gd.php + - + message: '#^Parameter \$image of method WP_Image_Editor_GD\:\:_save\(\) has invalid type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-gd.php + - + message: '#^Property WP_Image_Editor_GD\:\:\$image has unknown class GdImage as its type\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-gd.php + - + message: '#^Function wp_imagecreatetruecolor\(\) has invalid return type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-includes/media.php + - + message: '#^Parameter \$image of function is_gd_image\(\) has invalid type GdImage\.$#' + identifier: class.notFound + count: 1 + path: ../../../src/wp-includes/media.php diff --git a/tests/phpstan/baselines/encapsedStringPart.nonString.neon b/tests/phpstan/baselines/encapsedStringPart.nonString.neon new file mode 100644 index 0000000000000..707a2192a4c8a --- /dev/null +++ b/tests/phpstan/baselines/encapsedStringPart.nonString.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `encapsedStringPart.nonString` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/encapsedStringPart.nonString +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=encapsedStringPart.nonString +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Part \$form_fields\[''_final''\] \(non\-empty\-array\\) of encapsed string cannot be cast to string\.$#' + identifier: encapsedStringPart.nonString + count: 1 + path: ../../../src/wp-admin/includes/media.php diff --git a/tests/phpstan/baselines/greater.invalid.neon b/tests/phpstan/baselines/greater.invalid.neon new file mode 100644 index 0000000000000..bf9ca0aa0250f --- /dev/null +++ b/tests/phpstan/baselines/greater.invalid.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `greater.invalid` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/greater.invalid +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=greater.invalid +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Comparison operation "\>" between \*NEVER\* and 0 results in an error\.$#' + identifier: greater.invalid + count: 1 + path: ../../../src/wp-admin/includes/upgrade.php diff --git a/tests/phpstan/baselines/method.nonObject.neon b/tests/phpstan/baselines/method.nonObject.neon new file mode 100644 index 0000000000000..4d0727f8950f1 --- /dev/null +++ b/tests/phpstan/baselines/method.nonObject.neon @@ -0,0 +1,55 @@ +# PHPStan baseline for the `method.nonObject` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/method.nonObject +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=method.nonObject +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Cannot call method inline_edit\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/edit-tags.php + - + message: '#^Cannot call method inline_edit\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/edit.php + - + message: '#^Cannot call method embed_scripts\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/erase-personal-data.php + - + message: '#^Cannot call method process_bulk_action\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/erase-personal-data.php + - + message: '#^Cannot call method embed_scripts\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/export-personal-data.php + - + message: '#^Cannot call method process_bulk_action\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/export-personal-data.php + - + message: '#^Cannot call method theme_installer_single\(\) on WP_List_Table\|false\.$#' + identifier: method.nonObject + count: 1 + path: ../../../src/wp-admin/includes/theme-install.php diff --git a/tests/phpstan/baselines/method.notFound.neon b/tests/phpstan/baselines/method.notFound.neon new file mode 100644 index 0000000000000..5d6bccb070ecb --- /dev/null +++ b/tests/phpstan/baselines/method.notFound.neon @@ -0,0 +1,45 @@ +# PHPStan baseline for the `method.notFound` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/method.notFound +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=method.notFound +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Call to an undefined method WP_Upgrader\:\:get_name_for_update\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-language-pack-upgrader-skin.php + - + message: '#^Call to an undefined method WP_Upgrader\:\:plugin_info\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-plugin-installer-skin.php + - + message: '#^Call to an undefined method WP_Upgrader\:\:plugin_info\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-plugin-upgrader-skin.php + - + message: '#^Call to an undefined method WP_Upgrader\:\:theme_info\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-theme-installer-skin.php + - + message: '#^Call to an undefined method WP_Upgrader\:\:theme_info\(\)\.$#' + identifier: method.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-theme-upgrader-skin.php diff --git a/tests/phpstan/baselines/parameter.defaultValue.neon b/tests/phpstan/baselines/parameter.defaultValue.neon new file mode 100644 index 0000000000000..34b6b678fc447 --- /dev/null +++ b/tests/phpstan/baselines/parameter.defaultValue.neon @@ -0,0 +1,105 @@ +# PHPStan baseline for the `parameter.defaultValue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameter.defaultValue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameter.defaultValue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Default value of the parameter \#1 \$admin_header_callback \(''''\) of method Custom_Background\:\:__construct\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/class-custom-background.php + - + message: '#^Default value of the parameter \#2 \$admin_image_div_callback \(''''\) of method Custom_Background\:\:__construct\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/class-custom-background.php + - + message: '#^Default value of the parameter \#2 \$admin_image_div_callback \(''''\) of method Custom_Image_Header\:\:__construct\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/class-custom-image-header.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_comments_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_dashboard_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_links_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_management_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_media_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_menu_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_options_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_pages_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_plugins_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_posts_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_theme_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#5 \$callback \(''''\) of function add_users_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#6 \$callback \(''''\) of function add_submenu_page\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Default value of the parameter \#3 \$deprecated \(''''\) of function unregister_setting\(\) is incompatible with type callable\(\)\: mixed\.$#' + identifier: parameter.defaultValue + count: 1 + path: ../../../src/wp-includes/option.php diff --git a/tests/phpstan/baselines/parameter.notFound.neon b/tests/phpstan/baselines/parameter.notFound.neon new file mode 100644 index 0000000000000..c3835cd7903c4 --- /dev/null +++ b/tests/phpstan/baselines/parameter.notFound.neon @@ -0,0 +1,35 @@ +# PHPStan baseline for the `parameter.notFound` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameter.notFound +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameter.notFound +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^PHPDoc tag @param references unknown parameter\: \$key$#' + identifier: parameter.notFound + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^PHPDoc tag @param references unknown parameter\: \$url$#' + identifier: parameter.notFound + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^PHPDoc tag @param references unknown parameter\: \$value$#' + identifier: parameter.notFound + count: 1 + path: ../../../src/wp-includes/functions.php diff --git a/tests/phpstan/baselines/parameter.phpDocType.neon b/tests/phpstan/baselines/parameter.phpDocType.neon new file mode 100644 index 0000000000000..db8a7f3b32466 --- /dev/null +++ b/tests/phpstan/baselines/parameter.phpDocType.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `parameter.phpDocType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameter.phpDocType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameter.phpDocType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^PHPDoc tag @param for parameter \$block_type with type array\ is incompatible with native type string\.$#' + identifier: parameter.phpDocType + count: 1 + path: ../../../src/wp-includes/class-wp-block-processor.php diff --git a/tests/phpstan/baselines/parameter.unresolvableType.neon b/tests/phpstan/baselines/parameter.unresolvableType.neon new file mode 100644 index 0000000000000..1193e163ca555 --- /dev/null +++ b/tests/phpstan/baselines/parameter.unresolvableType.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `parameter.unresolvableType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameter.unresolvableType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameter.unresolvableType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^PHPDoc tag @param for parameter \$type contains unresolvable type\.$#' + identifier: parameter.unresolvableType + count: 1 + path: ../../../src/wp-includes/class-wp-feed-cache-transient.php diff --git a/tests/phpstan/baselines/property.nonObject.neon b/tests/phpstan/baselines/property.nonObject.neon new file mode 100644 index 0000000000000..81a4af3e09511 --- /dev/null +++ b/tests/phpstan/baselines/property.nonObject.neon @@ -0,0 +1,255 @@ +# PHPStan baseline for the `property.nonObject` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.nonObject +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.nonObject +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Cannot access property \$download_link on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Cannot access property \$id on int\|string\|WP_Term\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Cannot access property \$link on int\|string\|WP_Term\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Cannot access property \$name on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Cannot access property \$themes on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Cannot access property \$download_link on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Cannot access property \$name on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Cannot access property \$version on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Cannot access property \$current on array\|object\.$#' + identifier: property.nonObject + count: 3 + path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php + - + message: '#^Cannot access property \$response on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php + - + message: '#^Cannot access property \$version on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php + - + message: '#^Cannot access property \$info on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-plugin-install-list-table.php + - + message: '#^Cannot access property \$plugins on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-plugin-install-list-table.php + - + message: '#^Cannot access property \$parent on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-terms-list-table.php + - + message: '#^Cannot access property \$term_id on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/class-wp-terms-list-table.php + - + message: '#^Cannot access property \$info on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-theme-install-list-table.php + - + message: '#^Cannot access property \$themes on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/class-wp-theme-install-list-table.php + - + message: '#^Cannot access property \$author on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$downloaded on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$external on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$homepage on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$name on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$requires on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$sections on array\|object\.$#' + identifier: property.nonObject + count: 5 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$slug on array\|object\.$#' + identifier: property.nonObject + count: 3 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$tested on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$version on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Cannot access property \$meta_key on object\|true\.$#' + identifier: property.nonObject + count: 4 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Cannot access property \$post_id on object\|true\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Cannot access property \$download_link on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/update.php + - + message: '#^Cannot access property \$name on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/update.php + - + message: '#^Cannot access property \$version on array\|object\.$#' + identifier: property.nonObject + count: 2 + path: ../../../src/wp-admin/update.php + - + message: '#^Cannot access property \$comment_shortcuts on WP_User\|false\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/user-edit.php + - + message: '#^Cannot access property \$infinite_scrolling on WP_User\|false\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-admin/user-edit.php + - + message: '#^Cannot access property \$id on int\|string\|WP_Term\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/category-template.php + - + message: '#^Cannot access property \$link on int\|string\|WP_Term\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/category-template.php + - + message: '#^Cannot access property \$themes on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Cannot access property \$object_id on array\|WP_Error\|WP_Term\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/class-wp-term-query.php + - + message: '#^Cannot access property \$term_id on string\|WP_Customize_Setting\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-control.php + - + message: '#^Cannot access property \$link_id on array\|object\.$#' + identifier: property.nonObject + count: 3 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Cannot access property \$plugins on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-block-directory-controller.php + - + message: '#^Cannot access property \$auto_add on WP_Term\|false\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-menus-controller.php + - + message: '#^Cannot access property \$download_link on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php + - + message: '#^Cannot access property \$language_packs on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php + - + message: '#^Cannot access property \$parent on array\|object\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Cannot access property \$template_name on array\.$#' + identifier: property.nonObject + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Cannot access property \$term_id on array\|object\.$#' + identifier: property.nonObject + count: 4 + path: ../../../src/wp-includes/taxonomy.php diff --git a/tests/phpstan/baselines/property.notFound.neon b/tests/phpstan/baselines/property.notFound.neon new file mode 100644 index 0000000000000..7893a2dd24bb6 --- /dev/null +++ b/tests/phpstan/baselines/property.notFound.neon @@ -0,0 +1,330 @@ +# PHPStan baseline for the `property.notFound` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.notFound +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.notFound +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$language_update\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/class-language-pack-upgrader.php + - + message: '#^Access to an undefined property WP_Upgrader\:\:\$new_plugin_data\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-plugin-installer-skin.php + - + message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$plugin_active\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-plugin-upgrader.php + - + message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$plugin_info\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-plugin-upgrader.php + - + message: '#^Access to an undefined property WP_Upgrader\:\:\$new_theme_data\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-theme-installer-skin.php + - + message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$api\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Access to an undefined property WP_Upgrader_Skin\:\:\$theme_info\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-theme-upgrader.php + - + message: '#^Access to an undefined property WP_Post\:\:\$attr_title\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$menu_item_parent\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$object\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$object_id\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$target\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$title\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$type\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$xfn\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$description\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$menu_item_parent\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$object\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$object_id\.$#' + identifier: property.notFound + count: 3 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$target\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$title\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$type\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$type_label\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Post\:\:\$xfn\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$author\.$#' + identifier: property.notFound + count: 3 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$name\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$parent_theme\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$version\.$#' + identifier: property.notFound + count: 5 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$auto_update_forced\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-ms-themes-list-table.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$update_supported\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-ms-themes-list-table.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$name\.$#' + identifier: property.notFound + count: 8 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Access to an undefined property WP_Post\:\:\$_wp_attachment_image_alt\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/includes/image.php + - + message: '#^Access to an undefined property WP_Post\:\:\$front_or_home\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^Access to an undefined property WP_Post\:\:\$privacy_policy_page\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^Access to an undefined property wpdb\:\:\$categories\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-admin/includes/upgrade.php + - + message: '#^Access to an undefined property wpdb\:\:\$link2cat\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/includes/upgrade.php + - + message: '#^Access to an undefined property wpdb\:\:\$post2cat\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-admin/includes/upgrade.php + - + message: '#^Access to an undefined property WP_Term\:\:\$truncated_name\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-admin/nav-menus.php + - + message: '#^Access to an undefined property WP_Theme\:\:\$version\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-admin/update-core.php + - + message: '#^Access to an undefined property WP_Post\:\:\$description\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/functions.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-content/themes/twentynineteen/inc/icon-functions.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/inc/icon-functions.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/inc/template-functions.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/inc/icon-functions.php + - + message: '#^Access to an undefined property WP_Post\:\:\$classes\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-content/themes/twentytwenty/inc/template-tags.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/inc/template-tags.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/inc/menu-functions.php + - + message: '#^Access to an undefined property WP_Post_Type\:\:\$capabilities\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-includes/capabilities.php + - + message: '#^Access to an undefined property WP_Term\:\:\$link\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-includes/category-template.php + - + message: '#^Access to an undefined property WP_Post\:\:\$current\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Access to an undefined property WP_Post\:\:\$title\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Access to an undefined property WP_Query\:\:\$comments_by_type\.$#' + identifier: property.notFound + count: 3 + path: ../../../src/wp-includes/comment-template.php + - + message: '#^Access to an undefined property WP_Post\:\:\$attr_title\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Access to an undefined property WP_Post\:\:\$db_id\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Access to an undefined property WP_Post\:\:\$description\.$#' + identifier: property.notFound + count: 2 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Access to an undefined property WP_Post\:\:\$type\.$#' + identifier: property.notFound + count: 3 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Access to an undefined property WP_Post\:\:\$type_label\.$#' + identifier: property.notFound + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Access to an undefined property WP_Post\:\:\$url\.$#' + identifier: property.notFound + count: 4 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php diff --git a/tests/phpstan/baselines/property.private.neon b/tests/phpstan/baselines/property.private.neon new file mode 100644 index 0000000000000..900a8e51dc423 --- /dev/null +++ b/tests/phpstan/baselines/property.private.neon @@ -0,0 +1,60 @@ +# PHPStan baseline for the `property.private` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.private +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.private +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Access to private property WP_Theme\:\:\$stylesheet\.$#' + identifier: property.private + count: 20 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to private property WP_Theme\:\:\$template\.$#' + identifier: property.private + count: 2 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to private property WP_Block_Type\:\:\$uses_context\.$#' + identifier: property.private + count: 1 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Access to private property WP_Block_Type\:\:\$variations\.$#' + identifier: property.private + count: 1 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Access to private property WP_Block_Type\:\:\$uses_context\.$#' + identifier: property.private + count: 1 + path: ../../../src/wp-includes/class-wp-block.php + - + message: '#^Access to private property WP_Object_Cache\:\:\$cache\.$#' + identifier: property.private + count: 2 + path: ../../../src/wp-includes/ms-blogs.php + - + message: '#^Access to private property WP_Block_Type\:\:\$uses_context\.$#' + identifier: property.private + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php + - + message: '#^Access to private property WP_Block_Type\:\:\$variations\.$#' + identifier: property.private + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-block-types-controller.php diff --git a/tests/phpstan/baselines/property.protected.neon b/tests/phpstan/baselines/property.protected.neon new file mode 100644 index 0000000000000..b29d125bd2a7a --- /dev/null +++ b/tests/phpstan/baselines/property.protected.neon @@ -0,0 +1,60 @@ +# PHPStan baseline for the `property.protected` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.protected +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.protected +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Access to protected property WP_List_Table\:\:\$screen\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/erase-personal-data.php + - + message: '#^Access to protected property WP_List_Table\:\:\$screen\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/export-personal-data.php + - + message: '#^Access to protected property WP_List_Table\:\:\$screen\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Access to protected property wpdb\:\:\$dbh\.$#' + identifier: property.protected + count: 3 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to protected property wpdb\:\:\$dbhost\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to protected property wpdb\:\:\$dbname\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to protected property wpdb\:\:\$dbuser\.$#' + identifier: property.protected + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Access to protected property WP_Object_Cache\:\:\$global_groups\.$#' + identifier: property.protected + count: 2 + path: ../../../src/wp-includes/ms-blogs.php diff --git a/tests/phpstan/baselines/return.missing.neon b/tests/phpstan/baselines/return.missing.neon new file mode 100644 index 0000000000000..11bb654bafb2c --- /dev/null +++ b/tests/phpstan/baselines/return.missing.neon @@ -0,0 +1,225 @@ +# PHPStan baseline for the `return.missing` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/return.missing +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=return.missing +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Method Twenty_Eleven_Ephemera_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php + - + message: '#^Method Twenty_Fourteen_Ephemera_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php + - + message: '#^Function get_category_by_path\(\) should return array\|WP_Error\|WP_Term\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/category.php + - + message: '#^Method WP_Customize_Manager\:\:get_control\(\) should return WP_Customize_Control\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Method WP_Customize_Manager\:\:get_panel\(\) should return WP_Customize_Panel\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Method WP_Customize_Manager\:\:get_section\(\) should return WP_Customize_Section\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Method WP_Customize_Manager\:\:get_setting\(\) should return WP_Customize_Setting\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Method WP_Customize_Widgets\:\:get_setting_type\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-customize-widgets.php + - + message: '#^Method WP_Image_Editor_Imagick\:\:set_imagick_time_limit\(\) should return int\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Method WP_Customize_Header_Image_Control\:\:get_current_image_src\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-header-image-control.php + - + message: '#^Function post_type_archive_title\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function single_month_title\(\) should return string\|false\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function single_post_title\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function single_term_title\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function the_date\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function the_modified_date\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function wp_title\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function edit_term_link\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function get_next_posts_link\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function get_next_posts_page_link\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 2 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function get_previous_posts_link\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function get_previous_posts_page_link\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function next_posts\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function previous_posts\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Function wp_list_users\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/user.php + - + message: '#^Method WP_Nav_Menu_Widget\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-nav-menu-widget.php + - + message: '#^Method WP_Widget_Archives\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-archives.php + - + message: '#^Method WP_Widget_Block\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-block.php + - + message: '#^Method WP_Widget_Calendar\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-calendar.php + - + message: '#^Method WP_Widget_Categories\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-categories.php + - + message: '#^Method WP_Widget_Custom_HTML\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-custom-html.php + - + message: '#^Method WP_Widget_Links\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-links.php + - + message: '#^Method WP_Widget_Media\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-media.php + - + message: '#^Method WP_Widget_Meta\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-meta.php + - + message: '#^Method WP_Widget_Pages\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-pages.php + - + message: '#^Method WP_Widget_Recent_Comments\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-recent-comments.php + - + message: '#^Method WP_Widget_Recent_Posts\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-recent-posts.php + - + message: '#^Method WP_Widget_RSS\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-rss.php + - + message: '#^Method WP_Widget_Search\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-search.php + - + message: '#^Method WP_Widget_Tag_Cloud\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 2 + path: ../../../src/wp-includes/widgets/class-wp-widget-tag-cloud.php + - + message: '#^Method WP_Widget_Text\:\:form\(\) should return string\|null but return statement is missing\.$#' + identifier: return.missing + count: 2 + path: ../../../src/wp-includes/widgets/class-wp-widget-text.php diff --git a/tests/phpstan/baselines/staticClassAccess.privateMethod.neon b/tests/phpstan/baselines/staticClassAccess.privateMethod.neon new file mode 100644 index 0000000000000..c3a8969643a94 --- /dev/null +++ b/tests/phpstan/baselines/staticClassAccess.privateMethod.neon @@ -0,0 +1,190 @@ +# PHPStan baseline for the `staticClassAccess.privateMethod` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/staticClassAccess.privateMethod +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=staticClassAccess.privateMethod +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Unsafe call to private method WP_Classic_To_Block_Menu_Converter\:\:group_by_parent_id\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-classic-to-block-menu-converter.php + - + message: '#^Unsafe call to private method WP_Classic_To_Block_Menu_Converter\:\:to_blocks\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-classic-to-block-menu-converter.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:create_classic_menu_fallback\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:create_default_fallback\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_default_fallback_blocks\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_fallback_classic_menu\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_most_recently_created_nav_menu\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_most_recently_published_navigation\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 3 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_nav_menu_at_primary_location\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Navigation_Fallback\:\:get_nav_menu_with_primary_slug\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-navigation-fallback.php + - + message: '#^Unsafe call to private method WP_Theme_JSON_Resolver\:\:inject_variations_from_block_style_variation_files\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Unsafe call to private method WP_Theme_JSON_Resolver\:\:inject_variations_from_block_styles_registry\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Unsafe call to private method WP_Theme_JSON_Resolver\:\:recursively_iterate_json\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Unsafe call to private method WP_Theme_JSON_Resolver\:\:remove_json_comments\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Unsafe call to private method WP_Theme_JSON_Resolver\:\:style_variation_has_scope\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:compute_spacing_sizes\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 3 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_block_name_from_metadata_path\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_block_nodes\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 3 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_feature_selector\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:get_viewport_breakpoint_value_in_pixels\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:is_valid_viewport_breakpoint_size\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:merge_spacing_sizes\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:remove_indirect_properties\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:resolve_custom_css_format\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:sanitize_viewport_settings\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 3 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:unwrap_shared_block_style_variations\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_button_width_declarations\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 4 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_paragraph_text_indent_selector\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 4 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Theme_JSON\:\:update_separator_declarations\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Unsafe call to private method WP_Font_Face_Resolver\:\:convert_font_face_properties\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-face-resolver.php + - + message: '#^Unsafe call to private method WP_Font_Face_Resolver\:\:maybe_parse_name_from_comma_separated_list\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-face-resolver.php + - + message: '#^Unsafe call to private method WP_Font_Face_Resolver\:\:parse_settings\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 2 + path: ../../../src/wp-includes/fonts/class-wp-font-face-resolver.php + - + message: '#^Unsafe call to private method WP_Font_Face_Resolver\:\:to_kebab_case\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-face-resolver.php + - + message: '#^Unsafe call to private method WP_Font_Face_Resolver\:\:to_theme_file_uri\(\) through static\:\:\.$#' + identifier: staticClassAccess.privateMethod + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-face-resolver.php diff --git a/tests/phpstan/baselines/varTag.noVariable.neon b/tests/phpstan/baselines/varTag.noVariable.neon new file mode 100644 index 0000000000000..36e0f9fed1382 --- /dev/null +++ b/tests/phpstan/baselines/varTag.noVariable.neon @@ -0,0 +1,60 @@ +# PHPStan baseline for the `varTag.noVariable` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/varTag.noVariable +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=varTag.noVariable +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/wp-admin/install.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/wp-admin/profile.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/wp-admin/upgrade.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/wp-cron.php + - + message: '#^PHPDoc tag @var above assignment does not specify variable name\.$#' + identifier: varTag.noVariable + count: 9 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/wp-includes/kses.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 2 + path: ../../../src/wp-includes/rest-api.php + - + message: '#^PHPDoc tag @var does not specify variable name\.$#' + identifier: varTag.noVariable + count: 1 + path: ../../../src/xmlrpc.php From 8eda2df3613877b3cdfd70806f7f1ced303524ff Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 07:50:07 +0000 Subject: [PATCH 125/138] Build/Test Tools: Raise the PHPStan rule level to 3. This rule level includes: > return types, types assigned to properties Baselines are regenerated for errors at this level. Follow-up to r61699, r63019, r63020. Props westonruter, apermo. See Core-64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63021 602fd350-edb4-49c9-b593-d223f7449a82 --- phpstan.neon.dist | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/phpstan.neon.dist b/phpstan.neon.dist index e96b6cfd9ce20..43e42c278a7ce 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -23,24 +23,35 @@ includes: # and the list between the markers. Do not edit that list by hand. # phpstan:baselines start - tests/phpstan/baselines/arguments.count.neon + - tests/phpstan/baselines/assign.propertyType.neon - tests/phpstan/baselines/binaryOp.invalid.neon - tests/phpstan/baselines/class.nameCase.neon - tests/phpstan/baselines/class.notFound.neon - tests/phpstan/baselines/empty.variable.neon - tests/phpstan/baselines/encapsedStringPart.nonString.neon + - tests/phpstan/baselines/foreach.nonIterable.neon - tests/phpstan/baselines/greater.invalid.neon - tests/phpstan/baselines/isset.variable.neon + - tests/phpstan/baselines/method.childParameterType.neon - tests/phpstan/baselines/method.nonObject.neon - tests/phpstan/baselines/method.notFound.neon + - tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon + - tests/phpstan/baselines/offsetAccess.notFound.neon + - tests/phpstan/baselines/offsetAssign.valueType.neon - tests/phpstan/baselines/parameter.defaultValue.neon - tests/phpstan/baselines/parameter.notFound.neon - tests/phpstan/baselines/parameter.phpDocType.neon - tests/phpstan/baselines/parameter.unresolvableType.neon + - tests/phpstan/baselines/parameterByRef.type.neon + - tests/phpstan/baselines/property.defaultValue.neon - tests/phpstan/baselines/property.nonObject.neon - tests/phpstan/baselines/property.notFound.neon + - tests/phpstan/baselines/property.phpDocType.neon - tests/phpstan/baselines/property.private.neon - tests/phpstan/baselines/property.protected.neon + - tests/phpstan/baselines/return.empty.neon - tests/phpstan/baselines/return.missing.neon + - tests/phpstan/baselines/return.type.neon - tests/phpstan/baselines/staticClassAccess.privateMethod.neon - tests/phpstan/baselines/varTag.noVariable.neon - tests/phpstan/baselines/variable.undefined.neon @@ -48,7 +59,7 @@ includes: parameters: # https://phpstan.org/user-guide/rule-levels - level: 2 + level: 3 reportUnmatchedIgnoredErrors: true # The following ignored errors are not intended to be fixed, as distinct from the baselines From 194916fc381837f638e2784d71bd189b8856f3ad Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 08:00:29 +0000 Subject: [PATCH 126/138] Build/Test Tools: Add missing baselines from PHPStan level 3 bump. Follow-up to r63021. See #64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63022 602fd350-edb4-49c9-b593-d223f7449a82 --- .../baselines/assign.propertyType.neon | 160 +++++++++++++++++ .../baselines/foreach.nonIterable.neon | 25 +++ .../baselines/method.childParameterType.neon | 55 ++++++ .../offsetAccess.nonOffsetAccessible.neon | 35 ++++ .../baselines/offsetAccess.notFound.neon | 40 +++++ .../baselines/offsetAssign.valueType.neon | 25 +++ .../baselines/parameterByRef.type.neon | 50 ++++++ .../baselines/property.defaultValue.neon | 110 ++++++++++++ .../baselines/property.phpDocType.neon | 45 +++++ tests/phpstan/baselines/return.empty.neon | 30 ++++ tests/phpstan/baselines/return.type.neon | 165 ++++++++++++++++++ 11 files changed, 740 insertions(+) create mode 100644 tests/phpstan/baselines/assign.propertyType.neon create mode 100644 tests/phpstan/baselines/foreach.nonIterable.neon create mode 100644 tests/phpstan/baselines/method.childParameterType.neon create mode 100644 tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon create mode 100644 tests/phpstan/baselines/offsetAccess.notFound.neon create mode 100644 tests/phpstan/baselines/offsetAssign.valueType.neon create mode 100644 tests/phpstan/baselines/parameterByRef.type.neon create mode 100644 tests/phpstan/baselines/property.defaultValue.neon create mode 100644 tests/phpstan/baselines/property.phpDocType.neon create mode 100644 tests/phpstan/baselines/return.empty.neon create mode 100644 tests/phpstan/baselines/return.type.neon diff --git a/tests/phpstan/baselines/assign.propertyType.neon b/tests/phpstan/baselines/assign.propertyType.neon new file mode 100644 index 0000000000000..f53f802b7d1da --- /dev/null +++ b/tests/phpstan/baselines/assign.propertyType.neon @@ -0,0 +1,160 @@ +# PHPStan baseline for the `assign.propertyType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/assign.propertyType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=assign.propertyType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_Comment\:\:\$comment_ID \(numeric\-string\) does not accept int\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-admin/includes/comment.php + - + message: '#^Property WP_Comment\:\:\$comment_post_ID \(numeric\-string\) does not accept int\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-admin/includes/comment.php + - + message: '#^Property WP_Block_Template\:\:\$author \(int\|null\) does not accept string\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/block-template-utils.php + - + message: '#^Property WP_Customize_Control\:\:\$settings \(array\) does not accept string\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-customize-control.php + - + message: '#^Property WP_Customize_Setting\:\:\$default \(string\) does not accept stdClass\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-customize-setting.php + - + message: '#^Property WP_Image_Editor_Imagick\:\:\$image \(Imagick\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Property WP_Query\:\:\$posts \(array\\|null\) does not accept array\\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Property WP_Query\:\:\$posts \(array\\|null\) does not accept list\\|null\.$#' + identifier: assign.propertyType + count: 2 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Property WP_Query\:\:\$posts \(array\\|null\) does not accept list\\.$#' + identifier: assign.propertyType + count: 2 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Property WP_Rewrite\:\:\$rules \(array\\) does not accept string\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-rewrite.php + - + message: '#^Property WP_Term_Query\:\:\$terms \(array\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-term-query.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$blocks \(WP_Theme_JSON\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$core \(WP_Theme_JSON\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$i18n_schema \(array\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$theme \(WP_Theme_JSON\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$user \(WP_Theme_JSON\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Static property WP_Theme_JSON_Resolver\:\:\$user_custom_post_type_id \(int\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json-resolver.php + - + message: '#^Property WP_User\:\:\$roles \(array\\) does not accept array\\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wp-user.php + - + message: '#^Property wpdb\:\:\$col_info \(array\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wpdb.php + - + message: '#^Property wpdb\:\:\$last_query \(string\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/class-wpdb.php + - + message: '#^Property WP_Customize_Header_Image_Control\:\:\$default_headers \(string\) does not accept array\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-header-image-control.php + - + message: '#^Property WP_Customize_Header_Image_Control\:\:\$uploaded_headers \(string\) does not accept array\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-header-image-control.php + - + message: '#^Property WP_HTML_Tag_Processor\:\:\$is_closing_tag \(bool\) does not accept null\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Property WP_Translation_File\:\:\$entries \(array\\) does not accept array\\>\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/l10n/class-wp-translation-file.php + - + message: '#^Property WP_REST_Autosaves_Controller\:\:\$revisions_controller \(WP_REST_Revisions_Controller\) does not accept WP_REST_Controller\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php + - + message: '#^Property WP_REST_Template_Autosaves_Controller\:\:\$revisions_controller \(WP_REST_Revisions_Controller\) does not accept WP_REST_Controller\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php + - + message: '#^Property WP_Taxonomy\:\:\$labels \(stdClass\) does not accept array\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Static property WP_Widget_Media\:\:\$l10n_defaults \(array\\) does not accept array\\.$#' + identifier: assign.propertyType + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-media.php diff --git a/tests/phpstan/baselines/foreach.nonIterable.neon b/tests/phpstan/baselines/foreach.nonIterable.neon new file mode 100644 index 0000000000000..be8bba17a113c --- /dev/null +++ b/tests/phpstan/baselines/foreach.nonIterable.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `foreach.nonIterable` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/foreach.nonIterable +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=foreach.nonIterable +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Argument of an invalid type stdClass supplied for foreach, only iterables are supported\.$#' + identifier: foreach.nonIterable + count: 1 + path: ../../../src/wp-includes/class-wp-post-type.php diff --git a/tests/phpstan/baselines/method.childParameterType.neon b/tests/phpstan/baselines/method.childParameterType.neon new file mode 100644 index 0000000000000..7ddc1325be94c --- /dev/null +++ b/tests/phpstan/baselines/method.childParameterType.neon @@ -0,0 +1,55 @@ +# PHPStan baseline for the `method.childParameterType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/method.childParameterType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=method.childParameterType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Parameter \#1 \$comment_status \(bool\) of method WP_Post_Comments_List_Table\:\:get_per_page\(\) should be compatible with parameter \$comment_status \(string\) of method WP_Comments_List_Table\:\:get_per_page\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-admin/includes/class-wp-post-comments-list-table.php + - + message: '#^Parameter \#3 \$args \(stdClass\) of method Walker_Nav_Menu\:\:end_lvl\(\) should be compatible with parameter \$args \(array\) of method Walker\:\:end_lvl\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Parameter \#3 \$args \(stdClass\) of method Walker_Nav_Menu\:\:start_lvl\(\) should be compatible with parameter \$args \(array\) of method Walker\:\:start_lvl\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Parameter \#4 \$args \(stdClass\) of method Walker_Nav_Menu\:\:end_el\(\) should be compatible with parameter \$args \(array\) of method Walker\:\:end_el\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Parameter \#4 \$args \(stdClass\) of method Walker_Nav_Menu\:\:start_el\(\) should be compatible with parameter \$args \(array\) of method Walker\:\:start_el\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Parameter \#1 \$id \(int\) of method WP_REST_Global_Styles_Controller\:\:prepare_links\(\) should be compatible with parameter \$post \(WP_Post\) of method WP_REST_Posts_Controller\:\:prepare_links\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-controller.php + - + message: '#^Parameter \#1 \$parent_template_id \(string\) of method WP_REST_Template_Revisions_Controller\:\:get_parent\(\) should be compatible with parameter \$parent_post_id \(int\) of method WP_REST_Revisions_Controller\:\:get_parent\(\)$#' + identifier: method.childParameterType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-template-revisions-controller.php diff --git a/tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon b/tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon new file mode 100644 index 0000000000000..5b2396b941816 --- /dev/null +++ b/tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon @@ -0,0 +1,35 @@ +# PHPStan baseline for the `offsetAccess.nonOffsetAccessible` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/offsetAccess.nonOffsetAccessible +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=offsetAccess.nonOffsetAccessible +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Cannot access offset ''new_version'' on bool\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 4 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Cannot access offset mixed on bool\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Cannot access offset ''new_version'' on bool\.$#' + identifier: offsetAccess.nonOffsetAccessible + count: 1 + path: ../../../src/wp-admin/update-core.php diff --git a/tests/phpstan/baselines/offsetAccess.notFound.neon b/tests/phpstan/baselines/offsetAccess.notFound.neon new file mode 100644 index 0000000000000..a5e2eb0698cc8 --- /dev/null +++ b/tests/phpstan/baselines/offsetAccess.notFound.neon @@ -0,0 +1,40 @@ +# PHPStan baseline for the `offsetAccess.notFound` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/offsetAccess.notFound +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=offsetAccess.notFound +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Offset float does not exist on list\.$#' + identifier: offsetAccess.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Offset ''preview'' does not exist on array\{activate\: non\-falsy\-string\}\.$#' + identifier: offsetAccess.notFound + count: 1 + path: ../../../src/wp-admin/includes/class-wp-themes-list-table.php + - + message: '#^Offset ''basedir'' does not exist on string\.$#' + identifier: offsetAccess.notFound + count: 2 + path: ../../../src/wp-includes/fonts.php + - + message: '#^Offset ''baseurl'' does not exist on string\.$#' + identifier: offsetAccess.notFound + count: 2 + path: ../../../src/wp-includes/fonts.php diff --git a/tests/phpstan/baselines/offsetAssign.valueType.neon b/tests/phpstan/baselines/offsetAssign.valueType.neon new file mode 100644 index 0000000000000..8a28f7d980320 --- /dev/null +++ b/tests/phpstan/baselines/offsetAssign.valueType.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `offsetAssign.valueType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/offsetAssign.valueType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=offsetAssign.valueType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^WpOrg\\Requests\\Cookie\\Jar does not accept WpOrg\\Requests\\Cookie\.$#' + identifier: offsetAssign.valueType + count: 2 + path: ../../../src/wp-includes/class-wp-http.php diff --git a/tests/phpstan/baselines/parameterByRef.type.neon b/tests/phpstan/baselines/parameterByRef.type.neon new file mode 100644 index 0000000000000..8b7394add3c7e --- /dev/null +++ b/tests/phpstan/baselines/parameterByRef.type.neon @@ -0,0 +1,50 @@ +# PHPStan baseline for the `parameterByRef.type` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameterByRef.type +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameterByRef.type +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Parameter &\$stored_results by\-ref type of method WP_Scripts\:\:get_highest_fetchpriority_with_dependents\(\) expects array\, array\ given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../../../src/wp-includes/class-wp-scripts.php + - + message: '#^Parameter &\$query by\-ref type of method WP_Tax_Query\:\:clean_query\(\) expects array, WP_Error given\.$#' + identifier: parameterByRef.type + count: 2 + path: ../../../src/wp-includes/class-wp-tax-query.php + - + message: '#^Parameter &\$query by\-ref type of method WP_Tax_Query\:\:transform_query\(\) expects array, WP_Error given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../../../src/wp-includes/class-wp-tax-query.php + - + message: '#^Parameter &\$matched_token_byte_length by\-ref type of method WP_Token_Map\:\:read_token\(\) expects int\|null, \(float\|int\) given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../../../src/wp-includes/class-wp-token-map.php + - + message: '#^Parameter &\$has_noncharacters by\-ref type of function _wp_scan_utf8\(\) expects bool\|null, int given\.$#' + identifier: parameterByRef.type + count: 2 + path: ../../../src/wp-includes/compat-utf8.php + - + message: '#^Parameter &\$result by\-ref type of function _page_traverse_name\(\) expects array\, array given\.$#' + identifier: parameterByRef.type + count: 1 + path: ../../../src/wp-includes/post.php diff --git a/tests/phpstan/baselines/property.defaultValue.neon b/tests/phpstan/baselines/property.defaultValue.neon new file mode 100644 index 0000000000000..e604833eade20 --- /dev/null +++ b/tests/phpstan/baselines/property.defaultValue.neon @@ -0,0 +1,110 @@ +# PHPStan baseline for the `property.defaultValue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.defaultValue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.defaultValue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property Walker_Nav_Menu\:\:\$tree_type \(string\) does not accept default value of type array\\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-walker-nav-menu.php + - + message: '#^Property WP_Block\:\:\$inner_blocks \(WP_Block_List\) does not accept default value of type array\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-block.php + - + message: '#^Property WP_Comment_Query\:\:\$date_query \(WP_Date_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-comment-query.php + - + message: '#^Property WP_Comment_Query\:\:\$meta_query \(WP_Meta_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-comment-query.php + - + message: '#^Property WP_Customize_Control\:\:\$active_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-control.php + - + message: '#^Property WP_Customize_Panel\:\:\$active_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-panel.php + - + message: '#^Property WP_Customize_Panel\:\:\$theme_supports \(array\\) does not accept default value of type string\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-panel.php + - + message: '#^Property WP_Customize_Section\:\:\$active_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-section.php + - + message: '#^Property WP_Customize_Setting\:\:\$sanitize_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-setting.php + - + message: '#^Property WP_Customize_Setting\:\:\$sanitize_js_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-setting.php + - + message: '#^Property WP_Customize_Setting\:\:\$validate_callback \(callable\(\)\: mixed\) does not accept default value of type ''''\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-setting.php + - + message: '#^Property WP_Query\:\:\$date_query \(WP_Date_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Property WP_Query\:\:\$meta_query \(WP_Meta_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Property WP_Site_Query\:\:\$date_query \(WP_Date_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-site-query.php + - + message: '#^Property WP_Site_Query\:\:\$meta_query \(WP_Meta_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-site-query.php + - + message: '#^Property WP_Term_Query\:\:\$meta_query \(WP_Meta_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-term-query.php + - + message: '#^Property WP_Term\:\:\$term_group \(int\) does not accept default value of type string\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-term.php + - + message: '#^Property WP_User_Query\:\:\$meta_query \(WP_Meta_Query\) does not accept default value of type false\.$#' + identifier: property.defaultValue + count: 1 + path: ../../../src/wp-includes/class-wp-user-query.php diff --git a/tests/phpstan/baselines/property.phpDocType.neon b/tests/phpstan/baselines/property.phpDocType.neon new file mode 100644 index 0000000000000..2f69939d19f8b --- /dev/null +++ b/tests/phpstan/baselines/property.phpDocType.neon @@ -0,0 +1,45 @@ +# PHPStan baseline for the `property.phpDocType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.phpDocType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.phpDocType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^PHPDoc type array of property WP_Customize_Nav_Menu_Item_Setting\:\:\$default is not covariant with PHPDoc type string of overridden property WP_Customize_Setting\:\:\$default\.$#' + identifier: property.phpDocType + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^PHPDoc type array of property WP_Customize_Nav_Menu_Setting\:\:\$default is not covariant with PHPDoc type string of overridden property WP_Customize_Setting\:\:\$default\.$#' + identifier: property.phpDocType + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-setting.php + - + message: '#^PHPDoc type false of property WP_REST_Attachments_Controller\:\:\$allow_batch is not covariant with PHPDoc type array of overridden property WP_REST_Posts_Controller\:\:\$allow_batch\.$#' + identifier: property.phpDocType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php + - + message: '#^PHPDoc type false of property WP_REST_Font_Faces_Controller\:\:\$allow_batch is not covariant with PHPDoc type array of overridden property WP_REST_Posts_Controller\:\:\$allow_batch\.$#' + identifier: property.phpDocType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-faces-controller.php + - + message: '#^PHPDoc type false of property WP_REST_Font_Families_Controller\:\:\$allow_batch is not covariant with PHPDoc type array of overridden property WP_REST_Posts_Controller\:\:\$allow_batch\.$#' + identifier: property.phpDocType + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php diff --git a/tests/phpstan/baselines/return.empty.neon b/tests/phpstan/baselines/return.empty.neon new file mode 100644 index 0000000000000..5abf2badb5636 --- /dev/null +++ b/tests/phpstan/baselines/return.empty.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `return.empty` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/return.empty +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=return.empty +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Function twentytwenty_generate_css\(\) should return string but empty return statement found\.$#' + identifier: return.empty + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/inc/custom-css.php + - + message: '#^Function wp_dropdown_languages\(\) should return string but empty return statement found\.$#' + identifier: return.empty + count: 1 + path: ../../../src/wp-includes/l10n.php diff --git a/tests/phpstan/baselines/return.type.neon b/tests/phpstan/baselines/return.type.neon new file mode 100644 index 0000000000000..9d99e94d0abd6 --- /dev/null +++ b/tests/phpstan/baselines/return.type.neon @@ -0,0 +1,165 @@ +# PHPStan baseline for the `return.type` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/return.type +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=return.type +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Method WP_Automatic_Updater\:\:update\(\) should return WP_Error\|null but returns false\.$#' + identifier: return.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php + - + message: '#^Function convert_to_screen\(\) should return WP_Screen but returns object\{id\: string, base\: string\}&stdClass\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-admin/includes/template.php + - + message: '#^Function twentytwenty_get_color_for_area\(\) should return string but returns false\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/functions.php + - + message: '#^Function filter_block_kses\(\) should return array but returns ArrayAccess&WP_Block_Parser_Block\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/blocks.php + - + message: '#^Method WP_Block_Processor\:\:extract_full_block_and_advance\(\) should return array\\|null but returns array\\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-block-processor.php + - + message: '#^Method WP_Block_Processor\:\:extract_full_block_and_advance\(\) should return array\\|null but returns array\\|string\|null\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-block-processor.php + - + message: '#^Method WP_Block_Type\:\:__get\(\) should return array\\|string\|null but returns array\\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-block-type.php + - + message: '#^Method WP_Image_Editor_Imagick\:\:set_imagick_time_limit\(\) should return int\|null but returns float\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Method WP_Image_Editor_Imagick\:\:write_image\(\) should return WP_Error\|true but returns bool\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Method WP_Term_Query\:\:get_terms\(\) should return array\\|string but returns int\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-term-query.php + - + message: '#^Method wp_xmlrpc_server\:\:mw_newPost\(\) should return int\|IXR_Error but returns string\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-xmlrpc-server.php + - + message: '#^Method wp_xmlrpc_server\:\:wp_newTerm\(\) should return int\|IXR_Error but returns string\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/class-wp-xmlrpc-server.php + - + message: '#^Function _upgrade_cron_array\(\) should return array\{version\: 2, \.\.\.\, interval\?\: int\<0, max\>\}\>\>\>\} but returns non\-empty\-array\<''version''\|int, array\, interval\?\: int\<0, max\>\}\>\|int\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/cron.php + - + message: '#^Method WP_Customize_Nav_Menu_Setting\:\:filter_wp_get_nav_menu_object\(\) should return object\|null but returns false\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-setting.php + - + message: '#^Function _wp_filter_font_directory\(\) should return string but returns array\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/fonts.php + - + message: '#^Method WP_Translation_Controller\:\:get_entries\(\) should return array\ but returns array\\>\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/l10n/class-wp-translation-controller.php + - + message: '#^Method WP_Translation_File\:\:entries\(\) should return array\\> but returns array\\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/l10n/class-wp-translation-file.php + - + message: '#^Function update_meta_cache\(\) should return array\|false but returns bool\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/meta.php + - + message: '#^Function wp_post_revision_title\(\) should return string\|false but returns null\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Function wp_post_revision_title_expanded\(\) should return string\|false but returns null\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Function wp_set_post_categories\(\) should return array\|WP_Error\|false but returns true\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Function wp_trash_post\(\) should return WP_Post\|false\|null but returns bool\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Function wp_untrash_post\(\) should return WP_Post\|false\|null but returns bool\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Method WP_REST_Autosaves_Controller\:\:get_item\(\) should return WP_Error\|WP_Post but returns WP_REST_Response\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-autosaves-controller.php + - + message: '#^Method WP_REST_Controller\:\:get_object_type\(\) should return string but returns null\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-controller.php + - + message: '#^Method WP_REST_Template_Autosaves_Controller\:\:get_item\(\) should return WP_Error\|WP_Post but returns WP_REST_Response\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php + - + message: '#^Function _wp_preview_post_thumbnail_filter\(\) should return array\|null but returns string\.$#' + identifier: return.type + count: 2 + path: ../../../src/wp-includes/revision.php + - + message: '#^Function term_exists\(\) should return array\{term_id\: numeric\-string, term_taxonomy_id\: numeric\-string\}\|int\|null but returns string\.$#' + identifier: return.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Function _wp_get_current_user\(\) should return WP_User but returns null\.$#' + identifier: return.type + count: 2 + path: ../../../src/wp-includes/user.php From 79d902a8896d90270cd75f7cfa1af1d24c9b053b Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 08:27:05 +0000 Subject: [PATCH 127/138] Build/Test Tools: Raise the PHPStan rule level to 4. This rule level includes: > basic dead code checking - always false `instanceof` and other type checks, dead `else` branches, unreachable code after return; etc. Baselines are regenerated for errors at this level. Developed in https://github.com/WordPress/wordpress-develop/pull/12853. Follow-up to r61699, r63019, r63020, r63021, r63022. Props westonruter, apermo. See #64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63023 602fd350-edb4-49c9-b593-d223f7449a82 --- phpstan.neon.dist | 40 ++- .../baselines/booleanAnd.alwaysFalse.neon | 30 ++ .../baselines/booleanAnd.alwaysTrue.neon | 25 ++ .../baselines/booleanAnd.leftAlwaysTrue.neon | 45 +++ .../booleanAnd.rightAlwaysFalse.neon | 25 ++ .../baselines/booleanAnd.rightAlwaysTrue.neon | 65 ++++ .../baselines/booleanNot.alwaysFalse.neon | 50 +++ .../baselines/booleanNot.alwaysTrue.neon | 60 ++++ .../baselines/booleanOr.alwaysFalse.neon | 25 ++ .../baselines/booleanOr.alwaysTrue.neon | 30 ++ .../baselines/booleanOr.rightAlwaysTrue.neon | 25 ++ .../phpstan/baselines/catch.neverThrown.neon | 25 ++ .../baselines/deadCode.unreachable.neon | 305 ++++++++++++++++++ tests/phpstan/baselines/empty.offset.neon | 30 ++ tests/phpstan/baselines/empty.property.neon | 65 ++++ .../function.alreadyNarrowedType.neon | 105 ++++++ .../baselines/function.impossibleType.neon | 40 +++ .../baselines/function.resultUnused.neon | 40 +++ .../baselines/greaterOrEqual.alwaysTrue.neon | 60 ++++ .../baselines/identical.alwaysFalse.neon | 45 +++ .../baselines/identical.alwaysTrue.neon | 40 +++ tests/phpstan/baselines/if.alwaysFalse.neon | 55 ++++ tests/phpstan/baselines/if.alwaysTrue.neon | 55 ++++ .../baselines/instanceof.alwaysTrue.neon | 25 ++ tests/phpstan/baselines/isset.offset.neon | 40 +++ tests/phpstan/baselines/isset.property.neon | 220 +++++++++++++ tests/phpstan/baselines/method.unused.neon | 45 +++ .../baselines/notIdentical.alwaysTrue.neon | 75 +++++ .../baselines/nullCoalesce.offset.neon | 25 ++ .../baselines/nullCoalesce.property.neon | 55 ++++ .../baselines/parameterByRef.unusedType.neon | 30 ++ .../baselines/property.onlyWritten.neon | 25 ++ .../baselines/property.unusedType.neon | 25 ++ .../phpstan/baselines/return.unusedType.neon | 100 ++++++ .../baselines/smallerOrEqual.alwaysTrue.neon | 25 ++ .../baselines/ternary.alwaysFalse.neon | 25 ++ .../phpstan/baselines/ternary.alwaysTrue.neon | 30 ++ .../phpstan/baselines/while.alwaysFalse.neon | 25 ++ tests/phpstan/baselines/while.alwaysTrue.neon | 300 +++++++++++++++++ 39 files changed, 2354 insertions(+), 1 deletion(-) create mode 100644 tests/phpstan/baselines/booleanAnd.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/booleanAnd.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/booleanAnd.leftAlwaysTrue.neon create mode 100644 tests/phpstan/baselines/booleanAnd.rightAlwaysFalse.neon create mode 100644 tests/phpstan/baselines/booleanAnd.rightAlwaysTrue.neon create mode 100644 tests/phpstan/baselines/booleanNot.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/booleanNot.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/booleanOr.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/booleanOr.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/booleanOr.rightAlwaysTrue.neon create mode 100644 tests/phpstan/baselines/catch.neverThrown.neon create mode 100644 tests/phpstan/baselines/deadCode.unreachable.neon create mode 100644 tests/phpstan/baselines/empty.offset.neon create mode 100644 tests/phpstan/baselines/empty.property.neon create mode 100644 tests/phpstan/baselines/function.alreadyNarrowedType.neon create mode 100644 tests/phpstan/baselines/function.impossibleType.neon create mode 100644 tests/phpstan/baselines/function.resultUnused.neon create mode 100644 tests/phpstan/baselines/greaterOrEqual.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/identical.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/identical.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/if.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/if.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/instanceof.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/isset.offset.neon create mode 100644 tests/phpstan/baselines/isset.property.neon create mode 100644 tests/phpstan/baselines/method.unused.neon create mode 100644 tests/phpstan/baselines/notIdentical.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/nullCoalesce.offset.neon create mode 100644 tests/phpstan/baselines/nullCoalesce.property.neon create mode 100644 tests/phpstan/baselines/parameterByRef.unusedType.neon create mode 100644 tests/phpstan/baselines/property.onlyWritten.neon create mode 100644 tests/phpstan/baselines/property.unusedType.neon create mode 100644 tests/phpstan/baselines/return.unusedType.neon create mode 100644 tests/phpstan/baselines/smallerOrEqual.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/ternary.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/ternary.alwaysTrue.neon create mode 100644 tests/phpstan/baselines/while.alwaysFalse.neon create mode 100644 tests/phpstan/baselines/while.alwaysTrue.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index 43e42c278a7ce..d6c66d62e9bbe 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -25,16 +25,45 @@ includes: - tests/phpstan/baselines/arguments.count.neon - tests/phpstan/baselines/assign.propertyType.neon - tests/phpstan/baselines/binaryOp.invalid.neon + - tests/phpstan/baselines/booleanAnd.alwaysFalse.neon + - tests/phpstan/baselines/booleanAnd.alwaysTrue.neon + - tests/phpstan/baselines/booleanAnd.leftAlwaysTrue.neon + - tests/phpstan/baselines/booleanAnd.rightAlwaysFalse.neon + - tests/phpstan/baselines/booleanAnd.rightAlwaysTrue.neon + - tests/phpstan/baselines/booleanNot.alwaysFalse.neon + - tests/phpstan/baselines/booleanNot.alwaysTrue.neon + - tests/phpstan/baselines/booleanOr.alwaysFalse.neon + - tests/phpstan/baselines/booleanOr.alwaysTrue.neon + - tests/phpstan/baselines/booleanOr.rightAlwaysTrue.neon + - tests/phpstan/baselines/catch.neverThrown.neon - tests/phpstan/baselines/class.nameCase.neon - tests/phpstan/baselines/class.notFound.neon + - tests/phpstan/baselines/deadCode.unreachable.neon + - tests/phpstan/baselines/empty.offset.neon + - tests/phpstan/baselines/empty.property.neon - tests/phpstan/baselines/empty.variable.neon - tests/phpstan/baselines/encapsedStringPart.nonString.neon - tests/phpstan/baselines/foreach.nonIterable.neon + - tests/phpstan/baselines/function.alreadyNarrowedType.neon + - tests/phpstan/baselines/function.impossibleType.neon + - tests/phpstan/baselines/function.resultUnused.neon - tests/phpstan/baselines/greater.invalid.neon + - tests/phpstan/baselines/greaterOrEqual.alwaysTrue.neon + - tests/phpstan/baselines/identical.alwaysFalse.neon + - tests/phpstan/baselines/identical.alwaysTrue.neon + - tests/phpstan/baselines/if.alwaysFalse.neon + - tests/phpstan/baselines/if.alwaysTrue.neon + - tests/phpstan/baselines/instanceof.alwaysTrue.neon + - tests/phpstan/baselines/isset.offset.neon + - tests/phpstan/baselines/isset.property.neon - tests/phpstan/baselines/isset.variable.neon - tests/phpstan/baselines/method.childParameterType.neon - tests/phpstan/baselines/method.nonObject.neon - tests/phpstan/baselines/method.notFound.neon + - tests/phpstan/baselines/method.unused.neon + - tests/phpstan/baselines/notIdentical.alwaysTrue.neon + - tests/phpstan/baselines/nullCoalesce.offset.neon + - tests/phpstan/baselines/nullCoalesce.property.neon - tests/phpstan/baselines/offsetAccess.nonOffsetAccessible.neon - tests/phpstan/baselines/offsetAccess.notFound.neon - tests/phpstan/baselines/offsetAssign.valueType.neon @@ -43,23 +72,32 @@ includes: - tests/phpstan/baselines/parameter.phpDocType.neon - tests/phpstan/baselines/parameter.unresolvableType.neon - tests/phpstan/baselines/parameterByRef.type.neon + - tests/phpstan/baselines/parameterByRef.unusedType.neon - tests/phpstan/baselines/property.defaultValue.neon - tests/phpstan/baselines/property.nonObject.neon - tests/phpstan/baselines/property.notFound.neon + - tests/phpstan/baselines/property.onlyWritten.neon - tests/phpstan/baselines/property.phpDocType.neon - tests/phpstan/baselines/property.private.neon - tests/phpstan/baselines/property.protected.neon + - tests/phpstan/baselines/property.unusedType.neon - tests/phpstan/baselines/return.empty.neon - tests/phpstan/baselines/return.missing.neon - tests/phpstan/baselines/return.type.neon + - tests/phpstan/baselines/return.unusedType.neon + - tests/phpstan/baselines/smallerOrEqual.alwaysTrue.neon - tests/phpstan/baselines/staticClassAccess.privateMethod.neon + - tests/phpstan/baselines/ternary.alwaysFalse.neon + - tests/phpstan/baselines/ternary.alwaysTrue.neon - tests/phpstan/baselines/varTag.noVariable.neon - tests/phpstan/baselines/variable.undefined.neon + - tests/phpstan/baselines/while.alwaysFalse.neon + - tests/phpstan/baselines/while.alwaysTrue.neon # phpstan:baselines end parameters: # https://phpstan.org/user-guide/rule-levels - level: 3 + level: 4 reportUnmatchedIgnoredErrors: true # The following ignored errors are not intended to be fixed, as distinct from the baselines diff --git a/tests/phpstan/baselines/booleanAnd.alwaysFalse.neon b/tests/phpstan/baselines/booleanAnd.alwaysFalse.neon new file mode 100644 index 0000000000000..4bbff3cdb566b --- /dev/null +++ b/tests/phpstan/baselines/booleanAnd.alwaysFalse.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `booleanAnd.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanAnd.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanAnd.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Result of && is always false\.$#' + identifier: booleanAnd.alwaysFalse + count: 1 + path: ../../../src/wp-admin/themes.php + - + message: '#^Result of && is always false\.$#' + identifier: booleanAnd.alwaysFalse + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-attachments-controller.php diff --git a/tests/phpstan/baselines/booleanAnd.alwaysTrue.neon b/tests/phpstan/baselines/booleanAnd.alwaysTrue.neon new file mode 100644 index 0000000000000..52bae4992b186 --- /dev/null +++ b/tests/phpstan/baselines/booleanAnd.alwaysTrue.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `booleanAnd.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanAnd.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanAnd.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Result of && is always true\.$#' + identifier: booleanAnd.alwaysTrue + count: 2 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php diff --git a/tests/phpstan/baselines/booleanAnd.leftAlwaysTrue.neon b/tests/phpstan/baselines/booleanAnd.leftAlwaysTrue.neon new file mode 100644 index 0000000000000..c64a48177e085 --- /dev/null +++ b/tests/phpstan/baselines/booleanAnd.leftAlwaysTrue.neon @@ -0,0 +1,45 @@ +# PHPStan baseline for the `booleanAnd.leftAlwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanAnd.leftAlwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanAnd.leftAlwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Left side of && is always true\.$#' + identifier: booleanAnd.leftAlwaysTrue + count: 1 + path: ../../../src/wp-admin/network/users.php + - + message: '#^Left side of && is always true\.$#' + identifier: booleanAnd.leftAlwaysTrue + count: 1 + path: ../../../src/wp-admin/themes.php + - + message: '#^Left side of && is always true\.$#' + identifier: booleanAnd.leftAlwaysTrue + count: 1 + path: ../../../src/wp-includes/block-template-utils.php + - + message: '#^Left side of && is always true\.$#' + identifier: booleanAnd.leftAlwaysTrue + count: 1 + path: ../../../src/wp-includes/canonical.php + - + message: '#^Left side of && is always true\.$#' + identifier: booleanAnd.leftAlwaysTrue + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php diff --git a/tests/phpstan/baselines/booleanAnd.rightAlwaysFalse.neon b/tests/phpstan/baselines/booleanAnd.rightAlwaysFalse.neon new file mode 100644 index 0000000000000..367c8dd35051c --- /dev/null +++ b/tests/phpstan/baselines/booleanAnd.rightAlwaysFalse.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `booleanAnd.rightAlwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanAnd.rightAlwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanAnd.rightAlwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Right side of && is always false\.$#' + identifier: booleanAnd.rightAlwaysFalse + count: 1 + path: ../../../src/wp-includes/class-wpdb.php diff --git a/tests/phpstan/baselines/booleanAnd.rightAlwaysTrue.neon b/tests/phpstan/baselines/booleanAnd.rightAlwaysTrue.neon new file mode 100644 index 0000000000000..64071efcf3d23 --- /dev/null +++ b/tests/phpstan/baselines/booleanAnd.rightAlwaysTrue.neon @@ -0,0 +1,65 @@ +# PHPStan baseline for the `booleanAnd.rightAlwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanAnd.rightAlwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanAnd.rightAlwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/schema.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/header.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../../../src/wp-includes/block-supports/typography.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-walker.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 2 + path: ../../../src/wp-includes/functions.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 3 + path: ../../../src/wp-includes/l10n.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 4 + path: ../../../src/wp-includes/load.php + - + message: '#^Right side of && is always true\.$#' + identifier: booleanAnd.rightAlwaysTrue + count: 2 + path: ../../../src/wp-includes/user.php diff --git a/tests/phpstan/baselines/booleanNot.alwaysFalse.neon b/tests/phpstan/baselines/booleanNot.alwaysFalse.neon new file mode 100644 index 0000000000000..57e8a715cfc8d --- /dev/null +++ b/tests/phpstan/baselines/booleanNot.alwaysFalse.neon @@ -0,0 +1,50 @@ +# PHPStan baseline for the `booleanNot.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanNot.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanNot.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: ../../../src/wp-admin/includes/theme.php + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: ../../../src/wp-admin/link-manager.php + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 2 + path: ../../../src/wp-admin/network/users.php + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: ../../../src/wp-admin/plugins.php + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: ../../../src/wp-includes/class-wp-comment-query.php + - + message: '#^Negated boolean expression is always false\.$#' + identifier: booleanNot.alwaysFalse + count: 1 + path: ../../../src/wp-includes/nav-menu.php diff --git a/tests/phpstan/baselines/booleanNot.alwaysTrue.neon b/tests/phpstan/baselines/booleanNot.alwaysTrue.neon new file mode 100644 index 0000000000000..ae0b0afe52c56 --- /dev/null +++ b/tests/phpstan/baselines/booleanNot.alwaysTrue.neon @@ -0,0 +1,60 @@ +# PHPStan baseline for the `booleanNot.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanNot.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanNot.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-custom-image-header.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-language-pack-upgrader.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-wp-upgrader.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/file.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-block-templates-registry.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-block.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Negated boolean expression is always true\.$#' + identifier: booleanNot.alwaysTrue + count: 1 + path: ../../../src/wp-includes/option.php diff --git a/tests/phpstan/baselines/booleanOr.alwaysFalse.neon b/tests/phpstan/baselines/booleanOr.alwaysFalse.neon new file mode 100644 index 0000000000000..86e1740697619 --- /dev/null +++ b/tests/phpstan/baselines/booleanOr.alwaysFalse.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `booleanOr.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanOr.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanOr.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Result of \|\| is always false\.$#' + identifier: booleanOr.alwaysFalse + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php diff --git a/tests/phpstan/baselines/booleanOr.alwaysTrue.neon b/tests/phpstan/baselines/booleanOr.alwaysTrue.neon new file mode 100644 index 0000000000000..6ee9845afe5be --- /dev/null +++ b/tests/phpstan/baselines/booleanOr.alwaysTrue.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `booleanOr.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanOr.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanOr.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue + count: 1 + path: ../../../src/wp-includes/block-supports/position.php + - + message: '#^Result of \|\| is always true\.$#' + identifier: booleanOr.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-block.php diff --git a/tests/phpstan/baselines/booleanOr.rightAlwaysTrue.neon b/tests/phpstan/baselines/booleanOr.rightAlwaysTrue.neon new file mode 100644 index 0000000000000..3234f5ad209b0 --- /dev/null +++ b/tests/phpstan/baselines/booleanOr.rightAlwaysTrue.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `booleanOr.rightAlwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/booleanOr.rightAlwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=booleanOr.rightAlwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Right side of \|\| is always true\.$#' + identifier: booleanOr.rightAlwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php diff --git a/tests/phpstan/baselines/catch.neverThrown.neon b/tests/phpstan/baselines/catch.neverThrown.neon new file mode 100644 index 0000000000000..30c8a4a7cfe4b --- /dev/null +++ b/tests/phpstan/baselines/catch.neverThrown.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `catch.neverThrown` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/catch.neverThrown +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=catch.neverThrown +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Dead catch \- Exception is never thrown in the try block\.$#' + identifier: catch.neverThrown + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php diff --git a/tests/phpstan/baselines/deadCode.unreachable.neon b/tests/phpstan/baselines/deadCode.unreachable.neon new file mode 100644 index 0000000000000..f8a2c6671a783 --- /dev/null +++ b/tests/phpstan/baselines/deadCode.unreachable.neon @@ -0,0 +1,305 @@ +# PHPStan baseline for the `deadCode.unreachable` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/deadCode.unreachable +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=deadCode.unreachable +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-admin/about.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-admin/credits.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 3 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-admin/includes/class-wp-internal-pointers.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 2 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 2 + path: ../../../src/wp-admin/post.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/author.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/category.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/showcase.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/tag.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/author.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/category.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/tag.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/taxonomy-post_format.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/author.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/category.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/tag.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/taxonomy-post_format.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/author.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/category.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/tag.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/archive.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/index.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/search.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-includes/capabilities.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-includes/class-wp-block.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 31 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Unreachable statement \- code above always terminates\.$#' + identifier: deadCode.unreachable + count: 1 + path: ../../../src/wp-includes/sitemaps/class-wp-sitemaps.php diff --git a/tests/phpstan/baselines/empty.offset.neon b/tests/phpstan/baselines/empty.offset.neon new file mode 100644 index 0000000000000..ac1410fad0869 --- /dev/null +++ b/tests/phpstan/baselines/empty.offset.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `empty.offset` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/empty.offset +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=empty.offset +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Offset mixed on array\{\} in empty\(\) does not exist\.$#' + identifier: empty.offset + count: 1 + path: ../../../src/wp-admin/includes/class-wp-internal-pointers.php + - + message: '#^Offset ''created_timestamp'' on array\{\}\|array\{lossless\?\: mixed, bitrate\?\: int, bitrate_mode\?\: mixed, filesize\?\: int, mime_type\?\: mixed, length\?\: int, length_formatted\?\: mixed, width\?\: int, \.\.\.\} in empty\(\) does not exist\.$#' + identifier: empty.offset + count: 1 + path: ../../../src/wp-admin/includes/media.php diff --git a/tests/phpstan/baselines/empty.property.neon b/tests/phpstan/baselines/empty.property.neon new file mode 100644 index 0000000000000..5bc6d4e3cbdd3 --- /dev/null +++ b/tests/phpstan/baselines/empty.property.neon @@ -0,0 +1,65 @@ +# PHPStan baseline for the `empty.property` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/empty.property +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=empty.property +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_Block_Type\:\:\$render_callback \(callable\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/blocks.php + - + message: '#^Property WP_Customize_Control\:\:\$active_callback \(callable\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-control.php + - + message: '#^Property WP_Customize_Manager\:\:\$nav_menus \(WP_Customize_Nav_Menus\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 4 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Property WP_Customize_Manager\:\:\$widgets \(WP_Customize_Widgets\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Property WP_Customize_Panel\:\:\$active_callback \(callable\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-panel.php + - + message: '#^Property WP_Customize_Section\:\:\$active_callback \(callable\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-section.php + - + message: '#^Property WP_Customize_Manager\:\:\$nav_menus \(WP_Customize_Nav_Menus\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-item-setting.php + - + message: '#^Property WP_Customize_Manager\:\:\$nav_menus \(WP_Customize_Nav_Menus\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-nav-menu-setting.php + - + message: '#^Property WP_Customize_Partial\:\:\$render_callback \(callable\) in empty\(\) is not falsy\.$#' + identifier: empty.property + count: 2 + path: ../../../src/wp-includes/customize/class-wp-customize-partial.php diff --git a/tests/phpstan/baselines/function.alreadyNarrowedType.neon b/tests/phpstan/baselines/function.alreadyNarrowedType.neon new file mode 100644 index 0000000000000..5d0293fde3b5b --- /dev/null +++ b/tests/phpstan/baselines/function.alreadyNarrowedType.neon @@ -0,0 +1,105 @@ +# PHPStan baseline for the `function.alreadyNarrowedType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/function.alreadyNarrowedType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=function.alreadyNarrowedType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 2 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Call to function is_wp_error\(\) with WP_Error will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Call to function method_exists\(\) with ''ParagonIE_Sodium…'' and ''runtime_speed_test'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-admin/includes/file.php + - + message: '#^Call to function is_callable\(\) with ''exif_read_data'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-admin/includes/image.php + - + message: '#^Call to function is_callable\(\) with ''iptcparse'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-admin/includes/image.php + - + message: '#^Call to function is_numeric\(\) with float\|int\|numeric\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/block-editor.php + - + message: '#^Call to function is_string\(\) with string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/class-wp-block-bindings-registry.php + - + message: '#^Call to function method_exists\(\) with ''Imagick'' and ''setIteratorIndex'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Call to function is_callable\(\) with ''exif_read_data'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor.php + - + message: '#^Call to function method_exists\(\) with ''SimplePie_Cache'' and ''register'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/feed.php + - + message: '#^Call to function is_callable\(\) with ''exif_imagetype'' will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Call to function is_array\(\) with array will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/interactivity-api/class-wp-interactivity-api.php + - + message: '#^Call to function is_string\(\) with non\-falsy\-string will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 2 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Call to function wp_die\(\) with arguments non\-falsy\-string, mixed and array\{exit\: false, code\: ''mysql_not_found''\} will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^Call to function is_array\(\) with non\-empty\-array\ will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/ms-functions.php + - + message: '#^Call to function is_array\(\) with array\{non\-falsy\-string, non\-falsy\-string&numeric\-string, numeric\-string, numeric\-string\} will always evaluate to true\.$#' + identifier: function.alreadyNarrowedType + count: 1 + path: ../../../src/wp-includes/post.php diff --git a/tests/phpstan/baselines/function.impossibleType.neon b/tests/phpstan/baselines/function.impossibleType.neon new file mode 100644 index 0000000000000..b096e7ff399bd --- /dev/null +++ b/tests/phpstan/baselines/function.impossibleType.neon @@ -0,0 +1,40 @@ +# PHPStan baseline for the `function.impossibleType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/function.impossibleType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=function.impossibleType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Call to function is_string\(\) with bool will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php + - + message: '#^Call to function is_wp_error\(\) with 0\|0\.0\|''''\|''0''\|array\{\}\|false\|null will always evaluate to false\.$#' + identifier: function.impossibleType + count: 2 + path: ../../../src/wp-admin/update.php + - + message: '#^Call to function is_wp_error\(\) with array will always evaluate to false\.$#' + identifier: function.impossibleType + count: 2 + path: ../../../src/wp-includes/class-wp-tax-query.php + - + message: '#^Call to function is_string\(\) with bool will always evaluate to false\.$#' + identifier: function.impossibleType + count: 1 + path: ../../../src/wp-includes/load.php diff --git a/tests/phpstan/baselines/function.resultUnused.neon b/tests/phpstan/baselines/function.resultUnused.neon new file mode 100644 index 0000000000000..1ad6a84dbfa4c --- /dev/null +++ b/tests/phpstan/baselines/function.resultUnused.neon @@ -0,0 +1,40 @@ +# PHPStan baseline for the `function.resultUnused` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/function.resultUnused +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=function.resultUnused +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Call to function wp_cache_add_non_persistent_groups\(\) on a separate line has no effect\.$#' + identifier: function.resultUnused + count: 1 + path: ../../../src/wp-includes/class-wp-theme.php + - + message: '#^Call to function wp_cache_add_non_persistent_groups\(\) on a separate line has no effect\.$#' + identifier: function.resultUnused + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^Call to function wp_cache_close\(\) on a separate line has no effect\.$#' + identifier: function.resultUnused + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^Call to function wp_cache_add_non_persistent_groups\(\) on a separate line has no effect\.$#' + identifier: function.resultUnused + count: 1 + path: ../../../src/wp-includes/ms-blogs.php diff --git a/tests/phpstan/baselines/greaterOrEqual.alwaysTrue.neon b/tests/phpstan/baselines/greaterOrEqual.alwaysTrue.neon new file mode 100644 index 0000000000000..9b0969a81be78 --- /dev/null +++ b/tests/phpstan/baselines/greaterOrEqual.alwaysTrue.neon @@ -0,0 +1,60 @@ +# PHPStan baseline for the `greaterOrEqual.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/greaterOrEqual.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=greaterOrEqual.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Comparison operation "\>\=" between int\<70400, 80500\> and 70300 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-utils.php + - + message: '#^Comparison operation "\>\=" between int\<70400, 80500\> and 70400 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/fonts/class-wp-font-utils.php + - + message: '#^Comparison operation "\>\=" between int\<2592000, 31535999\> and 2592000 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Comparison operation "\>\=" between int\<31536000, max\> and 31536000 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Comparison operation "\>\=" between int\<3600, 86399\> and 3600 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Comparison operation "\>\=" between int\<60, 3599\> and 60 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Comparison operation "\>\=" between int\<604800, 2591999\> and 604800 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Comparison operation "\>\=" between int\<86400, 604799\> and 86400 is always true\.$#' + identifier: greaterOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/formatting.php diff --git a/tests/phpstan/baselines/identical.alwaysFalse.neon b/tests/phpstan/baselines/identical.alwaysFalse.neon new file mode 100644 index 0000000000000..47e10c0e67b9a --- /dev/null +++ b/tests/phpstan/baselines/identical.alwaysFalse.neon @@ -0,0 +1,45 @@ +# PHPStan baseline for the `identical.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/identical.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=identical.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Strict comparison using \=\=\= between ''update\-selected'' and mixed~\(''activate''\|''activate\-selected''\|''deactivate''\|''deactivate\-selected''\|''delete\-selected''\|''disable\-auto\-update''\|''disable\-auto\-update\-selected''\|''enable\-auto\-update''\|''enable\-auto\-update\-selected''\|''error_scrape''\|''resume''\|''update\-selected''\) will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/wp-admin/plugins.php + - + message: '#^Strict comparison using \=\=\= between ''exceeded\-max…'' and null will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php + - + message: '#^Strict comparison using \=\=\= between ''STATE_INCOMPLETE…'' and ''STATE_READY'' will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Strict comparison using \=\=\= between 3000000000 and 2147483647 will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Strict comparison using \=\=\= between false and mixed will always evaluate to false\.$#' + identifier: identical.alwaysFalse + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php diff --git a/tests/phpstan/baselines/identical.alwaysTrue.neon b/tests/phpstan/baselines/identical.alwaysTrue.neon new file mode 100644 index 0000000000000..59b590acc867e --- /dev/null +++ b/tests/phpstan/baselines/identical.alwaysTrue.neon @@ -0,0 +1,40 @@ +# PHPStan baseline for the `identical.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/identical.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=identical.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Strict comparison using \=\=\= between ''themezip'' and ''themezip'' will always evaluate to true\.$#' + identifier: identical.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-file-upload-upgrader.php + - + message: '#^Strict comparison using \=\=\= between ''sticky'' and ''sticky'' will always evaluate to true\.$#' + identifier: identical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/block-supports/position.php + - + message: '#^Strict comparison using \=\=\= between ''404'' and ''404'' will always evaluate to true\.$#' + identifier: identical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp.php + - + message: '#^Strict comparison using \=\=\= between true and true will always evaluate to true\.$#' + identifier: identical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/rest-api.php diff --git a/tests/phpstan/baselines/if.alwaysFalse.neon b/tests/phpstan/baselines/if.alwaysFalse.neon new file mode 100644 index 0000000000000..d0346f40c526c --- /dev/null +++ b/tests/phpstan/baselines/if.alwaysFalse.neon @@ -0,0 +1,55 @@ +# PHPStan baseline for the `if.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/if.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=if.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-admin/install.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 2 + path: ../../../src/wp-includes/class-wp-block-processor.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-includes/template.php + - + message: '#^If condition is always false\.$#' + identifier: if.alwaysFalse + count: 1 + path: ../../../src/wp-login.php diff --git a/tests/phpstan/baselines/if.alwaysTrue.neon b/tests/phpstan/baselines/if.alwaysTrue.neon new file mode 100644 index 0000000000000..f049efde2d19d --- /dev/null +++ b/tests/phpstan/baselines/if.alwaysTrue.neon @@ -0,0 +1,55 @@ +# PHPStan baseline for the `if.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/if.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=if.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: ../../../src/wp-admin/my-sites.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 2 + path: ../../../src/wp-admin/upload.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/comments.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/template-parts/footer/footer-widgets.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/functions.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/template-parts/modal-menu.php + - + message: '#^If condition is always true\.$#' + identifier: if.alwaysTrue + count: 2 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php diff --git a/tests/phpstan/baselines/instanceof.alwaysTrue.neon b/tests/phpstan/baselines/instanceof.alwaysTrue.neon new file mode 100644 index 0000000000000..087710cdf012e --- /dev/null +++ b/tests/phpstan/baselines/instanceof.alwaysTrue.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `instanceof.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/instanceof.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=instanceof.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Instanceof between Imagick and Imagick will always evaluate to true\.$#' + identifier: instanceof.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php diff --git a/tests/phpstan/baselines/isset.offset.neon b/tests/phpstan/baselines/isset.offset.neon new file mode 100644 index 0000000000000..1db99c69fbf03 --- /dev/null +++ b/tests/phpstan/baselines/isset.offset.neon @@ -0,0 +1,40 @@ +# PHPStan baseline for the `isset.offset` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/isset.offset +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=isset.offset +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Offset \(float\|int\) on non\-empty\-array\ in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: ../../../src/wp-admin/nav-menus.php + - + message: '#^Offset int\<1, max\> on non\-empty\-list\ in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Offset 2 on array\{string, non\-empty\-string, non\-empty\-string\} in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: ../../../src/wp-includes/media.php + - + message: '#^Offset ''orderby'' on array\{post_parent\: mixed, post_type\: ''revision'', post_status\: ''inherit'', posts_per_page\: mixed, orderby\: mixed, order\: mixed, suppress_filters\: true, post__not_in\?\: mixed, \.\.\.\} in isset\(\) always exists and is not nullable\.$#' + identifier: isset.offset + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php diff --git a/tests/phpstan/baselines/isset.property.neon b/tests/phpstan/baselines/isset.property.neon new file mode 100644 index 0000000000000..2a0c8971ceb55 --- /dev/null +++ b/tests/phpstan/baselines/isset.property.neon @@ -0,0 +1,220 @@ +# PHPStan baseline for the `isset.property` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/isset.property +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=isset.property +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_Post\:\:\$post_type \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 3 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-checklist.php + - + message: '#^Property WP_Post\:\:\$post_status \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Property WP_Post\:\:\$post_title \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-admin/includes/class-wp-posts-list-table.php + - + message: '#^Property WP_Screen\:\:\$post_type \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-admin/includes/class-wp-screen.php + - + message: '#^Property WP_Taxonomy\:\:\$meta_box_sanitize_cb \(callable\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Property WP_Site\:\:\$domain \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-admin/my-sites.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/theme-options.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/inc/customizer.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/customizer.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/inc/customizer.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/inc/customizer.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/functions.php + - + message: '#^Property WP_Customize_Manager\:\:\$selective_refresh \(WP_Customize_Selective_Refresh\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/functions.php + - + message: '#^Property WP_Block_Type\:\:\$editor_style_handles \(array\\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/block-editor.php + - + message: '#^Property WP_Block_Type\:\:\$selectors \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/block-supports/states.php + - + message: '#^Property WP_Customize_Control\:\:\$settings \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-control.php + - + message: '#^Property WP_Customize_Manager\:\:\$_changeset_post_id \(int\|false\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Property WP_Customize_Manager\:\:\$_changeset_uuid \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Property WP_Customize_Manager\:\:\$_post_values \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Property WP_Customize_Setting\:\:\$_previewed_blog_id \(int\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 2 + path: ../../../src/wp-includes/class-wp-customize-setting.php + - + message: '#^Property WP_Customize_Widgets\:\:\$selective_refreshable_widgets \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-customize-widgets.php + - + message: '#^Property WP_Http_Cookie\:\:\$domain \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php + - + message: '#^Property WP_Http_Cookie\:\:\$name \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php + - + message: '#^Property WP_Http_Cookie\:\:\$value \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php + - + message: '#^Property WP_Post\:\:\$ID \(int\<0, max\>\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Static property WP_Theme\:\:\$persistently_cache \(bool\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-theme.php + - + message: '#^Static property WP_User\:\:\$back_compat_keys \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-user.php + - + message: '#^Property WP_Widget\:\:\$alt_option_name \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wp-widget.php + - + message: '#^Property wpdb\:\:\$base_prefix \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/class-wpdb.php + - + message: '#^Property WP_Customize_Partial\:\:\$settings \(array\\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-partial.php + - + message: '#^Property WP_HTML_Text_Replacement\:\:\$text \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 2 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Property WP_Post\:\:\$post_status \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Property WP_Object_Cache\:\:\$cache \(array\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/ms-blogs.php + - + message: '#^Property WP_Object_Cache\:\:\$global_groups \(array\\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/ms-blogs.php + - + message: '#^Property WP_Post\:\:\$ID \(int\<0, max\>\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/nav-menu.php + - + message: '#^Property WP_Term\:\:\$term_id \(int\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/nav-menu.php + - + message: '#^Property WP_Post\:\:\$post_name \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php + - + message: '#^Property WP_Post\:\:\$post_title \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-families-controller.php + - + message: '#^Property WP_Query\:\:\$max_num_pages \(int\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/sitemaps/providers/class-wp-sitemaps-posts.php + - + message: '#^Property WP_Site\:\:\$domain \(string\) in isset\(\) is not nullable\.$#' + identifier: isset.property + count: 1 + path: ../../../src/wp-includes/user.php diff --git a/tests/phpstan/baselines/method.unused.neon b/tests/phpstan/baselines/method.unused.neon new file mode 100644 index 0000000000000..f4314a8b42a5c --- /dev/null +++ b/tests/phpstan/baselines/method.unused.neon @@ -0,0 +1,45 @@ +# PHPStan baseline for the `method.unused` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/method.unused +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=method.unused +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Static method WP_Internal_Pointers\:\:print_js\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: ../../../src/wp-admin/includes/class-wp-internal-pointers.php + - + message: '#^Method WP_Http\:\:_dispatch_request\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: ../../../src/wp-includes/class-wp-http.php + - + message: '#^Method WP_Script_Modules\:\:get_marked_for_enqueue\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: ../../../src/wp-includes/class-wp-script-modules.php + - + message: '#^Method WP_HTML_Tag_Processor\:\:skip_rawtext\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Method WP_HTML_Tag_Processor\:\:skip_script_data\(\) is unused\.$#' + identifier: method.unused + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php diff --git a/tests/phpstan/baselines/notIdentical.alwaysTrue.neon b/tests/phpstan/baselines/notIdentical.alwaysTrue.neon new file mode 100644 index 0000000000000..5fed187271bfc --- /dev/null +++ b/tests/phpstan/baselines/notIdentical.alwaysTrue.neon @@ -0,0 +1,75 @@ +# PHPStan baseline for the `notIdentical.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/notIdentical.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=notIdentical.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Strict comparison using \!\=\= between ''all'' and int will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/class-wp-links-list-table.php + - + message: '#^Strict comparison using \!\=\= between null and string will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/block-supports/layout.php + - + message: '#^Strict comparison using \!\=\= between null and int\|string will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 2 + path: ../../../src/wp-includes/class-wp-rewrite.php + - + message: '#^Strict comparison using \!\=\= between array\{\} and non\-empty\-array\ will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-view-config-data.php + - + message: '#^Strict comparison using \!\=\= between ''Etc'' and ''Africa''\|''America''\|''Antarctica''\|''Arctic''\|''Asia''\|''Atlantic''\|''Australia''\|''Europe''\|''Indian''\|''Pacific'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Strict comparison using \!\=\= between ''STATE_COMPLETE'' and ''STATE_READY'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Strict comparison using \!\=\= between ''STATE_INCOMPLETE…'' and ''STATE_READY'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Strict comparison using \!\=\= between ''STATE_MATCHED_TAG'' and ''STATE_READY'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Strict comparison using \!\=\= between 0 and int\\|int\<1, max\> will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/nav-menu.php + - + message: '#^Strict comparison using \!\=\= between float\|int\|numeric\-string and ''bottom''\|''footer''\|''header''\|''main''\|''menu\-1''\|''menu\-2''\|''navigation''\|''primary''\|''secondary''\|''social''\|''subsidiary''\|''top'' will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 2 + path: ../../../src/wp-includes/nav-menu.php + - + message: '#^Strict comparison using \!\=\= between false and int will always evaluate to true\.$#' + identifier: notIdentical.alwaysTrue + count: 1 + path: ../../../src/wp-includes/pluggable.php diff --git a/tests/phpstan/baselines/nullCoalesce.offset.neon b/tests/phpstan/baselines/nullCoalesce.offset.neon new file mode 100644 index 0000000000000..cdf94447df8f3 --- /dev/null +++ b/tests/phpstan/baselines/nullCoalesce.offset.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `nullCoalesce.offset` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/nullCoalesce.offset +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=nullCoalesce.offset +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Offset 1 on array\{list\, list\\} on left side of \?\? always exists and is not nullable\.$#' + identifier: nullCoalesce.offset + count: 1 + path: ../../../src/wp-includes/block-supports/block-style-variations.php diff --git a/tests/phpstan/baselines/nullCoalesce.property.neon b/tests/phpstan/baselines/nullCoalesce.property.neon new file mode 100644 index 0000000000000..3b30d530a3ab3 --- /dev/null +++ b/tests/phpstan/baselines/nullCoalesce.property.neon @@ -0,0 +1,55 @@ +# PHPStan baseline for the `nullCoalesce.property` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/nullCoalesce.property +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=nullCoalesce.property +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_User\:\:\$ID \(int\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/author-template.php + - + message: '#^Property WP_Http_Cookie\:\:\$path \(string\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php + - + message: '#^Property WP_Http_Cookie\:\:\$port \(int\|string\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/class-wp-http-cookie.php + - + message: '#^Property WP_Locale\:\:\$word_count_type \(string\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/class-wp-locale.php + - + message: '#^Property WP_Query\:\:\$max_num_pages \(int\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Property WP_Post_Type\:\:\$template \(array\\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-post-types-controller.php + - + message: '#^Property WP_User\:\:\$ID \(int\) on left side of \?\? is not nullable\.$#' + identifier: nullCoalesce.property + count: 1 + path: ../../../src/wp-includes/user.php diff --git a/tests/phpstan/baselines/parameterByRef.unusedType.neon b/tests/phpstan/baselines/parameterByRef.unusedType.neon new file mode 100644 index 0000000000000..73746ef20c078 --- /dev/null +++ b/tests/phpstan/baselines/parameterByRef.unusedType.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `parameterByRef.unusedType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/parameterByRef.unusedType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=parameterByRef.unusedType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Function _wp_scan_utf8\(\) never assigns null to &\$has_noncharacters so it can be removed from the by\-ref type\.$#' + identifier: parameterByRef.unusedType + count: 1 + path: ../../../src/wp-includes/compat-utf8.php + - + message: '#^Function _wp_utf8_codepoint_span\(\) never assigns null to &\$found_code_points so it can be removed from the by\-ref type\.$#' + identifier: parameterByRef.unusedType + count: 1 + path: ../../../src/wp-includes/compat-utf8.php diff --git a/tests/phpstan/baselines/property.onlyWritten.neon b/tests/phpstan/baselines/property.onlyWritten.neon new file mode 100644 index 0000000000000..f4b740e1bdf02 --- /dev/null +++ b/tests/phpstan/baselines/property.onlyWritten.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `property.onlyWritten` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.onlyWritten +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.onlyWritten +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_REST_Template_Autosaves_Controller\:\:\$parent_post_type is never read, only written\.$#' + identifier: property.onlyWritten + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-template-autosaves-controller.php diff --git a/tests/phpstan/baselines/property.unusedType.neon b/tests/phpstan/baselines/property.unusedType.neon new file mode 100644 index 0000000000000..9f1bd06e86c8f --- /dev/null +++ b/tests/phpstan/baselines/property.unusedType.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `property.unusedType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/property.unusedType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=property.unusedType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Property WP_HTML_Tag_Processor\:\:\$skip_newline_at \(int\|null\) is never assigned int so it can be removed from the property type\.$#' + identifier: property.unusedType + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php diff --git a/tests/phpstan/baselines/return.unusedType.neon b/tests/phpstan/baselines/return.unusedType.neon new file mode 100644 index 0000000000000..2acebf529a781 --- /dev/null +++ b/tests/phpstan/baselines/return.unusedType.neon @@ -0,0 +1,100 @@ +# PHPStan baseline for the `return.unusedType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/return.unusedType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=return.unusedType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Function plugins_api\(\) never returns array so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Function _fix_attachment_links\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Function get_preferred_from_update_core\(\) never returns array so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-admin/includes/update.php + - + message: '#^Function get_the_tag_list\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/category-template.php + - + message: '#^Function get_the_tag_list\(\) never returns false so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/category-template.php + - + message: '#^Function get_category\(\) never returns null so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/category.php + - + message: '#^Method WP_Recovery_Mode_Cookie_Service\:\:recovery_mode_hash\(\) never returns false so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/class-wp-recovery-mode-cookie-service.php + - + message: '#^Function wp_get_code_editor_settings\(\) never returns false so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Function get_post_gallery\(\) never returns string so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/media.php + - + message: '#^Function wp_imagecreatetruecolor\(\) never returns GdImage so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/media.php + - + message: '#^Function wp_mime_type_icon\(\) never returns false so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Function _set_preview\(\) never returns false so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/revision.php + - + message: '#^Function get_term_to_edit\(\) never returns int so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Function get_term_to_edit\(\) never returns null so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Function wp_is_password_reset_allowed_for_user\(\) never returns WP_Error so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-includes/user.php + - + message: '#^Function validate_another_blog_signup\(\) never returns null so it can be removed from the return type\.$#' + identifier: return.unusedType + count: 1 + path: ../../../src/wp-signup.php diff --git a/tests/phpstan/baselines/smallerOrEqual.alwaysTrue.neon b/tests/phpstan/baselines/smallerOrEqual.alwaysTrue.neon new file mode 100644 index 0000000000000..aed03b30ea48d --- /dev/null +++ b/tests/phpstan/baselines/smallerOrEqual.alwaysTrue.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `smallerOrEqual.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/smallerOrEqual.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=smallerOrEqual.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Comparison operation "\<\=" between 0 and int\<0, max\>\|false is always true\.$#' + identifier: smallerOrEqual.alwaysTrue + count: 1 + path: ../../../src/wp-includes/class-wp-theme-json.php diff --git a/tests/phpstan/baselines/ternary.alwaysFalse.neon b/tests/phpstan/baselines/ternary.alwaysFalse.neon new file mode 100644 index 0000000000000..b73c48bc42724 --- /dev/null +++ b/tests/phpstan/baselines/ternary.alwaysFalse.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `ternary.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/ternary.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=ternary.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Ternary operator condition is always false\.$#' + identifier: ternary.alwaysFalse + count: 2 + path: ../../../src/wp-admin/includes/class-wp-debug-data.php diff --git a/tests/phpstan/baselines/ternary.alwaysTrue.neon b/tests/phpstan/baselines/ternary.alwaysTrue.neon new file mode 100644 index 0000000000000..295254051f683 --- /dev/null +++ b/tests/phpstan/baselines/ternary.alwaysTrue.neon @@ -0,0 +1,30 @@ +# PHPStan baseline for the `ternary.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/ternary.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=ternary.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Ternary operator condition is always true\.$#' + identifier: ternary.alwaysTrue + count: 1 + path: ../../../src/wp-admin/menu-header.php + - + message: '#^Ternary operator condition is always true\.$#' + identifier: ternary.alwaysTrue + count: 1 + path: ../../../src/wp-admin/theme-install.php diff --git a/tests/phpstan/baselines/while.alwaysFalse.neon b/tests/phpstan/baselines/while.alwaysFalse.neon new file mode 100644 index 0000000000000..3c924003ea783 --- /dev/null +++ b/tests/phpstan/baselines/while.alwaysFalse.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `while.alwaysFalse` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/while.alwaysFalse +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=while.alwaysFalse +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^While loop condition is always false\.$#' + identifier: while.alwaysFalse + count: 1 + path: ../../../src/wp-includes/feed-rdf.php diff --git a/tests/phpstan/baselines/while.alwaysTrue.neon b/tests/phpstan/baselines/while.alwaysTrue.neon new file mode 100644 index 0000000000000..5da6550e89cc0 --- /dev/null +++ b/tests/phpstan/baselines/while.alwaysTrue.neon @@ -0,0 +1,300 @@ +# PHPStan baseline for the `while.alwaysTrue` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/while.alwaysTrue +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=while.alwaysTrue +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/author.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/category.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/showcase.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/tag.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/author.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/category.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/tag.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/taxonomy-post_format.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/front-page.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-attachment.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-page.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-single.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/author.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/category.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/tag.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/taxonomy-post_format.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/author.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/category.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/tag.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/singular.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/templates/template-cover.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/archive.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/index.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/search.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-includes/block-template.php + - + message: '#^While loop condition is always true\.$#' + identifier: while.alwaysTrue + count: 1 + path: ../../../src/wp-includes/theme-compat/embed.php From b00336ac8f018202db0b5a6760cbf2b87a7b34f1 Mon Sep 17 00:00:00 2001 From: Weston Ruter Date: Wed, 5 Aug 2026 08:37:55 +0000 Subject: [PATCH 128/138] Build/Test Tools: Raise the PHPStan rule level to 5. This rule level includes: > checking types of arguments passed to methods and functions Baselines are regenerated for errors at this level. Developed in https://github.com/WordPress/wordpress-develop/pull/12855. Follow-up to r61699, r63019, r63020, r63021, r63022, r63023. Props westonruter, apermo. See #64680. git-svn-id: https://develop.svn.wordpress.org/trunk@63024 602fd350-edb4-49c9-b593-d223f7449a82 --- phpstan.neon.dist | 5 +- tests/phpstan/baselines/argument.type.neon | 1885 +++++++++++++++++ .../baselines/argument.unresolvableType.neon | 25 + tests/phpstan/baselines/arrayValues.list.neon | 25 + 4 files changed, 1939 insertions(+), 1 deletion(-) create mode 100644 tests/phpstan/baselines/argument.type.neon create mode 100644 tests/phpstan/baselines/argument.unresolvableType.neon create mode 100644 tests/phpstan/baselines/arrayValues.list.neon diff --git a/phpstan.neon.dist b/phpstan.neon.dist index d6c66d62e9bbe..3dcf0f6c2c0de 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -22,7 +22,10 @@ includes: # Regenerate with `composer phpstan:baselines`, which rewrites both the files # and the list between the markers. Do not edit that list by hand. # phpstan:baselines start + - tests/phpstan/baselines/argument.type.neon + - tests/phpstan/baselines/argument.unresolvableType.neon - tests/phpstan/baselines/arguments.count.neon + - tests/phpstan/baselines/arrayValues.list.neon - tests/phpstan/baselines/assign.propertyType.neon - tests/phpstan/baselines/binaryOp.invalid.neon - tests/phpstan/baselines/booleanAnd.alwaysFalse.neon @@ -97,7 +100,7 @@ includes: parameters: # https://phpstan.org/user-guide/rule-levels - level: 4 + level: 5 reportUnmatchedIgnoredErrors: true # The following ignored errors are not intended to be fixed, as distinct from the baselines diff --git a/tests/phpstan/baselines/argument.type.neon b/tests/phpstan/baselines/argument.type.neon new file mode 100644 index 0000000000000..4415f515ba9e6 --- /dev/null +++ b/tests/phpstan/baselines/argument.type.neon @@ -0,0 +1,1885 @@ +# PHPStan baseline for the `argument.type` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/argument.type +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=argument.type +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Parameter \#1 \$key of function remove_query_arg expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-activate.php + - + message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/admin-header.php + - + message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/comment.php + - + message: '#^Parameter \#1 \$post of function get_post_status expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/comment.php + - + message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/comment.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, bool given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/customize.php + - + message: '#^Parameter \#1 \$position of function wp_comment_reply expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-comments.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-admin/edit-comments.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-comments.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-comments.php + - + message: '#^Parameter \#1 \$screen of function do_meta_boxes expects string\|WP_Screen, null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/edit-form-advanced.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-form-advanced.php + - + message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-form-comment.php + - + message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/edit-form-comment.php + - + message: '#^Parameter \#1 \$screen of function do_meta_boxes expects string\|WP_Screen, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-form-comment.php + - + message: '#^Parameter \#1 \$screen of function do_meta_boxes expects string\|WP_Screen, null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/edit-link-form.php + - + message: '#^Parameter \#3 \$name of function submit_button expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit-tag-form.php + - + message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit.php + - + message: '#^Parameter \#1 \$post of function get_post_type expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/edit.php + - + message: '#^Parameter \#1 \$attachment of function wp_get_attachment_id3_keys expects WP_Post, stdClass given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#1 \$comment_id of function _wp_ajax_delete_comment_response expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#2 \$compare_from of function wp_get_revision_ui_diff expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#3 \$compare_to of function wp_get_revision_ui_diff expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ajax-actions.php + - + message: '#^Parameter \#2 \$gmt of function current_time expects bool, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/bookmark.php + - + message: '#^Parameter \#2 \$allowed_html of function wp_kses expects array\\|string, array\\|true\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-automatic-upgrader-skin.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-bulk-upgrader-skin.php + - + message: '#^Parameter \#1 \$text of function esc_js expects string, int given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-admin/includes/class-bulk-upgrader-skin.php + - + message: '#^Parameter \#1 \$text of function submit_button expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-custom-background.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, \(float\|int\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-custom-image-header.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, float\|int given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-admin/includes/class-custom-image-header.php + - + message: '#^Parameter \#1 \$text of function submit_button expects string, null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-custom-image-header.php + - + message: '#^Parameter \#1 \$language_updates of method Language_Pack_Upgrader\:\:bulk_upgrade\(\) expects array\, list\\|string\|false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-language-pack-upgrader.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-walker-nav-menu-edit.php + - + message: '#^Parameter \#1 \$str of function md5 expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-automatic-updater.php + - + message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-comments-list-table.php + - + message: '#^Parameter \#3 \$post of function get_comment_class expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-comments-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-ms-users-list-table.php + - + message: '#^Parameter \#3 \$number of function _nx expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-plugin-install-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-plugins-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-privacy-data-export-requests-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-privacy-data-removal-requests-list-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/class-wp-privacy-requests-table.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-screen.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-screen.php + - + message: '#^Parameter \#1 \$version of function get_core_checksums expects string, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health-auto-updates.php + - + message: '#^Parameter \#1 \$bytes of function size_format expects int\|string, float\|false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Parameter \#2 \$allowed_html of function wp_kses expects array\\|string, array\\|true\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Parameter \#2 \$allowed_html of function wp_kses expects array\\|string, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-site-health.php + - + message: '#^Parameter \#1 \$args of function WP_Filesystem expects array\|false, true given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/class-wp-upgrader.php + - + message: '#^Parameter \#1 \$post of function _draft_or_post_title expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^Parameter \#1 \$post of function get_the_permalink expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^Parameter \#3 \$name of function submit_button expects string, false given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/dashboard.php + - + message: '#^Parameter \#1 \$callback of function array_map expects \(callable\(stdClass\)\: mixed\)\|null, ''get_comment'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/export.php + - + message: '#^Parameter \#1 \$term of function get_term expects int\|object, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/export.php + - + message: '#^Parameter \#2 \$callback of function add_filter expects callable\(\)\: mixed, ''wxr_filter_postmeta'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/export.php + - + message: '#^Parameter \#1 \$str of function md5 expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/file.php + - + message: '#^Parameter \#1 \$image of function is_gd_image expects GdImage\|resource\|false, WP_Image_Editor given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#1 \$width of function wp_imagecreatetruecolor expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#2 \$height of function wp_imagecreatetruecolor expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#5 \$src_x of function imagecopy expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#6 \$src_y of function imagecopy expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#7 \$src_w of function imagecopy expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#8 \$src_h of function imagecopy expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/image-edit.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_attachment expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/import.php + - + message: '#^Parameter \#1 \$number of function number_format_i18n expects float, string given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-admin/includes/media.php + - + message: '#^Parameter \#1 \$post_id of function get_media_items expects int, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/media.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/media.php + - + message: '#^Parameter \#2 \$result of function wp_parse_str expects array, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/menu.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/meta-boxes.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 8 + path: ../../../src/wp-admin/includes/misc.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/misc.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/misc.php + - + message: '#^Parameter \#1 \$link_id of function wp_delete_link expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ms.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_post expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ms.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ms.php + - + message: '#^Parameter \#3 \$value of function update_blog_status expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/ms.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_post expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^Parameter \#2 \$arr2 of function array_intersect expects an array of values castable to string, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^Parameter \#7 \$callback_args of function add_meta_box expects array\|null, WP_Post_Type given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/nav-menu.php + - + message: '#^Parameter \#1 \$tags of function wp_generate_tag_cloud expects array\, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Parameter \#3 \$name of function submit_button expects string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Parameter \#3 \$number of function _nx expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/plugin-install.php + - + message: '#^Parameter \#2 \$allowed_html of function wp_kses expects array\\|string, array\\|true\> given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-admin/includes/plugin.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Parameter \#2 \$fallback_title of function sanitize_title expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/includes/post.php + - + message: '#^Parameter \#1 \$user_id of function switch_to_user_locale expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/privacy-tools.php + - + message: '#^Parameter \#2 \$user_id of function get_the_author_meta expects int\|false, ''''\|numeric\-string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/revision.php + - + message: '#^Parameter \#1 \$str of function md5 expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/schema.php + - + message: '#^Parameter \#2 \$multiplier of function str_repeat expects int, float given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-admin/includes/template.php + - + message: '#^Parameter \#2 \$title of function add_meta_box expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/template.php + - + message: '#^Parameter \#3 \$callback of function add_meta_box expects callable\(\)\: mixed, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/template.php + - + message: '#^Parameter \#1 \$update of method Language_Pack_Upgrader\:\:upgrade\(\) expects string\|false, stdClass given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/translation-install.php + - + message: '#^Parameter \#3 \$overwrite of method WP_Filesystem_Base\:\:copy\(\) expects bool, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/update-core.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/update.php + - + message: '#^Parameter \#1 \$timestamp of function wp_schedule_event expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/upgrade.php + - + message: '#^Parameter \#3 \$deprecated of function add_option expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/upgrade.php + - + message: '#^Parameter \#1 \$bookmark_id of function clean_bookmark_cache expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#1 \$link_id of function wp_delete_link expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#1 \$post of function clean_post_cache expects int\|WP_Post, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_post expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#1 \$user of function wp_get_user_contact_methods expects WP_User\|null, stdClass given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/includes/user.php + - + message: '#^Parameter \#4 \$is_public of function wp_install expects bool, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/install.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 5 + path: ../../../src/wp-admin/nav-menus.php + - + message: '#^Parameter \#2 \$menu_data of function wp_save_nav_menu_items expects array\, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/nav-menus.php + - + message: '#^Parameter \#1 \$network_id of function can_edit_network expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-info.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-info.php + - + message: '#^Parameter \#1 \$network_id of function can_edit_network expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-settings.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-settings.php + - + message: '#^Parameter \#1 \$network_id of function can_edit_network expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-themes.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/network/site-themes.php + - + message: '#^Parameter \#1 \$network_id of function can_edit_network expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/network/site-users.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-admin/network/site-users.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-admin/network/sites.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<2, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/options-discussion.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, bool given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/options-general.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, 6\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/options-general.php + - + message: '#^Parameter \#2 \$callback of function array_filter expects \(callable\(mixed\)\: bool\)\|null, ''validate_file'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/plugins.php + - + message: '#^Parameter \#2 \$newvalue of function ini_set expects string, true given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/plugins.php + - + message: '#^Parameter \#2 \$newvalue of function ini_set expects string, true given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/update.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-admin/user-edit.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 10 + path: ../../../src/wp-admin/users.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/author.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/content-image.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-content/themes/twentyeleven/content-single.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/functions.php + - + message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/functions.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/image.php + - + message: '#^Parameter \#1 \$screen of function add_contextual_help expects string, WP_Screen\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/theme-options.php + - + message: '#^Parameter \#3 \$args of function register_setting expects array, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/theme-options.php + - + message: '#^Parameter \#3 \$deps of function wp_enqueue_style expects array\, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/theme-options.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/inc/widgets.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/showcase.php + - + message: '#^Parameter \#2 \$instance of function the_widget expects array, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyeleven/showcase.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/author-bio.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/image.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfifteen/inc/template-tags.php + - + message: '#^Parameter \#3 \$number of function _n expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/functions.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/image.php + - + message: '#^Parameter \#1 \$text of function esc_html expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-content/themes/twentyfourteen/image.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/template-tags.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyfourteen/inc/widgets.php + - + message: '#^Parameter \#3 \$deps of function wp_enqueue_style expects array\, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/functions.php + - + message: '#^Parameter \#1 \$num of function dechex expects int, float given\.$#' + identifier: argument.type + count: 6 + path: ../../../src/wp-content/themes/twentynineteen/inc/helper-functions.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/inc/helper-functions.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/inc/template-tags.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentynineteen/template-parts/post/author-bio.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/inc/color-patterns.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/inc/template-tags.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, \(float\|int\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page-panels.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, \(float\|int\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyseventeen/template-parts/page/content-front-page.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/image.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/inc/template-tags.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentysixteen/template-parts/biography.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/author.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/functions.php + - + message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/functions.php + - + message: '#^Parameter \#1 \$wp_head_callback of function add_custom_image_header expects callable\(\)\: mixed, '''' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/functions.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-attachment.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-attachment.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-attachment.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentyten/loop-single.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/author-bio.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/author.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/functions.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentythirteen/image.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/author.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/content.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/functions.php + - + message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/functions.php + - + message: '#^Parameter \#1 \$size of function next_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/image.php + - + message: '#^Parameter \#1 \$size of function previous_image_link expects array\\|string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwelve/image.php + - + message: '#^Parameter \#4 \$prefix of function twentytwenty_generate_css expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php + - + message: '#^Parameter \#5 \$suffix of function twentytwenty_generate_css expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/classes/class-twentytwenty-non-latin-languages.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-content/themes/twentytwenty/functions.php + - + message: '#^Parameter \#3 \$deps of function wp_enqueue_style expects array\, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/functions.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/inc/template-tags.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwenty/template-parts/entry-author-bio.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\|false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/inc/template-functions.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/inc/template-tags.php + - + message: '#^Parameter \#1 \$author_id of function get_author_posts_url expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/template-parts/post/author-bio.php + - + message: '#^Parameter \#2 \$size of function get_avatar expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-content/themes/twentytwentyone/template-parts/post/author-bio.php + - + message: '#^Parameter \#1 \$userid of function count_user_posts expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/author-template.php + - + message: '#^Parameter \#1 \$separator of function explode expects string, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/block-supports/layout.php + - + message: '#^Parameter \#1 \$block of function filter_block_kses expects WP_Block_Parser_Block, array given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/blocks.php + - + message: '#^Parameter \#4 \$block_context of function filter_block_kses_value expects array\|null, WP_Block_Parser_Block given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/blocks.php + - + message: '#^Parameter \#1 \$post of function get_permalink expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/canonical.php + - + message: '#^Parameter \#1 \$post_id of function get_post_comments_feed_link expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/canonical.php + - + message: '#^Parameter \#2 \$callback of function preg_replace_callback expects callable\(array\\)\: string, ''lowercase_octets'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/canonical.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/capabilities.php + - + message: '#^Parameter \#1 \$name of class WP_Block_Parser_Block constructor expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-block-parser.php + - + message: '#^Parameter \#1 \$child_id of method WP_Comment\:\:get_child\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-comment-query.php + - + message: '#^Parameter \#1 \$ids of function _prime_post_caches expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-comment-query.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-customize-control.php + - + message: '#^Parameter \#1 \$ajax_message of method WP_Customize_Manager\:\:wp_die\(\) expects string\|WP_Error, int given\.$#' + identifier: argument.type + count: 6 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Parameter \#1 \$month of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Parameter \#2 \$day of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Parameter \#3 \$year of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-customize-manager.php + - + message: '#^Parameter \#1 \$text of function esc_html expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-date-query.php + - + message: '#^Parameter \#2 \$parent_query of method WP_Date_Query\:\:get_sql_for_clause\(\) expects array, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-date-query.php + - + message: '#^Parameter \#2 \$timestamp of function gmdate expects int, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-date-query.php + - + message: '#^Parameter \#2 \$value of method WP_Date_Query\:\:build_value\(\) expects array\|string, int given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/class-wp-date-query.php + - + message: '#^Parameter \#2 \$value of method WP_Date_Query\:\:build_value\(\) expects array\|string, int\|null given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/class-wp-date-query.php + - + message: '#^Parameter \#1 \$value of static method WP_Duotone\:\:colord_parse_hue\(\) expects float, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-duotone.php + - + message: '#^Parameter \#3 \$priority of function _wp_filter_build_unique_id expects int, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-hook.php + - + message: '#^Parameter \#3 \$value of function curl_setopt expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-http-curl.php + - + message: '#^Parameter \#2 \$mode of function stream_set_blocking expects bool, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-http-streams.php + - + message: '#^Parameter \#2 \$callback of method WP_Image_Editor_GD\:\:make_image\(\) expects callable\(\)\: mixed, ''imageavif'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-gd.php + - + message: '#^Parameter \#2 \$interlace of function imageinterlace expects int, bool given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-gd.php + - + message: '#^Parameter \#2 \$limit of static method Imagick\:\:setResourceLimit\(\) expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Parameter \#2 \$value of method Imagick\:\:setOption\(\) expects string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Parameter \#2 \$value of method Imagick\:\:setOption\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Parameter \#2 \$value of method Imagick\:\:setOption\(\) expects string, true given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-image-editor-imagick.php + - + message: '#^Parameter \#1 \$ids of function _prime_post_caches expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-query.php + - + message: '#^Parameter \#1 \$pages of function get_page_hierarchy expects array\, list\\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-rewrite.php + - + message: '#^Parameter \#1 \$new_blog_id of function switch_to_blog expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-site.php + - + message: '#^Parameter \#1 \$metadata of method WP_Theme_JSON\:\:get_feature_declarations_for_node\(\) expects object, array given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Parameter \#1 \$node of method WP_Theme_JSON\:\:process_pseudo_selectors\(\) expects array, object given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Parameter \#1 \$styles of static method WP_Theme_JSON\:\:compute_style_properties\(\) expects array, object given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/class-wp-theme-json.php + - + message: '#^Parameter \#2 \$data of method WP_Theme\:\:cache_add\(\) expects array\|string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-theme.php + - + message: '#^Parameter \#1 \$str of function strtoupper expects string, bool given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-token-map.php + - + message: '#^Parameter \#1 \$level of method WP_User\:\:translate_level_to_cap\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-user.php + - + message: '#^Parameter \#1 \$number of method WP_Widget\:\:_set\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-widget.php + - + message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-xmlrpc-server.php + - + message: '#^Parameter \#1 \$term_id of method wp_xmlrpc_server\:\:get_term_custom_fields\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-xmlrpc-server.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/class-wp-xmlrpc-server.php + - + message: '#^Parameter \#1 \$comment_id of function get_page_of_comment expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment-template.php + - + message: '#^Parameter \#1 \$post of function get_permalink expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment-template.php + - + message: '#^Parameter \#1 \$post of function post_password_required expects int\|WP_Post\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment-template.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/comment-template.php + - + message: '#^Parameter \#1 \$comment of function get_comment_link expects int\|WP_Comment\|null, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$comment_id of function add_comment_meta expects int, string given\.$#' + identifier: argument.type + count: 5 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$comment_id of function delete_comment_meta expects int, string given\.$#' + identifier: argument.type + count: 8 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$comment_id of function get_comment_text expects int\|WP_Comment, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$comment_id of function get_page_of_comment expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$comments of function update_comment_cache expects array\, list\\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$content of function pingback expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$ids of function clean_comment_cache expects array\|int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$post_id of function wp_update_comment_count expects int\|null, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#2 \$object_ids of function update_meta_cache expects array\\|string, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/comment.php + - + message: '#^Parameter \#1 \$gmt_time of function spawn_cron expects int, float given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/cron.php + - + message: '#^Parameter \#1 \$container_context of method WP_Customize_Partial\:\:render\(\) expects array, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/customize/class-wp-customize-selective-refresh.php + - + message: '#^Parameter \#1 \$response of method WP_REST_Server\:\:response_to_data\(\) expects WP_REST_Response, WP_HTTP_Response given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/embed.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/embed.php + - + message: '#^Parameter \#1 \$post_id of function get_post_comments_feed_link expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/feed-atom-comments.php + - + message: '#^Parameter \#1 \$post_id of function get_post_comments_feed_link expects int, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/feed-rss2.php + - + message: '#^Parameter \#1 \$post of function get_the_guid expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/feed.php + - + message: '#^Parameter \#2 \$message of class WP_Error constructor expects string, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/feed.php + - + message: '#^Parameter \#2 \$callback of function preg_replace_callback expects callable\(array\\)\: string, ''_links_add_base'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Parameter \#2 \$callback of function preg_replace_callback expects callable\(array\\)\: string, ''_links_add_target'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/formatting.php + - + message: '#^Parameter \#1 \$prefix of function uniqid expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#1 \$weekday_number of method WP_Locale\:\:get_weekday\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#2 \$fallback_url of function wp_validate_redirect expects string, false given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#3 \$number of function _n expects int, string given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#4 \$mon of function mktime expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#5 \$day of function mktime expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#6 \$year of function mktime expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/functions.php + - + message: '#^Parameter \#1 \$string of function strlen expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#1 \$string of function substr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#1 \$string of function substr expects string, int\\|int\<1, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, float given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, int\<1, max\> given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, int\\|int\<2, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#3 \$url of function wp_admin_css_color expects string, false given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/general-template.php + - + message: '#^Parameter \#1 \$name of method WP_HTML_Tag_Processor\:\:set_bookmark\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-processor.php + - + message: '#^Parameter \#4 \$length of function substr_compare expects int, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/html-api/class-wp-html-tag-processor.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/link-template.php + - + message: '#^Parameter \#1 \$str of function md5 expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^Parameter \#2 \$newvalue of function ini_set expects string, int given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-includes/load.php + - + message: '#^Parameter \#3 \$subject of function str_replace expects array\\|string, array\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/load.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int\<1, 9\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/media-template.php + - + message: '#^Parameter \#1 \$text of function esc_html expects string, int\<1, 9\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/media-template.php + - + message: '#^Parameter \#5 \$text of function wp_get_attachment_link expects string\|false, bool given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/media.php + - + message: '#^Parameter \#2 \$callback of function array_walk expects callable\(non\-empty\-string\|null, int\<0, max\>\)\: mixed, ''clean_bookmark_cache'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-functions.php + - + message: '#^Parameter \#2 \$callback of function array_walk expects callable\(non\-empty\-string\|null, int\<0, max\>\)\: mixed, ''clean_post_cache'' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-functions.php + - + message: '#^Parameter \#3 \$value of function update_blog_status expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-functions.php + - + message: '#^Parameter \#1 \$network_id of static method WP_Network\:\:get_instance\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-load.php + - + message: '#^Parameter \#1 \$month of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-site.php + - + message: '#^Parameter \#2 \$day of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-site.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-site.php + - + message: '#^Parameter \#2 \$object_id of function delete_metadata expects int, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-site.php + - + message: '#^Parameter \#3 \$year of function wp_checkdate expects int, \(string\|false\) given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/ms-site.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_post expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/nav-menu.php + - + message: '#^Parameter \#2 \$value of function setcookie expects string, int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/option.php + - + message: '#^Parameter \#1 \$engine of class Text_Diff constructor expects string, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$number of function number_format_i18n expects float, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$post of function get_edit_post_link expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$post of function get_permalink expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 4 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$user of function user_can expects int\|WP_User, string given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$user_id of function get_userdata expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#3 \$number of function _n expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/pluggable.php + - + message: '#^Parameter \#1 \$attachment of function is_attachment expects array\\|int\|string, WP_Post given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Parameter \#1 \$url of function user_trailingslashit expects string, int\\|int\<2, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Parameter \#2 \$fallback of function sanitize_html_class expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Parameter \#2 \$replace of function str_replace expects array\\|string, int\<1, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Parameter \#2 \$user_id of function get_the_author_meta expects int\|false, ''''\|numeric\-string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post-template.php + - + message: '#^Parameter \#1 \$comment_id of function wp_delete_comment expects int\|WP_Comment, string\|null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$month of function wp_checkdate expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$post of function clean_post_cache expects int\|WP_Post, stdClass given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$post of function get_post expects int\|numeric\-string\|WP_Post\|null, stdClass given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$post_id of function wp_delete_post expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$posts of function update_post_cache expects array\, list\ given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$revision of function wp_delete_post_revision expects int\|WP_Post, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$string of function strlen expects string, int\<2, max\> given\.$#' + identifier: argument.type + count: 3 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#2 \$day of function wp_checkdate expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#2 \$object_id of function delete_metadata expects int, null given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#3 \$year of function wp_checkdate expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/post.php + - + message: '#^Parameter \#1 \$response of method WP_REST_Server\:\:response_to_data\(\) expects WP_REST_Response, WP_HTTP_Response given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api.php + - + message: '#^Parameter \#1 \$haystack of function str_starts_with expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/class-wp-rest-server.php + - + message: '#^Parameter \#1 \$response of method WP_REST_Server\:\:envelope_response\(\) expects WP_REST_Response, WP_HTTP_Response given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/class-wp-rest-server.php + - + message: '#^Parameter \#1 \$response of method WP_REST_Server\:\:response_to_data\(\) expects WP_REST_Response, WP_HTTP_Response given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/class-wp-rest-server.php + - + message: '#^Parameter \#1 \$data_object of method WP_REST_Controller\:\:update_additional_fields_for_object\(\) expects object, array given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-application-passwords-controller.php + - + message: '#^Parameter \#1 \$comment_id of function get_comment_type expects int\|WP_Comment, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#1 \$comment_id of function wp_delete_comment expects int\|WP_Comment, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#1 \$comment_id of function wp_trash_comment expects int\|WP_Comment, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#1 \$object_id of method WP_REST_Meta_Fields\:\:get_value\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#2 \$comment_id of method WP_REST_Comments_Controller\:\:handle_status_param\(\) expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#2 \$object_id of method WP_REST_Meta_Fields\:\:update_value\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-comments-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-font-collections-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-global-styles-revisions-controller.php + - + message: '#^Parameter \#1 \$data_object of method WP_REST_Controller\:\:update_additional_fields_for_object\(\) expects object, array given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-plugins-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-revisions-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-search-controller.php + - + message: '#^Parameter \#1 \$args of function get_taxonomies expects array, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-taxonomies-controller.php + - + message: '#^Parameter \#1 \$id of function get_block_template expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php + - + message: '#^Parameter \#1 \$id of method WP_REST_Templates_Controller\:\:prepare_links\(\) expects int, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-templates-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-terms-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int\<0, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-themes-controller.php + - + message: '#^Parameter \#2 \$value of method WP_HTTP_Response\:\:header\(\) expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/rest-api/endpoints/class-wp-rest-users-controller.php + - + message: '#^Parameter \#2 \$src of method WP_Dependencies\:\:add\(\) expects string\|false, true given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/script-loader.php + - + message: '#^Parameter \#1 \$object_id of function wp_remove_object_terms expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#1 \$object_id of function wp_set_object_terms expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#1 \$object_ids of function wp_get_object_terms expects array\\|int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#1 \$post_id of function update_post_meta expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#1 \$terms of function update_term_cache expects array\, list\\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#1 \$terms of function wp_update_term_count expects array\|int, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#2 \$fallback_title of function sanitize_title expects string, int given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#2 \$meta_id of function delete_metadata_by_mid expects int, string\|null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#2 \$taxonomy of function wp_update_term_count expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/taxonomy.php + - + message: '#^Parameter \#2 \$newvalue of function ini_set expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/template.php + - + message: '#^Parameter \#3 \$replacement of function _deprecated_file expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/theme-compat/comments.php + - + message: '#^Parameter \#3 \$replacement of function _deprecated_file expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/theme-compat/footer.php + - + message: '#^Parameter \#3 \$replacement of function _deprecated_file expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/theme-compat/header.php + - + message: '#^Parameter \#3 \$replacement of function _deprecated_file expects string, null given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/theme-compat/sidebar.php + - + message: '#^Parameter \#1 \$string of function strlen expects string, int\<2, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/theme-templates.php + - + message: '#^Parameter \#1 \$string of function mb_strlen expects string, int\<2, max\> given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/user.php + - + message: '#^Parameter \#1 \$user_id of function switch_to_user_locale expects int, string given\.$#' + identifier: argument.type + count: 2 + path: ../../../src/wp-includes/user.php + - + message: '#^Parameter \#3 \$control_callback of function wp_register_widget_control expects callable\(\)\: mixed, '''' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/widgets.php + - + message: '#^Parameter \#3 \$output_callback of function wp_register_sidebar_widget expects callable\(\)\: mixed, '''' given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/widgets.php + - + message: '#^Parameter \#1 \$text of function esc_attr expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-nav-menu-widget.php + - + message: '#^Parameter \#1 \$post of function get_the_title expects int\|WP_Post, string given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-includes/widgets/class-wp-widget-recent-comments.php + - + message: '#^Parameter \#1 \$text of function esc_html expects string, int given\.$#' + identifier: argument.type + count: 1 + path: ../../../src/wp-mail.php diff --git a/tests/phpstan/baselines/argument.unresolvableType.neon b/tests/phpstan/baselines/argument.unresolvableType.neon new file mode 100644 index 0000000000000..b6015731f858b --- /dev/null +++ b/tests/phpstan/baselines/argument.unresolvableType.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `argument.unresolvableType` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/argument.unresolvableType +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=argument.unresolvableType +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Parameter \#1 \$array_arg of function uksort contains unresolvable type\.$#' + identifier: argument.unresolvableType + count: 2 + path: ../../../src/wp-includes/cron.php diff --git a/tests/phpstan/baselines/arrayValues.list.neon b/tests/phpstan/baselines/arrayValues.list.neon new file mode 100644 index 0000000000000..630c8e6bd1879 --- /dev/null +++ b/tests/phpstan/baselines/arrayValues.list.neon @@ -0,0 +1,25 @@ +# PHPStan baseline for the `arrayValues.list` errors in WordPress core. +# +# https://phpstan.org/error-identifiers/arrayValues.list +# +# Each entry is scoped to a single file and carries an exact occurrence count, +# so that a new instance is reported as a new error rather than being absorbed +# silently. Fixing an occurrence therefore means decrementing or removing its +# entry here as part of the same change. +# +# The goal is to empty this file and delete it, along with the `includes` entry +# for it in phpstan.neon.dist. +# +# Generated by `composer phpstan:baselines`. Do not edit by hand; regenerate with +# +# composer phpstan:baselines -- --identifier=arrayValues.list +# +# which reruns the analysis with this file suppressed so the errors surface again. + +parameters: + ignoreErrors: + - + message: '#^Parameter \#1 \$array \(non\-empty\-list\\) of array_values is already a list, call has no effect\.$#' + identifier: arrayValues.list + count: 1 + path: ../../../src/wp-admin/includes/image.php From 7d6fa3a8728c3d25ea173d3893a69c1f13d1b65a Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 5 Aug 2026 09:01:33 +0000 Subject: [PATCH 129/138] Tests: Add unit tests for `wp_privacy_exports_dir()`. This adds coverage for the personal data exports directory, verifying both the default location under the uploads directory and that the filter of the same name can override it. Developed in: https://github.com/WordPress/wordpress-develop/pull/5553 Props desrosj, masteradhoc, mindctrl, pbearne, wildworks. Fixes #59710. git-svn-id: https://develop.svn.wordpress.org/trunk@63025 602fd350-edb4-49c9-b593-d223f7449a82 --- .../tests/functions/wpPrivacyExportsDir.php | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 tests/phpunit/tests/functions/wpPrivacyExportsDir.php diff --git a/tests/phpunit/tests/functions/wpPrivacyExportsDir.php b/tests/phpunit/tests/functions/wpPrivacyExportsDir.php new file mode 100644 index 0000000000000..ddf068e4d8475 --- /dev/null +++ b/tests/phpunit/tests/functions/wpPrivacyExportsDir.php @@ -0,0 +1,43 @@ +assertSame( $expected, wp_privacy_exports_dir() ); + } + + /** + * @ticket 59710 + */ + public function test_wp_privacy_exports_dir_filtered() { + add_filter( 'wp_privacy_exports_dir', array( $this, 'filter_wp_privacy_exports_dir' ) ); + + $upload_dir = wp_upload_dir(); + $expected_dir = trailingslashit( $upload_dir['basedir'] ) . 'filtered-exports/'; + $actual_dir = wp_privacy_exports_dir(); + $this->assertSame( $expected_dir, $actual_dir ); + + remove_filter( 'wp_privacy_exports_dir', array( $this, 'filter_wp_privacy_exports_dir' ) ); + } + + /** + * Filters the personal data exports directory for tests. + * + * @param string $exports_dir Default exports directory. + * @return string Filtered exports directory. + */ + public function filter_wp_privacy_exports_dir( $exports_dir ) { + return str_replace( 'wp-personal-data-exports/', 'filtered-exports/', $exports_dir ); + } +} From 08993c360f31447edca778db953c9baacbb46e0d Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 5 Aug 2026 12:07:22 +0000 Subject: [PATCH 130/138] General: Bump the pinned hash for Gutenberg to `f05e40`. This updates the pinned commit hash of the Gutenberg repository from `fd715a6833679d098d9fee84b642f8f1bc27341b` to `f05e40e91c54f29c449b1f33d0db89f5166812d9`. A full list of changes included in this commit can be found on GitHub: https://github.com/WordPress/gutenberg/compare/fd715a6833679d098d9fee84b642f8f1bc27341b...f05e40e91c54f29c449b1f33d0db89f5166812d9 - Writing flow: forward delete an empty paragraph without breaking apart the next block (https://github.com/WordPress/gutenberg/pull/80813) - Upload Media: Fail the item when the /finalize request fails (https://github.com/WordPress/gutenberg/pull/80725) - Fix template `modified` and `date` return value for file templates (https://github.com/WordPress/gutenberg/pull/80733) - Boot: Adjust specificity of the image reset styles so components can size their own images (https://github.com/WordPress/gutenberg/pull/80845) - Quote: Ensure paragraph placeholder appears after deleting nested blocks (https://github.com/WordPress/gutenberg/pull/77151) - Block editor: make the Group action wrap blocks with a group transform (https://github.com/WordPress/gutenberg/pull/80891) - Copy: preserve the block when its entire text is selected (https://github.com/WordPress/gutenberg/pull/80994) - Add opt-out for block style state controls (https://github.com/WordPress/gutenberg/pull/80956) (https://github.com/WordPress/gutenberg/pull/81004) - Tabs: Support Home and End keys for keyboard navigation (https://github.com/WordPress/gutenberg/pull/80912) - Rename blockStatesEnabled setting to blockStatesEditingEnabled (https://github.com/WordPress/gutenberg/pull/81058) - [WP 7.1] Background: Fix the legacy gradient UI where a gradient cannot be selected (https://github.com/WordPress/gutenberg/pull/81059) - Views: honor developer-defined view config overrides (https://github.com/WordPress/gutenberg/pull/80832) - Playlist: Add track icon (https://github.com/WordPress/gutenberg/pull/81078) - Remove the CODEOWNERS file from wp/7.1. (https://github.com/WordPress/gutenberg/pull/81104) - Notes: Email users mentioned in a note (https://github.com/WordPress/gutenberg/pull/79606) - Backport 81068 80744 80642 (https://github.com/WordPress/gutenberg/pull/81135) - Site Editor: Add E2E coverage for view config extensibility (https://github.com/WordPress/gutenberg/pull/80577) - change from https://github.com/WordPress/gutenberg/pull/81068/ (https://github.com/WordPress/gutenberg/pull/81140) - Link Control: Restore the preview title underline (https://github.com/WordPress/gutenberg/pull/81083) - Button: Suppress UA focus ring when focused and pressed (https://github.com/WordPress/gutenberg/pull/81113) - View config: add reference docs (https://github.com/WordPress/gutenberg/pull/81149) - Editor: Fix document tools button focus ring (https://github.com/WordPress/gutenberg/pull/81115) - Interface: Increase footer breadcrumb height to prevent focus ring clipping (https://github.com/WordPress/gutenberg/pull/81156) - Post editor: Add ThemeProvider for admin color schemes (https://github.com/WordPress/gutenberg/pull/81112) - Pass Playlist controls to track blocks (https://github.com/WordPress/gutenberg/pull/81158) - Theme: Omit color properties when neither provided nor inherited (https://github.com/WordPress/gutenberg/pull/80600) (https://github.com/WordPress/gutenberg/pull/81172) - Media: Improve the HEIC upload error and keep any upload errors up until dismissed (https://github.com/WordPress/gutenberg/pull/81130) - Video: Hide settings for the GIF variation (https://github.com/WordPress/gutenberg/pull/81142) - Video: clarify the Video variation description (https://github.com/WordPress/gutenberg/pull/81181) - Button: turn on the width setting by default in theme.json (https://github.com/WordPress/gutenberg/pull/81196) - Edit Widgets: Fix header toolbar button focus ring (https://github.com/WordPress/gutenberg/pull/81176) - Build: Wrap script bundles in an IIFE to contain 'use strict' (https://github.com/WordPress/gutenberg/pull/79792) - Customizer widgets: Add ThemeProvider for admin color schemes (https://github.com/WordPress/gutenberg/pull/81174) - Fix: Tabs block: Start with empty tab labels with placeholders (https://github.com/WordPress/gutenberg/pull/81197) - PanelColorSettings: Restore the missing space below the panel header (https://github.com/WordPress/gutenberg/pull/81155) - Visual revisions: add shareable urls (https://github.com/WordPress/gutenberg/pull/81205) - Notes: fix the mention notification email composition (https://github.com/WordPress/gutenberg/pull/81187) - Fix ESLint warnings for 'navigateRegionsProps' spread (https://github.com/WordPress/gutenberg/pull/81208) - Widgets editor: Add ThemeProvider for admin color schemes (https://github.com/WordPress/gutenberg/pull/81173) - Remove the editableRoot opt-in from the paragraph block (https://github.com/WordPress/gutenberg/pull/81184) - Media Attached to: Fix issue with the popover unexpectedly flipping, tweak wording (https://github.com/WordPress/gutenberg/pull/81206) - Ensure device preview is always accurate when window is zoomed in (https://github.com/WordPress/gutenberg/pull/81215) Props wildworks. See #65529. git-svn-id: https://develop.svn.wordpress.org/trunk@63026 602fd350-edb4-49c9-b593-d223f7449a82 --- package.json | 2 +- .../assets/script-loader-packages.php | 138 +++++++++--------- .../assets/script-modules-packages.php | 8 +- src/wp-includes/blocks/blocks-json.php | 1 + src/wp-includes/blocks/playlist/block.json | 1 + .../build/routes/connectors-home/content.js | 8 +- .../connectors-home/content.min.asset.php | 2 +- .../routes/connectors-home/content.min.js | 2 +- src/wp-includes/theme.json | 1 + 9 files changed, 86 insertions(+), 77 deletions(-) diff --git a/package.json b/package.json index 5264d752b8e4e..1fa7810849728 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "url": "https://develop.svn.wordpress.org/trunk" }, "gutenberg": { - "sha": "fd715a6833679d098d9fee84b642f8f1bc27341b", + "sha": "f05e40e91c54f29c449b1f33d0db89f5166812d9", "ghcrRepo": "WordPress/gutenberg/gutenberg-wp-develop-build" }, "engines": { diff --git a/src/wp-includes/assets/script-loader-packages.php b/src/wp-includes/assets/script-loader-packages.php index 47dd96b9b3485..6b0ed2811e9d4 100644 --- a/src/wp-includes/assets/script-loader-packages.php +++ b/src/wp-includes/assets/script-loader-packages.php @@ -4,7 +4,7 @@ 'wp-dom-ready', 'wp-i18n' ), - 'version' => '483af07a6016f640f456' + 'version' => '31c6cec5a4ff7aff483d' ), 'annotations.js' => array( 'dependencies' => array( @@ -13,7 +13,7 @@ 'wp-i18n', 'wp-rich-text' ), - 'version' => 'd4fe1eeb787c2fd5ee89' + 'version' => '348a030f1b5717cfaba4' ), 'api-fetch.js' => array( 'dependencies' => array( @@ -21,25 +21,25 @@ 'wp-private-apis', 'wp-url' ), - 'version' => 'b5b51750518787a93005' + 'version' => '6f2a4faeee3c722b1e57' ), 'autop.js' => array( 'dependencies' => array( ), - 'version' => '9d0d0901b46f0a9027c9' + 'version' => '4e10a18cb6f21a043fc0' ), 'base-styles.js' => array( 'dependencies' => array( ), - 'version' => '8ebe97b095beb7e9279b' + 'version' => '67fd7250ac73fa2feba5' ), 'blob.js' => array( 'dependencies' => array( ), - 'version' => '198af75fe06d924090d8' + 'version' => 'c7582a735ddd2edc9731' ), 'block-directory.js' => array( 'dependencies' => array( @@ -66,7 +66,7 @@ 'wp-theme', 'wp-url' ), - 'version' => 'e534a0f04643c4175bf3' + 'version' => '7c679438bdaf9853987a' ), 'block-editor.js' => array( 'dependencies' => array( @@ -104,7 +104,7 @@ 'wp-url', 'wp-warning' ), - 'version' => 'b1292aac86a5d819f737' + 'version' => '3e3993ced88d35b1fafc' ), 'block-library.js' => array( 'dependencies' => array( @@ -150,19 +150,19 @@ 'import' => 'dynamic' ) ), - 'version' => '97b70e2d8d72d9b83b4e' + 'version' => '6569ec7523b3693a2b2e' ), 'block-serialization-default-parser.js' => array( 'dependencies' => array( ), - 'version' => 'bff55bd3f1ce9df0c99c' + 'version' => '4c6f3dd40077f7c17604' ), 'block-serialization-spec-parser.js' => array( 'dependencies' => array( ), - 'version' => '9ebc5e95e1de1cabd1e6' + 'version' => '7b0b496c3d48b1ef3f9e' ), 'blocks.js' => array( 'dependencies' => array( @@ -183,7 +183,7 @@ 'wp-shortcode', 'wp-warning' ), - 'version' => '524509cfc84da30a4133' + 'version' => 'c0e57a630a0b6f6c3bb5' ), 'commands.js' => array( 'dependencies' => array( @@ -199,7 +199,7 @@ 'wp-primitives', 'wp-private-apis' ), - 'version' => '148d9b31ef4d2952561e' + 'version' => '1a4910212c7ed2355300' ), 'components.js' => array( 'dependencies' => array( @@ -224,7 +224,7 @@ 'wp-theme', 'wp-warning' ), - 'version' => 'd5254b2fdf63282d09f7' + 'version' => '7937a1d6ffdc16e88517' ), 'compose.js' => array( 'dependencies' => array( @@ -239,7 +239,7 @@ 'wp-private-apis', 'wp-undo-manager' ), - 'version' => '6176e314156a3d1f9501' + 'version' => '0e8bde2a499ea6073b42' ), 'core-commands.js' => array( 'dependencies' => array( @@ -256,7 +256,7 @@ 'wp-router', 'wp-url' ), - 'version' => '8fc41d3503f7892d3ed8' + 'version' => '426a33508599b7f31db3' ), 'core-data.js' => array( 'dependencies' => array( @@ -277,7 +277,7 @@ 'wp-url', 'wp-warning' ), - 'version' => 'c7a571126b75599516cf' + 'version' => 'f0176a9c136b2962fdc4' ), 'customize-widgets.js' => array( 'dependencies' => array( @@ -306,7 +306,13 @@ 'wp-theme', 'wp-widgets' ), - 'version' => '05ff2e24b332f5dc0ea1' + 'module_dependencies' => array( + array( + 'id' => '@wordpress/route', + 'import' => 'static' + ) + ), + 'version' => 'a73c35651dc8614d5fb3' ), 'data.js' => array( 'dependencies' => array( @@ -319,7 +325,7 @@ 'wp-private-apis', 'wp-redux-routine' ), - 'version' => 'c547bd40753de57cdc64' + 'version' => '14a216e0932d72c22976' ), 'data-controls.js' => array( 'dependencies' => array( @@ -327,32 +333,32 @@ 'wp-data', 'wp-deprecated' ), - 'version' => '730061ade69d7f341014' + 'version' => '7e8f932da184d5537725' ), 'date.js' => array( 'dependencies' => array( 'moment', 'wp-deprecated' ), - 'version' => '2faaf49020b2074de156' + 'version' => '8173fc0fc12b7bb7eaf0' ), 'deprecated.js' => array( 'dependencies' => array( 'wp-hooks' ), - 'version' => '990e85f234fee8f7d446' + 'version' => 'fe587bac92b7d0ef760e' ), 'dom.js' => array( 'dependencies' => array( 'wp-deprecated' ), - 'version' => 'e13e9a880cb4f091f98e' + 'version' => 'c95f94cbbc1ac3fde84f' ), 'dom-ready.js' => array( 'dependencies' => array( ), - 'version' => 'a06281ae5cf5500e9317' + 'version' => '3fe927cab37bf38d6a23' ), 'edit-post.js' => array( 'dependencies' => array( @@ -396,7 +402,7 @@ 'import' => 'static' ) ), - 'version' => '823ecf7905c05ce03022' + 'version' => 'e566fa04fc489a642398' ), 'edit-site.js' => array( 'dependencies' => array( @@ -446,7 +452,7 @@ 'import' => 'static' ) ), - 'version' => '64590e045eedae65347d' + 'version' => 'b818e670c0d0297645f2' ), 'edit-widgets.js' => array( 'dependencies' => array( @@ -487,7 +493,7 @@ 'import' => 'static' ) ), - 'version' => '9d38df85a4b408821722' + 'version' => 'a84bb1dba0b91cf80efa' ), 'editor.js' => array( 'dependencies' => array( @@ -537,7 +543,7 @@ 'import' => 'static' ) ), - 'version' => '2f1a5efaa6f78167e6c7' + 'version' => 'e3c5b4a412541c51a59d' ), 'element.js' => array( 'dependencies' => array( @@ -545,13 +551,13 @@ 'react-dom', 'wp-escape-html' ), - 'version' => 'ce395381f7d64d2a6d71' + 'version' => '4a4370b2b349066fd440' ), 'escape-html.js' => array( 'dependencies' => array( ), - 'version' => '3f093e5cca67aa0f8b56' + 'version' => '87ebe53e97bba59805a5' ), 'format-library.js' => array( 'dependencies' => array( @@ -578,31 +584,31 @@ 'import' => 'dynamic' ) ), - 'version' => 'fc1a40ac6923d97797a4' + 'version' => 'd69ac704b4a81b89c946' ), 'hooks.js' => array( 'dependencies' => array( ), - 'version' => '7496969728ca0f95732d' + 'version' => 'f0f188028580e8dc1255' ), 'html-entities.js' => array( 'dependencies' => array( ), - 'version' => '8c6fa5b869dfeadc4af2' + 'version' => 'a976ff3a0f00bc2999a3' ), 'i18n.js' => array( 'dependencies' => array( 'wp-hooks' ), - 'version' => '125448662852c5e18937' + 'version' => '1dfe7db3940c23ea9216' ), 'is-shallow-equal.js' => array( 'dependencies' => array( ), - 'version' => '5d84b9f3cb50d2ce7d04' + 'version' => '7ad271045c1fe60f5496' ), 'keyboard-shortcuts.js' => array( 'dependencies' => array( @@ -611,13 +617,13 @@ 'wp-element', 'wp-keycodes' ), - 'version' => '0dd268b2132a3f82b1d4' + 'version' => '37da95806f2339bc80d0' ), 'keycodes.js' => array( 'dependencies' => array( 'wp-i18n' ), - 'version' => 'b156d58a707bff518176' + 'version' => 'd0b4204e4bbeb412df6e' ), 'list-reusable-blocks.js' => array( 'dependencies' => array( @@ -629,7 +635,7 @@ 'wp-element', 'wp-i18n' ), - 'version' => 'a44da9be02cdfef6e44d' + 'version' => '68a57d388ce085b9691e' ), 'media-utils.js' => array( 'dependencies' => array( @@ -657,7 +663,7 @@ 'wp-url', 'wp-warning' ), - 'version' => '8addf2ae46aa60243073' + 'version' => 'b8bf604c1cc119e63ee6' ), 'notices.js' => array( 'dependencies' => array( @@ -665,14 +671,14 @@ 'wp-components', 'wp-data' ), - 'version' => '505026883bbd05994872' + 'version' => 'c09a068fdab0eb465e14' ), 'nux.js' => array( 'dependencies' => array( 'wp-data', 'wp-deprecated' ), - 'version' => 'b0afe722eacfd6e9a364' + 'version' => '1a78c05bba2c02820a7e' ), 'patterns.js' => array( 'dependencies' => array( @@ -695,7 +701,7 @@ 'wp-theme', 'wp-url' ), - 'version' => '1d5dc833056614a65601' + 'version' => 'be5af192f57cc14d340f' ), 'plugins.js' => array( 'dependencies' => array( @@ -707,7 +713,7 @@ 'wp-is-shallow-equal', 'wp-primitives' ), - 'version' => '50bcc9bb42e4c0723a8c' + 'version' => '673d1e05ca49004ab160' ), 'preferences.js' => array( 'dependencies' => array( @@ -723,32 +729,32 @@ 'wp-primitives', 'wp-private-apis' ), - 'version' => 'ba5e81b3db928d4649c6' + 'version' => '5a169e3fc0e657f74172' ), 'preferences-persistence.js' => array( 'dependencies' => array( 'wp-api-fetch' ), - 'version' => 'e8033be98338d1861bca' + 'version' => 'a34abbdacd8f50f9acb1' ), 'primitives.js' => array( 'dependencies' => array( 'react-jsx-runtime', 'wp-element' ), - 'version' => 'a5c905ec27bcd76ef287' + 'version' => '44cc5a35c7b9fe07a838' ), 'priority-queue.js' => array( 'dependencies' => array( ), - 'version' => '1f0e89e247bc0bd3f9b9' + 'version' => '6c0aa59b65d55dfd509b' ), 'private-apis.js' => array( 'dependencies' => array( ), - 'version' => 'd253db066c622f144ae7' + 'version' => 'eb85f28c4c729bb4f002' ), 'react-i18n.js' => array( 'dependencies' => array( @@ -756,13 +762,13 @@ 'wp-element', 'wp-i18n' ), - 'version' => '9b74577dbd7e50f6b77b' + 'version' => 'ba2bd3d7a3817f0494af' ), 'redux-routine.js' => array( 'dependencies' => array( ), - 'version' => '64f9f5001aabc046c605' + 'version' => 'acca2b4857d83ad1790e' ), 'reusable-blocks.js' => array( 'dependencies' => array( @@ -779,7 +785,7 @@ 'wp-primitives', 'wp-url' ), - 'version' => '00a57a244d360831336a' + 'version' => '5161508c6662b8490ee8' ), 'rich-text.js' => array( 'dependencies' => array( @@ -794,7 +800,7 @@ 'wp-keycodes', 'wp-private-apis' ), - 'version' => '9f145f4a11c41d022c83' + 'version' => '3e5852e42cee1c239bae' ), 'router.js' => array( 'dependencies' => array( @@ -804,7 +810,7 @@ 'wp-private-apis', 'wp-url' ), - 'version' => '0249e6724784b1c2583b' + 'version' => 'dda75cd9ff9d7e0eb19f' ), 'server-side-render.js' => array( 'dependencies' => array( @@ -818,19 +824,19 @@ 'wp-i18n', 'wp-url' ), - 'version' => '77621917ec58330ec283' + 'version' => '83e806a0634df6b93530' ), 'shortcode.js' => array( 'dependencies' => array( ), - 'version' => '11742fe18cc215d3d5ab' + 'version' => 'f6273476300cc5fad4cd' ), 'style-engine.js' => array( 'dependencies' => array( ), - 'version' => '50b0461aa90d44c4123b' + 'version' => '914befb08774033e6265' ), 'sync.js' => array( 'dependencies' => array( @@ -838,7 +844,7 @@ 'wp-hooks', 'wp-private-apis' ), - 'version' => '82121af3ec5dd7ba0296' + 'version' => '15f3a34404da1c4bb483' ), 'theme.js' => array( 'dependencies' => array( @@ -848,19 +854,19 @@ 'wp-element', 'wp-private-apis' ), - 'version' => 'f017490f1df372de8462' + 'version' => '48f91740a3d737558e9c' ), 'token-list.js' => array( 'dependencies' => array( ), - 'version' => '16f0aebdd39d87c2a84b' + 'version' => 'e86ab419d8302d57822c' ), 'undo-manager.js' => array( 'dependencies' => array( 'wp-is-shallow-equal' ), - 'version' => '27bb0ae036a2c9d4a1b5' + 'version' => '4554fce6276d8910a4ae' ), 'upload-media.js' => array( 'dependencies' => array( @@ -883,13 +889,13 @@ 'import' => 'dynamic' ) ), - 'version' => 'a16fcecc49ab54f868c2' + 'version' => 'f7174b0617bcd68e57c3' ), 'url.js' => array( 'dependencies' => array( ), - 'version' => '9dd5f16a5ce37bf4ba2c' + 'version' => '7b0de086d4ae11d55704' ), 'viewport.js' => array( 'dependencies' => array( @@ -897,13 +903,13 @@ 'wp-data', 'wp-element' ), - 'version' => '83b39beb77dcc56c4d26' + 'version' => 'a56e3489ed4faeac7720' ), 'warning.js' => array( 'dependencies' => array( ), - 'version' => '36fdbdc984d93aee8a97' + 'version' => 'a0978839debc564a6608' ), 'widgets.js' => array( 'dependencies' => array( @@ -920,12 +926,12 @@ 'wp-notices', 'wp-primitives' ), - 'version' => '2a2e101698084ec9e2c3' + 'version' => '087235ca647aa1a33227' ), 'wordcount.js' => array( 'dependencies' => array( ), - 'version' => 'f53ba7c5b085d7a53357' + 'version' => 'f0b1f0e977b2ff6e0132' ) ); \ No newline at end of file diff --git a/src/wp-includes/assets/script-modules-packages.php b/src/wp-includes/assets/script-modules-packages.php index fc6e0c98dd365..1213445dd9d48 100644 --- a/src/wp-includes/assets/script-modules-packages.php +++ b/src/wp-includes/assets/script-modules-packages.php @@ -128,7 +128,7 @@ 'import' => 'static' ) ), - 'version' => '581cf5c9168a7665f2dd' + 'version' => 'cc1a34b1bee3c2e17bc4' ), 'boot/index.js' => array( 'dependencies' => array( @@ -164,7 +164,7 @@ 'import' => 'static' ) ), - 'version' => '4b0281842169241e3d0e' + 'version' => 'e6158521d3acdf579ed2' ), 'connectors/index.js' => array( 'dependencies' => array( @@ -211,7 +211,7 @@ 'import' => 'static' ) ), - 'version' => '2fe152df83cad8d59403' + 'version' => 'b9a1df775b12692a9ffb' ), 'core-abilities/index.js' => array( 'dependencies' => array( @@ -247,7 +247,7 @@ 'import' => 'static' ) ), - 'version' => '35485e5cfea4689dcaa1' + 'version' => 'e2f82d3d1c3179d25626' ), 'interactivity/index.js' => array( 'dependencies' => array( diff --git a/src/wp-includes/blocks/blocks-json.php b/src/wp-includes/blocks/blocks-json.php index d37e7583dd027..4e3a2878536a4 100644 --- a/src/wp-includes/blocks/blocks-json.php +++ b/src/wp-includes/blocks/blocks-json.php @@ -4975,6 +4975,7 @@ 'supports' => array( 'anchor' => true, 'align' => true, + '__experimentalExposeControlsToChildren' => true, 'color' => array( 'gradients' => true, 'link' => true, diff --git a/src/wp-includes/blocks/playlist/block.json b/src/wp-includes/blocks/playlist/block.json index 796b3d580e6a6..566174e50d3c9 100644 --- a/src/wp-includes/blocks/playlist/block.json +++ b/src/wp-includes/blocks/playlist/block.json @@ -69,6 +69,7 @@ "supports": { "anchor": true, "align": true, + "__experimentalExposeControlsToChildren": true, "color": { "gradients": true, "link": true, diff --git a/src/wp-includes/build/routes/connectors-home/content.js b/src/wp-includes/build/routes/connectors-home/content.js index 186807ef4d8e6..521cbcd5b9dc1 100644 --- a/src/wp-includes/build/routes/connectors-home/content.js +++ b/src/wp-includes/build/routes/connectors-home/content.js @@ -8937,9 +8937,9 @@ if (typeof process === "undefined" || true) { } var resets_default = { "box-sizing": "_336cd3e4e743482f__box-sizing" }; if (typeof process === "undefined" || true) { - registerStyle3("5f8e7aa0bc", "@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active),:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}}}"); + registerStyle3("da99a163ac", "@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus{outline:none}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active){@include mixins.focus-ring()}}}"); } -var focus_default = { "outset-ring--focus": "_08e8a2e44959f892__outset-ring--focus", "outset-ring--focus-except-active": "e25b2bdd7aa21721__outset-ring--focus-except-active", "outset-ring--focus-visible": "d0541bc9dd9dc7b6__outset-ring--focus-visible", "outset-ring--focus-within": "cd83dfc2126a0846__outset-ring--focus-within", "outset-ring--focus-within-except-active": "_970d04df7376df67__outset-ring--focus-within-except-active", "outset-ring--focus-within-visible": "c5cb3ee4bddaa8e4__outset-ring--focus-within-visible", "outset-ring--focus-parent-visible": "ecadb9e080e2dfa5__outset-ring--focus-parent-visible" }; +var focus_default = { "outset-ring--focus": "_08e8a2e44959f892__outset-ring--focus", "outset-ring--focus-visible": "d0541bc9dd9dc7b6__outset-ring--focus-visible", "outset-ring--focus-within": "cd83dfc2126a0846__outset-ring--focus-within", "outset-ring--focus-within-visible": "c5cb3ee4bddaa8e4__outset-ring--focus-within-visible", "outset-ring--focus-parent-visible": "ecadb9e080e2dfa5__outset-ring--focus-parent-visible", "outset-ring--focus-except-active": "e25b2bdd7aa21721__outset-ring--focus-except-active", "outset-ring--focus-within-except-active": "_970d04df7376df67__outset-ring--focus-within-except-active" }; if (typeof process === "undefined" || true) { registerStyle3("af6d9984a6", "._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}"); } @@ -9904,9 +9904,9 @@ if (typeof process === "undefined" || true) { } var resets_default3 = { "box-sizing": "_336cd3e4e743482f__box-sizing" }; if (typeof process === "undefined" || true) { - registerStyle10("5f8e7aa0bc", "@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active),:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}}}"); + registerStyle10("da99a163ac", "@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus{outline:none}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active){@include mixins.focus-ring()}}}"); } -var focus_default2 = { "outset-ring--focus": "_08e8a2e44959f892__outset-ring--focus", "outset-ring--focus-except-active": "e25b2bdd7aa21721__outset-ring--focus-except-active", "outset-ring--focus-visible": "d0541bc9dd9dc7b6__outset-ring--focus-visible", "outset-ring--focus-within": "cd83dfc2126a0846__outset-ring--focus-within", "outset-ring--focus-within-except-active": "_970d04df7376df67__outset-ring--focus-within-except-active", "outset-ring--focus-within-visible": "c5cb3ee4bddaa8e4__outset-ring--focus-within-visible", "outset-ring--focus-parent-visible": "ecadb9e080e2dfa5__outset-ring--focus-parent-visible" }; +var focus_default2 = { "outset-ring--focus": "_08e8a2e44959f892__outset-ring--focus", "outset-ring--focus-visible": "d0541bc9dd9dc7b6__outset-ring--focus-visible", "outset-ring--focus-within": "cd83dfc2126a0846__outset-ring--focus-within", "outset-ring--focus-within-visible": "c5cb3ee4bddaa8e4__outset-ring--focus-within-visible", "outset-ring--focus-parent-visible": "ecadb9e080e2dfa5__outset-ring--focus-parent-visible", "outset-ring--focus-except-active": "e25b2bdd7aa21721__outset-ring--focus-except-active", "outset-ring--focus-within-except-active": "_970d04df7376df67__outset-ring--focus-within-except-active" }; if (typeof process === "undefined" || true) { registerStyle10("e8e6a9be37", '@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{.d4250949359b05ce__link{text-decoration-thickness:from-font;text-underline-offset:.2em}.c6055659b8e2cd2c__is-brand,.c6055659b8e2cd2c__is-brand:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9))}.c6055659b8e2cd2c__is-brand:active,.c6055659b8e2cd2c__is-brand:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000))}._92e0dfcaeee15b88__is-neutral,._92e0dfcaeee15b88__is-neutral:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);text-decoration-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d)}._92e0dfcaeee15b88__is-neutral:active,._92e0dfcaeee15b88__is-neutral:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e)}.cf122a9bf1035d42__is-unstyled{--_gcd-a-color:inherit;color:inherit;text-decoration:none}._0cb411afac4c86c7__link-icon{display:inline-block;font-weight:var(--wpds-typography-font-weight-default,400);line-height:1;margin-inline-start:var(--wpds-dimension-padding-xs,4px);text-decoration:none}._0cb411afac4c86c7__link-icon:after{content:"\\2197"}._0cb411afac4c86c7__link-icon:dir(rtl):after{content:"\\2196"}}}'); } diff --git a/src/wp-includes/build/routes/connectors-home/content.min.asset.php b/src/wp-includes/build/routes/connectors-home/content.min.asset.php index 666c2ec30313d..d033468a89d76 100644 --- a/src/wp-includes/build/routes/connectors-home/content.min.asset.php +++ b/src/wp-includes/build/routes/connectors-home/content.min.asset.php @@ -1 +1 @@ - array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/connectors', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '22188cb77ae78d025593'); \ No newline at end of file + array('react', 'react-dom', 'react-jsx-runtime', 'wp-components', 'wp-compose', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-notices', 'wp-primitives', 'wp-private-apis', 'wp-theme', 'wp-url'), 'module_dependencies' => array(array('id' => '@wordpress/a11y', 'import' => 'static'), array('id' => '@wordpress/connectors', 'import' => 'static'), array('id' => '@wordpress/route', 'import' => 'static')), 'version' => '1c478cb5cadaf4aded06'); \ No newline at end of file diff --git a/src/wp-includes/build/routes/connectors-home/content.min.js b/src/wp-includes/build/routes/connectors-home/content.min.js index 3f51fd2690b81..62f17f892185e 100644 --- a/src/wp-includes/build/routes/connectors-home/content.min.js +++ b/src/wp-includes/build/routes/connectors-home/content.min.js @@ -1,4 +1,4 @@ -var wf=Object.create;var _r=Object.defineProperty;var vf=Object.getOwnPropertyDescriptor;var _f=Object.getOwnPropertyNames;var yf=Object.getPrototypeOf,xf=Object.prototype.hasOwnProperty;var Re=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),At=(e,t)=>{for(var o in t)_r(e,o,{get:t[o],enumerable:!0})},Rf=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of _f(t))!xf.call(e,r)&&r!==o&&_r(e,r,{get:()=>t[r],enumerable:!(n=vf(t,r))||n.enumerable});return e};var h=(e,t,o)=>(o=e!=null?wf(yf(e)):{},Rf(t||!e||!e.__esModule?_r(o,"default",{value:e,enumerable:!0}):o,e));var Ot=Re((g0,Gs)=>{Gs.exports=window.wp.i18n});var de=Re((h0,Ks)=>{Ks.exports=window.wp.element});var z=Re((w0,qs)=>{qs.exports=window.React});var Q=Re((E0,$s)=>{$s.exports=window.ReactJSXRuntime});var Mt=Re((Ah,Ta)=>{Ta.exports=window.ReactDOM});var Mc=Re(Ic=>{"use strict";var wo=z();function Tm(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var km=typeof Object.is=="function"?Object.is:Tm,Pm=wo.useState,Cm=wo.useEffect,Am=wo.useLayoutEffect,Om=wo.useDebugValue;function Nm(e,t){var o=t(),n=Pm({inst:{value:o,getSnapshot:t}}),r=n[0].inst,i=n[1];return Am(function(){r.value=o,r.getSnapshot=t,ri(r)&&i({inst:r})},[e,o,t]),Cm(function(){return ri(r)&&i({inst:r}),e(function(){ri(r)&&i({inst:r})})},[e]),Om(o),o}function ri(e){var t=e.getSnapshot;e=e.value;try{var o=t();return!km(e,o)}catch{return!0}}function Lm(e,t){return t()}var Im=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Lm:Nm;Ic.useSyncExternalStore=wo.useSyncExternalStore!==void 0?wo.useSyncExternalStore:Im});var ii=Re((w1,Bc)=>{"use strict";Bc.exports=Mc()});var zc=Re(Hc=>{"use strict";var Dn=z(),Mm=ii();function Bm(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Hm=typeof Object.is=="function"?Object.is:Bm,zm=Mm.useSyncExternalStore,Dm=Dn.useRef,jm=Dn.useEffect,Fm=Dn.useMemo,Vm=Dn.useDebugValue;Hc.useSyncExternalStoreWithSelector=function(e,t,o,n,r){var i=Dm(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=Fm(function(){function d(m){if(!c){if(c=!0,l=m,m=n(m),r!==void 0&&s.hasValue){var u=s.value;if(r(u,m))return f=u}return f=m}if(u=f,Hm(l,m))return u;var g=n(m);return r!==void 0&&r(u,g)?(l=m,u):(l=m,f=g)}var c=!1,l,f,p=o===void 0?null:o;return[function(){return d(t())},p===null?void 0:function(){return d(p())}]},[t,o,n,r]);var a=zm(e,i[0],i[1]);return jm(function(){s.hasValue=!0,s.value=a},[a]),Vm(a),a}});var jc=Re((_1,Dc)=>{"use strict";Dc.exports=zc()});var $t=Re((X2,md)=>{md.exports=window.wp.primitives});var Rd=Re((g4,xd)=>{xd.exports=window.wp.theme});var Qi=Re((b4,Sd)=>{Sd.exports=window.wp.privateApis});var on=Re((q5,Au)=>{Au.exports=window.wp.components});var rn=Re((a3,zu)=>{zu.exports=window.wp.data});var mr=Re((c3,Du)=>{Du.exports=window.wp.coreData});var Hs=Re((u3,Fu)=>{Fu.exports=window.wp.notices});var Wu=Re((f3,Vu)=>{Vu.exports=window.wp.url});function Xs(e){var t,o,n="";if(typeof e=="string"||typeof e=="number")n+=e;else if(typeof e=="object")if(Array.isArray(e)){var r=e.length;for(t=0;te();function Y(e){let t=Se(kf).current;return t.next=e,Tf(t.effect),t.trampoline}function kf(){let e={next:void 0,callback:Pf,trampoline:(...t)=>e.callback?.(...t),effect:()=>{e.callback=e.next}};return e}function Pf(){}var Js=h(z(),1),Cf=()=>{},D=typeof document<"u"?Js.useLayoutEffect:Cf;var hn=h(z(),1),Af=hn.createContext(void 0);function so(){return hn.useContext(Af)?.direction??"ltr"}function Of(e,t){return function(n,...r){let i=new URL(e);return i.searchParams.set("code",n.toString()),r.forEach(s=>i.searchParams.append("args[]",s)),`${t} error #${n}; visit ${i} for the full message.`}}var Nf=Of("https://base-ui.com/production-error","Base UI"),Pe=Nf;var Wt=h(z(),1);function xr(e,t,o,n){let r=Se(ta).current;return Lf(r,e,t,o,n)&&oa(r,[e,t,o,n]),r.callback}function ea(e){let t=Se(ta).current;return If(t,e)&&oa(t,e),t.callback}function ta(){return{callback:null,cleanup:null,refs:[]}}function Lf(e,t,o,n,r){return e.refs[0]!==t||e.refs[1]!==o||e.refs[2]!==n||e.refs[3]!==r}function If(e,t){return e.refs.length!==t.length||e.refs.some((o,n)=>o!==t[n])}function oa(e,t){if(e.refs=t,t.every(o=>o==null)){e.callback=null;return}e.callback=o=>{if(e.cleanup&&(e.cleanup(),e.cleanup=null),o!=null){let n=Array(t.length).fill(null);for(let r=0;r{for(let r=0;r=e}function Rr(e){if(!ra.isValidElement(e))return null;let t=e,o=t.props;return(ao(19)?o?.ref:t.ref)??null}function Bo(e,t){if(e&&!t)return e;if(!e&&t)return t;if(e||t)return{...e,...t}}function Nt(){}var I0=Object.freeze([]),be=Object.freeze({});function ia(e,t){let o={};for(let n in e){let r=e[n];if(t?.hasOwnProperty(n)){let i=t[n](r);i!=null&&Object.assign(o,i);continue}r===!0?o[`data-${n.toLowerCase()}`]="":r&&(o[`data-${n.toLowerCase()}`]=r.toString())}return o}function sa(e,t){return typeof e=="function"?e(t):e}function aa(e,t){return typeof e=="function"?e(t):e}var Sr={};function ye(e,t,o,n,r){if(!o&&!n&&!r&&!e)return wn(t);let i=wn(e);return t&&(i=Ho(i,t)),o&&(i=Ho(i,o)),n&&(i=Ho(i,n)),r&&(i=Ho(i,r)),i}function ca(e){if(e.length===0)return Sr;if(e.length===1)return wn(e[0]);let t=wn(e[0]);for(let o=1;o=65&&r<=90&&(typeof t=="function"||typeof t>"u")}function Er(e){return typeof e=="function"}function da(e,t){return Er(e)?e(t):e??Sr}function zf(e,t){return t?e?(...o)=>{let n=o[0];if(fa(n)){let i=n;zo(i);let s=t(...o);return i.baseUIHandlerPrevented||e?.(...o),s}let r=t(...o);return e?.(...o),r}:ua(t):e}function ua(e){return e&&((...t)=>{let o=t[0];return fa(o)&&zo(o),e(...t)})}function zo(e){return e.preventBaseUIHandler=()=>{e.baseUIHandlerPrevented=!0},e}function Tr(e,t){return t?e?t+" "+e:t:e}function fa(e){return e!=null&&typeof e=="object"&&"nativeEvent"in e}var kr=h(z(),1);function Ce(e,t,o={}){let n=t.render,r=Df(t,o);if(o.enabled===!1)return null;let i=o.state??be;return Vf(e,n,r,i)}function Df(e,t={}){let{className:o,style:n,render:r}=e,{state:i=be,ref:s,props:a,stateAttributesMapping:d,enabled:c=!0}=t,l=c?sa(o,i):void 0,f=c?aa(n,i):void 0,p=c?ia(i,d):be,m=c&&a?jf(a):void 0,u=c?Bo(p,m)??{}:be;return typeof document<"u"&&(c?Array.isArray(s)?u.ref=ea([u.ref,Rr(r),...s]):u.ref=xr(u.ref,Rr(r),s):xr(null,null)),c?(l!==void 0&&(u.className=Tr(u.className,l)),f!==void 0&&(u.style=Bo(u.style,f)),u):be}function jf(e){return Array.isArray(e)?ca(e):ye(void 0,e)}var Ff=Symbol.for("react.lazy");function Vf(e,t,o,n){if(t){if(typeof t=="function")return t(o,n);let r=ye(o,t.props);r.ref=o.ref;let i=t;return i?.$$typeof===Ff&&(i=Wt.Children.toArray(t)[0]),Wt.cloneElement(i,r)}if(e&&typeof e=="string")return Wf(e,o);throw new Error(Pe(8))}function Wf(e,t){return e==="button"?(0,kr.createElement)("button",{type:"button",...t,key:t.key}):e==="img"?(0,kr.createElement)("img",{alt:"",...t,key:t.key}):Wt.createElement(e,t)}var vn=h(z(),1);var pa=0;function Yf(e,t="mui"){let[o,n]=vn.useState(e),r=e||o;return vn.useEffect(()=>{o==null&&(pa+=1,n(`${t}-${pa}`))},[o,t]),r}var ma=Mo.useId;function Lt(e,t){if(ma!==void 0){let o=ma();return e??(t?`${t}-${o}`:o)}return Yf(e,t)}function ga(e){return Lt(e,"base-ui")}var U={};At(U,{cancelOpen:()=>wp,chipRemovePress:()=>ep,clearPress:()=>$f,closePress:()=>Qf,closeWatcher:()=>up,decrementPress:()=>np,disabled:()=>_p,drag:()=>gp,escapeKey:()=>dp,focusOut:()=>lp,imperativeAction:()=>Rp,incrementPress:()=>op,initial:()=>xp,inputBlur:()=>sp,inputChange:()=>rp,inputClear:()=>ip,inputPaste:()=>ap,inputPress:()=>cp,itemPress:()=>Zf,keyboard:()=>pp,linkPress:()=>Jf,listNavigation:()=>fp,missing:()=>yp,none:()=>Uf,outsidePress:()=>qf,pointer:()=>mp,scrub:()=>hp,siblingOpen:()=>vp,swipe:()=>Sp,trackPress:()=>tp,triggerFocus:()=>Kf,triggerHover:()=>Xf,triggerPress:()=>Gf,wheel:()=>bp,windowResize:()=>Ep});var Uf="none",Gf="trigger-press",Xf="trigger-hover",Kf="trigger-focus",qf="outside-press",Zf="item-press",Qf="close-press",Jf="link-press",$f="clear-press",ep="chip-remove-press",tp="track-press",op="increment-press",np="decrement-press",rp="input-change",ip="input-clear",sp="input-blur",ap="input-paste",cp="input-press",lp="focus-out",dp="escape-key",up="close-watcher",fp="list-navigation",pp="keyboard",mp="pointer",gp="drag",bp="wheel",hp="scrub",wp="cancel-open",vp="sibling-open",_p="disabled",yp="missing",xp="initial",Rp="imperative-action",Sp="swipe",Ep="window-resize";function ee(e,t,o,n){let r=!1,i=!1,s=n??be;return{reason:e,event:t??new Event("base-ui"),cancel(){r=!0},allowPropagation(){i=!0},get isCanceled(){return r},get isPropagationAllowed(){return i},trigger:o,...s}}var Cr=h(z(),1);var ba=h(z(),1),Tp=[];function co(e){ba.useEffect(e,Tp)}var _n=null,ah=globalThis.requestAnimationFrame,Pr=class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=t=>{this.isScheduled=!1;let o=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let r=0;r=this.callbacks.length||(this.callbacks[o]=null,this.callbacksCount-=1)}},yn=new Pr,ft=class e{static create(){return new e}static request(t){return yn.request(t)}static cancel(t){return yn.cancel(t)}currentId=_n;request(t){this.cancel(),this.currentId=yn.request(()=>{this.currentId=_n,t()})}cancel=()=>{this.currentId!==_n&&(yn.cancel(this.currentId),this.currentId=_n)};disposeEffect=()=>this.cancel};function lo(){let e=Se(ft.create).current;return co(e.disposeEffect),e}function ha(e,t=!1,o=!1){let[n,r]=Cr.useState(e&&t?"idle":void 0),[i,s]=Cr.useState(e);return e&&!i&&(s(!0),r("starting")),!e&&i&&n!=="ending"&&!o&&r("ending"),!e&&!i&&n==="ending"&&r(void 0),D(()=>{if(!e&&i&&n!=="ending"&&o){let a=ft.request(()=>{r("ending")});return()=>{ft.cancel(a)}}},[e,i,n,o]),D(()=>{if(!e||t)return;let a=ft.request(()=>{r(void 0)});return()=>{ft.cancel(a)}},[t,e]),D(()=>{if(!e||!t)return;e&&i&&n!=="idle"&&r("starting");let a=ft.request(()=>{r("idle")});return()=>{ft.cancel(a)}},[t,e,i,n]),{mounted:i,setMounted:s,transitionStatus:n}}var Yt=(function(e){return e.startingStyle="data-starting-style",e.endingStyle="data-ending-style",e})({}),kp={[Yt.startingStyle]:""},Pp={[Yt.endingStyle]:""},wa={transitionStatus(e){return e==="starting"?kp:e==="ending"?Pp:null}};var po=h(z(),1);function xn(){return typeof window<"u"}function Gt(e){return Rn(e)?(e.nodeName||"").toLowerCase():"#document"}function ge(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function ot(e){var t;return(t=(Rn(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function Rn(e){return xn()?e instanceof Node||e instanceof ge(e).Node:!1}function V(e){return xn()?e instanceof Element||e instanceof ge(e).Element:!1}function we(e){return xn()?e instanceof HTMLElement||e instanceof ge(e).HTMLElement:!1}function uo(e){return!xn()||typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof ge(e).ShadowRoot}function fo(e){let{overflow:t,overflowX:o,overflowY:n,display:r}=Ae(e);return/auto|scroll|overlay|hidden|clip/.test(t+n+o)&&r!=="inline"&&r!=="contents"}function va(e){return/^(table|td|th)$/.test(Gt(e))}function Do(e){try{if(e.matches(":popover-open"))return!0}catch{}try{return e.matches(":modal")}catch{return!1}}var Cp=/transform|translate|scale|rotate|perspective|filter/,Ap=/paint|layout|strict|content/,Ut=e=>!!e&&e!=="none",Ar;function Sn(e){let t=V(e)?Ae(e):e;return Ut(t.transform)||Ut(t.translate)||Ut(t.scale)||Ut(t.rotate)||Ut(t.perspective)||!En()&&(Ut(t.backdropFilter)||Ut(t.filter))||Cp.test(t.willChange||"")||Ap.test(t.contain||"")}function _a(e){let t=tt(e);for(;we(t)&&!nt(t);){if(Sn(t))return t;if(Do(t))return null;t=tt(t)}return null}function En(){return Ar==null&&(Ar=typeof CSS<"u"&&CSS.supports&&CSS.supports("-webkit-backdrop-filter","none")),Ar}function nt(e){return/^(html|body|#document)$/.test(Gt(e))}function Ae(e){return ge(e).getComputedStyle(e)}function jo(e){return V(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function tt(e){if(Gt(e)==="html")return e;let t=e.assignedSlot||e.parentNode||uo(e)&&e.host||ot(e);return uo(t)?t.host:t}function ya(e){let t=tt(e);return nt(t)?e.ownerDocument?e.ownerDocument.body:e.body:we(t)&&fo(t)?t:ya(t)}function It(e,t,o){var n;t===void 0&&(t=[]),o===void 0&&(o=!0);let r=ya(e),i=r===((n=e.ownerDocument)==null?void 0:n.body),s=ge(r);if(i){let a=Tn(s);return t.concat(s,s.visualViewport||[],fo(r)?r:[],a&&o?It(a):[])}else return t.concat(r,It(r,[],o))}function Tn(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}var kn=h(z(),1),Op=kn.createContext(void 0);function xa(e=!1){let t=kn.useContext(Op);if(t===void 0&&!e)throw new Error(Pe(16));return t}var Ra=h(z(),1);function Sa(e){let{focusableWhenDisabled:t,disabled:o,composite:n=!1,tabIndex:r=0,isNativeButton:i}=e,s=n&&t!==!1,a=n&&t===!1;return{props:Ra.useMemo(()=>{let c={onKeyDown(l){o&&t&&l.key!=="Tab"&&l.preventDefault()}};return n||(c.tabIndex=r,!i&&o&&(c.tabIndex=t?r:-1)),(i&&(t||s)||!i&&o)&&(c["aria-disabled"]=o),i&&(!t||a)&&(c.disabled=o),c},[n,o,t,s,a,i,r])}}function Ea(e={}){let{disabled:t=!1,focusableWhenDisabled:o,tabIndex:n=0,native:r=!0,composite:i}=e,s=po.useRef(null),a=xa(!0),d=i??a!==void 0,{props:c}=Sa({focusableWhenDisabled:o,disabled:t,composite:d,tabIndex:n,isNativeButton:r}),l=po.useCallback(()=>{let m=s.current;Or(m)&&d&&t&&c.disabled===void 0&&m.disabled&&(m.disabled=!1)},[t,c.disabled,d]);D(l,[l]);let f=po.useCallback((m={})=>{let{onClick:u,onMouseDown:g,onKeyUp:v,onKeyDown:_,onPointerDown:w,...y}=m;return ye({onClick(b){if(t){b.preventDefault();return}u?.(b)},onMouseDown(b){t||g?.(b)},onKeyDown(b){if(t||(zo(b),_?.(b),b.baseUIHandlerPrevented))return;let S=b.target===b.currentTarget,x=b.currentTarget,E=Or(x),T=!r&&Np(x),k=S&&(r?E:!T),C=b.key==="Enter",j=b.key===" ",A=x.getAttribute("role"),L=A?.startsWith("menuitem")||A==="option"||A==="gridcell";if(S&&d&&j){if(b.defaultPrevented&&L)return;b.preventDefault(),T||r&&E?(x.click(),b.preventBaseUIHandler()):k&&(u?.(b),b.preventBaseUIHandler());return}k&&(!r&&(j||C)&&b.preventDefault(),!r&&C&&u?.(b))},onKeyUp(b){if(!t){if(zo(b),v?.(b),b.target===b.currentTarget&&r&&d&&Or(b.currentTarget)&&b.key===" "){b.preventDefault();return}b.baseUIHandlerPrevented||b.target===b.currentTarget&&!r&&!d&&b.key===" "&&u?.(b)}},onPointerDown(b){if(t){b.preventDefault();return}w?.(b)}},r?{type:"button"}:{role:"button"},c,y)},[t,c,d,r]),p=Y(m=>{s.current=m,l()});return{getButtonProps:f,buttonRef:p}}function Or(e){return we(e)&&e.tagName==="BUTTON"}function Np(e){return!!(e?.tagName==="A"&&e?.href)}function re(e,t,o,n){return e.addEventListener(t,o,n),()=>{e.removeEventListener(t,o,n)}}function ze(e){let t=Se(Lp,e).current;return t.next=e,D(t.effect),t}function Lp(e){let t={current:e,next:e,effect:()=>{t.current=t.next}};return t}function xe(e){return e?.ownerDocument||document}var Ca=h(z(),1);var Pa=h(Mt(),1);function ka(e){return e==null?e:"current"in e?e.current:e}function mo(e,t=!1,o=!0){let n=lo();return Y((r,i=null)=>{n.cancel();let s=ka(e);if(s==null)return;let a=s,d=()=>{Pa.flushSync(r)};if(typeof a.getAnimations!="function"||globalThis.BASE_UI_ANIMATIONS_DISABLED){r();return}function c(){Promise.all(a.getAnimations().map(l=>l.finished)).then(()=>{i?.aborted||d()}).catch(()=>{if(o){i?.aborted||d();return}let l=a.getAnimations();!i?.aborted&&l.length>0&&l.some(f=>f.pending||f.playState!=="finished")&&c()})}if(t){let l=Yt.startingStyle;if(!a.hasAttribute(l)){n.request(c);return}let f=new MutationObserver(()=>{a.hasAttribute(l)||(f.disconnect(),c())});f.observe(a,{attributes:!0,attributeFilter:[l]}),i?.addEventListener("abort",()=>f.disconnect(),{once:!0});return}n.request(c)})}function Pn(e){let{enabled:t=!0,open:o,ref:n,onComplete:r}=e,i=Y(r),s=mo(n,o,!1);Ca.useEffect(()=>{if(!t)return;let a=new AbortController;return s(i,a.signal),()=>{a.abort()}},[t,o,i,s])}var Aa=h(z(),1);function Oa(e){let t=Aa.useRef(!0);t.current&&(t.current=!1,e())}var xt={};At(xt,{engine:()=>Br,env:()=>zr,os:()=>Ir,screenReader:()=>Hr});var Ir={};At(Ir,{android:()=>Ia,apple:()=>Lr,ios:()=>Nr,linux:()=>zp,mac:()=>Ma,windows:()=>Hp});function Ip(){return typeof navigator>"u"?{userAgent:"",platform:"",maxTouchPoints:0}:{userAgent:navigator.userAgent,platform:navigator.platform??"",maxTouchPoints:navigator.maxTouchPoints??0}}var{userAgent:Mp,platform:Bp,maxTouchPoints:Na}=Ip(),Xt=Mp.toLowerCase(),Kt=Bp.toLowerCase();var Nr=/^i(os$|p)/.test(Kt)||Kt==="macintel"&&Na>1,La="android",Ia=Kt===La||Xt.includes(La),Ma=!Nr&&Kt.startsWith("mac"),Hp=Kt.startsWith("win"),zp=!Ia&&/^(linux|chrome os)/.test(Kt),Lr=Ma||Nr;var Br={};At(Br,{blink:()=>jp,gecko:()=>Dp,webkit:()=>Mr});var Mr=typeof CSS<"u"&&!!CSS.supports?.("-webkit-backdrop-filter:none"),Dp=!Mr&&Xt.includes("firefox"),jp=!Mr&&Xt.includes("chrom");var Hr={};At(Hr,{voiceOver:()=>Fp});var Fp=Lr;var zr={};At(zr,{jsdom:()=>Vp});var Vp=/jsdom|happydom/.test(Xt);var Fo=0,Ye=class e{static create(){return new e}currentId=Fo;start(t,o){this.clear(),this.currentId=setTimeout(()=>{this.currentId=Fo,o()},t)}isStarted(){return this.currentId!==Fo}clear=()=>{this.currentId!==Fo&&(clearTimeout(this.currentId),this.currentId=Fo)};disposeEffect=()=>this.clear};function rt(){let e=Se(Ye.create).current;return co(e.disposeEffect),e}var Oe=h(z(),1);function Ba(e){return"nativeEvent"in e}function Rt(e,t){let o=["mouse","pen"];return t||o.push("",void 0),o.includes(e)}function Ha(e){let t=e.type;return t==="click"||t==="mousedown"||t==="keydown"||t==="keyup"}var Dr="data-base-ui-focusable";var jr="input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";function Cn(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function ie(e,t){if(!e||!t)return!1;let o=t.getRootNode?.();if(e.contains(t))return!0;if(o&&uo(o)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function Me(e){return"composedPath"in e?e.composedPath()[0]:e.target}function Bt(e,t){if(!V(e))return!1;let o=e;if(t.hasElement(o))return!o.hasAttribute("data-trigger-disabled");for(let[,n]of t.entries())if(ie(n,o))return!n.hasAttribute("data-trigger-disabled");return!1}function An(e,t){if(t==null)return!1;if("composedPath"in e)return e.composedPath().includes(t);let o=e;return o.target!=null&&t.contains(o.target)}function za(e){return e.matches("html,body")}function Da(e){return we(e)&&e.matches(jr)}function Fr(e){return e?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${jr}`)!=null}function ja(e){if(!e||xt.env.jsdom)return!0;try{return e.matches(":focus-visible")}catch{return!0}}function Wp(e,t){return t!=null&&!Rt(t)?0:typeof e=="function"?e():e}function St(e,t,o){let n=Wp(e,o);return typeof n=="number"?n:n?.[t]}function Vr(e){return typeof e=="function"?e():e}function On(e,t){return t||e==="click"||e==="mousedown"}function Fa(e){return e?.includes("mouse")&&e!=="mousedown"}var Va=h(Q(),1),Wa=Oe.createContext({hasProvider:!1,timeoutMs:0,delayRef:{current:0},initialDelayRef:{current:0},timeout:new Ye,currentIdRef:{current:null},currentContextRef:{current:null}});function Yp(e,t){e.current=t.current}function Wr(e){let{children:t,delay:o,timeoutMs:n=0}=e,r=Oe.useRef(o),i=Oe.useRef(o),s=Oe.useRef(null),a=Oe.useRef(null),d=rt();return D(()=>{if(i.current=o,!s.current){r.current=o;return}r.current={open:St(r.current,"open"),close:St(o,"close")}},[o,s,r,i]),(0,Va.jsx)(Wa.Provider,{value:Oe.useMemo(()=>({hasProvider:!0,delayRef:r,initialDelayRef:i,currentIdRef:s,timeoutMs:n,currentContextRef:a,timeout:d}),[n,d]),children:t})}function Yr(e,t={open:!1}){let{open:o}=t,n="rootStore"in e?e.rootStore:e,r=n.useState("floatingId"),i=Oe.useContext(Wa),{currentIdRef:s,delayRef:a,timeoutMs:d,initialDelayRef:c,currentContextRef:l,hasProvider:f,timeout:p}=i,[m,u]=Oe.useState(!1),g=Oe.useRef(o),v=Oe.useRef(!1);return D(()=>{g.current=o},[o]),D(()=>()=>{v.current=!0},[]),D(()=>{function _(){v.current||u(!1),l.current?.setIsInstantPhase(!1),s.current=null,l.current=null,a.current=c.current,p.clear()}if(s.current&&!o&&s.current===r){if(u(!1),d){let w=r;return p.start(d,()=>{n.select("open")||s.current&&s.current!==w||_()}),()=>{(g.current||s.current!==w)&&p.clear()}}_()}},[o,r,s,a,d,c,l,p,n]),D(()=>{if(!o)return;let _=l.current,w=s.current;p.clear(),l.current={onOpenChange:n.setOpen,setIsInstantPhase:u},s.current=r,a.current={open:0,close:St(c.current,"close")},w!==null&&w!==r?(u(!0),_?.setIsInstantPhase(!0),_?.onOpenChange(!1,ee(U.none))):(u(!1),_?.setIsInstantPhase(!1))},[o,r,n,s,a,c,l,p]),D(()=>()=>{if(s.current===r){if(l.current=null,!g.current)return;s.current=null,Yp(a,c),p.clear()}},[l,s,a,r,c,p]),Oe.useMemo(()=>({hasProvider:f,delayRef:a,isInstantPhase:m}),[f,a,m])}function it(...e){return()=>{for(let t=0;t({x:e,y:e}),Up={left:"right",right:"left",bottom:"top",top:"bottom"};function Yo(e,t,o){return Be(e,Ht(t,o))}function at(e,t){return typeof e=="function"?e(t):e}function Ee(e){return e.split("-")[0]}function ct(e){return e.split("-")[1]}function Ln(e){return e==="x"?"y":"x"}function Uo(e){return e==="y"?"height":"width"}function De(e){let t=e[0];return t==="t"||t==="b"?"y":"x"}function Go(e){return Ln(De(e))}function Xa(e,t,o){o===void 0&&(o=!1);let n=ct(e),r=Go(e),i=Uo(r),s=r==="x"?n===(o?"end":"start")?"right":"left":n==="start"?"bottom":"top";return t.reference[i]>t.floating[i]&&(s=Vo(s)),[s,Vo(s)]}function Ka(e){let t=Vo(e);return[Nn(e),t,Nn(t)]}function Nn(e){return e.includes("start")?e.replace("start","end"):e.replace("end","start")}var Ya=["left","right"],Ua=["right","left"],Gp=["top","bottom"],Xp=["bottom","top"];function Kp(e,t,o){switch(e){case"top":case"bottom":return o?t?Ua:Ya:t?Ya:Ua;case"left":case"right":return t?Gp:Xp;default:return[]}}function qa(e,t,o,n){let r=ct(e),i=Kp(Ee(e),o==="start",n);return r&&(i=i.map(s=>s+"-"+r),t&&(i=i.concat(i.map(Nn)))),i}function Vo(e){let t=Ee(e);return Up[t]+e.slice(t.length)}function qp(e){return{top:0,right:0,bottom:0,left:0,...e}}function In(e){return typeof e!="number"?qp(e):{top:e,right:e,bottom:e,left:e}}function qt(e){let{x:t,y:o,width:n,height:r}=e;return{width:n,height:r,top:o,left:t,right:t+n,bottom:o+r,x:t,y:o}}function Et(e,t,o=!0){return e.filter(r=>r.parentId===t).flatMap(r=>[...!o||r.context?.open?[r]:[],...Et(e,r.id,o)])}function go(e){return`data-base-ui-${e}`}var Ue=h(z(),1),Ja=h(Mt(),1);var Za={style:{transition:"none"}};var Zp="data-base-ui-swipe-ignore",Qp="data-swipe-ignore",ww=`[${Zp}]`,vw=`[${Qp}]`;var Qa={fallbackAxisSide:"end"};var $a=h(Q(),1),Jp=Ue.createContext(null),$p=()=>Ue.useContext(Jp),em=go("portal");function Ur(e={}){let{ref:t,container:o,componentProps:n=be,elementProps:r}=e,i=Lt(),a=$p()?.portalNode,[d,c]=Ue.useState(null),[l,f]=Ue.useState(null),p=Y(v=>{v!==null&&f(v)}),m=Ue.useRef(null);D(()=>{if(o===null){m.current&&(m.current=null,f(null),c(null));return}if(i==null)return;let v=(o&&(Rn(o)?o:o.current))??a??document.body;if(v==null){m.current&&(m.current=null,f(null),c(null));return}m.current!==v&&(m.current=v,f(null),c(v))},[o,a,i]);let u=Ce("div",n,{ref:[t,p],props:[{id:i,[em]:""},r]});return{portalNode:l,portalSubtree:d&&u?Ja.createPortal(u,d):null}}var Zt=h(z(),1);function ec(){let e=new Map;return{emit(t,o){e.get(t)?.forEach(n=>n(o))},on(t,o){e.has(t)||e.set(t,new Set),e.get(t).add(o)},off(t,o){e.get(t)?.delete(o)}}}var tm=h(Q(),1),om=Zt.createContext(null),nm=Zt.createContext(null),bo=()=>Zt.useContext(om)?.id||null,Dt=e=>{let t=Zt.useContext(nm);return e??t};var je=h(z(),1);function rm(e,t){let o=null,n=null,r=!1;return{contextElement:e||void 0,getBoundingClientRect(){let i=e?.getBoundingClientRect()||{width:0,height:0,x:0,y:0},s=t.axis==="x"||t.axis==="both",a=t.axis==="y"||t.axis==="both",d=["mouseenter","mousemove"].includes(t.dataRef.current.openEvent?.type||"")&&t.pointerType!=="touch",c=i.width,l=i.height,f=i.x,p=i.y;return o==null&&t.x&&s&&(o=i.x-t.x),n==null&&t.y&&a&&(n=i.y-t.y),f-=o||0,p-=n||0,c=0,l=0,!r||d?(c=t.axis==="y"?i.width:0,l=t.axis==="x"?i.height:0,f=s&&t.x!=null?t.x:f,p=a&&t.y!=null?t.y:p):r&&!d&&(l=t.axis==="x"?i.height:l,c=t.axis==="y"?i.width:c),r=!0,{width:c,height:l,x:f,y:p,top:p,right:f+c,bottom:p+l,left:f}}}}function tc(e){return e!=null&&e.clientX!=null}function Gr(e,t={}){let{enabled:o=!0,axis:n="both"}=t,r="rootStore"in e?e.rootStore:e,i=r.useState("open"),s=r.useState("floatingElement"),a=r.useState("domReferenceElement"),d=r.context.dataRef,c=je.useRef(!1),l=je.useRef(null),[f,p]=je.useState(),[m,u]=je.useState([]),g=Y(b=>{r.set("positionReference",b)}),v=Y((b,S,x)=>{c.current||d.current.openEvent&&!tc(d.current.openEvent)||r.set("positionReference",rm(x??a,{x:b,y:S,axis:n,dataRef:d,pointerType:f}))}),_=Y(b=>{i?l.current||(v(b.clientX,b.clientY,b.currentTarget),u([])):v(b.clientX,b.clientY,b.currentTarget)}),w=Rt(f)?s:i;je.useEffect(()=>{if(!o){g(a);return}if(!w)return;function b(){l.current?.(),l.current=null}let S=ge(s);function x(E){let T=Me(E);ie(s,T)?b():v(E.clientX,E.clientY)}return!d.current.openEvent||tc(d.current.openEvent)?l.current=re(S,"mousemove",x):g(a),b},[w,o,s,d,a,r,v,g,m]),je.useEffect(()=>()=>{r.set("positionReference",null)},[r]),je.useEffect(()=>{o&&!s&&(c.current=!1)},[o,s]),je.useEffect(()=>{!o&&i&&(c.current=!0)},[o,i]);let y=je.useMemo(()=>{function b(S){p(S.pointerType)}return{onPointerDown:b,onPointerEnter:b,onMouseMove:_,onMouseEnter:_}},[_]);return je.useMemo(()=>o?{reference:y,trigger:y}:{},[o,y])}var Fe=h(z(),1);function im(){return!1}function sm(e){return{escapeKey:typeof e=="boolean"?e:e?.escapeKey??!1,outsidePress:typeof e=="boolean"?e:e?.outsidePress??!0}}function Xr(e,t={}){let{enabled:o=!0,escapeKey:n=!0,outsidePress:r=!0,outsidePressEvent:i="sloppy",referencePress:s=im,bubbles:a,externalTree:d}=t,c="rootStore"in e?e.rootStore:e,l=c.useState("open"),f=c.useState("floatingElement"),{dataRef:p}=c.context,m=Dt(d),u=Y(typeof r=="function"?r:()=>!1),g=typeof r=="function"?u:r,v=g!==!1,_=Y(()=>i),{escapeKey:w,outsidePress:y}=sm(a),b=Fe.useRef(!1),S=Fe.useRef(!1),x=Fe.useRef(!1),E=Fe.useRef(!1),T=Fe.useRef(""),k=Fe.useRef(null),C=rt(),j=rt(),A=Y(()=>{j.clear(),p.current.insideReactTree=!1}),L=Y(W=>{let oe=p.current.floatingContext?.nodeId;return(m?Et(m.nodesRef.current,oe):[]).some(se=>se.context?.open&&!se.context.dataRef.current[W])}),I=Y(W=>An(W,c.select("floatingElement"))||An(W,c.select("domReferenceElement"))),R=Y(W=>{s()&&c.setOpen(!1,ee(U.triggerPress,W.nativeEvent))}),N=Y(W=>{if(!l||!o||!n||W.key!=="Escape"||E.current||!w&&L("__escapeKeyBubbles"))return;let oe=Ba(W)?W.nativeEvent:W,te=ee(U.escapeKey,oe);c.setOpen(!1,te),te.isCanceled||W.preventDefault(),!w&&!te.isPropagationAllowed&&W.stopPropagation()}),H=Y(()=>{p.current.insideReactTree=!0,j.start(0,A)}),P=Y(W=>{if(!l||!o||W.button!==0)return;let oe=Me(W.nativeEvent);ie(c.select("floatingElement"),oe)&&(b.current||(b.current=!0,S.current=!1))}),O=Y(W=>{!l||!o||(W.defaultPrevented||W.nativeEvent.defaultPrevented)&&b.current&&(S.current=!0)});Fe.useEffect(()=>{if(!l||!o)return;p.current.__escapeKeyBubbles=w,p.current.__outsidePressBubbles=y;let W=new Ye,oe=new Ye;function te(){W.clear(),E.current=!0}function se(){W.start(xt.engine.webkit?5:0,()=>{E.current=!1})}function G(){x.current=!0,oe.start(0,()=>{x.current=!1})}function K(){b.current=!1,S.current=!1}function J(){let B=T.current,F=B==="pen"||!B?"mouse":B,he=_(),ke=typeof he=="function"?he():he;return typeof ke=="string"?ke:ke[F]}function ne(B){let F=J();return F==="intentional"&&B.type!=="click"||F==="sloppy"&&B.type==="click"}function me(B){let F=p.current.floatingContext?.nodeId,he=m&&Et(m.nodesRef.current,F).some(ke=>An(B,ke.context?.elements.floating));return I(B)||he}function le(B){if(ne(B)){B.type!=="click"&&!I(B)&&(oe.clear(),x.current=!1),A();return}if(p.current.insideReactTree){A();return}let F=Me(B),he=`[${go("inert")}]`,ke=V(F)?F.getRootNode():null,kt=Array.from((uo(ke)?ke:xe(c.select("floatingElement"))).querySelectorAll(he)),Lo=c.context.triggerElements;if(F&&(Lo.hasElement(F)||Lo.hasMatchingElement(We=>ie(We,F))))return;let _t=V(F)?F:null;for(;_t&&!nt(_t);){let We=tt(_t);if(nt(We)||!V(We))break;_t=We}if(!(kt.length&&V(F)&&!za(F)&&!ie(F,c.select("floatingElement"))&&kt.every(We=>!ie(_t,We)))){if(we(F)&&!("touches"in B)){let We=nt(F),Pt=Ae(F),Ct=/auto|scroll/,un=We||Ct.test(Pt.overflowX),fn=We||Ct.test(Pt.overflowY),pn=un&&F.clientWidth>0&&F.scrollWidth>F.clientWidth,mn=fn&&F.clientHeight>0&&F.scrollHeight>F.clientHeight,gn=Pt.direction==="rtl",ae=mn&&(gn?B.offsetX<=F.offsetWidth-F.clientWidth:B.offsetX>F.clientWidth),Ie=pn&&B.offsetY>F.clientHeight;if(ae||Ie)return}if(!me(B)){if(J()==="intentional"&&x.current){oe.clear(),x.current=!1;return}typeof g=="function"&&!g(B)||L("__outsidePressBubbles")||(c.setOpen(!1,ee(U.outsidePress,B)),A())}}}function X(B){J()!=="sloppy"||B.pointerType==="touch"||!c.select("open")||!o||I(B)||le(B)}function pe(B){if(J()!=="sloppy"||!c.select("open")||!o||I(B))return;let F=B.touches[0];F&&(k.current={startTime:Date.now(),startX:F.clientX,startY:F.clientY,dismissOnTouchEnd:!1,dismissOnMouseDown:!0},C.start(1e3,()=>{k.current&&(k.current.dismissOnTouchEnd=!1,k.current.dismissOnMouseDown=!1)}))}function ue(B,F){let he=Me(B);if(!he)return;let ke=re(he,B.type,()=>{F(B),ke()})}function vt(B){T.current="touch",ue(B,pe)}function Te(B){C.clear(),B.type==="pointerdown"&&(T.current=B.pointerType),!(B.type==="mousedown"&&k.current&&!k.current.dismissOnMouseDown)&&ue(B,F=>{F.type==="pointerdown"?X(F):le(F)})}function Ve(B){if(!b.current)return;let F=S.current;if(K(),J()==="intentional"){if(B.type==="pointercancel"){F&&G();return}if(!me(B)){if(F){G();return}typeof g=="function"&&!g(B)||(oe.clear(),x.current=!0,A())}}}function Ke(B){if(J()!=="sloppy"||!k.current||I(B))return;let F=B.touches[0];if(!F)return;let he=Math.abs(F.clientX-k.current.startX),ke=Math.abs(F.clientY-k.current.startY),kt=Math.sqrt(he*he+ke*ke);kt>5&&(k.current.dismissOnTouchEnd=!0),kt>10&&(le(B),C.clear(),k.current=null)}function He(B){ue(B,Ke)}function no(B){J()!=="sloppy"||!k.current||I(B)||(k.current.dismissOnTouchEnd&&le(B),C.clear(),k.current=null)}function dn(B){ue(B,no)}let _e=xe(f),ro=it(n&&it(re(_e,"keydown",N),re(_e,"compositionstart",te),re(_e,"compositionend",se)),v&&it(re(_e,"click",Te,!0),re(_e,"pointerdown",Te,!0),re(_e,"pointerup",Ve,!0),re(_e,"pointercancel",Ve,!0),re(_e,"mousedown",Te,!0),re(_e,"mouseup",Ve,!0),re(_e,"touchstart",vt,!0),re(_e,"touchmove",He,!0),re(_e,"touchend",dn,!0)));return()=>{ro(),W.clear(),oe.clear(),K(),x.current=!1}},[p,f,n,v,g,l,o,w,y,N,A,_,L,I,m,c,C]),Fe.useEffect(A,[g,A]);let M=Fe.useMemo(()=>({onKeyDown:N,onPointerDown:R,onClick:R}),[N,R]),Z=Fe.useMemo(()=>({onKeyDown:N,onPointerDown:O,onMouseDown:O,onClickCapture:H,onMouseDownCapture(W){H(),P(W)},onPointerDownCapture(W){H(),P(W)},onMouseUpCapture:H,onTouchEndCapture:H,onTouchMoveCapture:H}),[N,H,P,O]);return Fe.useMemo(()=>o?{reference:M,floating:Z,trigger:M}:{},[o,M,Z])}var Ne=h(z(),1);function oc(e,t,o){let{reference:n,floating:r}=e,i=De(t),s=Go(t),a=Uo(s),d=Ee(t),c=i==="y",l=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2,p=n[a]/2-r[a]/2,m;switch(d){case"top":m={x:l,y:n.y-r.height};break;case"bottom":m={x:l,y:n.y+n.height};break;case"right":m={x:n.x+n.width,y:f};break;case"left":m={x:n.x-r.width,y:f};break;default:m={x:n.x,y:n.y}}switch(ct(t)){case"start":m[s]-=p*(o&&c?-1:1);break;case"end":m[s]+=p*(o&&c?-1:1);break}return m}async function ic(e,t){var o;t===void 0&&(t={});let{x:n,y:r,platform:i,rects:s,elements:a,strategy:d}=e,{boundary:c="clippingAncestors",rootBoundary:l="viewport",elementContext:f="floating",altBoundary:p=!1,padding:m=0}=at(t,e),u=In(m),v=a[p?f==="floating"?"reference":"floating":f],_=qt(await i.getClippingRect({element:(o=await(i.isElement==null?void 0:i.isElement(v)))==null||o?v:v.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(a.floating)),boundary:c,rootBoundary:l,strategy:d})),w=f==="floating"?{x:n,y:r,width:s.floating.width,height:s.floating.height}:s.reference,y=await(i.getOffsetParent==null?void 0:i.getOffsetParent(a.floating)),b=await(i.isElement==null?void 0:i.isElement(y))?await(i.getScale==null?void 0:i.getScale(y))||{x:1,y:1}:{x:1,y:1},S=qt(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:a,rect:w,offsetParent:y,strategy:d}):w);return{top:(_.top-S.top+u.top)/b.y,bottom:(S.bottom-_.bottom+u.bottom)/b.y,left:(_.left-S.left+u.left)/b.x,right:(S.right-_.right+u.right)/b.x}}var am=50,sc=async(e,t,o)=>{let{placement:n="bottom",strategy:r="absolute",middleware:i=[],platform:s}=o,a=s.detectOverflow?s:{...s,detectOverflow:ic},d=await(s.isRTL==null?void 0:s.isRTL(t)),c=await s.getElementRects({reference:e,floating:t,strategy:r}),{x:l,y:f}=oc(c,n,d),p=n,m=0,u={};for(let g=0;gI<=0)){var j,A;let I=(((j=i.flip)==null?void 0:j.index)||0)+1,R=E[I];if(R&&(!(f==="alignment"?w!==De(R):!1)||C.every(P=>De(P.placement)===w?P.overflows[0]>0:!0)))return{data:{index:I,overflows:C},reset:{placement:R}};let N=(A=C.filter(H=>H.overflows[0]<=0).sort((H,P)=>H.overflows[1]-P.overflows[1])[0])==null?void 0:A.placement;if(!N)switch(m){case"bestFit":{var L;let H=(L=C.filter(P=>{if(x){let O=De(P.placement);return O===w||O==="y"}return!0}).map(P=>[P.placement,P.overflows.filter(O=>O>0).reduce((O,M)=>O+M,0)]).sort((P,O)=>P[1]-O[1])[0])==null?void 0:L[0];H&&(N=H);break}case"initialPlacement":N=a;break}if(r!==N)return{reset:{placement:N}}}return{}}}};function nc(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function rc(e){return Ga.some(t=>e[t]>=0)}var cc=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){let{rects:o,platform:n}=t,{strategy:r="referenceHidden",...i}=at(e,t);switch(r){case"referenceHidden":{let s=await n.detectOverflow(t,{...i,elementContext:"reference"}),a=nc(s,o.reference);return{data:{referenceHiddenOffsets:a,referenceHidden:rc(a)}}}case"escaped":{let s=await n.detectOverflow(t,{...i,altBoundary:!0}),a=nc(s,o.floating);return{data:{escapedOffsets:a,escaped:rc(a)}}}default:return{}}}}};var lc=new Set(["left","top"]);async function cm(e,t){let{placement:o,platform:n,elements:r}=e,i=await(n.isRTL==null?void 0:n.isRTL(r.floating)),s=Ee(o),a=ct(o),d=De(o)==="y",c=lc.has(s)?-1:1,l=i&&d?-1:1,f=at(t,e),{mainAxis:p,crossAxis:m,alignmentAxis:u}=typeof f=="number"?{mainAxis:f,crossAxis:0,alignmentAxis:null}:{mainAxis:f.mainAxis||0,crossAxis:f.crossAxis||0,alignmentAxis:f.alignmentAxis};return a&&typeof u=="number"&&(m=a==="end"?u*-1:u),d?{x:m*l,y:p*c}:{x:p*c,y:m*l}}var dc=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var o,n;let{x:r,y:i,placement:s,middlewareData:a}=t,d=await cm(t,e);return s===((o=a.offset)==null?void 0:o.placement)&&(n=a.arrow)!=null&&n.alignmentOffset?{}:{x:r+d.x,y:i+d.y,data:{...d,placement:s}}}}},uc=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){let{x:o,y:n,placement:r,platform:i}=t,{mainAxis:s=!0,crossAxis:a=!1,limiter:d={fn:_=>{let{x:w,y}=_;return{x:w,y}}},...c}=at(e,t),l={x:o,y:n},f=await i.detectOverflow(t,c),p=De(Ee(r)),m=Ln(p),u=l[m],g=l[p];if(s){let _=m==="y"?"top":"left",w=m==="y"?"bottom":"right",y=u+f[_],b=u-f[w];u=Yo(y,u,b)}if(a){let _=p==="y"?"top":"left",w=p==="y"?"bottom":"right",y=g+f[_],b=g-f[w];g=Yo(y,g,b)}let v=d.fn({...t,[m]:u,[p]:g});return{...v,data:{x:v.x-o,y:v.y-n,enabled:{[m]:s,[p]:a}}}}}},fc=function(e){return e===void 0&&(e={}),{options:e,fn(t){let{x:o,y:n,placement:r,rects:i,middlewareData:s}=t,{offset:a=0,mainAxis:d=!0,crossAxis:c=!0}=at(e,t),l={x:o,y:n},f=De(r),p=Ln(f),m=l[p],u=l[f],g=at(a,t),v=typeof g=="number"?{mainAxis:g,crossAxis:0}:{mainAxis:0,crossAxis:0,...g};if(d){let y=p==="y"?"height":"width",b=i.reference[p]-i.floating[y]+v.mainAxis,S=i.reference[p]+i.reference[y]-v.mainAxis;mS&&(m=S)}if(c){var _,w;let y=p==="y"?"width":"height",b=lc.has(Ee(r)),S=i.reference[f]-i.floating[y]+(b&&((_=s.offset)==null?void 0:_[f])||0)+(b?0:v.crossAxis),x=i.reference[f]+i.reference[y]+(b?0:((w=s.offset)==null?void 0:w[f])||0)-(b?v.crossAxis:0);ux&&(u=x)}return{[p]:m,[f]:u}}}},pc=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){var o,n;let{placement:r,rects:i,platform:s,elements:a}=t,{apply:d=()=>{},...c}=at(e,t),l=await s.detectOverflow(t,c),f=Ee(r),p=ct(r),m=De(r)==="y",{width:u,height:g}=i.floating,v,_;f==="top"||f==="bottom"?(v=f,_=p===(await(s.isRTL==null?void 0:s.isRTL(a.floating))?"start":"end")?"left":"right"):(_=f,v=p==="end"?"top":"bottom");let w=g-l.top-l.bottom,y=u-l.left-l.right,b=Ht(g-l[v],w),S=Ht(u-l[_],y),x=!t.middlewareData.shift,E=b,T=S;if((o=t.middlewareData.shift)!=null&&o.enabled.x&&(T=y),(n=t.middlewareData.shift)!=null&&n.enabled.y&&(E=w),x&&!p){let C=Be(l.left,0),j=Be(l.right,0),A=Be(l.top,0),L=Be(l.bottom,0);m?T=u-2*(C!==0||j!==0?C+j:Be(l.left,l.right)):E=g-2*(A!==0||L!==0?A+L:Be(l.top,l.bottom))}await d({...t,availableWidth:T,availableHeight:E});let k=await s.getDimensions(a.floating);return u!==k.width||g!==k.height?{reset:{rects:!0}}:{}}}};function hc(e){let t=Ae(e),o=parseFloat(t.width)||0,n=parseFloat(t.height)||0,r=we(e),i=r?e.offsetWidth:o,s=r?e.offsetHeight:n,a=zt(o)!==i||zt(n)!==s;return a&&(o=i,n=s),{width:o,height:n,$:a}}function qr(e){return V(e)?e:e.contextElement}function ho(e){let t=qr(e);if(!we(t))return st(1);let o=t.getBoundingClientRect(),{width:n,height:r,$:i}=hc(t),s=(i?zt(o.width):o.width)/n,a=(i?zt(o.height):o.height)/r;return(!s||!Number.isFinite(s))&&(s=1),(!a||!Number.isFinite(a))&&(a=1),{x:s,y:a}}var lm=st(0);function wc(e){let t=ge(e);return!En()||!t.visualViewport?lm:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function dm(e,t,o){return t===void 0&&(t=!1),!o||t&&o!==ge(e)?!1:t}function Qt(e,t,o,n){t===void 0&&(t=!1),o===void 0&&(o=!1);let r=e.getBoundingClientRect(),i=qr(e),s=st(1);t&&(n?V(n)&&(s=ho(n)):s=ho(e));let a=dm(i,o,n)?wc(i):st(0),d=(r.left+a.x)/s.x,c=(r.top+a.y)/s.y,l=r.width/s.x,f=r.height/s.y;if(i){let p=ge(i),m=n&&V(n)?ge(n):n,u=p,g=Tn(u);for(;g&&n&&m!==u;){let v=ho(g),_=g.getBoundingClientRect(),w=Ae(g),y=_.left+(g.clientLeft+parseFloat(w.paddingLeft))*v.x,b=_.top+(g.clientTop+parseFloat(w.paddingTop))*v.y;d*=v.x,c*=v.y,l*=v.x,f*=v.y,d+=y,c+=b,u=ge(g),g=Tn(u)}}return qt({width:l,height:f,x:d,y:c})}function Mn(e,t){let o=jo(e).scrollLeft;return t?t.left+o:Qt(ot(e)).left+o}function vc(e,t){let o=e.getBoundingClientRect(),n=o.left+t.scrollLeft-Mn(e,o),r=o.top+t.scrollTop;return{x:n,y:r}}function um(e){let{elements:t,rect:o,offsetParent:n,strategy:r}=e,i=r==="fixed",s=ot(n),a=t?Do(t.floating):!1;if(n===s||a&&i)return o;let d={scrollLeft:0,scrollTop:0},c=st(1),l=st(0),f=we(n);if((f||!f&&!i)&&((Gt(n)!=="body"||fo(s))&&(d=jo(n)),f)){let m=Qt(n);c=ho(n),l.x=m.x+n.clientLeft,l.y=m.y+n.clientTop}let p=s&&!f&&!i?vc(s,d):st(0);return{width:o.width*c.x,height:o.height*c.y,x:o.x*c.x-d.scrollLeft*c.x+l.x+p.x,y:o.y*c.y-d.scrollTop*c.y+l.y+p.y}}function fm(e){return Array.from(e.getClientRects())}function pm(e){let t=ot(e),o=jo(e),n=e.ownerDocument.body,r=Be(t.scrollWidth,t.clientWidth,n.scrollWidth,n.clientWidth),i=Be(t.scrollHeight,t.clientHeight,n.scrollHeight,n.clientHeight),s=-o.scrollLeft+Mn(e),a=-o.scrollTop;return Ae(n).direction==="rtl"&&(s+=Be(t.clientWidth,n.clientWidth)-r),{width:r,height:i,x:s,y:a}}var mc=25;function mm(e,t){let o=ge(e),n=ot(e),r=o.visualViewport,i=n.clientWidth,s=n.clientHeight,a=0,d=0;if(r){i=r.width,s=r.height;let l=En();(!l||l&&t==="fixed")&&(a=r.offsetLeft,d=r.offsetTop)}let c=Mn(n);if(c<=0){let l=n.ownerDocument,f=l.body,p=getComputedStyle(f),m=l.compatMode==="CSS1Compat"&&parseFloat(p.marginLeft)+parseFloat(p.marginRight)||0,u=Math.abs(n.clientWidth-f.clientWidth-m);u<=mc&&(i-=u)}else c<=mc&&(i+=c);return{width:i,height:s,x:a,y:d}}function gm(e,t){let o=Qt(e,!0,t==="fixed"),n=o.top+e.clientTop,r=o.left+e.clientLeft,i=we(e)?ho(e):st(1),s=e.clientWidth*i.x,a=e.clientHeight*i.y,d=r*i.x,c=n*i.y;return{width:s,height:a,x:d,y:c}}function gc(e,t,o){let n;if(t==="viewport")n=mm(e,o);else if(t==="document")n=pm(ot(e));else if(V(t))n=gm(t,o);else{let r=wc(e);n={x:t.x-r.x,y:t.y-r.y,width:t.width,height:t.height}}return qt(n)}function _c(e,t){let o=tt(e);return o===t||!V(o)||nt(o)?!1:Ae(o).position==="fixed"||_c(o,t)}function bm(e,t){let o=t.get(e);if(o)return o;let n=It(e,[],!1).filter(a=>V(a)&&Gt(a)!=="body"),r=null,i=Ae(e).position==="fixed",s=i?tt(e):e;for(;V(s)&&!nt(s);){let a=Ae(s),d=Sn(s);!d&&a.position==="fixed"&&(r=null),(i?!d&&!r:!d&&a.position==="static"&&!!r&&(r.position==="absolute"||r.position==="fixed")||fo(s)&&!d&&_c(e,s))?n=n.filter(l=>l!==s):r=a,s=tt(s)}return t.set(e,n),n}function hm(e){let{element:t,boundary:o,rootBoundary:n,strategy:r}=e,s=[...o==="clippingAncestors"?Do(t)?[]:bm(t,this._c):[].concat(o),n],a=gc(t,s[0],r),d=a.top,c=a.right,l=a.bottom,f=a.left;for(let p=1;p{s(!1,1e-7)},1e3)}E===1&&!xc(c,e.getBoundingClientRect())&&s(),b=!1}try{o=new IntersectionObserver(S,{...y,root:r.ownerDocument})}catch{o=new IntersectionObserver(S,y)}o.observe(e)}return s(!0),i}function Xo(e,t,o,n){n===void 0&&(n={});let{ancestorScroll:r=!0,ancestorResize:i=!0,elementResize:s=typeof ResizeObserver=="function",layoutShift:a=typeof IntersectionObserver=="function",animationFrame:d=!1}=n,c=qr(e),l=r||i?[...c?It(c):[],...t?It(t):[]]:[];l.forEach(_=>{r&&_.addEventListener("scroll",o,{passive:!0}),i&&_.addEventListener("resize",o)});let f=c&&a?xm(c,o):null,p=-1,m=null;s&&(m=new ResizeObserver(_=>{let[w]=_;w&&w.target===c&&m&&t&&(m.unobserve(t),cancelAnimationFrame(p),p=requestAnimationFrame(()=>{var y;(y=m)==null||y.observe(t)})),o()}),c&&!d&&m.observe(c),t&&m.observe(t));let u,g=d?Qt(e):null;d&&v();function v(){let _=Qt(e);g&&!xc(g,_)&&o(),g=_,u=requestAnimationFrame(v)}return o(),()=>{var _;l.forEach(w=>{r&&w.removeEventListener("scroll",o),i&&w.removeEventListener("resize",o)}),f?.(),(_=m)==null||_.disconnect(),m=null,d&&cancelAnimationFrame(u)}}var Rc=dc;var Sc=uc,Ec=ac,Tc=pc,kc=cc;var Pc=fc,Bn=(e,t,o)=>{let n=new Map,r={platform:Zr,...o},i={...r.platform,_c:n};return sc(e,t,{...r,platform:i})};var ve=h(z(),1),Ac=h(z(),1),Oc=h(Mt(),1),Sm=typeof document<"u",Em=function(){},Hn=Sm?Ac.useLayoutEffect:Em;function zn(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let o,n,r;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(o=e.length,o!==t.length)return!1;for(n=o;n--!==0;)if(!zn(e[n],t[n]))return!1;return!0}if(r=Object.keys(e),o=r.length,o!==Object.keys(t).length)return!1;for(n=o;n--!==0;)if(!{}.hasOwnProperty.call(t,r[n]))return!1;for(n=o;n--!==0;){let i=r[n];if(!(i==="_owner"&&e.$$typeof)&&!zn(e[i],t[i]))return!1}return!0}return e!==e&&t!==t}function Nc(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function Cc(e,t){let o=Nc(e);return Math.round(t*o)/o}function Qr(e){let t=ve.useRef(e);return Hn(()=>{t.current=e}),t}function Lc(e){e===void 0&&(e={});let{placement:t="bottom",strategy:o="absolute",middleware:n=[],platform:r,elements:{reference:i,floating:s}={},transform:a=!0,whileElementsMounted:d,open:c}=e,[l,f]=ve.useState({x:0,y:0,strategy:o,placement:t,middlewareData:{},isPositioned:!1}),[p,m]=ve.useState(n);zn(p,n)||m(n);let[u,g]=ve.useState(null),[v,_]=ve.useState(null),w=ve.useCallback(P=>{P!==x.current&&(x.current=P,g(P))},[]),y=ve.useCallback(P=>{P!==E.current&&(E.current=P,_(P))},[]),b=i||u,S=s||v,x=ve.useRef(null),E=ve.useRef(null),T=ve.useRef(l),k=d!=null,C=Qr(d),j=Qr(r),A=Qr(c),L=ve.useCallback(()=>{if(!x.current||!E.current)return;let P={placement:t,strategy:o,middleware:p};j.current&&(P.platform=j.current),Bn(x.current,E.current,P).then(O=>{let M={...O,isPositioned:A.current!==!1};I.current&&!zn(T.current,M)&&(T.current=M,Oc.flushSync(()=>{f(M)}))})},[p,t,o,j,A]);Hn(()=>{c===!1&&T.current.isPositioned&&(T.current.isPositioned=!1,f(P=>({...P,isPositioned:!1})))},[c]);let I=ve.useRef(!1);Hn(()=>(I.current=!0,()=>{I.current=!1}),[]),Hn(()=>{if(b&&(x.current=b),S&&(E.current=S),b&&S){if(C.current)return C.current(b,S,L);L()}},[b,S,L,C,k]);let R=ve.useMemo(()=>({reference:x,floating:E,setReference:w,setFloating:y}),[w,y]),N=ve.useMemo(()=>({reference:b,floating:S}),[b,S]),H=ve.useMemo(()=>{let P={position:o,left:0,top:0};if(!N.floating)return P;let O=Cc(N.floating,l.x),M=Cc(N.floating,l.y);return a?{...P,transform:"translate("+O+"px, "+M+"px)",...Nc(N.floating)>=1.5&&{willChange:"transform"}}:{position:o,left:O,top:M}},[o,a,N.floating,l.x,l.y]);return ve.useMemo(()=>({...l,update:L,refs:R,elements:N,floatingStyles:H}),[l,L,R,N,H])}var Jr=(e,t)=>{let o=Rc(e);return{name:o.name,fn:o.fn,options:[e,t]}},$r=(e,t)=>{let o=Sc(e);return{name:o.name,fn:o.fn,options:[e,t]}},ei=(e,t)=>({fn:Pc(e).fn,options:[e,t]}),ti=(e,t)=>{let o=Ec(e);return{name:o.name,fn:o.fn,options:[e,t]}},oi=(e,t)=>{let o=Tc(e);return{name:o.name,fn:o.fn,options:[e,t]}};var ni=(e,t)=>{let o=kc(e);return{name:o.name,fn:o.fn,options:[e,t]}};var _o=h(z(),1),qc=h(Mt(),1);var Xc=h(z(),1);var q=(e,t,o,n,r,i,...s)=>{if(s.length>0)throw new Error(Pe(1));let a;if(e&&t&&o&&n&&r&&i)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f),g=n(d,c,l,f),v=r(d,c,l,f);return i(p,m,u,g,v,c,l,f)};else if(e&&t&&o&&n&&r)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f),g=n(d,c,l,f);return r(p,m,u,g,c,l,f)};else if(e&&t&&o&&n)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f);return n(p,m,u,c,l,f)};else if(e&&t&&o)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f);return o(p,m,c,l,f)};else if(e&&t)a=(d,c,l,f)=>{let p=e(d,c,l,f);return t(p,c,l,f)};else if(e)a=e;else throw new Error("Missing arguments");return a};var Uc=h(z(),1),li=h(ii(),1),Gc=h(jc(),1);var Fc=h(z(),1);var si=[],ai;function Vc(){return ai}function Wc(e){si.push(e)}function ci(e){let t=(o,n)=>{let r=Se(Wm).current,i;try{ai=r;for(let s of si)s.before(r);i=e(o,n);for(let s of si)s.after(r);r.didInitialize=!0}finally{ai=void 0}return i};return t.displayName=e.displayName||e.name,t}function Yc(e){return Fc.forwardRef(ci(e))}function Wm(){return{didInitialize:!1}}var Ym=ao(19),Um=Ym?Xm:Km;function jn(e,t,o,n,r){return Um(e,t,o,n,r)}function Gm(e,t,o,n,r){let i=Uc.useCallback(()=>t(e.getSnapshot(),o,n,r),[e,t,o,n,r]);return(0,li.useSyncExternalStore)(e.subscribe,i,i)}Wc({before(e){e.syncIndex=0,e.didInitialize||(e.syncTick=1,e.syncHooks=[],e.didChangeStore=!0,e.getSnapshot=()=>{let t=!1;for(let o=0;o0&&(e.didChangeStore&&(e.didChangeStore=!1,e.subscribe=t=>{let o=new Set;for(let r of e.syncHooks)o.add(r.store);let n=[];for(let r of o)n.push(r.subscribe(t));return()=>{for(let r of n)r()}}),(0,li.useSyncExternalStore)(e.subscribe,e.getSnapshot,e.getSnapshot))}});function Xm(e,t,o,n,r){let i=Vc();if(!i)return Gm(e,t,o,n,r);let s=i.syncIndex;i.syncIndex+=1;let a;return i.didInitialize?(a=i.syncHooks[s],(a.store!==e||a.selector!==t||!Object.is(a.a1,o)||!Object.is(a.a2,n)||!Object.is(a.a3,r))&&(a.store!==e&&(i.didChangeStore=!0),a.store=e,a.selector=t,a.a1=o,a.a2=n,a.a3=r,a.value=t(e.getSnapshot(),o,n,r))):(a={store:e,selector:t,a1:o,a2:n,a3:r,value:t(e.getSnapshot(),o,n,r)},i.syncHooks.push(a)),a.value}function Km(e,t,o,n,r){return(0,Gc.useSyncExternalStoreWithSelector)(e.subscribe,e.getSnapshot,e.getSnapshot,i=>t(i,o,n,r))}var Fn=class{constructor(t){this.state=t,this.listeners=new Set,this.updateTick=0}subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});getSnapshot=()=>this.state;setState(t){if(this.state===t)return;this.state=t,this.updateTick+=1;let o=this.updateTick;for(let n of this.listeners){if(o!==this.updateTick)return;n(t)}}update(t){for(let o in t)if(!Object.is(this.state[o],t[o])){this.setState({...this.state,...t});return}}set(t,o){Object.is(this.state[t],o)||this.setState({...this.state,[t]:o})}notifyAll(){let t={...this.state};this.setState(t)}use(t,o,n,r){return jn(this,t,o,n,r)}};var Jt=h(z(),1);var vo=class extends Fn{constructor(t,o={},n){super(t),this.context=o,this.selectors=n}useSyncedValue(t,o){Jt.useDebugValue(t);let n=this;D(()=>{n.state[t]!==o&&n.set(t,o)},[n,t,o])}useSyncedValueWithCleanup(t,o){let n=this;D(()=>(n.state[t]!==o&&n.set(t,o),()=>{n.set(t,void 0)}),[n,t,o])}useSyncedValues(t){let o=this,n=Object.values(t);D(()=>{o.update(t)},[o,...n])}useControlledProp(t,o){Jt.useDebugValue(t);let n=this,r=o!==void 0;D(()=>{r&&!Object.is(n.state[t],o)&&n.setState({...n.state,[t]:o})},[n,t,o,r])}select(t,o,n,r){let i=this.selectors[t];return i(this.state,o,n,r)}useState(t,o,n,r){return Jt.useDebugValue(t),jn(this,this.selectors[t],o,n,r)}useContextCallback(t,o){Jt.useDebugValue(t);let n=Y(o??Nt);this.context[t]=n}useStateSetter(t){let o=Jt.useRef(void 0);return o.current===void 0&&(o.current=n=>{this.set(t,n)}),o.current}observe(t,o){let n;typeof t=="function"?n=t:n=this.selectors[t];let r=n(this.state);return o(r,r,this),this.subscribe(i=>{let s=n(i);if(!Object.is(r,s)){let a=r;r=s,o(s,a,this)}})}};var qm={open:q(e=>e.open),transitionStatus:q(e=>e.transitionStatus),domReferenceElement:q(e=>e.domReferenceElement),referenceElement:q(e=>e.positionReference??e.referenceElement),floatingElement:q(e=>e.floatingElement),floatingId:q(e=>e.floatingId)},pt=class extends vo{constructor(t){let{syncOnly:o,nested:n,onOpenChange:r,triggerElements:i,...s}=t;super({...s,positionReference:s.referenceElement,domReferenceElement:s.referenceElement},{onOpenChange:r,dataRef:{current:{}},events:ec(),nested:n,triggerElements:i},qm),this.syncOnly=o}syncOpenEvent=(t,o)=>{(!t||!this.state.open||o!=null&&Ha(o))&&(this.context.dataRef.current.openEvent=t?o:void 0)};dispatchOpenChange=(t,o)=>{this.syncOpenEvent(t,o.event);let n={open:t,reason:o.reason,nativeEvent:o.event,nested:this.context.nested,triggerElement:o.trigger};this.context.events.emit("openchange",n)};setOpen=(t,o)=>{if(this.syncOnly){this.context.onOpenChange?.(t,o);return}this.dispatchOpenChange(t,o),this.context.onOpenChange?.(t,o)}};function Kc(e){let{popupStore:t,treatPopupAsFloatingElement:o=!1,floatingRootContext:n,floatingId:r,nested:i,onOpenChange:s}=e,a=t.useState("open"),d=t.useState("activeTriggerElement"),c=t.useState(o?"popupElement":"positionerElement"),l=t.context.triggerElements,f=s,p=Xc.useRef(null);n===void 0&&p.current===null&&(p.current=new pt({open:a,transitionStatus:void 0,referenceElement:d,floatingElement:c,triggerElements:l,onOpenChange:f,floatingId:r,syncOnly:!0,nested:i}));let m=n??p.current;return t.useSyncedValue("floatingId",r),D(()=>{let u={open:a,floatingId:r,referenceElement:d,floatingElement:c};V(d)&&(u.domReferenceElement=d),m.state.positionReference===m.state.referenceElement&&(u.positionReference=d),m.update(u)},[a,r,d,c,m]),m.context.onOpenChange=f,m.context.nested=i,m}var Zc={tabIndex:-1,[Dr]:""};function Qc(e,t,o=!1){let n=Lt(),r=bo()!=null,i=_o.useRef(null);e===void 0&&i.current===null&&(i.current=t(n,r));let s=e??i.current;return Kc({popupStore:s,treatPopupAsFloatingElement:o,floatingRootContext:s.state.floatingRootContext,floatingId:n,nested:r,onOpenChange:s.setOpen}),{store:s,internalStore:i.current}}function Zm(e,t){let o=_o.useRef(null),n=_o.useRef(null);return _o.useCallback(r=>{if(e===void 0)return;let i=!1;if(o.current!==null){let s=o.current,a=n.current,d=t.context.triggerElements.getById(s);a&&d===a&&(t.context.triggerElements.delete(s),i=!0),o.current=null,n.current=null}if(r!==null&&(o.current=e,n.current=r,t.context.triggerElements.add(e,r),i=!0),i){let s=t.context.triggerElements.size;t.select("open")&&t.state.triggerCount!==s&&t.set("triggerCount",s)}},[t,e])}function Qm(e,t,o,n=!1){t?e.preventUnmountingOnClose=!1:n&&(e.preventUnmountingOnClose=!0);let r=o?.id??null;(r||t)&&(e.activeTriggerId=r,e.activeTriggerElement=o??null)}function Jm(e){let t=!1;return e.preventUnmountOnClose=()=>{t=!0},()=>t}function Jc(e,t,o,n={}){let r=o.reason,i=r===U.triggerHover,s=t&&r===U.triggerFocus,a=!t&&(r===U.triggerPress||r===U.escapeKey),d=Jm(o);if(e.context.onOpenChange?.(t,o),o.isCanceled)return;n.onBeforeDispatch?.(),e.state.floatingRootContext.dispatchOpenChange(t,o);let c=()=>{let l={...n.extraState,open:t};s?l.instantType="focus":a?l.instantType="dismiss":i&&(l.instantType=void 0),Qm(l,t,o.trigger,d()),e.update(l)};i?qc.flushSync(c):c()}function $c(e,t,o,n){Oa(()=>{t===void 0&&e.state.open===!1&&o&&(e.state={...e.state,open:!0,activeTriggerId:n,preventUnmountingOnClose:!1})})}function el(e,t,o,n){let r=o.useState("isMountedByTrigger",e),i=Zm(e,o),s=Y(a=>{if(i(a),!a)return;let d=o.select("open"),c=o.select("activeTriggerId");if(c===e){o.update({activeTriggerElement:a,...d?n:null});return}c==null&&d&&o.update({activeTriggerId:e,activeTriggerElement:a,...n})});return D(()=>{r&&o.update({activeTriggerElement:t.current,...n})},[r,o,t,...Object.values(n)]),{registerTrigger:s,isMountedByThisTrigger:r}}function tl(e,t={}){let{closeOnActiveTriggerUnmount:o=!1}=t,n=e.useState("open"),r=e.useState("triggerCount");D(()=>{if(!n){e.state.triggerCount!==0&&e.set("triggerCount",0);return}let i=e.context.triggerElements.size,s={};e.state.triggerCount!==i&&(s.triggerCount=i);let a=e.select("activeTriggerId"),d=null;if(a){let c=e.context.triggerElements.getById(a);c?c!==e.state.activeTriggerElement&&(s.activeTriggerElement=c):d=a}if(!d&&!a&&i===1){let c=e.context.triggerElements.entries().next();if(!c.done){let[l,f]=c.value;s.activeTriggerId=l,s.activeTriggerElement=f}}(s.triggerCount!==void 0||s.activeTriggerId!==void 0||s.activeTriggerElement!==void 0)&&e.update(s),d&&o&&queueMicrotask(()=>{if(e.select("open")&&e.select("activeTriggerId")===d&&!e.context.triggerElements.getById(d)){let c=ee(U.none);e.setOpen(!1,c),c.isCanceled||e.update({activeTriggerId:null,activeTriggerElement:null})}})},[n,e,r,o])}function ol(e,t,o){let{mounted:n,setMounted:r,transitionStatus:i}=ha(e),s=t.useState("preventUnmountingOnClose"),a=e?!1:s;t.useSyncedValues({mounted:n,transitionStatus:i,preventUnmountingOnClose:a});let d=Y(()=>{r(!1),t.update({activeTriggerId:null,activeTriggerElement:null,mounted:!1,preventUnmountingOnClose:!1}),o?.(),t.context.onOpenChangeComplete?.(!1)});return Pn({enabled:n&&!e&&!a,open:e,ref:t.context.popupRef,onComplete(){e||d()}}),{forceUnmount:d,transitionStatus:i}}function nl(e,t){e.useSyncedValues(t),D(()=>()=>{e.update({activeTriggerProps:be,inactiveTriggerProps:be,popupProps:be})},[e])}var jt=class{constructor(){this.elementsSet=new Set,this.idMap=new Map}add(t,o){let n=this.idMap.get(t);n!==o&&(n!==void 0&&this.elementsSet.delete(n),this.elementsSet.add(o),this.idMap.set(t,o))}delete(t){let o=this.idMap.get(t);o&&(this.elementsSet.delete(o),this.idMap.delete(t))}hasElement(t){return this.elementsSet.has(t)}hasMatchingElement(t){for(let o of this.elementsSet)if(t(o))return!0;return!1}getById(t){return this.idMap.get(t)}entries(){return this.idMap.entries()}elements(){return this.elementsSet.values()}get size(){return this.idMap.size}};function rl(){return new pt({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:new jt,floatingId:void 0,syncOnly:!1,nested:!1,onOpenChange:void 0})}function sl(){return{open:!1,openProp:void 0,mounted:!1,transitionStatus:void 0,floatingRootContext:rl(),floatingId:void 0,triggerCount:0,preventUnmountingOnClose:!1,payload:void 0,activeTriggerId:null,activeTriggerElement:null,triggerIdProp:void 0,popupElement:null,positionerElement:null,activeTriggerProps:be,inactiveTriggerProps:be,popupProps:be}}function al(e,t,o=!1){return new pt({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:e,floatingId:t,syncOnly:!0,nested:o,onOpenChange:void 0})}var Ko=q(e=>e.triggerIdProp??e.activeTriggerId),di=q(e=>e.openProp??e.open),il=q(e=>(e.popupElement?.id??e.floatingId)||void 0);function cl(e,t){return t!==void 0&&di(e)&&Ko(e)===t}function $m(e,t){return cl(e,t)?!0:t!==void 0&&di(e)&&Ko(e)==null&&e.triggerCount===1}var ll={open:di,mounted:q(e=>e.mounted),transitionStatus:q(e=>e.transitionStatus),floatingRootContext:q(e=>e.floatingRootContext),triggerCount:q(e=>e.triggerCount),preventUnmountingOnClose:q(e=>e.preventUnmountingOnClose),payload:q(e=>e.payload),activeTriggerId:Ko,activeTriggerElement:q(e=>e.mounted?e.activeTriggerElement:null),popupId:il,isTriggerActive:q((e,t)=>t!==void 0&&Ko(e)===t),isOpenedByTrigger:q((e,t)=>cl(e,t)),isMountedByTrigger:q((e,t)=>t!==void 0&&Ko(e)===t&&e.mounted),triggerProps:q((e,t)=>t?e.activeTriggerProps:e.inactiveTriggerProps),triggerPopupId:q((e,t)=>$m(e,t)?il(e):void 0),popupProps:q(e=>e.popupProps),popupElement:q(e=>e.popupElement),positionerElement:q(e=>e.positionerElement)};function dl(e){let{open:t=!1,onOpenChange:o,elements:n={}}=e,r=Lt(),i=bo()!=null,s=Se(()=>new pt({open:t,transitionStatus:void 0,onOpenChange:o,referenceElement:n.reference??null,floatingElement:n.floating??null,triggerElements:new jt,floatingId:r,syncOnly:!1,nested:i})).current;return D(()=>{let a={open:t,floatingId:r};n.reference!==void 0&&(a.referenceElement=n.reference,a.domReferenceElement=V(n.reference)?n.reference:null),n.floating!==void 0&&(a.floatingElement=n.floating),s.update(a)},[t,r,n.reference,n.floating,s]),s.context.onOpenChange=o,s.context.nested=i,s}function ui(e={}){let{nodeId:t,externalTree:o}=e,n=dl(e),r=e.rootContext||n,i=r.useState("referenceElement"),s=r.useState("floatingElement"),a=r.useState("domReferenceElement"),d=r.useState("open"),c=r.useState("floatingId"),[l,f]=Ne.useState(null),[p,m]=Ne.useState(void 0),[u,g]=Ne.useState(void 0),v=Ne.useRef(null),_=Dt(o),w=Ne.useMemo(()=>({reference:i,floating:s,domReference:a}),[i,s,a]),y=Lc({...e,elements:{...w,...l&&{reference:l}}}),b=V(p)?p:null,S=u===void 0?r.state.floatingElement:u;r.useSyncedValue("referenceElement",p??null),r.useSyncedValue("domReferenceElement",p===void 0?a:b),r.useSyncedValue("floatingElement",S);let x=Ne.useCallback(A=>{let L=V(A)?{getBoundingClientRect:()=>A.getBoundingClientRect(),getClientRects:()=>A.getClientRects(),contextElement:A}:A;f(L),y.refs.setReference(L)},[y.refs]),E=Ne.useCallback(A=>{(V(A)||A===null)&&(v.current=A,m(A)),(V(y.refs.reference.current)||y.refs.reference.current===null||A!==null&&!V(A))&&y.refs.setReference(A)},[y.refs,m]),T=Ne.useCallback(A=>{g(A),y.refs.setFloating(A)},[y.refs]),k=Ne.useMemo(()=>({...y.refs,setReference:E,setFloating:T,setPositionReference:x,domReference:v}),[y.refs,E,T,x]),C=Ne.useMemo(()=>({...y.elements,domReference:a}),[y.elements,a]),j=Ne.useMemo(()=>({...y,dataRef:r.context.dataRef,open:d,onOpenChange:r.setOpen,events:r.context.events,floatingId:c,refs:k,elements:C,nodeId:t,rootStore:r}),[y,k,C,t,r,d,c]);return D(()=>{a&&(v.current=a)},[a]),D(()=>{r.context.dataRef.current.floatingContext=j;let A=_?.nodesRef.current.find(L=>L.id===t);A&&(A.context=j)}),Ne.useMemo(()=>({...y,context:j,refs:k,elements:C,rootStore:r}),[y,k,C,j,r])}var mt=h(z(),1);var fi=xt.os.mac&&xt.engine.webkit;function pi(e,t={}){let{enabled:o=!0,delay:n}=t,r="rootStore"in e?e.rootStore:e,{events:i,dataRef:s}=r.context,a=mt.useRef(!1),d=mt.useRef(null),c=mt.useRef(!0),l=rt();mt.useEffect(()=>{let p=r.select("domReferenceElement");if(!o)return;let m=ge(p);function u(){let _=r.select("domReferenceElement");!r.select("open")&&we(_)&&_===Cn(xe(_))&&(a.current=!0)}function g(){c.current=!0}function v(){c.current=!1}return it(re(m,"blur",u),fi&&re(m,"keydown",g,!0),fi&&re(m,"pointerdown",v,!0))},[r,o]),mt.useEffect(()=>{if(!o)return;function p(m){if(m.reason===U.triggerPress||m.reason===U.escapeKey){let u=r.select("domReferenceElement");V(u)&&(d.current=u,a.current=!0)}}return i.on("openchange",p),()=>{i.off("openchange",p)}},[i,o,r]);let f=mt.useMemo(()=>{function p(){a.current=!1,d.current=null}return{onMouseLeave(){p()},onFocus(m){let u=m.currentTarget;if(a.current){if(d.current===u)return;p()}let g=Me(m.nativeEvent);if(V(g)){if(fi&&!m.relatedTarget){if(!c.current&&!Da(g))return}else if(!ja(g))return}let v=Bt(m.relatedTarget,r.context.triggerElements),{nativeEvent:_,currentTarget:w}=m,y=typeof n=="function"?n():n;if(r.select("open")&&v||y===0||y===void 0){r.setOpen(!0,ee(U.triggerFocus,_,w));return}l.start(y,()=>{a.current||r.setOpen(!0,ee(U.triggerFocus,_,w))})},onBlur(m){p();let u=m.relatedTarget,g=m.nativeEvent,v=V(u)&&u.hasAttribute(go("focus-guard"))&&u.getAttribute("data-type")==="outside";l.start(0,()=>{let _=r.select("domReferenceElement"),w=Cn(xe(_));!u&&w===_||ie(s.current.floatingContext?.refs.floating.current,w)||ie(_,w)||v||Bt(u??w,r.context.triggerElements)||r.setOpen(!1,ee(U.triggerFocus,g))})}}},[s,n,r,l]);return mt.useMemo(()=>o?{reference:f,trigger:f}:{},[o,f])}var gi=h(z(),1);var mi=class e{constructor(){this.pointerType=void 0,this.interactedInside=!1,this.handler=void 0,this.blockMouseMove=!0,this.performedPointerEventsMutation=!1,this.pointerEventsScopeElement=null,this.pointerEventsReferenceElement=null,this.pointerEventsFloatingElement=null,this.restTimeoutPending=!1,this.openChangeTimeout=new Ye,this.restTimeout=new Ye,this.handleCloseOptions=void 0}static create(){return new e}dispose=()=>{this.openChangeTimeout.clear(),this.restTimeout.clear()};disposeEffect=()=>this.dispose},Vn=new WeakMap;function yo(e){if(!e.performedPointerEventsMutation)return;let t=e.pointerEventsScopeElement;t&&Vn.get(t)===e&&(e.pointerEventsScopeElement?.style.removeProperty("pointer-events"),e.pointerEventsReferenceElement?.style.removeProperty("pointer-events"),e.pointerEventsFloatingElement?.style.removeProperty("pointer-events"),Vn.delete(t)),e.performedPointerEventsMutation=!1,e.pointerEventsScopeElement=null,e.pointerEventsReferenceElement=null,e.pointerEventsFloatingElement=null}function Wn(e,t){let{scopeElement:o,referenceElement:n,floatingElement:r}=t,i=Vn.get(o);i&&i!==e&&yo(i),yo(e),e.performedPointerEventsMutation=!0,e.pointerEventsScopeElement=o,e.pointerEventsReferenceElement=n,e.pointerEventsFloatingElement=r,Vn.set(o,e),o.style.pointerEvents="none",n.style.pointerEvents="auto",r.style.pointerEvents="auto"}function xo(e){let t=e.context.dataRef.current,o=Se(()=>t.hoverInteractionState??mi.create()).current;return t.hoverInteractionState||(t.hoverInteractionState=o),co(t.hoverInteractionState.disposeEffect),t.hoverInteractionState}function bi(e,t={}){let{enabled:o=!0,closeDelay:n=0,nodeId:r}=t,i="rootStore"in e?e.rootStore:e,s=i.useState("open"),a=i.useState("floatingElement"),d=i.useState("domReferenceElement"),{dataRef:c}=i.context,l=Dt(),f=bo(),p=xo(i),m=rt(),u=Y(()=>On(c.current.openEvent?.type,p.interactedInside)),g=Y(()=>Fa(c.current.openEvent?.type)),v=Y(()=>{yo(p)});D(()=>{s||(p.pointerType=void 0,p.restTimeoutPending=!1,p.interactedInside=!1,v())},[s,p,v]),gi.useEffect(()=>v,[v]),D(()=>{if(o&&s&&p.handleCloseOptions?.blockPointerEvents&&g()&&V(d)&&a){let _=d,w=a,y=xe(a),b=l?.nodesRef.current.find(T=>T.id===f)?.context?.elements.floating;b&&(b.style.pointerEvents="");let S=p.pointerEventsScopeElement!==w?p.pointerEventsScopeElement:null,x=b!==w?b:null,E=p.handleCloseOptions?.getScope?.()??S??x??_.closest("[data-rootownerid]")??y.body;return Wn(p,{scopeElement:E,referenceElement:_,floatingElement:w}),()=>{v()}}},[o,s,d,a,p,g,l,f,v]),gi.useEffect(()=>{if(!o)return;function _(){return!!(l&&f&&Et(l.nodesRef.current,f).length>0)}function w(T){let k=St(n,"close",p.pointerType),C=()=>{i.setOpen(!1,ee(U.triggerHover,T)),l?.events.emit("floating.closed",T)};k?p.openChangeTimeout.start(k,C):(p.openChangeTimeout.clear(),C())}function y(T){let k=Me(T);if(!Fr(k)){p.interactedInside=!1;return}p.interactedInside=k?.closest("[aria-haspopup]")!=null}function b(){p.openChangeTimeout.clear(),m.clear(),l?.events.off("floating.closed",x),v()}function S(T){if(_()&&l){l.events.on("floating.closed",x);return}if(Bt(T.relatedTarget,i.context.triggerElements))return;let k=c.current.floatingContext?.nodeId??r,C=T.relatedTarget;if(!(l&&k&&V(C)&&Et(l.nodesRef.current,k,!1).some(A=>ie(A.context?.elements.floating,C)))){if(p.handler){p.handler(T);return}v(),g()&&!u()&&w(T)}}function x(T){!l||!f||_()||m.start(0,()=>{l.events.off("floating.closed",x),i.setOpen(!1,ee(U.triggerHover,T)),l.events.emit("floating.closed",T)})}let E=a;return it(E&&re(E,"mouseenter",b),E&&re(E,"mouseleave",S),E&&re(E,"pointerdown",y,!0),()=>{l?.events.off("floating.closed",x)})},[o,a,i,c,n,r,g,u,v,p,l,f,m])}var Ft=h(z(),1),ul=h(Mt(),1);var eg={current:null};function hi(e,t={}){let{enabled:o=!0,delay:n=0,handleClose:r=null,mouseOnly:i=!1,restMs:s=0,move:a=!0,triggerElementRef:d=eg,externalTree:c,isActiveTrigger:l=!0,getHandleCloseContext:f,isClosing:p,shouldOpen:m}=t,u="rootStore"in e?e.rootStore:e,{dataRef:g,events:v}=u.context,_=Dt(c),w=xo(u),y=Ft.useRef(!1),b=ze(r),S=ze(n),x=ze(s),E=ze(o),T=ze(m),k=ze(p),C=Y(()=>On(g.current.openEvent?.type,w.interactedInside)),j=Y(()=>T.current?.()!==!1),A=Y((R,N,H)=>{let P=u.context.triggerElements;if(P.hasElement(N))return!R||!ie(R,N);if(!V(H))return!1;let O=H;return P.hasMatchingElement(M=>ie(M,O))&&(!R||!ie(R,O))}),L=Y(()=>{if(!w.handler)return;xe(u.select("domReferenceElement")).removeEventListener("mousemove",w.handler),w.handler=void 0}),I=Y(()=>{yo(w)});return l&&(w.handleCloseOptions=b.current?.__options),Ft.useEffect(()=>L,[L]),Ft.useEffect(()=>{if(!o)return;function R(N){N.open?y.current=!1:(y.current=N.reason===U.triggerHover,L(),w.openChangeTimeout.clear(),w.restTimeout.clear(),w.blockMouseMove=!0,w.restTimeoutPending=!1)}return v.on("openchange",R),()=>{v.off("openchange",R)}},[o,v,w,L]),Ft.useEffect(()=>{if(!o)return;function R(O,M=!0){let Z=St(S.current,"close",w.pointerType);Z?w.openChangeTimeout.start(Z,()=>{u.setOpen(!1,ee(U.triggerHover,O)),_?.events.emit("floating.closed",O)}):M&&(w.openChangeTimeout.clear(),u.setOpen(!1,ee(U.triggerHover,O)),_?.events.emit("floating.closed",O))}let N=d.current??(l?u.select("domReferenceElement"):null);if(!V(N))return;function H(O){if(w.openChangeTimeout.clear(),w.blockMouseMove=!1,i&&!Rt(w.pointerType))return;let M=Vr(x.current),Z=St(S.current,"open",w.pointerType),W=Me(O),oe=O.currentTarget??null,te=u.select("domReferenceElement"),se=oe;if(V(W)&&!u.context.triggerElements.hasElement(W)){for(let ue of u.context.triggerElements.elements())if(ie(ue,W)){se=ue;break}}V(oe)&&V(te)&&!u.context.triggerElements.hasElement(oe)&&ie(oe,te)&&(se=te);let G=se==null?!1:A(te,se,W),K=u.select("open"),J=k.current?.()??u.select("transitionStatus")==="ending",ne=!K&&J&&y.current,me=!G&&V(se)&&V(te)&&ie(te,se)&&ne,le=M>0&&!Z,X=G&&(K||ne)||me,pe=!K||G;if(X){j()&&u.setOpen(!0,ee(U.triggerHover,O,se));return}le||(Z?w.openChangeTimeout.start(Z,()=>{pe&&j()&&u.setOpen(!0,ee(U.triggerHover,O,se))}):pe&&j()&&u.setOpen(!0,ee(U.triggerHover,O,se)))}function P(O){if(C()){I();return}L();let M=u.select("domReferenceElement"),Z=xe(M);w.restTimeout.clear(),w.restTimeoutPending=!1;let W=g.current.floatingContext??f?.();if(Bt(O.relatedTarget,u.context.triggerElements))return;if(b.current&&W){u.select("open")||w.openChangeTimeout.clear();let te=d.current;w.handler=b.current({...W,tree:_,x:O.clientX,y:O.clientY,onClose(){I(),L(),E.current&&!C()&&te===u.select("domReferenceElement")&&R(O,!0)}}),Z.addEventListener("mousemove",w.handler),w.handler(O);return}(w.pointerType!=="touch"||!ie(u.select("floatingElement"),O.relatedTarget))&&R(O)}return a?it(re(N,"mousemove",H,{once:!0}),re(N,"mouseenter",H),re(N,"mouseleave",P)):it(re(N,"mouseenter",H),re(N,"mouseleave",P))},[L,I,g,S,u,o,b,w,l,A,C,i,a,x,d,_,E,f,k,j]),Ft.useMemo(()=>{if(!o)return;function R(N){w.pointerType=N.pointerType}return{onPointerDown:R,onPointerEnter:R,onMouseMove(N){let{nativeEvent:H}=N,P=N.currentTarget,O=u.select("domReferenceElement"),M=u.select("open"),Z=A(O,P,N.target);if(i&&!Rt(w.pointerType))return;if(M&&Z&&w.handleCloseOptions?.blockPointerEvents){let te=u.select("floatingElement");if(te){let se=w.handleCloseOptions?.getScope?.()??P.ownerDocument.body;Wn(w,{scopeElement:se,referenceElement:P,floatingElement:te})}}let W=Vr(x.current);if(M&&!Z||W===0||!Z&&w.restTimeoutPending&&N.movementX**2+N.movementY**2<2)return;w.restTimeout.clear();function oe(){if(w.restTimeoutPending=!1,C())return;let te=u.select("open");!w.blockMouseMove&&(!te||Z)&&j()&&u.setOpen(!0,ee(U.triggerHover,H,P))}w.pointerType==="touch"?ul.flushSync(()=>{oe()}):Z&&M?oe():(w.restTimeoutPending=!0,w.restTimeout.start(W,oe))}}},[o,w,C,A,i,u,x,j])}var fl=.1,tg=fl*fl,ce=.5;function Yn(e,t,o,n,r,i){return n>=t!=i>=t&&e<=(r-o)*(t-n)/(i-n)+o}function Un(e,t,o,n,r,i,s,a,d,c){let l=!1;return Yn(e,t,o,n,r,i)&&(l=!l),Yn(e,t,r,i,s,a)&&(l=!l),Yn(e,t,s,a,d,c)&&(l=!l),Yn(e,t,d,c,o,n)&&(l=!l),l}function og(e,t,o){return e>=o.x&&e<=o.x+o.width&&t>=o.y&&t<=o.y+o.height}function Gn(e,t,o,n,r,i){let s=Math.min(o,r),a=Math.max(o,r),d=Math.min(n,i),c=Math.max(n,i);return e>=s&&e<=a&&t>=d&&t<=c}function wi(e={}){let{blockPointerEvents:t=!1}=e,o=new Ye,n=({x:r,y:i,placement:s,elements:a,onClose:d,nodeId:c,tree:l})=>{let f=s?.split("-")[0],p=!1,m=null,u=null,g=typeof performance<"u"?performance.now():0;function v(w,y){let b=performance.now(),S=b-g;if(m===null||u===null||S===0)return m=w,u=y,g=b,!1;let x=w-m,E=y-u,T=x*x+E*E,k=S*S*tg;return m=w,u=y,g=b,T0)}function L(){A()||_()}if(A())return;let I=b.getBoundingClientRect(),R=S.getBoundingClientRect(),N=r>R.right-R.width/2,H=i>R.bottom-R.height/2,P=R.width>I.width,O=R.height>I.height,M=(P?I:R).left,Z=(P?I:R).right,W=(O?I:R).top,oe=(O?I:R).bottom;if(f==="top"&&i>=I.bottom-1||f==="bottom"&&i<=I.top+1||f==="left"&&r>=I.right-1||f==="right"&&r<=I.left+1){L();return}let te=!1;switch(f){case"top":te=Gn(x,E,M,I.top+1,Z,R.bottom-1);break;case"bottom":te=Gn(x,E,M,R.top+1,Z,I.bottom-1);break;case"left":te=Gn(x,E,R.right-1,oe,I.left+1,W);break;case"right":te=Gn(x,E,I.right-1,oe,R.left+1,W);break;default:}if(te)return;if(p&&!og(x,E,I)){L();return}if(!k&&v(x,E)){L();return}let se=!1;switch(f){case"top":{let G=P?ce/2:ce*4,K=P||N?r+G:r-G,J=P?r-G:N?r+G:r-G,ne=i+ce+1,me=N||P?R.bottom-ce:R.top,le=N?P?R.bottom-ce:R.top:R.bottom-ce;se=Un(x,E,K,ne,J,ne,R.left,me,R.right,le);break}case"bottom":{let G=P?ce/2:ce*4,K=P||N?r+G:r-G,J=P?r-G:N?r+G:r-G,ne=i-ce,me=N||P?R.top+ce:R.bottom,le=N?P?R.top+ce:R.bottom:R.top+ce;se=Un(x,E,K,ne,J,ne,R.left,me,R.right,le);break}case"left":{let G=O?ce/2:ce*4,K=O||H?i+G:i-G,J=O?i-G:H?i+G:i-G,ne=r+ce+1,me=H||O?R.right-ce:R.left,le=H?O?R.right-ce:R.left:R.right-ce;se=Un(x,E,me,R.top,le,R.bottom,ne,K,ne,J);break}case"right":{let G=O?ce/2:ce*4,K=O||H?i+G:i-G,J=O?i-G:H?i+G:i-G,ne=r-ce,me=H||O?R.left+ce:R.right,le=H?O?R.left+ce:R.right:R.left+ce;se=Un(x,E,ne,K,ne,J,me,R.top,le,R.bottom);break}default:}se?p||o.start(40,L):L()}};return n.__options={...e,blockPointerEvents:t},n}var vi=(function(e){return e.open="data-open",e.closed="data-closed",e[e.startingStyle=Yt.startingStyle]="startingStyle",e[e.endingStyle=Yt.endingStyle]="endingStyle",e.anchorHidden="data-anchor-hidden",e.side="data-side",e.align="data-align",e})({}),qo=(function(e){return e.popupOpen="data-popup-open",e.pressed="data-pressed",e})({}),ng={[qo.popupOpen]:""},B_={[qo.popupOpen]:"",[qo.pressed]:""},rg={[vi.open]:""},ig={[vi.closed]:""},sg={[vi.anchorHidden]:""},pl={open(e){return e?ng:null}};var Ro={open(e){return e?rg:ig},anchorHidden(e){return e?sg:null}};function ml(e){return ao(19)?e:e?"true":void 0}var Ge=h(z(),1);var ag=e=>({name:"arrow",options:e,async fn(t){let{x:o,y:n,placement:r,rects:i,platform:s,elements:a,middlewareData:d}=t,{element:c,padding:l=0,offsetParent:f="real"}=at(e,t)||{};if(c==null)return{};let p=In(l),m={x:o,y:n},u=Go(r),g=Uo(u),v=await s.getDimensions(c),_=u==="y",w=_?"top":"left",y=_?"bottom":"right",b=_?"clientHeight":"clientWidth",S=i.reference[g]+i.reference[u]-m[u]-i.floating[g],x=m[u]-i.reference[u],E=f==="real"?await s.getOffsetParent?.(c):a.floating,T=a.floating[b]||i.floating[g];(!T||!await s.isElement?.(E))&&(T=a.floating[b]||i.floating[g]);let k=S/2-x/2,C=T/2-v[g]/2-1,j=Math.min(p[w],C),A=Math.min(p[y],C),L=j,I=T-v[g]-A,R=T/2-v[g]/2+k,N=Yo(L,R,I),H=!d.arrow&&ct(r)!=null&&R!==N&&i.reference[g]/2-(R({...ag(e),options:[e,t]});var cg=ni().fn,bl={name:"hide",async fn(e){let{width:t,height:o,x:n,y:r}=e.rects.reference,i=t===0&&o===0&&n===0&&r===0;return{data:{referenceHidden:(await cg(e)).data?.referenceHidden||i}}}};var Zo={sideX:"left",sideY:"top"},hl={name:"adaptiveOrigin",async fn(e){let{x:t,y:o,rects:{floating:n},elements:{floating:r},platform:i,strategy:s,placement:a}=e,d=ge(r),c=d.getComputedStyle(r);if(!(c.transitionDuration!=="0s"&&c.transitionDuration!==""))return{x:t,y:o,data:Zo};let f=await i.getOffsetParent?.(r),p={width:0,height:0};if(s==="fixed"&&d?.visualViewport)p={width:d.visualViewport.width,height:d.visualViewport.height};else if(f===d){let w=xe(r);p={width:w.documentElement.clientWidth,height:w.documentElement.clientHeight}}else await i.isElement?.(f)&&(p=await i.getDimensions(f));let m=Ee(a),u=t,g=o;m==="left"&&(u=p.width-(t+n.width)),m==="top"&&(g=p.height-(o+n.height));let v=m==="left"?"right":Zo.sideX,_=m==="top"?"bottom":Zo.sideY;return{x:u,y:g,data:{sideX:v,sideY:_}}}};function _l(e,t,o){let n=e==="inline-start"||e==="inline-end";return{top:"top",right:n?o?"inline-start":"inline-end":"right",bottom:"bottom",left:n?o?"inline-end":"inline-start":"left"}[t]}function wl(e,t,o){let{rects:n,placement:r}=e;return{side:_l(t,Ee(r),o),align:ct(r)||"center",anchor:{width:n.reference.width,height:n.reference.height},positioner:{width:n.floating.width,height:n.floating.height}}}function yl(e){let{anchor:t,positionMethod:o="absolute",side:n="bottom",sideOffset:r=0,align:i="center",alignOffset:s=0,collisionBoundary:a,collisionPadding:d=5,sticky:c=!1,arrowPadding:l=5,disableAnchorTracking:f=!1,inline:p,keepMounted:m=!1,floatingRootContext:u,mounted:g,collisionAvoidance:v,shiftCrossAxis:_=!1,nodeId:w,adaptiveOrigin:y,lazyFlip:b=!1,externalTree:S}=e,[x,E]=Ge.useState(null);!g&&x!==null&&E(null);let T=v.side||"flip",k=v.align||"flip",C=v.fallbackAxisSide||"end",j=typeof t=="function"?t:void 0,A=Y(j),L=j?A:t,I=ze(t),R=ze(g),H=so()==="rtl",P=x||{top:"top",right:"right",bottom:"bottom",left:"left","inline-end":H?"left":"right","inline-start":H?"right":"left"}[n],O=i==="center"?P:`${P}-${i}`,M=d,Z=1,W=n==="bottom"?Z:0,oe=n==="top"?Z:0,te=n==="right"?Z:0,se=n==="left"?Z:0;typeof M=="number"?M={top:M+W,right:M+se,bottom:M+oe,left:M+te}:M&&(M={top:(M.top||0)+W,right:(M.right||0)+se,bottom:(M.bottom||0)+oe,left:(M.left||0)+te});let G={boundary:a==="clipping-ancestors"?"clippingAncestors":a,padding:M},K=Ge.useRef(null),J=ze(r),ne=ze(s),me=typeof r!="function"?r:0,le=typeof s!="function"?s:0,X=[];p&&X.push(p),X.push(Jr(ae=>{let Ie=wl(ae,n,H),ut=typeof J.current=="function"?J.current(Ie):J.current,qe=typeof ne.current=="function"?ne.current(Ie):ne.current;return{mainAxis:ut,crossAxis:qe,alignmentAxis:qe}},[me,le,H,n]));let pe=k==="none"&&T!=="shift",ue=!pe&&(c||_||T==="shift"),vt=T==="none"?null:ti({...G,padding:{top:M.top+Z,right:M.right+Z,bottom:M.bottom+Z,left:M.left+Z},mainAxis:!_&&T==="flip",crossAxis:k==="flip"?"alignment":!1,fallbackAxisSideDirection:C}),Te=pe?null:$r(ae=>{let Ie=xe(ae.elements.floating).documentElement;return{...G,rootBoundary:_?{x:0,y:0,width:Ie.clientWidth,height:Ie.clientHeight}:void 0,mainAxis:k!=="none",crossAxis:ue,limiter:c||_?void 0:ei(ut=>{if(!K.current)return{};let{width:qe,height:yt}=K.current.getBoundingClientRect(),et=De(Ee(ut.placement)),Vt=et==="y"?qe:yt,io=et==="y"?M.left+M.right:M.top+M.bottom;return{offset:Vt/2+io/2}})}},[G,c,_,M,k]);T==="shift"||k==="shift"||i==="center"?X.push(Te,vt):X.push(vt,Te),X.push(oi({...G,apply({elements:{floating:ae},availableWidth:Ie,availableHeight:ut,rects:qe}){if(!R.current)return;let yt=ae.style;yt.setProperty("--available-width",`${Ie}px`),yt.setProperty("--available-height",`${ut}px`);let et=ge(ae).devicePixelRatio||1,{x:Vt,y:io,width:bn,height:br}=qe.reference,hr=(Math.round((Vt+bn)*et)-Math.round(Vt*et))/et,wr=(Math.round((io+br)*et)-Math.round(io*et))/et;yt.setProperty("--anchor-width",`${hr}px`),yt.setProperty("--anchor-height",`${wr}px`)}}),gl(ae=>({element:K.current||xe(ae.elements.floating).createElement("div"),padding:l,offsetParent:"floating"}),[l]),{name:"transformOrigin",fn(ae){let{elements:Ie,middlewareData:ut,placement:qe,rects:yt,y:et}=ae,Vt=Ee(qe),io=De(Vt),bn=K.current,br=ut.arrow?.x||0,hr=ut.arrow?.y||0,wr=bn?.clientWidth||0,ff=bn?.clientHeight||0,vr=br+wr/2,Us=hr+ff/2,pf=Math.abs(ut.shift?.y||0),mf=yt.reference.height/2,Io=typeof r=="function"?r(wl(ae,n,H)):r,gf=pf>Io,bf={top:`${vr}px calc(100% + ${Io}px)`,bottom:`${vr}px ${-Io}px`,left:`calc(100% + ${Io}px) ${Us}px`,right:`${-Io}px ${Us}px`}[Vt],hf=`${vr}px ${yt.reference.y+mf-et}px`;return Ie.floating.style.setProperty("--transform-origin",ue&&io==="y"&&gf?hf:bf),{}}},bl,y),D(()=>{!g&&u&&u.update({referenceElement:null,floatingElement:null,domReferenceElement:null,positionReference:null})},[g,u]);let Ve=Ge.useMemo(()=>({elementResize:!f&&typeof ResizeObserver<"u",layoutShift:!f&&typeof IntersectionObserver<"u"}),[f]),{refs:Ke,elements:He,x:no,y:dn,middlewareData:_e,update:ro,placement:B,context:F,isPositioned:he,floatingStyles:ke}=ui({rootContext:u,open:m?g:void 0,placement:O,middleware:X,strategy:o,whileElementsMounted:m?void 0:(...ae)=>Xo(...ae,Ve),nodeId:w,externalTree:S}),{sideX:kt,sideY:Lo}=_e.adaptiveOrigin||Zo,_t=he?o:"fixed",We=Ge.useMemo(()=>{let ae=y?{position:_t,[kt]:no,[Lo]:dn}:{position:_t,...ke};return he||(ae.opacity=0),ae},[y,_t,kt,no,Lo,dn,ke,he]),Pt=Ge.useRef(null);D(()=>{if(!g)return;let ae=I.current,Ie=typeof ae=="function"?ae():ae,qe=(vl(Ie)?Ie.current:Ie)||null||null;qe!==Pt.current&&(Ke.setPositionReference(qe),Pt.current=qe)},[g,Ke,L,I]),Ge.useEffect(()=>{if(!g)return;let ae=I.current;typeof ae!="function"&&vl(ae)&&ae.current!==Pt.current&&(Ke.setPositionReference(ae.current),Pt.current=ae.current)},[g,Ke,L,I]),Ge.useEffect(()=>{if(m&&g&&He.reference&&He.floating)return Xo(He.reference,He.floating,ro,Ve)},[m,g,He,ro,Ve]);let Ct=Ee(B),un=_l(n,Ct,H),fn=ct(B)||"center",pn=!!_e.hide?.referenceHidden;D(()=>{b&&g&&he&&E(Ct)},[b,g,he,Ct]);let mn=Ge.useMemo(()=>({position:"absolute",top:_e.arrow?.y,left:_e.arrow?.x}),[_e.arrow]),gn=_e.arrow?.centerOffset!==0;return Ge.useMemo(()=>({positionerStyles:We,arrowStyles:mn,arrowRef:K,arrowUncentered:gn,side:un,align:fn,physicalSide:Ct,anchorHidden:pn,refs:Ke,context:F,isPositioned:he,update:ro}),[We,mn,K,gn,un,fn,Ct,pn,Ke,F,he,ro])}function vl(e){return e!=null&&"current"in e}function Xn(e){return e==="starting"?Za:be}function xl(e,t,{styles:o,transitionStatus:n,props:r,refs:i,hidden:s,inert:a=!1}){let d={...o};return a&&(d.pointerEvents="none"),Ce("div",e,{state:t,ref:i,props:[{role:"presentation",hidden:s,style:d},Xn(n),r],stateAttributesMapping:Ro})}var Rl=h(z(),1);var _i=Rl.forwardRef(function(t,o){let{render:n,className:r,disabled:i=!1,focusableWhenDisabled:s=!1,nativeButton:a=!0,style:d,...c}=t,{getButtonProps:l,buttonRef:f}=Ea({disabled:i,focusableWhenDisabled:s,native:a});return Ce("button",t,{state:{disabled:i},ref:[o,f],props:[c,l]})});var Le=h(z(),1),Cl=h(Mt(),1);var Sl=h(z(),1);function El(e){let[t,o]=Sl.useState({current:e,previous:null});return e!==t.current&&o({current:e,previous:t.current}),t.previous}var So=h(z(),1);function yi(e){let t=Ae(e),o=parseFloat(t.width)||0,n=parseFloat(t.height)||0,r=we(e),i=r?e.offsetWidth:o,s=r?e.offsetHeight:n;return(zt(o)!==i||zt(n)!==s)&&(o=i,n=s),{width:o,height:n}}function kl(e){let{popupElement:t,positionerElement:o,content:n,mounted:r,onMeasureLayout:i,onMeasureLayoutComplete:s,side:a,direction:d}=e,c=mo(t,!0,!1),l=lo(),f=So.useRef(null),p=So.useRef(!0),m=So.useRef(Nt),u=Y(i),g=Y(s),v=So.useMemo(()=>{let _=a==="top",w=a==="left";return d==="rtl"?(_=_||a==="inline-end",w=w||a==="inline-end"):(_=_||a==="inline-start",w=w||a==="inline-start"),_?{position:"absolute",[a==="top"?"bottom":"top"]:"0",[w?"right":"left"]:"0"}:be},[a,d]);D(()=>{if(!r){m.current=Nt,p.current=!0,f.current=null;return}if(!t||!o)return;m.current=Tl(t,v),xi(t,"auto");let _=qn(t,"position","static"),w=qn(t,"transform","none"),y=qn(t,"scale","1"),b=Tl(o,{"--available-width":"max-content","--available-height":"max-content"});function S(){_(),w(),b()}function x(){S(),y()}if(u?.(),p.current||f.current===null){Kn(o,"max-content");let C=yi(t);return f.current=C,Kn(o,C),x(),g?.(null,C),p.current=!1,()=>{m.current(),m.current=Nt}}Kn(o,"max-content");let E=f.current,T=yi(t);f.current=T,xi(t,E),x(),g?.(E,T),Kn(o,T);let k=new AbortController;return l.request(()=>{xi(t,T),c(()=>{t.style.setProperty("--popup-width","auto"),t.style.setProperty("--popup-height","auto")},k.signal)}),()=>{k.abort(),l.cancel(),m.current(),m.current=Nt}},[n,t,o,c,l,r,u,g,v])}function qn(e,t,o){let n=e.style.getPropertyValue(t);return e.style.setProperty(t,o),()=>{e.style.setProperty(t,n)}}function Tl(e,t){let o=[];for(let[n,r]of Object.entries(t))o.push(qn(e,n,r));return o.length?()=>{o.forEach(n=>n())}:Nt}function xi(e,t){let o=t==="auto"?"auto":`${t.width}px`,n=t==="auto"?"auto":`${t.height}px`;e.style.setProperty("--popup-width",o),e.style.setProperty("--popup-height",n)}function Kn(e,t){let o=t==="max-content"?"max-content":`${t.width}px`,n=t==="max-content"?"max-content":`${t.height}px`;e.style.setProperty("--positioner-width",o),e.style.setProperty("--positioner-height",n)}var Eo=h(Q(),1);function Al(e){let{store:t,side:o,cssVars:n,children:r}=e,i=so(),s=t.useState("activeTriggerElement"),a=t.useState("activeTriggerId"),d=t.useState("open"),c=t.useState("payload"),l=t.useState("mounted"),f=t.useState("popupElement"),p=t.useState("positionerElement"),m=El(d?s:null),u=ug(a,c),g=Le.useRef(null),[v,_]=Le.useState(null),[w,y]=Le.useState(null),b=Le.useRef(null),S=Le.useRef(null),x=mo(b,!0,!1),E=lo(),[T,k]=Le.useState(null),[C,j]=Le.useState(!1);D(()=>(t.set("hasViewport",!0),()=>{t.set("hasViewport",!1)}),[t]);let A=Y(()=>{b.current?.style.setProperty("animation","none"),b.current?.style.setProperty("transition","none"),S.current?.style.setProperty("display","none")}),L=Y(P=>{b.current?.style.removeProperty("animation"),b.current?.style.removeProperty("transition"),S.current?.style.removeProperty("display"),P&&k(P)}),I=Le.useRef(null);D(()=>{(!d||!l)&&(I.current=null)},[d,l]),D(()=>{if(s&&m&&s!==m&&I.current!==s&&g.current){_(g.current),j(!0);let P=dg(m,s);y(P),E.request(()=>{Cl.flushSync(()=>{j(!1)}),x(()=>{_(null),k(null),g.current=null})}),I.current=s}},[s,m,v,x,E]),D(()=>{let P=b.current;if(!P)return;let O=xe(P).createElement("div");for(let M of Array.from(P.childNodes))O.appendChild(M.cloneNode(!0));g.current=O});let R=v!=null,N;R?N=(0,Eo.jsxs)(Le.Fragment,{children:[(0,Eo.jsx)("div",{"data-previous":!0,inert:ml(!0),ref:S,style:{...T?{[n.popupWidth]:`${T.width}px`,[n.popupHeight]:`${T.height}px`}:null,position:"absolute"},"data-ending-style":C?void 0:""},"previous"),(0,Eo.jsx)("div",{"data-current":!0,ref:b,"data-starting-style":C?"":void 0,children:r},u)]}):N=(0,Eo.jsx)("div",{"data-current":!0,ref:b,children:r},u),D(()=>{let P=S.current;!P||!v||P.replaceChildren(...Array.from(v.childNodes))},[v]),kl({popupElement:f,positionerElement:p,mounted:l,content:c,onMeasureLayout:A,onMeasureLayoutComplete:L,side:o,direction:i});let H={activationDirection:lg(w),transitioning:R};return{children:N,state:H}}function lg(e){if(e)return`${Pl(e.horizontal,5,"right","left")} ${Pl(e.vertical,5,"down","up")}`}function Pl(e,t,o,n){return e>t?o:e<-t?n:""}function dg(e,t){let o=e.getBoundingClientRect(),n=t.getBoundingClientRect(),r={x:o.left+o.width/2,y:o.top+o.height/2},i={x:n.left+n.width/2,y:n.top+n.height/2};return{horizontal:i.x-r.x,vertical:i.y-r.y}}function ug(e,t){let[o,n]=Le.useState(0),r=Le.useRef(e),i=Le.useRef(t),s=Le.useRef(!1);return D(()=>{let a=r.current,d=i.current,c=e!==a,l=t!==d;c?(n(f=>f+1),s.current=!l):s.current&&l&&(n(f=>f+1),s.current=!1),r.current=e,i.current=t},[e,t]),`${e??"current"}-${o}`}var Zn=h(z(),1),Ol=h(Mt(),1);var Nl=h(Q(),1),Ll=Zn.forwardRef(function(t,o){let{children:n,container:r,className:i,render:s,style:a,...d}=t,{portalNode:c,portalSubtree:l}=Ur({container:r,ref:o,componentProps:t,elementProps:d});return!l&&!c?null:(0,Nl.jsxs)(Zn.Fragment,{children:[l,c&&Ol.createPortal(n,c)]})});var Qe={};At(Qe,{Arrow:()=>ql,Handle:()=>Qo,Popup:()=>Xl,Portal:()=>Wl,Positioner:()=>Ul,Provider:()=>Zl,Root:()=>Ml,Trigger:()=>jl,Viewport:()=>$l,createHandle:()=>ed});var gt=h(z(),1);var Qn=h(z(),1),Ri=Qn.createContext(void 0);function Ze(e){let t=Qn.useContext(Ri);if(t===void 0&&!e)throw new Error(Pe(72));return t}var Il=h(z(),1);var fg={...ll,disabled:q(e=>e.disabled),instantType:q(e=>e.instantType),isInstantPhase:q(e=>e.isInstantPhase),trackCursorAxis:q(e=>e.trackCursorAxis),disableHoverablePopup:q(e=>e.disableHoverablePopup),lastOpenChangeReason:q(e=>e.openChangeReason),closeOnClick:q(e=>e.closeOnClick),closeDelay:q(e=>e.closeDelay),hasViewport:q(e=>e.hasViewport)},To=class e extends vo{constructor(t,o,n=!1){let r=new jt,i={...pg(),...t};i.floatingRootContext=al(r,o,n),super(i,{popupRef:Il.createRef(),onOpenChange:void 0,onOpenChangeComplete:void 0,triggerElements:r},fg)}setOpen=(t,o)=>{Jc(this,t,o,{extraState:{openChangeReason:o.reason}})};cancelPendingOpen(t){this.state.floatingRootContext.dispatchOpenChange(!1,ee(U.triggerPress,t))}static useStore(t,o){return Qc(t,(r,i)=>new e(o,r,i)).store}};function pg(){return{...sl(),disabled:!1,instantType:void 0,isInstantPhase:!1,trackCursorAxis:"none",disableHoverablePopup:!1,openChangeReason:null,closeOnClick:!0,closeDelay:0,hasViewport:!1}}var Jn=h(Q(),1),Ml=ci(function(t){let{disabled:o=!1,defaultOpen:n=!1,open:r,disableHoverablePopup:i=!1,trackCursorAxis:s="none",actionsRef:a,onOpenChange:d,onOpenChangeComplete:c,handle:l,triggerId:f,defaultTriggerId:p=null,children:m}=t,u=To.useStore(l?.store,{open:n,openProp:r,activeTriggerId:p,triggerIdProp:f});$c(u,r,n,p),u.useControlledProp("openProp",r),u.useControlledProp("triggerIdProp",f),u.useContextCallback("onOpenChange",d),u.useContextCallback("onOpenChangeComplete",c);let g=u.useState("open"),v=!o&&g,_=u.useState("activeTriggerId"),w=u.useState("mounted"),y=u.useState("payload");u.useSyncedValues({trackCursorAxis:s,disableHoverablePopup:i}),u.useSyncedValue("disabled",o),tl(u,{closeOnActiveTriggerUnmount:!0});let{forceUnmount:b,transitionStatus:S}=ol(v,u),x=u.useState("isInstantPhase"),E=u.useState("instantType"),T=u.useState("lastOpenChangeReason"),k=gt.useRef(null);D(()=>{g&&o&&u.setOpen(!1,ee(U.disabled))},[g,o,u]),D(()=>{S==="ending"&&T===U.none||S!=="ending"&&x?(E!=="delay"&&(k.current=E),u.set("instantType","delay")):k.current!==null&&(u.set("instantType",k.current),k.current=null)},[S,x,T,E,u]),D(()=>{v&&_==null&&u.set("payload",void 0)},[u,_,v]);let C=gt.useCallback(()=>{u.setOpen(!1,ee(U.imperativeAction))},[u]);gt.useImperativeHandle(a,()=>({unmount:b,close:C}),[b,C]);let j=v||w||!o&&s!=="none";return(0,Jn.jsxs)(Ri.Provider,{value:u,children:[j&&(0,Jn.jsx)(mg,{store:u,disabled:o,trackCursorAxis:s}),typeof m=="function"?m({payload:y}):m]})});function mg({store:e,disabled:t,trackCursorAxis:o}){let n=e.useState("floatingRootContext"),r=Xr(n,{enabled:!t,referencePress:()=>e.select("closeOnClick")}),i=Gr(n,{enabled:!t&&o!=="none",axis:o==="none"?void 0:o}),s=gt.useMemo(()=>ye(i.reference,r.reference),[i.reference,r.reference]),a=gt.useMemo(()=>ye(i.trigger,r.trigger),[i.trigger,r.trigger]),d=gt.useMemo(()=>ye(Zc,i.floating,r.floating),[i.floating,r.floating]);return nl(e,{activeTriggerProps:s,inactiveTriggerProps:a,popupProps:d}),null}var er=h(z(),1);var $n=h(z(),1),Si=$n.createContext(void 0);function Bl(){return $n.useContext(Si)}var Hl=(function(e){return e[e.popupOpen=qo.popupOpen]="popupOpen",e.triggerDisabled="data-trigger-disabled",e})({});var Dl="data-base-ui-tooltip-trigger";function zl(e){if("composedPath"in e){let o=e.composedPath();for(let n=0;ng.select("transitionStatus")==="ending",shouldOpen(){return!O.current}}),G=pi(y,{enabled:!R}).reference,K=X=>{let pe=O.current,ue=zl(X),vt=te(ue),Te=b.current,Ve=Te&&ue&&ie(Te,ue);if(vt&&g.select("open")&&g.select("lastOpenChangeReason")===U.triggerHover){g.setOpen(!1,ee(U.triggerHover,X));return}if(pe&&!vt&&Ve&&!N.current&&!g.select("open")&&Te&&Rt(Z.current)){let Ke=()=>{!O.current&&!N.current&&!g.select("open")&&g.setOpen(!0,ee(U.triggerHover,X,Te))},He=W();He===0?(M.clear(),Ke()):M.start(He,Ke)}},J=g.useState("triggerProps",T);return Ce("button",t,{state:{open:w},ref:[o,E,b],props:[se,G,T||H!=="none"?J:void 0,{onMouseOver(X){K(X.nativeEvent)},onFocus(X){oe(zl(X.nativeEvent))&&X.preventBaseUIHandler()},onMouseLeave(){O.current=!1,M.clear(),Z.current=void 0},onPointerEnter(X){Z.current=X.pointerType},onPointerDown(X){Z.current=X.pointerType,g.set("closeOnClick",l),l&&!g.select("open")&&g.cancelPendingOpen(X.nativeEvent)},onClick(X){l&&!g.select("open")&&g.cancelPendingOpen(X.nativeEvent)},id:v,[Hl.triggerDisabled]:R?"":void 0,[Dl]:R?void 0:""},m],stateAttributesMapping:pl})});var Vl=h(z(),1);var tr=h(z(),1),Ei=tr.createContext(void 0);function Fl(){let e=tr.useContext(Ei);if(e===void 0)throw new Error(Pe(70));return e}var Ti=h(Q(),1),Wl=Vl.forwardRef(function(t,o){let{keepMounted:n=!1,...r}=t;return Ze().useState("mounted")||n?(0,Ti.jsx)(Ei.Provider,{value:n,children:(0,Ti.jsx)(Ll,{ref:o,...r})}):null});var nr=h(z(),1);var or=h(z(),1),ki=or.createContext(void 0);function ko(){let e=or.useContext(ki);if(e===void 0)throw new Error(Pe(71));return e}var Yl=h(Q(),1),Ul=nr.forwardRef(function(t,o){let{render:n,className:r,anchor:i,positionMethod:s="absolute",side:a="top",align:d="center",sideOffset:c=0,alignOffset:l=0,collisionBoundary:f="clipping-ancestors",collisionPadding:p=5,arrowPadding:m=5,sticky:u=!1,disableAnchorTracking:g=!1,collisionAvoidance:v=Qa,style:_,...w}=t,y=Ze(),b=Fl(),S=y.useState("open"),x=y.useState("mounted"),E=y.useState("trackCursorAxis"),T=y.useState("disableHoverablePopup"),k=y.useState("floatingRootContext"),C=y.useState("instantType"),j=y.useState("transitionStatus"),A=y.useState("hasViewport"),L=yl({anchor:i,positionMethod:s,floatingRootContext:k,mounted:x,side:a,sideOffset:c,align:d,alignOffset:l,collisionBoundary:f,collisionPadding:p,sticky:u,arrowPadding:m,disableAnchorTracking:g,keepMounted:b,collisionAvoidance:v,adaptiveOrigin:A?hl:void 0}),I=nr.useMemo(()=>({open:S,side:L.side,align:L.align,anchorHidden:L.anchorHidden,instant:E!=="none"?"tracking-cursor":C}),[S,L.side,L.align,L.anchorHidden,E,C]),R=xl(t,I,{styles:L.positionerStyles,transitionStatus:j,props:w,refs:[o,y.useStateSetter("positionerElement")],hidden:!x,inert:!S||E==="both"||T});return(0,Yl.jsx)(ki.Provider,{value:L,children:R})});var Gl=h(z(),1);var bg={...Ro,...wa},Xl=Gl.forwardRef(function(t,o){let{render:n,className:r,style:i,...s}=t,a=Ze(),{side:d,align:c}=ko(),l=a.useState("open"),f=a.useState("instantType"),p=a.useState("transitionStatus"),m=a.useState("popupProps"),u=a.useState("floatingRootContext"),g=a.useState("disabled"),v=a.useState("closeDelay");Pn({open:l,ref:a.context.popupRef,onComplete(){l&&a.context.onOpenChangeComplete?.(!0)}}),bi(u,{enabled:!g,closeDelay:v});let _=a.useStateSetter("popupElement");return Ce("div",t,{state:{open:l,side:d,align:c,instant:f,transitionStatus:p},ref:[o,a.context.popupRef,_],props:[m,Xn(p),s],stateAttributesMapping:bg})});var Kl=h(z(),1);var ql=Kl.forwardRef(function(t,o){let{render:n,className:r,style:i,...s}=t,a=Ze(),{arrowRef:d,side:c,align:l,arrowUncentered:f,arrowStyles:p}=ko(),m=a.useState("open"),u=a.useState("instantType");return Ce("div",t,{state:{open:m,side:c,align:l,uncentered:f,instant:u},ref:[o,d],props:[{style:p,"aria-hidden":!0},s],stateAttributesMapping:Ro})});var Pi=h(z(),1);var Ci=h(Q(),1),Zl=function(t){let{delay:o,closeDelay:n,timeout:r=400}=t,i=Pi.useMemo(()=>({delay:o,closeDelay:n}),[o,n]),s=Pi.useMemo(()=>({open:o,close:n}),[o,n]);return(0,Ci.jsx)(Si.Provider,{value:i,children:(0,Ci.jsx)(Wr,{delay:s,timeoutMs:r,children:t.children})})};var Jl=h(z(),1);var Ql=(function(e){return e.popupWidth="--popup-width",e.popupHeight="--popup-height",e})({});var hg={activationDirection:e=>e?{"data-activation-direction":e}:null},$l=Jl.forwardRef(function(t,o){let{render:n,className:r,style:i,children:s,...a}=t,d=Ze(),c=ko(),l=d.useState("instantType"),{children:f,state:p}=Al({store:d,side:c.side,cssVars:Ql,children:s}),m={activationDirection:p.activationDirection,transitioning:p.transitioning,instant:l};return Ce("div",t,{state:m,ref:o,props:[a,{children:f}],stateAttributesMapping:hg})});var Qo=class{constructor(){this.store=new To}open(t){let o=t?this.store.context.triggerElements.getById(t):void 0;if(t&&!o)throw new Error(Pe(81,t));this.store.setOpen(!0,ee(U.imperativeAction,void 0,o))}close(){this.store.setOpen(!1,ee(U.imperativeAction,void 0,void 0))}get isOpen(){return this.store.select("open")}};function ed(){return new Qo}function bt(e){return Ce(e.defaultTagName??"div",e,e)}var nd=h(de(),1),Ai="data-wp-hash";function Oi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&vg(document)),e.__wpStyleRuntime}function wg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ai}]`))if(o.getAttribute(Ai)===t)return!0;return!1}function rd(e,t,o){if(!e.head)return;let n=Oi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(wg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ai,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function vg(e){let t=Oi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)rd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function id(e,t){let o=Oi();o.styles.set(e,t);for(let n of o.documents.keys())rd(n,e,t)}typeof process>"u",id("a495f9d138",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._83ed8a8da5dd50ea__text{margin:0}._14437cfb77831647__heading-2xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-2xl,32px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-2xl,32px);--_gcd-p-line-height:var(--wpds-typography-line-height-2xl,40px);font-size:var(--wpds-typography-font-size-2xl,32px);line-height:var(--wpds-typography-line-height-2xl,40px)}._14437cfb77831647__heading-2xl,._3c78b7fa9b4072dd__heading-xl{font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-emphasis,600)}._3c78b7fa9b4072dd__heading-xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-p-line-height:var(--wpds-typography-line-height-md,24px);font-size:var(--wpds-typography-font-size-xl,20px);line-height:var(--wpds-typography-line-height-md,24px)}.aa58f227716bcde2__heading-lg{--_gcd-heading-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-lg,15px)}.aa58f227716bcde2__heading-lg,.fc4da56d8dfe52c4__heading-md{font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-emphasis,600);line-height:var(--wpds-typography-line-height-sm,20px)}.fc4da56d8dfe52c4__heading-md{--_gcd-heading-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-md,13px)}.a9b78c7c82e8dff7__heading-sm{--_gcd-heading-font-size:var(--wpds-typography-font-size-xs,11px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-xs,11px);--_gcd-p-line-height:var(--wpds-typography-line-height-xs,16px);font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-xs,11px);font-weight:var(--wpds-typography-font-weight-emphasis,600);line-height:var(--wpds-typography-line-height-xs,16px);text-transform:uppercase}._305ff559e52180d5__body-xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-p-line-height:var(--wpds-typography-line-height-xl,32px);font-size:var(--wpds-typography-font-size-xl,20px);line-height:var(--wpds-typography-line-height-xl,32px)}._305ff559e52180d5__body-xl,.ca1aa3fc2029e958__body-lg{font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-default,400)}.ca1aa3fc2029e958__body-lg{--_gcd-heading-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-p-line-height:var(--wpds-typography-line-height-md,24px);font-size:var(--wpds-typography-font-size-lg,15px);line-height:var(--wpds-typography-line-height-md,24px)}._131101940be12424__body-md{--_gcd-heading-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-md,13px);line-height:var(--wpds-typography-line-height-sm,20px)}._0e8d87a42c1f75fa__body-sm,._131101940be12424__body-md{font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-default,400)}._0e8d87a42c1f75fa__body-sm{--_gcd-heading-font-size:var(--wpds-typography-font-size-sm,12px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-sm,12px);--_gcd-p-line-height:var(--wpds-typography-line-height-xs,16px);font-size:var(--wpds-typography-font-size-sm,12px);line-height:var(--wpds-typography-line-height-xs,16px)}}}');var td={text:"_83ed8a8da5dd50ea__text","heading-2xl":"_14437cfb77831647__heading-2xl","heading-xl":"_3c78b7fa9b4072dd__heading-xl","heading-lg":"aa58f227716bcde2__heading-lg","heading-md":"fc4da56d8dfe52c4__heading-md","heading-sm":"a9b78c7c82e8dff7__heading-sm","body-xl":"_305ff559e52180d5__body-xl","body-lg":"ca1aa3fc2029e958__body-lg","body-md":"_131101940be12424__body-md","body-sm":"_0e8d87a42c1f75fa__body-sm"};typeof process>"u",id("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var od={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},Je=(0,nd.forwardRef)(function({variant:t="body-md",render:o,className:n,...r},i){return bt({render:o,defaultTagName:"span",ref:i,props:ye(r,{className:$(td.text,od.heading,od.p,td[t],n)})})});var ld=h(Q(),1),Ni="data-wp-hash";function Li(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&yg(document)),e.__wpStyleRuntime}function _g(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ni}]`))if(o.getAttribute(Ni)===t)return!0;return!1}function cd(e,t,o){if(!e.head)return;let n=Li(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(_g(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ni,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function yg(e){let t=Li();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)cd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function xg(e,t){let o=Li();o.styles.set(e,t);for(let n of o.documents.keys())cd(n,e,t)}typeof process>"u",xg("9db2873e7f","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._96e6251aad1a6136__badge{border-radius:var(--wpds-border-radius-lg,8px);padding-block:var(--wpds-dimension-padding-xs,4px);padding-inline:var(--wpds-dimension-padding-sm,8px)}._99f7158cb520f750__is-high-intent{background-color:var(--wpds-color-background-surface-error,#f6e6e3);color:var(--wpds-color-foreground-content-error,#470000)}.c20ebef2365bc8b7__is-medium-intent{background-color:var(--wpds-color-background-surface-warning,#fde6be);color:var(--wpds-color-foreground-content-warning,#2e1900)}._365e1626c6202e52__is-low-intent{background-color:var(--wpds-color-background-surface-caution,#fee995);color:var(--wpds-color-foreground-content-caution,#281d00)}._33f8198127ddf4ef__is-stable-intent{background-color:var(--wpds-color-background-surface-success,#c6f7cd);color:var(--wpds-color-foreground-content-success,#002900)}._04c1aca8fc449412__is-informational-intent{background-color:var(--wpds-color-background-surface-info,#deebfa);color:var(--wpds-color-foreground-content-info,#001b4f)}._90726e69d495ec19__is-draft-intent{background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);color:var(--wpds-color-foreground-content-neutral,#1e1e1e)}._898f4a544993bd39__is-none-intent{background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral,#dbdbdb);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);padding-block:calc(var(--wpds-dimension-padding-xs, 4px) - var(--wpds-border-width-xs, 1px));padding-inline:calc(var(--wpds-dimension-padding-sm, 8px) - var(--wpds-border-width-xs, 1px))}}}");var sd={badge:"_96e6251aad1a6136__badge","is-high-intent":"_99f7158cb520f750__is-high-intent","is-medium-intent":"c20ebef2365bc8b7__is-medium-intent","is-low-intent":"_365e1626c6202e52__is-low-intent","is-stable-intent":"_33f8198127ddf4ef__is-stable-intent","is-informational-intent":"_04c1aca8fc449412__is-informational-intent","is-draft-intent":"_90726e69d495ec19__is-draft-intent","is-none-intent":"_898f4a544993bd39__is-none-intent"},Ii=(0,ad.forwardRef)(function({intent:t="none",className:o,...n},r){return(0,ld.jsx)(Je,{ref:r,className:$(sd.badge,sd[`is-${t}-intent`],o),...n,variant:"body-sm"})});var rr=h(de(),1),dd=h(Ot(),1),fd=h(Q(),1);import{speak as Rg}from"@wordpress/a11y";var Mi="data-wp-hash";function Bi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Eg(document)),e.__wpStyleRuntime}function Sg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Mi}]`))if(o.getAttribute(Mi)===t)return!0;return!1}function ud(e,t,o){if(!e.head)return;let n=Bi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Sg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Mi,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Eg(e){let t=Bi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)ud(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function ir(e,t){let o=Bi();o.styles.set(e,t);for(let n of o.documents.keys())ud(n,e,t)}typeof process>"u",ir("b74f1ac304",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._97b0fc33c028be1a__button,.abbb272e2ce49bd6__is-unstyled{appearance:none;padding:0}._97b0fc33c028be1a__button{--wp-ui-button-font-weight:var(--wpds-typography-font-weight-emphasis,600);--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-strong,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-strong-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 93%,#000));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand-strong,#fff);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-strong-active,#fff);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-strong-disabled,#8d8d8d);--wp-ui-button-padding-block:var(--wpds-dimension-padding-xs,4px);--wp-ui-button-padding-inline:var(--wpds-dimension-padding-md,12px);--wp-ui-button-height:var(--wpds-dimension-size-lg,40px);--wp-ui-button-aspect-ratio:auto;--wp-ui-button-font-size:var(--wpds-typography-font-size-md,13px);--wp-ui-button-min-width:calc(4ch + var(--wp-ui-button-padding-inline)*2);--wp-ui-button-icon-margin:calc((var(--wpds-dimension-size-2xs, 16px) - var(--wpds-dimension-size-sm, 24px))/2);--wp-ui-button-border-color:var(--wp-ui-button-background-color);--wp-ui-button-border-color-active:var(--wp-ui-button-background-color-active);--wp-ui-button-border-color-disabled:var(--wp-ui-button-background-color-disabled);--_gcd-button-font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);--_gcd-button-font-size:var(--wp-ui-button-font-size);--_gcd-button-font-weight:var(--wp-ui-button-font-weight);align-items:center;aspect-ratio:var(--wp-ui-button-aspect-ratio);background-clip:border-box;background-color:var(--wp-ui-button-background-color);border-color:var(--wp-ui-button-border-color);border-radius:var(--wpds-border-radius-sm,2px);border-style:solid;border-width:1px;color:var(--wp-ui-button-foreground-color);display:inline-flex;font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wp-ui-button-font-size);font-weight:var(--wp-ui-button-font-weight);gap:var(--wpds-dimension-gap-sm,8px);justify-content:center;line-height:var(--wpds-typography-line-height-sm,20px);max-width:100%;min-height:var(--wp-ui-button-height);min-width:var(--wp-ui-button-min-width);overflow-wrap:anywhere;padding-block:var(--wp-ui-button-padding-block);padding-inline:var(--wp-ui-button-padding-inline);position:relative;text-align:center;text-decoration:none;&:not([data-disabled]){cursor:var(--wpds-cursor-control,pointer)}@media not (prefers-reduced-motion){transition:color .1s ease-out;*{transition:opacity .1s ease-out}}&[href]{cursor:pointer}[href]{color:inherit;text-decoration:inherit}&:not([data-disabled]):is(:hover,:active,:focus){background-color:var(--wp-ui-button-background-color-active);border-color:var(--wp-ui-button-border-color-active);color:var(--wp-ui-button-foreground-color-active)}&[data-disabled]:not(._914b42f315c0e580__is-loading){background-color:var(--wp-ui-button-background-color-disabled);border-color:var(--wp-ui-button-border-color-disabled);color:var(--wp-ui-button-foreground-color-disabled);@media (forced-colors:active){border-bottom-color:GrayText;border-left-color:GrayText;border-right-color:GrayText;border-top-color:GrayText;color:GrayText}}&:before{aspect-ratio:1;border:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid;border-block-end-color:transparent;border-block-start-color:var(--wp-ui-button-foreground-color);border-inline-end-color:var(--wp-ui-button-foreground-color);border-inline-start-color:transparent;border-radius:50%;box-sizing:border-box;content:"";display:block;height:var(--wp-ui-button-font-size);inset-inline-start:50%;opacity:0;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);@media not (prefers-reduced-motion){transition:opacity .1s ease-out}@media (forced-colors:active){border-block-end-style:none;border-bottom-color:ButtonText;border-inline-start-style:none;border-left-color:ButtonText;border-right-color:ButtonText;border-top-color:ButtonText}}}._908205475f9f2a92__is-small{--wp-ui-button-padding-block:0px;--wp-ui-button-padding-inline:var(--wpds-dimension-padding-sm,8px);--wp-ui-button-height:var(--wpds-dimension-size-sm,24px)}._9f6fc6553aeb36fe__icon{margin:var(--wp-ui-button-icon-margin)}.dd460c965226cc77__is-brand{&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 85%,#000));--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-brand-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000)}}.e722a8f96726aa99__is-neutral{&.ad0619a3217c6a5b__is-minimal[aria-pressed=true],&.b50b3358c5fb4d0b__is-solid{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-strong,#2d2d2d);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-strong-active,#1e1e1e);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral-strong,#f0f0f0);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-strong-active,#f0f0f0);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-strong-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d);--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-neutral-active,#6e6e6e);--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-neutral-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000)}}.abbb272e2ce49bd6__is-unstyled{background:none;border:none;min-width:unset}.cf59cf1b69629838__is-compact{--wp-ui-button-height:var(--wpds-dimension-size-md,32px)}._914b42f315c0e580__is-loading:not(.abbb272e2ce49bd6__is-unstyled){color:transparent;&:not([data-disabled]):is(:hover,:active,:focus){color:transparent}@media (forced-colors:active){color:ButtonFace}*{opacity:0}&:before{opacity:1;transition-delay:.05s;@media not (prefers-reduced-motion){animation:_5a1d53da6f830c8d__loading-animation 1s linear infinite}}}}@keyframes _5a1d53da6f830c8d__loading-animation{0%{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(1turn)}}}');var Jo={button:"_97b0fc33c028be1a__button","is-unstyled":"abbb272e2ce49bd6__is-unstyled","is-loading":"_914b42f315c0e580__is-loading","is-small":"_908205475f9f2a92__is-small",icon:"_9f6fc6553aeb36fe__icon","is-brand":"dd460c965226cc77__is-brand","is-outline":"_62d5a778b7b258ee__is-outline","is-minimal":"ad0619a3217c6a5b__is-minimal","is-neutral":"e722a8f96726aa99__is-neutral","is-solid":"b50b3358c5fb4d0b__is-solid","is-compact":"cf59cf1b69629838__is-compact","loading-animation":"_5a1d53da6f830c8d__loading-animation"};typeof process>"u",ir("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var Tg={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",ir("5f8e7aa0bc","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active),:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}}}");var kg={"outset-ring--focus":"_08e8a2e44959f892__outset-ring--focus","outset-ring--focus-except-active":"e25b2bdd7aa21721__outset-ring--focus-except-active","outset-ring--focus-visible":"d0541bc9dd9dc7b6__outset-ring--focus-visible","outset-ring--focus-within":"cd83dfc2126a0846__outset-ring--focus-within","outset-ring--focus-within-except-active":"_970d04df7376df67__outset-ring--focus-within-except-active","outset-ring--focus-within-visible":"c5cb3ee4bddaa8e4__outset-ring--focus-within-visible","outset-ring--focus-parent-visible":"ecadb9e080e2dfa5__outset-ring--focus-parent-visible"};typeof process>"u",ir("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var Pg={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},pd=(0,rr.forwardRef)(function({tone:t="brand",variant:o="solid",size:n="default",className:r,focusableWhenDisabled:i=!0,disabled:s,loading:a,loadingAnnouncement:d=(0,dd.__)("Loading"),children:c,...l},f){let p=$(Pg.button,Tg["box-sizing"],kg["outset-ring--focus-except-active"],o!=="unstyled"&&Jo.button,Jo[`is-${t}`],Jo[`is-${o}`],Jo[`is-${n}`],a&&Jo["is-loading"],r);return(0,rr.useEffect)(()=>{a&&d&&Rg(d)},[a,d]),(0,fd.jsx)(_i,{ref:f,className:p,focusableWhenDisabled:i,disabled:s??a,...l,children:c})});var wd=h(de(),1);var gd=h(de(),1),bd=h($t(),1),hd=h(Q(),1),eo=(0,gd.forwardRef)(function({icon:t,size:o=24,...n},r){return(0,hd.jsx)(bd.SVG,{ref:r,...t.props,...n,width:o,height:o})});var _d=h(Q(),1),Hi="data-wp-hash";function zi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ag(document)),e.__wpStyleRuntime}function Cg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Hi}]`))if(o.getAttribute(Hi)===t)return!0;return!1}function vd(e,t,o){if(!e.head)return;let n=zi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Cg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Hi,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ag(e){let t=zi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)vd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Og(e,t){let o=zi();o.styles.set(e,t);for(let n of o.documents.keys())vd(n,e,t)}typeof process>"u",Og("b74f1ac304",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._97b0fc33c028be1a__button,.abbb272e2ce49bd6__is-unstyled{appearance:none;padding:0}._97b0fc33c028be1a__button{--wp-ui-button-font-weight:var(--wpds-typography-font-weight-emphasis,600);--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-strong,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-strong-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 93%,#000));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand-strong,#fff);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-strong-active,#fff);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-strong-disabled,#8d8d8d);--wp-ui-button-padding-block:var(--wpds-dimension-padding-xs,4px);--wp-ui-button-padding-inline:var(--wpds-dimension-padding-md,12px);--wp-ui-button-height:var(--wpds-dimension-size-lg,40px);--wp-ui-button-aspect-ratio:auto;--wp-ui-button-font-size:var(--wpds-typography-font-size-md,13px);--wp-ui-button-min-width:calc(4ch + var(--wp-ui-button-padding-inline)*2);--wp-ui-button-icon-margin:calc((var(--wpds-dimension-size-2xs, 16px) - var(--wpds-dimension-size-sm, 24px))/2);--wp-ui-button-border-color:var(--wp-ui-button-background-color);--wp-ui-button-border-color-active:var(--wp-ui-button-background-color-active);--wp-ui-button-border-color-disabled:var(--wp-ui-button-background-color-disabled);--_gcd-button-font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);--_gcd-button-font-size:var(--wp-ui-button-font-size);--_gcd-button-font-weight:var(--wp-ui-button-font-weight);align-items:center;aspect-ratio:var(--wp-ui-button-aspect-ratio);background-clip:border-box;background-color:var(--wp-ui-button-background-color);border-color:var(--wp-ui-button-border-color);border-radius:var(--wpds-border-radius-sm,2px);border-style:solid;border-width:1px;color:var(--wp-ui-button-foreground-color);display:inline-flex;font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wp-ui-button-font-size);font-weight:var(--wp-ui-button-font-weight);gap:var(--wpds-dimension-gap-sm,8px);justify-content:center;line-height:var(--wpds-typography-line-height-sm,20px);max-width:100%;min-height:var(--wp-ui-button-height);min-width:var(--wp-ui-button-min-width);overflow-wrap:anywhere;padding-block:var(--wp-ui-button-padding-block);padding-inline:var(--wp-ui-button-padding-inline);position:relative;text-align:center;text-decoration:none;&:not([data-disabled]){cursor:var(--wpds-cursor-control,pointer)}@media not (prefers-reduced-motion){transition:color .1s ease-out;*{transition:opacity .1s ease-out}}&[href]{cursor:pointer}[href]{color:inherit;text-decoration:inherit}&:not([data-disabled]):is(:hover,:active,:focus){background-color:var(--wp-ui-button-background-color-active);border-color:var(--wp-ui-button-border-color-active);color:var(--wp-ui-button-foreground-color-active)}&[data-disabled]:not(._914b42f315c0e580__is-loading){background-color:var(--wp-ui-button-background-color-disabled);border-color:var(--wp-ui-button-border-color-disabled);color:var(--wp-ui-button-foreground-color-disabled);@media (forced-colors:active){border-bottom-color:GrayText;border-left-color:GrayText;border-right-color:GrayText;border-top-color:GrayText;color:GrayText}}&:before{aspect-ratio:1;border:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid;border-block-end-color:transparent;border-block-start-color:var(--wp-ui-button-foreground-color);border-inline-end-color:var(--wp-ui-button-foreground-color);border-inline-start-color:transparent;border-radius:50%;box-sizing:border-box;content:"";display:block;height:var(--wp-ui-button-font-size);inset-inline-start:50%;opacity:0;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);@media not (prefers-reduced-motion){transition:opacity .1s ease-out}@media (forced-colors:active){border-block-end-style:none;border-bottom-color:ButtonText;border-inline-start-style:none;border-left-color:ButtonText;border-right-color:ButtonText;border-top-color:ButtonText}}}._908205475f9f2a92__is-small{--wp-ui-button-padding-block:0px;--wp-ui-button-padding-inline:var(--wpds-dimension-padding-sm,8px);--wp-ui-button-height:var(--wpds-dimension-size-sm,24px)}._9f6fc6553aeb36fe__icon{margin:var(--wp-ui-button-icon-margin)}.dd460c965226cc77__is-brand{&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 85%,#000));--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-brand-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000)}}.e722a8f96726aa99__is-neutral{&.ad0619a3217c6a5b__is-minimal[aria-pressed=true],&.b50b3358c5fb4d0b__is-solid{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-strong,#2d2d2d);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-strong-active,#1e1e1e);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral-strong,#f0f0f0);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-strong-active,#f0f0f0);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-strong-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d);--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-neutral-active,#6e6e6e);--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-neutral-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000)}}.abbb272e2ce49bd6__is-unstyled{background:none;border:none;min-width:unset}.cf59cf1b69629838__is-compact{--wp-ui-button-height:var(--wpds-dimension-size-md,32px)}._914b42f315c0e580__is-loading:not(.abbb272e2ce49bd6__is-unstyled){color:transparent;&:not([data-disabled]):is(:hover,:active,:focus){color:transparent}@media (forced-colors:active){color:ButtonFace}*{opacity:0}&:before{opacity:1;transition-delay:.05s;@media not (prefers-reduced-motion){animation:_5a1d53da6f830c8d__loading-animation 1s linear infinite}}}}@keyframes _5a1d53da6f830c8d__loading-animation{0%{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(1turn)}}}');var Ng={button:"_97b0fc33c028be1a__button","is-unstyled":"abbb272e2ce49bd6__is-unstyled","is-loading":"_914b42f315c0e580__is-loading","is-small":"_908205475f9f2a92__is-small",icon:"_9f6fc6553aeb36fe__icon","is-brand":"dd460c965226cc77__is-brand","is-outline":"_62d5a778b7b258ee__is-outline","is-minimal":"ad0619a3217c6a5b__is-minimal","is-neutral":"e722a8f96726aa99__is-neutral","is-solid":"b50b3358c5fb4d0b__is-solid","is-compact":"cf59cf1b69629838__is-compact","loading-animation":"_5a1d53da6f830c8d__loading-animation"},Di=(0,wd.forwardRef)(function({className:t,icon:o,...n},r){return(0,_d.jsx)(eo,{ref:r,icon:o,className:$(Ng.icon,t),size:24,...n})});Di.displayName="Button.Icon";var sr=Object.assign(pd,{Icon:Di});var ar=h($t(),1),ji=h(Q(),1),Fi=(0,ji.jsx)(ar.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,ji.jsx)(ar.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-.75 12v-1.5h1.5V16h-1.5Zm0-8v5h1.5V8h-1.5Z"})});var cr=h($t(),1),Vi=h(Q(),1),Wi=(0,Vi.jsx)(cr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Vi.jsx)(cr.Path,{d:"M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"})});var lr=h($t(),1),Yi=h(Q(),1),Ui=(0,Yi.jsx)(lr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Yi.jsx)(lr.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M12.218 5.377a.25.25 0 0 0-.436 0l-7.29 12.96a.25.25 0 0 0 .218.373h14.58a.25.25 0 0 0 .218-.372l-7.29-12.96Zm-1.743-.735c.669-1.19 2.381-1.19 3.05 0l7.29 12.96a1.75 1.75 0 0 1-1.525 2.608H4.71a1.75 1.75 0 0 1-1.525-2.608l7.29-12.96ZM12.75 17.46h-1.5v-1.5h1.5v1.5Zm-1.5-3h1.5v-5h-1.5v5Z"})});var dr=h($t(),1),Gi=h(Q(),1),Xi=(0,Gi.jsx)(dr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Gi.jsx)(dr.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm.75 4v1.5h-1.5V8h1.5Zm0 8v-5h-1.5v5h1.5Z"})});var ur=h($t(),1),Ki=h(Q(),1),qi=(0,Ki.jsx)(ur.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Ki.jsx)(ur.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M12 18.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13ZM4 12a8 8 0 1 1 16 0 8 8 0 0 1-16 0Zm11.53-1.47-1.06-1.06L11 12.94l-1.47-1.47-1.06 1.06L11 15.06l4.53-4.53Z"})});var yd=h(de(),1);function Zi(e,t,o){return(0,yd.cloneElement)(e??t,{children:o})}var Lg=h(Rd(),1);var Ed=h(Qi(),1),{lock:h4,unlock:Td}=(0,Ed.__dangerousOptInToUnstableAPIsOnlyForCoreModules)("I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.","@wordpress/ui");function Ig(){let e=Lg;if(e.ThemeProvider)return e.ThemeProvider;if(!e.privateApis)throw new Error("@wordpress/ui: @wordpress/theme must expose `ThemeProvider` or `privateApis.ThemeProvider`.");return Td(e.privateApis).ThemeProvider}var kd=Ig();var Pd=h(de(),1),Ji="data-wp-hash";function $i(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Bg(document)),e.__wpStyleRuntime}function Mg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ji}]`))if(o.getAttribute(Ji)===t)return!0;return!1}function Cd(e,t,o){if(!e.head)return;let n=$i(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Mg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ji,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Bg(e){let t=$i();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Cd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Hg(e,t){let o=$i();o.styles.set(e,t);for(let n of o.documents.keys())Cd(n,e,t)}typeof process>"u",Hg("32aba35fe1","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._19ce0419607e1896__stack{display:flex}}}");var zg={stack:"_19ce0419607e1896__stack"},Dg={xs:"var(--wpds-dimension-gap-xs, 4px)",sm:"var(--wpds-dimension-gap-sm, 8px)",md:"var(--wpds-dimension-gap-md, 12px)",lg:"var(--wpds-dimension-gap-lg, 16px)",xl:"var(--wpds-dimension-gap-xl, 24px)","2xl":"var(--wpds-dimension-gap-2xl, 32px)","3xl":"var(--wpds-dimension-gap-3xl, 40px)"},Po=(0,Pd.forwardRef)(function({direction:t,gap:o,align:n,justify:r,wrap:i,render:s,...a},d){let c={gap:o&&Dg[o],alignItems:n,justifyContent:r,flexDirection:t,flexWrap:i};return bt({render:s,ref:d,props:ye(a,{style:c,className:zg.stack})})});var Kd=h(de(),1);var Vd=h(de(),1);var Id=h(de(),1);var ts="data-wp-hash";function os(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Fg(document)),e.__wpStyleRuntime}function jg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ts}]`))if(o.getAttribute(ts)===t)return!0;return!1}function Od(e,t,o){if(!e.head)return;let n=os(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(jg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ts,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Fg(e){let t=os();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Od(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Vg(e,t){let o=os();o.styles.set(e,t);for(let n of o.documents.keys())Od(n,e,t)}typeof process>"u",Vg("be37f31c1e","._11fc52b637ff8a7e__slot{inset:0;isolation:isolate;pointer-events:none;position:fixed;z-index:1000000003}@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._11fc52b637ff8a7e__slot>*{pointer-events:auto}}}");var Ad={slot:"_11fc52b637ff8a7e__slot"},Nd="data-wp-compat-overlay-slot";function Wg(){return typeof document>"u"?null:document}function Yg(){let e;try{e=window.top?.wp}catch{}let t=e??window.wp;return typeof t?.components=="object"&&t.components!==null}var ht=null;function es(e){return e.setAttribute("aria-hidden","false"),e}function Ug(e){let t=e.createElement("div");return t.setAttribute(Nd,""),Ad.slot&&t.classList.add(Ad.slot),e.body.appendChild(t),t}function Ld(){if(typeof window>"u"||!Yg()&&window.__wpUiCompatOverlaySlotEnabled!==!0)return;let e=Wg();if(!e||!e.body)return;if(ht&&ht.ownerDocument===e&&ht.isConnected)return es(ht);let t=e.querySelector(`[${Nd}]`);return t instanceof HTMLDivElement?(ht=es(t),ht):(ht?.isConnected&&ht.remove(),ht=es(Ug(e)),ht)}var Md=h(Q(),1),Bd=(0,Id.forwardRef)(function({container:t,...o},n){return(0,Md.jsx)(Qe.Portal,{container:t??Ld(),...o,ref:n})});var Hd=h(de(),1),jd=h(Q(),1),ns="data-wp-hash";function rs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Xg(document)),e.__wpStyleRuntime}function Gg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ns}]`))if(o.getAttribute(ns)===t)return!0;return!1}function zd(e,t,o){if(!e.head)return;let n=rs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Gg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ns,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Xg(e){let t=rs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)zd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Dd(e,t){let o=rs();o.styles.set(e,t);for(let n of o.documents.keys())zd(n,e,t)}typeof process>"u",Dd("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var Kg={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",Dd("19fcc06039",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._480b748dd3510e64__positioner{z-index:var(--wp-ui-tooltip-z-index,initial)}._50096b232db7709d__popup{--_wp-ui-elevation-sm:0 1px 2px rgba(0,0,0,.05),0 2px 3px rgba(0,0,0,.04),0 6px 6px rgba(0,0,0,.03),0 8px 8px rgba(0,0,0,.02);background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border-radius:var(--wpds-border-radius-md,4px);box-shadow:var(--_wp-ui-elevation-sm);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-sm,12px);line-height:1.4;padding:var(--wpds-dimension-padding-xs,4px) var(--wpds-dimension-padding-sm,8px);@media (forced-colors:active){border-bottom-color:CanvasText;border-bottom-style:solid;border-bottom-width:1px;border-left-color:CanvasText;border-left-style:solid;border-left-width:1px;border-right-color:CanvasText;border-right-style:solid;border-right-width:1px;border-top-color:CanvasText;border-top-style:solid;border-top-width:1px}}}}');var qg={positioner:"_480b748dd3510e64__positioner",popup:"_50096b232db7709d__popup"},Fd=(0,Hd.forwardRef)(function({align:t="center",className:o,side:n="top",sideOffset:r=4,...i},s){return(0,jd.jsx)(Qe.Positioner,{ref:s,align:t,side:n,sideOffset:r,...i,className:$(Kg["box-sizing"],qg.positioner,o)})});var $o=h(Q(),1),is="data-wp-hash";function ss(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Qg(document)),e.__wpStyleRuntime}function Zg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${is}]`))if(o.getAttribute(is)===t)return!0;return!1}function Wd(e,t,o){if(!e.head)return;let n=ss(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Zg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(is,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Qg(e){let t=ss();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Wd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Jg(e,t){let o=ss();o.styles.set(e,t);for(let n of o.documents.keys())Wd(n,e,t)}typeof process>"u",Jg("19fcc06039",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._480b748dd3510e64__positioner{z-index:var(--wp-ui-tooltip-z-index,initial)}._50096b232db7709d__popup{--_wp-ui-elevation-sm:0 1px 2px rgba(0,0,0,.05),0 2px 3px rgba(0,0,0,.04),0 6px 6px rgba(0,0,0,.03),0 8px 8px rgba(0,0,0,.02);background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border-radius:var(--wpds-border-radius-md,4px);box-shadow:var(--_wp-ui-elevation-sm);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-sm,12px);line-height:1.4;padding:var(--wpds-dimension-padding-xs,4px) var(--wpds-dimension-padding-sm,8px);@media (forced-colors:active){border-bottom-color:CanvasText;border-bottom-style:solid;border-bottom-width:1px;border-left-color:CanvasText;border-left-style:solid;border-left-width:1px;border-right-color:CanvasText;border-right-style:solid;border-right-width:1px;border-top-color:CanvasText;border-top-style:solid;border-top-width:1px}}}}');var $g={positioner:"_480b748dd3510e64__positioner",popup:"_50096b232db7709d__popup"},eb={background:"#1e1e1e"},as=(0,Vd.forwardRef)(function({portal:t,positioner:o,children:n,className:r,...i},s){let a=(0,$o.jsx)(kd,{color:eb,children:(0,$o.jsx)(Qe.Popup,{ref:s,className:$($g.popup,r),...i,children:n})}),d=Zi(o,(0,$o.jsx)(Fd,{}),a);return Zi(t,(0,$o.jsx)(Bd,{}),d)});var Yd=h(de(),1),Ud=h(Q(),1),cs=(0,Yd.forwardRef)(function(t,o){return(0,Ud.jsx)(Qe.Trigger,{ref:o,...t})});var Gd=h(Q(),1);function ls(e){return(0,Gd.jsx)(Qe.Root,{...e})}var lt=h(Q(),1),ds="data-wp-hash";function us(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&nb(document)),e.__wpStyleRuntime}function ob(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ds}]`))if(o.getAttribute(ds)===t)return!0;return!1}function qd(e,t,o){if(!e.head)return;let n=us(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ob(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ds,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function nb(e){let t=us();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)qd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function rb(e,t){let o=us();o.styles.set(e,t);for(let n of o.documents.keys())qd(n,e,t)}typeof process>"u",rb("c5cdafb1bc","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer compositions{._28cfdc260e755391__icon-button{--wp-ui-button-aspect-ratio:1;--wp-ui-button-padding-inline:0px;--wp-ui-button-min-width:unset}.f1c70d719989a85a__icon{margin:-1px}}}");var Xd={"icon-button":"_28cfdc260e755391__icon-button",icon:"f1c70d719989a85a__icon"},fs=(0,Kd.forwardRef)(function({label:t,className:o,children:n,disabled:r,focusableWhenDisabled:i=!0,icon:s,size:a,shortcut:d,positioner:c,...l},f){let p=$(Xd["icon-button"],o);return(0,lt.jsxs)(ls,{children:[(0,lt.jsx)(cs,{ref:f,disabled:r&&!i,render:(0,lt.jsx)(sr,{...l,size:a,"aria-label":t,"aria-keyshortcuts":d?.ariaKeyShortcut,disabled:r,focusableWhenDisabled:i}),className:p,children:(0,lt.jsx)(eo,{icon:s,size:24,className:Xd.icon})}),(0,lt.jsxs)(as,{positioner:c,children:[t,d&&(0,lt.jsxs)(lt.Fragment,{children:[" ",(0,lt.jsx)("span",{"aria-hidden":"true",children:d.displayShortcut})]})]})]})});var Zd=h(de(),1),Qd=h(Ot(),1),Co=h(Q(),1),ps="data-wp-hash";function ms(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&sb(document)),e.__wpStyleRuntime}function ib(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ps}]`))if(o.getAttribute(ps)===t)return!0;return!1}function Jd(e,t,o){if(!e.head)return;let n=ms(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ib(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ps,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function sb(e){let t=ms();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Jd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function pr(e,t){let o=ms();o.styles.set(e,t);for(let n of o.documents.keys())Jd(n,e,t)}typeof process>"u",pr("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var ab={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",pr("5f8e7aa0bc","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active),:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}}}");var cb={"outset-ring--focus":"_08e8a2e44959f892__outset-ring--focus","outset-ring--focus-except-active":"e25b2bdd7aa21721__outset-ring--focus-except-active","outset-ring--focus-visible":"d0541bc9dd9dc7b6__outset-ring--focus-visible","outset-ring--focus-within":"cd83dfc2126a0846__outset-ring--focus-within","outset-ring--focus-within-except-active":"_970d04df7376df67__outset-ring--focus-within-except-active","outset-ring--focus-within-visible":"c5cb3ee4bddaa8e4__outset-ring--focus-within-visible","outset-ring--focus-parent-visible":"ecadb9e080e2dfa5__outset-ring--focus-parent-visible"};typeof process>"u",pr("e8e6a9be37",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{.d4250949359b05ce__link{text-decoration-thickness:from-font;text-underline-offset:.2em}.c6055659b8e2cd2c__is-brand,.c6055659b8e2cd2c__is-brand:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9))}.c6055659b8e2cd2c__is-brand:active,.c6055659b8e2cd2c__is-brand:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000))}._92e0dfcaeee15b88__is-neutral,._92e0dfcaeee15b88__is-neutral:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);text-decoration-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d)}._92e0dfcaeee15b88__is-neutral:active,._92e0dfcaeee15b88__is-neutral:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e)}.cf122a9bf1035d42__is-unstyled{--_gcd-a-color:inherit;color:inherit;text-decoration:none}._0cb411afac4c86c7__link-icon{display:inline-block;font-weight:var(--wpds-typography-font-weight-default,400);line-height:1;margin-inline-start:var(--wpds-dimension-padding-xs,4px);text-decoration:none}._0cb411afac4c86c7__link-icon:after{content:"\\2197"}._0cb411afac4c86c7__link-icon:dir(rtl):after{content:"\\2196"}}}');var fr={link:"d4250949359b05ce__link","is-brand":"c6055659b8e2cd2c__is-brand","is-neutral":"_92e0dfcaeee15b88__is-neutral","is-unstyled":"cf122a9bf1035d42__is-unstyled","link-icon":"_0cb411afac4c86c7__link-icon"};typeof process>"u",pr("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var lb={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},en=(0,Zd.forwardRef)(function({children:t,variant:o="default",tone:n="brand",openInNewTab:r=!1,render:i,className:s,...a},d){return bt({render:i,defaultTagName:"a",ref:d,props:ye(a,{className:$(lb.a,ab["box-sizing"],cb["outset-ring--focus-except-active"],o!=="unstyled"&&fr.link,o!=="unstyled"&&fr[`is-${n}`],o==="unstyled"&&fr["is-unstyled"],s),target:r?"_blank":void 0,children:(0,Co.jsxs)(Co.Fragment,{children:[t,r&&(0,Co.jsx)("span",{className:fr["link-icon"],role:"img","aria-label":(0,Qd.__)("(opens in a new tab)")})]})})})});var tn={};At(tn,{ActionButton:()=>xu,ActionLink:()=>Eu,Actions:()=>fu,CloseIcon:()=>hu,Description:()=>lu,Root:()=>tu,Title:()=>iu});var Ao=h(de(),1);import{speak as db}from"@wordpress/a11y";var Oo=h(Q(),1),bs="data-wp-hash";function hs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&fb(document)),e.__wpStyleRuntime}function ub(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${bs}]`))if(o.getAttribute(bs)===t)return!0;return!1}function $d(e,t,o){if(!e.head)return;let n=hs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ub(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(bs,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function fb(e){let t=hs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)$d(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function eu(e,t){let o=hs();o.styles.set(e,t);for(let n of o.documents.keys())$d(n,e,t)}typeof process>"u",eu("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var pb={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",eu("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var gs={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},mb={neutral:null,info:Xi,warning:Fi,success:qi,error:Ui};function gb(e){return e==="error"?"assertive":"polite"}function bb(e){if(e){if(typeof e=="string")return e;try{return(0,Ao.renderToString)(e)}catch{return}}}function hb(e,t){let o=bb(e);(0,Ao.useEffect)(()=>{o&&db(o,t)},[o,t])}var tu=(0,Ao.forwardRef)(function({intent:t="neutral",children:o,icon:n,spokenMessage:r=o,politeness:i=gb(t),render:s,...a},d){hb(r,i);let c=n===null?null:n??mb[t],l=$(gs.notice,gs[`is-${t}`],pb["box-sizing"]);return bt({defaultTagName:"div",render:s,ref:d,props:ye({className:l,children:(0,Oo.jsxs)(Oo.Fragment,{children:[o,c&&(0,Oo.jsx)(eo,{className:gs.icon,icon:c})]})},a)})});var ou=h(de(),1);var ru=h(Q(),1),ws="data-wp-hash";function vs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&vb(document)),e.__wpStyleRuntime}function wb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ws}]`))if(o.getAttribute(ws)===t)return!0;return!1}function nu(e,t,o){if(!e.head)return;let n=vs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(wb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ws,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function vb(e){let t=vs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)nu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function _b(e,t){let o=vs();o.styles.set(e,t);for(let n of o.documents.keys())nu(n,e,t)}typeof process>"u",_b("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var yb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},iu=(0,ou.forwardRef)(function({className:t,...o},n){return(0,ru.jsx)(Je,{ref:n,variant:"heading-md",className:$(yb.title,t),...o})});var su=h(de(),1);var cu=h(Q(),1),_s="data-wp-hash";function ys(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Rb(document)),e.__wpStyleRuntime}function xb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${_s}]`))if(o.getAttribute(_s)===t)return!0;return!1}function au(e,t,o){if(!e.head)return;let n=ys(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(xb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(_s,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Rb(e){let t=ys();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)au(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Sb(e,t){let o=ys();o.styles.set(e,t);for(let n of o.documents.keys())au(n,e,t)}typeof process>"u",Sb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Eb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},lu=(0,su.forwardRef)(function({className:t,...o},n){return(0,cu.jsx)(Je,{ref:n,variant:"body-md",className:$(Eb.description,t),...o})});var du=h(de(),1);var xs="data-wp-hash";function Rs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&kb(document)),e.__wpStyleRuntime}function Tb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${xs}]`))if(o.getAttribute(xs)===t)return!0;return!1}function uu(e,t,o){if(!e.head)return;let n=Rs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Tb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(xs,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function kb(e){let t=Rs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)uu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Pb(e,t){let o=Rs();o.styles.set(e,t);for(let n of o.documents.keys())uu(n,e,t)}typeof process>"u",Pb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Cb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},fu=(0,du.forwardRef)(function({render:t,...o},n){return bt({defaultTagName:"div",render:t,ref:n,props:ye({className:Cb.actions},o)})});var pu=h(de(),1),mu=h(Ot(),1);var bu=h(Q(),1),Ss="data-wp-hash";function Es(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ob(document)),e.__wpStyleRuntime}function Ab(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ss}]`))if(o.getAttribute(Ss)===t)return!0;return!1}function gu(e,t,o){if(!e.head)return;let n=Es(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Ab(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ss,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ob(e){let t=Es();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)gu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Nb(e,t){let o=Es();o.styles.set(e,t);for(let n of o.documents.keys())gu(n,e,t)}typeof process>"u",Nb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Lb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},hu=(0,pu.forwardRef)(function({className:t,icon:o=Wi,label:n=(0,mu.__)("Dismiss"),...r},i){return(0,bu.jsx)(fs,{...r,ref:i,className:$(Lb["close-icon"],t),variant:"minimal",size:"small",tone:"neutral",icon:o,label:n})});var vu=h(de(),1);var yu=h(Q(),1),Ts="data-wp-hash";function ks(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Mb(document)),e.__wpStyleRuntime}function Ib(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ts}]`))if(o.getAttribute(Ts)===t)return!0;return!1}function _u(e,t,o){if(!e.head)return;let n=ks(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Ib(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ts,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Mb(e){let t=ks();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)_u(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Bb(e,t){let o=ks();o.styles.set(e,t);for(let n of o.documents.keys())_u(n,e,t)}typeof process>"u",Bb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var wu={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},xu=(0,vu.forwardRef)(function({className:t,loading:o,loadingAnnouncement:n,variant:r,...i},s){return(0,yu.jsx)(sr,{...i,...o!==void 0?{loading:o,loadingAnnouncement:n??""}:{},ref:s,size:"compact",tone:"neutral",variant:r,className:$(wu["action-button"],wu[`is-action-button-${r}`],t)})});var Ru=h(de(),1);var Cs=h(Q(),1),Ps="data-wp-hash";function As(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&zb(document)),e.__wpStyleRuntime}function Hb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ps}]`))if(o.getAttribute(Ps)===t)return!0;return!1}function Su(e,t,o){if(!e.head)return;let n=As(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Hb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ps,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function zb(e){let t=As();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Su(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Db(e,t){let o=As();o.styles.set(e,t);for(let n of o.documents.keys())Su(n,e,t)}typeof process>"u",Db("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var jb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},Eu=(0,Ru.forwardRef)(function({className:t,render:o,...n},r){return(0,Cs.jsx)(Je,{ref:r,className:$(jb["action-link"],t),...n,variant:"body-md",render:(0,Cs.jsx)(en,{tone:"neutral",variant:"default",render:o})})});var Tu=h(de(),1),ku=h(Q(),1),Pu=(0,Tu.forwardRef)(({children:e,className:t,ariaLabel:o,as:n="div",...r},i)=>(0,ku.jsx)(n,{ref:i,className:$("admin-ui-navigable-region",t),"aria-label":o,role:"region",tabIndex:"-1",...r,children:e}));Pu.displayName="NavigableRegion";var Cu=Pu;var Ou=h(on(),1),{Fill:Nu,Slot:Lu}=(0,Ou.createSlotFill)("SidebarToggle");var $e=h(Q(),1),Os="data-wp-hash";function Ns(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Vb(document)),e.__wpStyleRuntime}function Fb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Os}]`))if(o.getAttribute(Os)===t)return!0;return!1}function Iu(e,t,o){if(!e.head)return;let n=Ns(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Fb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Os,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Vb(e){let t=Ns();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Iu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Wb(e,t){let o=Ns();o.styles.set(e,t);for(let n of o.documents.keys())Iu(n,e,t)}typeof process>"u",Wb("ddd9aab364","._956b6df0898efed0__page{text-wrap:pretty;background-color:var(--wpds-color-background-surface-neutral,#fcfcfc);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);display:flex;flex-flow:column;height:100%;position:relative;z-index:1}._0625b55e82a0d93d__header{background:var(--wpds-color-background-surface-neutral-strong,#fff);border-block-end:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral-weak,#f0f0f0);inset-block-start:0;padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px);position:sticky;z-index:1}.a43c44d5ae28b2e8__header-content{min-height:var(--wpds-dimension-size-md,32px)}.b7cb5b9daf3a3b25__header-actions{flex-shrink:0}._8113be94e7caf73c__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._9a776c7f70996f61__header-visual{display:grid;flex-shrink:0;grid-template-columns:1fr;grid-template-rows:1fr;height:var(--wpds-dimension-size-sm,24px);width:var(--wpds-dimension-size-sm,24px);>*{grid-column:1/-1;grid-row:1/-1;max-height:100%;max-width:100%}}.d5e0920cd15d35bc__sidebar-toggle-slot:empty{display:none}._60fea2f6bf5319cd__header-subtitle{color:var(--wpds-color-foreground-content-neutral-weak,#707070);padding-block-end:var(--wpds-dimension-padding-xs,4px)}.be5e57d029ec4036__content{display:flex;flex-direction:column;flex-grow:1;overflow:auto;&._128806d0b26e3a50__has-padding{padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px)}}");var to={page:"_956b6df0898efed0__page",header:"_0625b55e82a0d93d__header","header-content":"a43c44d5ae28b2e8__header-content","header-actions":"b7cb5b9daf3a3b25__header-actions","header-title":"_8113be94e7caf73c__header-title","header-visual":"_9a776c7f70996f61__header-visual","sidebar-toggle-slot":"d5e0920cd15d35bc__sidebar-toggle-slot","header-subtitle":"_60fea2f6bf5319cd__header-subtitle",content:"be5e57d029ec4036__content","has-padding":"_128806d0b26e3a50__has-padding"};function Mu({headingLevel:e=1,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,actions:s,showSidebarToggle:a=!0}){let d=`h${e}`;return(0,$e.jsxs)(Po,{direction:"column",className:to.header,children:[(0,$e.jsxs)(Po,{className:to["header-content"],direction:"row",gap:"sm",justify:"space-between",children:[(0,$e.jsxs)(Po,{direction:"row",gap:"sm",align:"center",justify:"start",children:[a&&(0,$e.jsx)(Lu,{bubblesVirtually:!0,className:to["sidebar-toggle-slot"]}),n&&(0,$e.jsx)("div",{className:to["header-visual"],"aria-hidden":"true",children:n}),r&&(0,$e.jsx)(Je,{className:to["header-title"],render:(0,$e.jsx)(d,{}),variant:"heading-lg",children:r}),t,o]}),s&&(0,$e.jsx)(Po,{align:"center",className:to["header-actions"],direction:"row",gap:"sm",children:s})]}),i&&(0,$e.jsx)(Je,{render:(0,$e.jsx)("p",{}),variant:"body-md",className:to["header-subtitle"],children:i})]})}var nn=h(Q(),1),Is="data-wp-hash";function Ms(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ub(document)),e.__wpStyleRuntime}function Yb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Is}]`))if(o.getAttribute(Is)===t)return!0;return!1}function Bu(e,t,o){if(!e.head)return;let n=Ms(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Yb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Is,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ub(e){let t=Ms();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Bu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Gb(e,t){let o=Ms();o.styles.set(e,t);for(let n of o.documents.keys())Bu(n,e,t)}typeof process>"u",Gb("ddd9aab364","._956b6df0898efed0__page{text-wrap:pretty;background-color:var(--wpds-color-background-surface-neutral,#fcfcfc);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);display:flex;flex-flow:column;height:100%;position:relative;z-index:1}._0625b55e82a0d93d__header{background:var(--wpds-color-background-surface-neutral-strong,#fff);border-block-end:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral-weak,#f0f0f0);inset-block-start:0;padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px);position:sticky;z-index:1}.a43c44d5ae28b2e8__header-content{min-height:var(--wpds-dimension-size-md,32px)}.b7cb5b9daf3a3b25__header-actions{flex-shrink:0}._8113be94e7caf73c__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._9a776c7f70996f61__header-visual{display:grid;flex-shrink:0;grid-template-columns:1fr;grid-template-rows:1fr;height:var(--wpds-dimension-size-sm,24px);width:var(--wpds-dimension-size-sm,24px);>*{grid-column:1/-1;grid-row:1/-1;max-height:100%;max-width:100%}}.d5e0920cd15d35bc__sidebar-toggle-slot:empty{display:none}._60fea2f6bf5319cd__header-subtitle{color:var(--wpds-color-foreground-content-neutral-weak,#707070);padding-block-end:var(--wpds-dimension-padding-xs,4px)}.be5e57d029ec4036__content{display:flex;flex-direction:column;flex-grow:1;overflow:auto;&._128806d0b26e3a50__has-padding{padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px)}}");var Ls={page:"_956b6df0898efed0__page",header:"_0625b55e82a0d93d__header","header-content":"a43c44d5ae28b2e8__header-content","header-actions":"b7cb5b9daf3a3b25__header-actions","header-title":"_8113be94e7caf73c__header-title","header-visual":"_9a776c7f70996f61__header-visual","sidebar-toggle-slot":"d5e0920cd15d35bc__sidebar-toggle-slot","header-subtitle":"_60fea2f6bf5319cd__header-subtitle",content:"be5e57d029ec4036__content","has-padding":"_128806d0b26e3a50__has-padding"};function Hu({headingLevel:e,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,children:s,className:a,actions:d,ariaLabel:c,hasPadding:l=!1,showSidebarToggle:f=!0}){let p=$(Ls.page,a);return(0,nn.jsxs)(Cu,{className:p,ariaLabel:c??(typeof r=="string"?r:""),children:[(r||t||o||d||n)&&(0,nn.jsx)(Mu,{headingLevel:e,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,actions:d,showSidebarToggle:f}),l?(0,nn.jsx)("div",{className:$(Ls.content,Ls["has-padding"]),children:s}):s]})}Hu.SidebarToggleFill=Nu;var Bs=Hu;var dt=h(on()),lf=h(rn()),df=h(de()),Tt=h(Ot()),uf=h(mr());import{privateApis as l0}from"@wordpress/connectors";var ju=h(Qi()),{lock:l3,unlock:No}=(0,ju.__dangerousOptInToUnstableAPIsOnlyForCoreModules)("I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.","@wordpress/routes");if(typeof document<"u"&&!document.head.querySelector("style[data-wp-hash='09e9b056ea']")){let e=document.createElement("style");e.setAttribute("data-wp-hash","09e9b056ea"),e.appendChild(document.createTextNode(".connectors-page{box-sizing:border-box;margin:0 auto;max-width:680px;padding:24px;width:100%}.connectors-page .components-item{background:#fff;border:1px solid #ddd;border-radius:8px;overflow:hidden;padding:20px;scroll-margin-top:120px}.connectors-page .connector-settings__error{color:#cc1818}.connectors-page .connector-settings .components-text-control__input{font-family:monospace;scroll-margin-top:120px}.connectors-page__file-mods-notice{margin-bottom:16px}.connectors-page--empty{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:32px;justify-content:center;text-align:center}.connectors-page .ai-plugin-callout{background-color:#e7d4e4;background-image:radial-gradient(ellipse 70% 120% at 18% 115%,rgba(202,158,198,.75) 0,rgba(202,158,198,0) 60%),radial-gradient(ellipse 55% 110% at 92% -15%,rgba(208,175,217,.7) 0,rgba(208,175,217,0) 65%),radial-gradient(ellipse 40% 85% at 58% -10%,rgba(170,130,184,.45) 0,rgba(170,130,184,0) 70%);border-radius:8px;overflow:hidden;padding:24px;padding-inline-end:150px;position:relative}[dir=rtl] .connectors-page .ai-plugin-callout{background-image:radial-gradient(ellipse 70% 120% at 82% 115%,rgba(202,158,198,.75) 0,rgba(202,158,198,0) 60%),radial-gradient(ellipse 55% 110% at 8% -15%,rgba(208,175,217,.7) 0,rgba(208,175,217,0) 65%),radial-gradient(ellipse 40% 85% at 42% -10%,rgba(170,130,184,.45) 0,rgba(170,130,184,0) 70%)}.connectors-page .ai-plugin-callout__content{align-items:flex-start;display:flex;flex-direction:column;gap:12px;padding-top:2px}.connectors-page .ai-plugin-callout__content p{font-size:13px;line-height:20px;margin:0}.connectors-page .ai-plugin-callout__decoration{height:110px;inset-inline-end:16px;position:absolute;top:12px;width:110px}.connectors-page>p{color:#949494}@media (max-width:680px){.connectors-page .ai-plugin-callout{padding:12px;padding-inline-end:100px}.connectors-page .ai-plugin-callout__decoration{height:75px;inset-inline-end:8px;top:8px;width:75px}}@media (max-width:480px){.connectors-page{padding:8px}.connectors-page .ai-plugin-callout{padding-inline-end:130px}.connectors-page .components-item{padding:12px}.connectors-page .components-item>.components-v-stack>.components-h-stack:first-child svg{height:32px;width:32px}.connectors-page .components-item>.components-v-stack>.components-h-stack:first-child>.components-h-stack:last-child{align-items:flex-end;flex-direction:column}}")),document.head.appendChild(e)}var cn=h(on()),Ws=h(mr()),ln=h(rn()),wt=h(de()),Xe=h(Ot()),rf=h(Hs()),sf=h(Wu());var gr=h(on()),js=h(de()),Qu=h(rn()),oo=h(Ot());import{__experimentalRegisterConnector as Xb,__experimentalConnectorItem as Zu,__experimentalDefaultConnectorSettings as Kb,__experimentalApplicationPasswordConnectorSettings as qb,privateApis as Zb}from"@wordpress/connectors";var zs=h(mr()),an=h(rn()),sn=h(de()),fe=h(Ot()),Yu=h(Hs());function Ds({file:e,settingName:t,connectorName:o,isInstalled:n,isActivated:r,keySource:i="none",initialIsConnected:s=!1}){let[a,d]=(0,sn.useState)(!1),[c,l]=(0,sn.useState)(!1),[f,p]=(0,sn.useState)(s),[m,u]=(0,sn.useState)(null),g=e?.replace(/\.php$/,""),v=g?.includes("/")?g.split("/")[0]:g,{derivedPluginStatus:_,canManagePlugins:w,currentApiKey:y,currentUsername:b,hasStoredCredentials:S,hasResolvedSettings:x,canInstallPlugins:E}=(0,an.useSelect)(K=>{let J=K(zs.store),me=J.getEntityRecord("root","site")?.[t],le=typeof me=="string"?me:"",X=typeof me=="object"&&me!==null?me:void 0,pe=X!==void 0?!!X.username&&!!X.password:!!le,ue=J.hasFinishedResolution("getEntityRecord",["root","site"]),vt=!!J.canUser("create",{kind:"root",name:"plugin"}),Te={currentApiKey:le,currentUsername:X?.username??"",hasStoredCredentials:pe,hasResolvedSettings:ue,canInstallPlugins:vt};if(!e)return{...Te,derivedPluginStatus:ue?"active":"checking",canManagePlugins:void 0};let Ve=J.getEntityRecord("root","plugin",g);if(!J.hasFinishedResolution("getEntityRecord",["root","plugin",g]))return{...Te,derivedPluginStatus:"checking",canManagePlugins:void 0};if(Ve){let no=Ve.status==="active"||Ve.status==="network-active";return{...Te,derivedPluginStatus:no?"active":"inactive",canManagePlugins:!0}}let He="not-installed";return r?He="active":n&&(He="inactive"),{...Te,derivedPluginStatus:He,canManagePlugins:!1}},[e,g,t,n,r]),T=m??_,k=w,C=T==="active"&&f||m==="active"&&S,{saveEntityRecord:j,invalidateResolution:A}=(0,an.useDispatch)(zs.store),{createSuccessNotice:L,createErrorNotice:I}=(0,an.useDispatch)(Yu.store),R=K=>j("root","site",{[t]:K},{throwOnError:!0}),N=()=>{L((0,fe.sprintf)((0,fe.__)("%s connected successfully."),o),{id:"connector-connect-success",type:"snackbar"})},H=()=>{L((0,fe.sprintf)((0,fe.__)("%s disconnected."),o),{id:"connector-disconnect-success",type:"snackbar"})},P=()=>{I((0,fe.sprintf)((0,fe.__)("Failed to disconnect %s."),o),{id:"connector-disconnect-error",type:"snackbar"})},O=async()=>{if(v){l(!0);try{await j("root","plugin",{slug:v,status:"active"},{throwOnError:!0}),u("active"),A("getEntityRecord",["root","site"]),d(!0),L((0,fe.sprintf)((0,fe.__)("Plugin for %s installed and activated successfully."),o),{id:"connector-plugin-install-success",type:"snackbar"})}catch{I((0,fe.sprintf)((0,fe.__)("Failed to install plugin for %s."),o),{id:"connector-plugin-install-error",type:"snackbar"})}finally{l(!1)}}},M=async()=>{if(e){l(!0);try{await j("root","plugin",{plugin:g,status:"active"},{throwOnError:!0}),u("active"),A("getEntityRecord",["root","site"]),d(!0),L((0,fe.sprintf)((0,fe.__)("Plugin for %s activated successfully."),o),{id:"connector-plugin-activate-success",type:"snackbar"})}catch{I((0,fe.sprintf)((0,fe.__)("Failed to activate plugin for %s."),o),{id:"connector-plugin-activate-error",type:"snackbar"})}finally{l(!1)}}};return{pluginStatus:T,canInstallPlugins:E,canActivatePlugins:k,isExpanded:a,setIsExpanded:d,isBusy:c,isConnected:C,currentApiKey:y,currentUsername:b,hasResolvedSettings:x,keySource:i,handleButtonClick:()=>{if(T==="not-installed"){if(E===!1)return;O()}else if(T==="inactive"){if(k===!1)return;M()}else d(!a)},getButtonLabel:()=>{if(c)return T==="not-installed"?(0,fe.__)("Installing\u2026"):(0,fe.__)("Activating\u2026");if(a)return(0,fe.__)("Cancel");if(C)return(0,fe.__)("Edit");switch(T){case"checking":return(0,fe.__)("Checking\u2026");case"not-installed":return(0,fe.__)("Install");case"inactive":return(0,fe.__)("Activate");case"active":return(0,fe.__)("Set up")}},saveApiKey:async K=>{let J=y;try{let le=(await R(K))?.[t];if(K&&(le===J||!le))throw new Error("It was not possible to connect to the provider using this key.");p(!0),N()}catch(ne){throw console.error("Failed to save API key:",ne),ne}},removeApiKey:async()=>{try{await R(""),p(!1),H()}catch(K){console.error("Failed to remove API key:",K),P()}},saveCredentials:async({username:K,applicationPassword:J})=>{try{let le=(await R({username:K,password:J}))?.[t];if(!le?.username||!le?.password)throw new Error((0,fe.__)("It was not possible to save these credentials."));p(!0),N()}catch(ne){throw console.error("Failed to save credentials:",ne),ne}},removeCredentials:async()=>{try{await R({username:"",password:""}),p(!1),H()}catch(K){console.error("Failed to remove credentials:",K),P()}}}}var Uu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364l2.0201-1.1685a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.4043-.6813zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z",fill:"currentColor"})),Gu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 32 32",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M6.2 21.024L12.416 17.536L12.52 17.232L12.416 17.064H12.112L11.072 17L7.52 16.904L4.44 16.776L1.456 16.616L0.704 16.456L0 15.528L0.072 15.064L0.704 14.64L1.608 14.72L3.608 14.856L6.608 15.064L8.784 15.192L12.008 15.528H12.52L12.592 15.32L12.416 15.192L12.28 15.064L9.176 12.96L5.816 10.736L4.056 9.456L3.104 8.808L2.624 8.2L2.416 6.872L3.28 5.92L4.44 6L4.736 6.08L5.912 6.984L8.424 8.928L11.704 11.344L12.184 11.744L12.376 11.608L12.4 11.512L12.184 11.152L10.4 7.928L8.496 4.648L7.648 3.288L7.424 2.472C7.344 2.136 7.288 1.856 7.288 1.512L8.272 0.176L8.816 0L10.128 0.176L10.68 0.656L11.496 2.52L12.816 5.456L14.864 9.448L15.464 10.632L15.784 11.728L15.904 12.064H16.112V11.872L16.28 9.624L16.592 6.864L16.896 3.312L17 2.312L17.496 1.112L18.48 0.464L19.248 0.832L19.88 1.736L19.792 2.32L19.416 4.76L18.68 8.584L18.2 11.144H18.48L18.8 10.824L20.096 9.104L22.272 6.384L23.232 5.304L24.352 4.112L25.072 3.544H26.432L27.432 5.032L26.984 6.568L25.584 8.344L24.424 9.848L22.76 12.088L21.72 13.88L21.816 14.024L22.064 14L25.824 13.2L27.856 12.832L30.28 12.416L31.376 12.928L31.496 13.448L31.064 14.512L28.472 15.152L25.432 15.76L20.904 16.832L20.848 16.872L20.912 16.952L22.952 17.144L23.824 17.192H25.96L29.936 17.488L30.976 18.176L31.6 19.016L31.496 19.656L29.896 20.472L27.736 19.96L22.696 18.76L20.968 18.328H20.728V18.472L22.168 19.88L24.808 22.264L28.112 25.336L28.28 26.096L27.856 26.696L27.408 26.632L24.504 24.448L23.384 23.464L20.848 21.328H20.68V21.552L21.264 22.408L24.352 27.048L24.512 28.472L24.288 28.936L23.488 29.216L22.608 29.056L20.8 26.52L18.936 23.664L17.432 21.104L17.248 21.208L16.36 30.768L15.944 31.256L14.984 31.624L14.184 31.016L13.76 30.032L14.184 28.088L14.696 25.552L15.112 23.536L15.488 21.032L15.712 20.2L15.696 20.144L15.512 20.168L13.624 22.76L10.752 26.64L8.48 29.072L7.936 29.288L6.992 28.8L7.08 27.928L7.608 27.152L10.752 23.152L12.648 20.672L13.872 19.24L13.864 19.032H13.792L5.44 24.456L3.952 24.648L3.312 24.048L3.392 23.064L3.696 22.744L6.208 21.016L6.2 21.024Z",fill:"#D97757"})),Xu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 32 32",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M0 4C0 1.79086 1.79086 0 4 0H28C30.2091 0 32 1.79086 32 4V28C32 30.2091 30.2091 32 28 32H4C1.79086 32 0 30.2091 0 28V4Z",fill:"#F0F0F0"}),React.createElement("path",{d:"M14.5 8V12H17.5V8H19V12H20.5C20.7652 12 21.0196 12.1054 21.2071 12.2929C21.3946 12.4804 21.5 12.7348 21.5 13V17L18.5 21V23C18.5 23.2652 18.3946 23.5196 18.2071 23.7071C18.0196 23.8946 17.7652 24 17.5 24H14.5C14.2348 24 13.9804 23.8946 13.7929 23.7071C13.6054 23.5196 13.5 23.2652 13.5 23V21L10.5 17V13C10.5 12.7348 10.6054 12.4804 10.7929 12.2929C10.9804 12.1054 11.2348 12 11.5 12H13V8H14.5ZM15 20.5V22.5H17V20.5L20 16.5V13.5H12V16.5L15 20.5Z",fill:"#949494"})),Ku=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 44 44",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("rect",{width:"44",height:"44",fill:"#357B49",rx:"6"}),React.createElement("path",{fill:"#fff",fillRule:"evenodd",d:"m29.746 28.31-6.392-16.797c-.152-.397-.305-.672-.789-.675-.673 0-1.408.611-1.746 1.316l-7.378 16.154c-.072.16-.143.311-.214.454-.5.995-1.045 1.546-2.357 1.626a.399.399 0 0 0-.16.033l-.01.004a.399.399 0 0 0-.23.392v.01c0 .054.01.106.03.155l.004.01a.416.416 0 0 0 .394.252h6.212a.417.417 0 0 0 .307-.12.416.416 0 0 0 .124-.305.398.398 0 0 0-.105-.302.399.399 0 0 0-.294-.127c-.757 0-2.197-.062-2.197-1.164.02-.318.103-.63.245-.916l1.399-3.152c.52-1.163 1.654-1.163 2.572-1.163h5.843c.023 0 .044 0 .062.003.13.014.16.081.214.242l1.534 4.07a2.857 2.857 0 0 1 .216 1.04c0 .054-.003.104-.01.153-.09.726-.831.887-1.49.887a.4.4 0 0 0-.294.127l-.007.008-.007.008a.401.401 0 0 0-.092.286v.01c0 .054.01.106.03.155l.005.01a.42.42 0 0 0 .395.252h7.011a.413.413 0 0 0 .279-.13.412.412 0 0 0 .11-.297.387.387 0 0 0-.09-.294.388.388 0 0 0-.277-.135c-1.448-.122-2.295-.643-2.847-2.08Zm-11.985-5.844 2.847-6.304c.361-.728.659-1.486.889-2.265 0-.06.03-.092.06-.092s.061.032.061.091c.02.122.045.247.073.374.197.888.584 1.878.914 2.723l.176.453 1.684 4.529a.927.927 0 0 1 .092.4.473.473 0 0 1-.009.094c-.041.202-.228.272-.602.272h-6.063c-.122 0-.184-.03-.184-.092a.36.36 0 0 1 .062-.183Zm17.107-.721c0 .786-.446 1.231-1.25 1.231-.806 0-1.125-.409-1.125-1.034 0-.786.465-1.231 1.25-1.231.785 0 1.125.427 1.125 1.034ZM9.629 23.002c.803 0 1.25-.447 1.25-1.231 0-.607-.343-1.036-1.128-1.036-.785 0-1.25.447-1.25 1.231 0 .625.325 1.036 1.128 1.036Z",clipRule:"evenodd"})),qu=()=>React.createElement("svg",{width:"40",height:"40",style:{flex:"none",lineHeight:1},viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"#3186FF"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-0)"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-1)"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-2)"}),React.createElement("defs",null,React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-0",x1:"7",x2:"11",y1:"15.5",y2:"12"},React.createElement("stop",{stopColor:"#08B962"}),React.createElement("stop",{offset:"1",stopColor:"#08B962",stopOpacity:"0"})),React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-1",x1:"8",x2:"11.5",y1:"5.5",y2:"11"},React.createElement("stop",{stopColor:"#F94543"}),React.createElement("stop",{offset:"1",stopColor:"#F94543",stopOpacity:"0"})),React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-2",x1:"3.5",x2:"17.5",y1:"13.5",y2:"12"},React.createElement("stop",{stopColor:"#FABC12"}),React.createElement("stop",{offset:".46",stopColor:"#FABC12",stopOpacity:"0"}))));var{store:Qb}=No(Zb);function Ju(){try{return JSON.parse(document.getElementById("wp-script-module-data-options-connectors-wp-admin")?.textContent??"{}")}catch{return{}}}function Fs(){return Ju().connectors??{}}function $u(){return!!Ju().isFileModDisabled}var Jb={google:qu,openai:Uu,anthropic:Gu,akismet:Ku};function $b(e,t){if(t)return React.createElement("img",{src:t,alt:"",width:40,height:40});let o=Jb[e];return React.createElement(o||Xu,null)}var e0=()=>React.createElement("span",{style:{color:"#345b37",backgroundColor:"#eff8f0",padding:"4px 12px",borderRadius:"2px",fontSize:"13px",fontWeight:"var(--wpds-typography-font-weight-emphasis)",whiteSpace:"nowrap"}},(0,oo.__)("Connected")),t0=({slug:e})=>React.createElement(en,{href:(0,oo.sprintf)((0,oo.__)("https://wordpress.org/plugins/%s/"),e),openInNewTab:!0},(0,oo.__)("Learn more")),o0=()=>React.createElement(Ii,null,(0,oo.__)("Not available"));function ef({isConnected:e,showUnavailableBadge:t,pluginSlug:o,isExpanded:n,isBusy:r,pluginStatus:i,actionButtonRef:s,handleButtonClick:a,getButtonLabel:d}){return React.createElement(gr.__experimentalHStack,{spacing:3,expanded:!1},e&&React.createElement(e0,null),t&&(o?React.createElement(t0,{slug:o}):React.createElement(o0,null)),!t&&React.createElement(gr.Button,{ref:s,variant:n||e?"tertiary":"secondary",size:"compact",onClick:a,disabled:i==="checking"||r,isBusy:r,accessibleWhenDisabled:!0},d()))}function tf(e){let t=e?.replace(/\.php$/,"");return t?.includes("/")?t.split("/")[0]:t}function n0({name:e,description:t,logo:o,authentication:n,plugin:r}){let i=n?.method==="api_key"?n:void 0,s=i?.settingName??"",a=i?.credentialsUrl??void 0,d=tf(r?.file),{pluginStatus:c,canInstallPlugins:l,canActivatePlugins:f,isExpanded:p,setIsExpanded:m,isBusy:u,isConnected:g,currentApiKey:v,hasResolvedSettings:_,keySource:w,handleButtonClick:y,getButtonLabel:b,saveApiKey:S,removeApiKey:x}=Ds({file:r?.file,settingName:s,connectorName:e,isInstalled:r?.isInstalled,isActivated:r?.isActivated,keySource:i?.keySource,initialIsConnected:i?.isConnected}),E=w==="env"||w==="constant",T=c==="not-installed"&&l===!1||c==="inactive"&&f===!1,k=(0,js.useRef)(null);return React.createElement(Zu,{className:d?`connector-item--${d}`:void 0,logo:o,name:e,description:t,actionArea:React.createElement(ef,{isConnected:g,showUnavailableBadge:T,pluginSlug:d,isExpanded:p,isBusy:u,pluginStatus:c,actionButtonRef:k,handleButtonClick:y,getButtonLabel:b})},p&&c==="active"&&_&&React.createElement(Kb,{key:g?"connected":"setup",initialValue:E?"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022":v,helpUrl:a,readOnly:g||E,keySource:w,onRemove:E?void 0:async()=>{await x(),k.current?.focus()},onSave:async C=>{await S(C),m(!1),k.current?.focus()}}))}function r0({name:e,description:t,logo:o,authentication:n,plugin:r}){let i=n?.method==="application_password"?n:void 0,s=i?.settingName??"",a=i?.credentialsUrl??void 0,d=tf(r?.file),{pluginStatus:c,canInstallPlugins:l,canActivatePlugins:f,isExpanded:p,setIsExpanded:m,isBusy:u,isConnected:g,currentUsername:v,hasResolvedSettings:_,keySource:w,handleButtonClick:y,getButtonLabel:b,saveCredentials:S,removeCredentials:x}=Ds({file:r?.file,settingName:s,connectorName:e,isInstalled:r?.isInstalled,isActivated:r?.isActivated,keySource:i?.keySource,initialIsConnected:i?.isConnected}),E=w==="env"||w==="constant",T=(0,js.useRef)(null),k=c==="not-installed"&&l===!1||c==="inactive"&&f===!1;return React.createElement(Zu,{className:d?`connector-item--${d}`:void 0,logo:o,name:e,description:t,actionArea:React.createElement(ef,{isConnected:g,showUnavailableBadge:k,pluginSlug:d,isExpanded:p,isBusy:u,pluginStatus:c,actionButtonRef:T,handleButtonClick:y,getButtonLabel:b})},p&&c==="active"&&_&&React.createElement(qb,{key:g?"connected":"setup",initialUsername:E?"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022":v,helpUrl:a,readOnly:g||E,keySource:w,onRemove:E?void 0:async()=>{await x(),T.current?.focus()},onSave:async C=>{await S(C),m(!1),T.current?.focus()}}))}function of(){let e=Fs(),t=o=>o.replace(/[^a-z0-9-_]/gi,"-");for(let[o,n]of Object.entries(e)){if(o==="akismet"&&!n.plugin?.isInstalled)continue;let{authentication:r}=n,i=t(o),s={name:n.name,description:n.description,type:n.type,logo:$b(o,n.logoUrl),authentication:r,plugin:n.plugin},a=No((0,Qu.select)(Qb)).getConnector(i);r.method==="api_key"&&!a?.render?s.render=n0:r.method==="application_password"&&!a?.render&&(s.render=r0),Xb(i,s)}}function nf(){return React.createElement("div",{className:"ai-plugin-callout__decoration","aria-hidden":"true"},React.createElement("svg",{viewBox:"0 0 248 248",xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",focusable:"false",style:{width:"100%",height:"100%"}},React.createElement("image",{href:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAQAElEQVR4AezdC3ojWW5tYflOzPbIbI/M9sh8+WdrdZ+KpiiKL5FB5KedwN7AeSFIpHRYmfX/PubXVGAqMBV4kQpMw3qRBzXbnApMBT4+pmHNq2AqMBV4mQpMw3qZR3X9RmeGqcCrV2Aa1qs/wdn/VOCNKjAN640e9hx1KvDqFZiG9epPcPY/FThWgZ1q07B2+mDnWFOBPVZgGtYen+qcaSqw0wpMw9rpg51jTQX2WIFpWMee6mhTganAU1ZgGtZTPpbZ1FRgKnCsAtOwjlVltKnAVOApKzAN6ykfy2zqcRWYlV6pAtOwXulpzV6nAm9egWlYb/4CmONPBV6pAtOwXulpve9e//Nw9P/7xL8d7Hy9aQWubFhvWrU59qMr8D+HBcPBna93rcA0rHd98q91bs3q3w9bBv7Bna93rMA0rHd86nPmqcCLVmAa1os+uF/Y9m8u6Q7rvw8bgLnDOhTiXb+mYb3rk3+tc//rYbsaVTjQP18amct4+h9hftt3BaZh7fv57v107rNg7+ec831WYBrWZyHGPHUF/vewu//6xNqg+HMRfyjMrb+edb5pWM/6ZGZfawX86Bc0qTU2/htVYBrWGz3sOepU4NUrMA3r1Z/g7H8q8EYVmIZ1h4c9U04FpgL3qcA0rPvUdWadCkwF7lCBaVh3KOpMORWYCtynAtOw7lPXmfVdKjDnfGgFpmE9tNyz2FRgKnBNBaZhXVO9GTsVmAo8tALTsB5a7llsKjAVuKYCv9uwrtn5jJ0KTAXergLTsN7ukc+BpwKvW4FpWK/77GbnU4G3q8A0rLd75L914Fl3KnB9BaZhXV/DmWEqMBV4UAWmYT2o0LPMVGAqcH0FpmFdX8OZYSowFfhrBe7GpmHdrbQz8VRgKnDrCkzDunVFZ76pwFTgbhWYhnW30s7EU4GpwK0rMA3r1hW9fr6ZYSowFfiiAtOwvijMyFOBqcDzVWAa1vM9k9nRVGAq8EUFpmF9UZiRpwKPqMCs8bMKTMP6Wb0meyowFfjFCkzD+sXiz9JTganAzyowDetn9ZrsqcBU4Bcr8NIN6xfrNktPBaYCv1CBaVi/UPRZciowFbisAtOwLqvbjJoKTAV+oQLTsH6h6LPkBRWYIVOBQwWmYR2KMF9TganAa1RgGtZrPKfZ5VRgKnCowDSsQxHmayowFXimCny9l2lYX9dmIlOBqcCTVWAa1pM9kNnOVGAq8HUFpmF9XZuJTAWmAk9WgWlYT/ZArt/OzDAV2G8FpmHt99nOyaYCu6vANKzdPdK7HOjfDrP+9yf4B/fP138efoeDma+pwP0rMA3r/jXewwqaVFjP8x8HAmIHd74eXIG3W24a1ts98pse+H8Os8HBzNdU4P4VmIZ1/xrvYQU/9v3L4SCwNqh/P2iwagdpvqYC96nANKz71HVmnQpMBe5QgXduWHco526n9B3W9tJ91fi7Pfwc7HkqMA3reZ7FM+/kXw+bc7EeDvTPV1z8jzC/TQXuWYFpWPes7sw9FZgK3LQC07BuWs7dTva/h5P91ye6YGfT2EP4eb9mZ/uowDSsfTzHe5/CHVXQqKzHbjX6YCpwtwpMw7pbaX808f8dsoN7oQOdr6nAVGBbgWlY24o8hvvEzXcnp1YTl3cq51ExTdRe7GldE6ev2vhTgbtV4KyGdbfV33diDeC7T9bE5T1LlezFntb94PRVG38qcLcKTMO6W2lPTuy/GPdfiJfED+6G6Lg8/m/Dnuxne7lOe5Y9/naNZv0HVGAa1gOKfMYSGkI4I/1XUp59f79SlFn0sRWYhvXYereaex/3PyunQT9iiePlPMbOKlOBJ67ANKzfeTiakvufVsdDmjgtPnYq8PYVmIb1Oy8B9z7uf06tLi7vVM7EpgJvVYFpWM/xuF1mB3dFz7Gr2cXOK/B6x5uG9RzPzH1VeI4dzS6mAk9YgWlYT/hQZktTganA8QpMwzpel1GnAlOBJ6zANKyLH8oMnApMBR5dgWlYj674rDcVmApcXIFpWBeXbgZOBaYCj67ANKxHV3zWe8UKzJ6fpALTsJ7kQcw2pgJTge8rMA3r+xpNxlRgKvAkFZiG9SQPYrYxFZgKfF+BRzSs73cxGVOBqcBU4IwKTMM6o0iTMhWYCjxHBaZhPcdzmF1MBaYCZ1RgGtYZRXrSFP9Wln/gD/htEwd/mTqNT4Nyj2ny+7/3sDgYh4NxNBYHcdrH4Tc8HOifL/E044hsmjgN0tj2Ko6DcfLE8EADcfmAg1w64IMXrcA0rNd5cN6Y3njrjnE4pvkHANP58iCNxQO+B3x11v84HA6c9+DO1ytWYBrW6zw1/6Df/FtZlz8vtYPLZ5iRv16BaVi//gjO3sD2zYb7F0mB30Q4aHBpfBqU68cjHPjl4iHNPy5oDljH4yBeLh7SxNN+Mr7cY+PFmpNtLf52/2suv9yx11TgF8ZOw/qFor/gkt7kKzrCJZox9xzf3GN3WIFpWK/xUN27hHbsuyIXyyBGZ/FAgzgrh7aO59PE5AQaiKfJ2WriNCiPPZabxsqBa8ebw9rAD9agmX+r0QcvVoFpWK/xwLzxvOFcGq87pof0OHtKE5MDLqpxwAMO4mksDfggjgMecBBPY2lsEKdBGouDOB5oEGdx4Ac8pLFpY1+sAtOwfuuBXb+uN/H1s9x2hm0zWH/8u+1KM9tbVmAa1ms8dj/SuEh2odyOXUSHtTGksadyjZETjuWm/e/BKc+4A/1g09iPw69j2kH+OHe8XHMF89GOjaeXx+LAD41nt5rcwYtVYBrWiz2wZbvehBoZ8IVYPNAgzuKw5vK32prLD8dy08xRHosDP5TLbrVtLg7lscbRWDzQIM7isObyaYMXrMA0rBd8aN9s2Y9lodQ4m/ZK1r7Duu80Np0f0n7ZzvK3qsA0rFtV8vHzeFP6r9+Bbwesy/lAgzgrh8YaC+t3I3SclRdoEGflbDU6TYwfaBBn5Ww1fN2nPB820ECcZiweaLDmyqGBcSunDV6sAtOwXuyBPWC73tTe9NulaNuLfhqsuY1nV13eOeONMRb4t4Q93HK+mevBFZiG9eCC33i5ay+S3efAui3fibjc3+o06625OH3VjKOZZ9V9aCB/1XC5q2YczTyrfq7vgt5YWMc076qN/2IVeIGG9WIVfdx2vSG9CaFVaRpDSI+zcuisxgDrHMXYFfLhO018m0eDrY6D2AoapNmjvUN7FcdDueLyQU762B1UYBrWDh7iHGEq8C4VmIa1vyfdJbTvNDqdi/Ww3g3JgfKe1TpT+2+/zpHGtne6HEgbu5MKTMPayYNcjuENC9sL7iXl765LaPi78MvOLZZ3dmc65/y3WG/meGAFpmE9sNhPuJQ7HhffT7i1i7fkTODy/eJJZuBzVmAa1nM+l2t21SW0S+fm4Qdv5lV/hR+dNNXt/p0jje1M6a9wrvY89swKTMM6s1AvnuZNHF7xKO092xnibNrYF6nAJduchnVJ1Z57jO8sQjt1aR3c8aS/inWe7f6dI43tLPSQNnYnFZiGtZMHuRzDhTOsl869gdkl9cOna7Bqz+g7i72H9hhnV00DU4O0sTupwDSsnTzIOcZU4B0qMA3rRZ/yiW27gAYX1aXxw3rf0wV9ec9qfeJ3bP9pbHv346NzqUHa2J1UYBrWTh7kcgwNKSR7E4e0V7LtnXU2e2fxQBvsvALTsHb+gD+P544nfEovZdo7u24cD6s+/k4rMA1rfw/WJTq4eO50/OANvtXjz2pdoLd/31HZp3OksTQQx1n89TEn+HsFpmH9vRRv6XjTw94O70w+Wdzbud7+PNOw9vcScLcDLqq/O52Lafgu75Xizu5M60X8K+1/9nqiAtOwThTnRUPerLD+SORTs+AN3dH4EH9W6zztv3PZdxrb3ukhbexOKrD/hrWTBzXHmApMBT4+pmHt71Xgwhn6TsQJXcIH9zs04AP/meE87b9z2Xca2/7pciBt7E4qMA1rJw9yOYY3LJxz6awRwDL85V1n96niOed/+cO+2wGmYb3bE//reXd21/PncJ3pnA8d/gyY316nAtOwXudZnbvTfzkkgovqg/vnix+8of+Ih9/SDu5Tf/nEr722fzaN7QDp8yNhFdmRnYa1o4d54ijexOFE2tOG2nu2jcbZtLE7rsA0rP09XN9ZhE7nniq440l/Fes82/07Rxr7KmeZfV5RgaVhXTHLDH2mCrhwhvXS2Zs7rHutEazaM/rO0v7Z9sgPac7kU8NpYlVkR3Ya1o4e5hzlLxWYS/e/lGMfZBrWPp7jeoouqNl0fljve3w3sl5Yl/9sVvM5tv80tj07kw8d2LSxO6nANKydPMjlGN6omhIk0wLt1dDe2c7F4uHVzjT7vaAC07AuKNoLDumeh33B7X/Yd/hYfqWxizzuXiswDWt/T9aFM6yXzvywvrnTnr0KPkRor76jsl/nSGNpII6z+GBHFZiGtaOHecFRvOnhgqFPPcSZfLL41Jt81Ob2tM40rD09zb+dxd0OuKj+m/L17y7c4euM14v4zsqZ1ov41zvF7PhoBaZhHS3LS4verOCN20F8ahY0s3Q+xJ/VOk/771z2ncauexeDVRt/BxWYhrWDhzhHmAq8SwWmYX3zpF8w7MIZ+k7EEVzCB/c7NOAD/5nhPO2/c9l3Gtv+6XIgbexOKjANaycPcjmGNyycc+msEcAy/OVdZ/ep4jnnf/nDvtsBpmG92xP/63nd88Bf1ddmzgPnfOjw2id9w91Pw9rfQ3cBDS6qOx0/eDNv9fizWp/4bffvHGlse0//+Y+EzTD2aSswDetpH81NN+ZNHG468YMma+/Zlo2zaWN3XIFpWPt7uL6zCJ0uzrrjSX+Utaa1gW9dFg+0r7Dm8strLJs2dscVmIa1v4frwhnWS2c8rCf26Rqs2j381mZrOCwO617pPghg24uckM6mseVqXs5kjrSxO6nA7RrWTgoyx3iaCmhIT7OZ2chzVGAa1nM8h1vuwgV1aN44u973uJyH8u5lfWJnbWh9Fg+tTXeJ7jultGPjxRrL4mCcM5kDH+yoAtOwdvQwP4/iDQve+J/SBx4+fuFXa7Pti8WBf2pbckK5bBp7avzEdlKBaVg7eZDfHMOPV+Gb1HPCP85pbbbB/BXpx+xXeV/px+YYbQcVmIa1g4e4OYILZ1gvnfnBm7wh8mDVil1jfcezzulSvPXFzC2eJk4DcTqLgzgN0tfxdHkgjrP4YEcVmIa1o4f5w6N4w/9wyFnp5tVgzkr+Iskc6yeHX6R9KV87/suJJ/C7FZiG9bv1v8fq7nbARfWp+eW4rIZTeT+NmdeFN/vTsfKNsyfAf4prx/90vb3nP9X5pmE91eO4yWY0C1h/JPKpWfCGbiE5sGrFrrHb+eyn9a1nbjZNnAbGirE4iJcrRhNPY2lAl8Pigx1VYBrWjh7mHGUqsPcKTMPa3xN24Qy+y+h0LtaD+x06Kwfwe8Ia9gTWtRaLgzjtK8hpoPtu7gAAEABJREFU/+Uan8Y2li4H0sbupALTsO77IH9jdm9YOOfS2uU4yL/3Xq0B6zo4nLPXddwp33zOdMs5T603sQdWYBrWA4s9Sz2kAu6u4LsPHR6ymVnkthWYhnXbej7DbC6gwUV1++EHb2Y6Kw/4tHvBj2fWgdZi29N3nwiKl2ucfbJpLA3SrYkPdlSBaVg7epgnjuJNHE6kPTzUnthTi4uvKPeYVuzhdha8fwWmYd2/xo9ewR0OrN9h8INYe+JD/FmtPR7bfxr7rHuffd2wAtOwbljMJ5nKJ2qwXjq7hA5tUxOQB/z0Z7TtnW2vLB7at+blU0PnShu7kwpMw9rJg5xjTAXeoQJP07DeodgPOqML6tCSx+56aC6rgV/uM1qf+NkjrPvDQ7rvsJxJDdLG7qQC07B28iCXY3jDgjdysjdwWHU+lPes1nnaP98+7TuNpQUxiI/dSQWmYe3kQX5zDPc94ZvUpwy3d3bdIB5WffydVmAa1v4erAtnWC+d+cEb3KlZecCnPQY/X8XFevvvOyx7TmObVRxn08bupALTsHbyIOcYf6mAZrZ+SvqX4JDXrcA0rNd9dl/t3N0NuKj+Kocux8U04HvBXs+1l+dz1TmmYV1Vvqcc7AIa1h+J/JWY4A3dxuXAqhV7Jus87d9+7c2e01ga0OWw+OBXK3Dbxadh3baeM9tUYCpwxwpMw7pjcR8wtbsaaCm+S/SQHmflpL+K9R2Ti3Ro/6zzhM4iJ8hJH7uDCkzDeu2H2Bvz0lNoBHDp+EeO03zCqXXLYU/lTewFKzAN66kf2rebc08D3yZ+kaBZXTP+i2lHngrcpwLTsO5T10fN6jIaWk/zwUN6nJWTzm457dmgsdo7tF8WD+05zspJH7uDCkzD2sFD3BzBmzQUirNpr2btPbT3OHtKKzb2xSswDet1H6A7Gt95AL+T4CFNPKTtwXZOtvPwgzNv9VUr9gx29nBGBaZhnVGkJ03xxvNXVoBvmyweaEC/9oLePM8EZ+qc63/Vnsa2Xw0MB+PSx75YBaZhvdgDm+1OBd65AtOwXvfpu7cJ6ynS2HTfYbiEhrQ9WH+tKHQe515Bx8vj0wYvWIG9NKwXLP3VW/bG04BAQzLhqtFpQQzir26dxbmB33mcO6SJywN++tgXq8A0rBd7YMt23cWERf5IYz/u+Mv8K1rqmFbsEfbY+se0R+xl1rhxBaZh3bigd5rOhfn2r6B4E9LBdw6WXjU67RZo3tYxZ5p1XGbTAA84GNf+jaMBH/iXwFhzs41vbTadxUF+uXScTRv7xBWYhvXED+fJtuZNvX4ad4vtmVMT+dFcS7Lxa7NcQme5144/a5FJul0FpmHdrpb3nMm/beXuBe65zqm5u7Q+lXMqZu+w5vjuZv2nYdbYOb753Fex5+Rvc6x/zfjtfMPvXIFpWHcu8I2m743lzdWUNG924NO9cfFAuwXMaw22+fDWWfeVxq65cmCdo/il1lywjrduKLbulb/ml7Nq4z9pBaZhPemDmW1NBaYCHx8fmyJMw9oU5AmoexXfBbBtpwtrNl2O+x9IK/8aay5Y57CGtcG6YiwO4jTAAw7iacbRrEGHNPq1MJc5oblop9Zfcxsz9gkrMA3r+R6KS2Twhv5ud3JCubg3aPyn1nhvYPanY3+abw245WW+ucwJ3+1HTvgud+JPUIFpWE/wEDZb6IJ9I59N3cnA2QM2ica6YGc3oaFTgd+twDSs363/sdV9d+Rymi2OhxqJ+FYr/285sZ9ZY829jtLAtmvJSRMvP41NE8fB/HQWB3HaLWAuc0LzrXu1Lp2VE2iDJ6/ANKwnf0Cf2/PmCp/SH5PG/hHu9Jv5V7TMJZoxp8YXu9SaP6xzpLHp/JA29okrMA3r+R6O7wZCu4uz7lzS+RC/hbVGaD5rpPHpbBpLA37AYc3lbzX5tHvBmtYAfuvgIU08jZ8+9gkqMA3rdx+CNwS0C74L95AeZ9PkuhwHfvq11hqhueJsa7E4uOg+lntMM47OGgvrePqtz2RO6wB/uz6dBvyAvwjeY5vTsH73OXvzwLFd+FHlmH5P7au93HPNY3PbBxyLjfbGFZiG9bsPvx891l1oVODTwnQ8rFoXxmLp11qX1qG57MUakMYP4sf0NPFy0+Ks+Kr7L9XVJu1aa43OxG8+fkizl2O5xcf+YgWmYf1i8Y8s7c1TE1rfsGmsnIbyIX6tNZd1Q/Ph1gY+XS4OaXQ84CCexqd9NV7s1rCWdYFvfrY9sTSQE/DBE1VgGtafh/FUv/lRKLSxOJt2L2uN0Bpx9pj2lX4q15gV5T7SHlv/mPbIPc1aJyowDetEce4c8qf4uX9dxCV08IZqa3yIX2vN1Tps87mExsG+6WuuOA3kBBzE04yjsWniNDA/ncVvAWtVa745WesEGsRZOTTg33JP5hz8sALTsH5YsCdL9yaCJ9vWVdvxiaEzsVdNdOPBmirceNqZ7icVmIb1k2rdNtcdSrh0Zn/iw6Xjn3GcS291YW+5P3PCpXO6iF/vui6dZ8ZdUYFpWFcU78qh3jzeAFDTofmELLREnJWTfmtrbmuE5rfHtPbKpomXm8amieNgHJ3FQZwGdJzFbwHnMifwzclaO9AgzsqhAR/4g1+qwDSsXyr8LDsVmAr8vALTsH5es0tGuJPxHQM0nu9iF8TpLB5oEGfl0G453lzmNLc1Ag3E0+RsNXEalMfiII7DT8Yfy01jzResA3FWDu3Y+mJygjyIs3Jo63g+bfALFfhpw/qFLe5iSZe1sF4k870hQgeNs6c0MTkBhziLAz/gIc1etppYmjge0uPiW00sTRwP6XHxrSaWJo6H9Dh7ShOTE3CIszjwAx7S7CVt7IMrMA3rwQWf5aYCU4HLKzAN6/La/WSky16XuGzj+tSJ1mUui4dy46wcuh9NcEhj8SAP4qwc2jreXmhicgINxNPk0I6Np5fH4nDp+NY6Nl7MGsE6EGfl0Na9prFygjyIs3Jo63h7oQ1+oQLTsH6h6J9LejOs+JQ/ztU+Dr/OzT2Wdxj+cUz/u/bxj1+rxi/CD+dq8s/NPZZ3yXjzGBdwiLM48AMe0ti0sQ+uwDSsxxTcn9DBXYhV2a1GT2Nx4AfjaOxWo6exOPCDcTQ2jaUBP+Cw5vK3mnwa8AMOxqTxaZDG4sAP5bJbbZuLQ3mscTQWBz4N8IBDnC2XxYM8iLP44M4VmIZ15wJ/Tu/CPXxKH3HWG4LO4oEGcRaHNZe/1dZcfpAHxqR1kbxqYvKAH+TQ2LTG09NYOV9p3uRy4KvxxoKc0JxsGisP+AGHNZe/1eTTgB9wMCbtu73KH9ypAtOw7lTYN53WG/tNj/7ix36R7U/DesyDcu+xwqr+6kkaHtLYn2ryjQs4xFkc+MFeaJDG4iCOAw78IL7VitHFV06Ls+I0wAMO4luNnsbiwA84xFk84OFczV7KdQEf0sbesQLTsO5Y3GVqnziFZD8SpfHp3jxpLA34QQ6NTbv3ePOfWkvcnqA8FgdxHPi0Y/unywlyaMak8WliaSwN+EEOjU271XjzmivggztXYBrWnQv8Ob0flcKn9BHPfnz+irOf0gc/fCy/0thkfjiliZXH4sAPOMSzNIizOPADDvEsDeIsDvyAQzxLgziLAz/gIY39qSbfuIBDnMUHd67ANKxbFPgfc3jh9u8u+ZO3iL/mEeTQXeJuNbE0Vh7wgxya+beaWBorD/hBDm0dby80sfJYGojjIId2bDxdTsDh0vGtdWy8WOuw1gF+kENb95rGlsfKA36QQ1vH2wtNrDyWFsTyx96wAtOwbljMmWoq8FkBDUyT+6RjblWBaVi3quQ/5nFfEv6hjvdOFfC3GrwG3unMDznrNKzbltmLtMtdfrN7AYd0eWn9aSyWxp4ab4wc4Mu9dLy9nBovbh1oLRYHceMBDziIpxlHY9PEaZDGOg9NHAfjaGJ4oEGclUMzBgc+TQwPNIizcmjG4P/y8fFhLzSxNJa2Qnzl49+gAtOwblDEmWIqMBV4TAWmYV1XZ5er0Cz+JHZ/Afx0PJQvvtXE0thHjbcXa321vrj9gBy5q8angZyAg3jaT8Yfy01jm5O1DvCDHNqx9cXKY+UBP8ihreP5NLHyWBqI4yCHNrhRBaZhXV5IL0Yvyj41aiY6rH+FAw/liaex6fxwShMrj8WBH3CIs3jAwV62Gj1NHA/pcfGtJpYmjof0uPhWE0sTx0N6nD2lickJOMRZHPgBD2n2stXE0sRxSBt7owo8uGHdaNfPM417ivW/fH6enc1OpgI7rMA0rMsfqmblAtaPAM1C669qsOn8IIeu0W01epq5cUhjG8/iwJcHOPxkvHxjgR9wOLZXa5bHygN+wOHS8db4ajy9dVgc+KHx7Fbb5uJQHmscjcUDDeIsDny1B+NogxtVYBrWjQr5OY0XqAYG/E/5Aw8fn7/ibLksDvzP1A88fHz+Ek/jk9mtRk9jcTiWu2prLj/I+Wo8vTwWB364x3hzWwf4AQdrpvG3mhgN+AEHY9L4W02MBuIBH9ywAtOwLi+mOwovVOCbicUDDeKsHBqLA58GeMAhzpbL4sCXB3jAIc6Wy+JBHsRZHNZc/lZbc/kA8sAYHPhbjU4DfjiWm7bNxaGxbLksDnx5gAcc4my5LB7kQZzFYc3lb7U1V2zwgwpMw/pBsTapLtvD+sJMc/nakDT2mHZs/Fe5jTdGDvDpLB5oEGdxWHPb66qtufwg56vx9PJYHPjhHuPNbR3gBxysmcbfamI04AccjEm7Za3MPfhBBaZh/aBYkzoVmAr8bgWmYV1efxfJ27uKOCve7HhIE99qYmksDvyAQ5zFAx7O1ezlVK74qTnFHz3eeu2JxYEfcIizeMDDudotz9qaL28fdYBpWJdX2l2ET4KAbyYvfhzS6HiQQxNP49PE0lga8IMcGpt27/HmP7WWuD1BeSwO4jjwacf2T5cT5NCMSePTxNJYGvCDHBqbdu/x5j+1lrg9DS6owDSsC4r2OcS9xopP+eMSzZiPz1/88Cl9xNmP5RcekuPsKU1MTsAhzuLAX0GDSzRjjAV+wCHO4sBfQYNztZ/kHpvz0vHmMhb4AR9cUIFpWOcVzZ+K/qt2thEuYWnghUgXx0GcBngoV3yriaWxxgI/yKGta6Wx5bHygB/k0Nbx9kITK4+lgTgOcmjHxtPlBBwuHd9ax8aLtQ5rHeAHObR1r2lseaw84Ac5tHW8vdDEymNpII6DHNqx8fTBDyswDeu8gvlkyIuPPW/ED7Im9a0r4B98fOsC/OTw07DOq5aLVvcg7HkjJmsqcF4Fjv3TNOeNfMOsaVjnPXTf0rtIZRuBe7FBOouDeLl40Pjo4mnG0cTSWBrwgxyaMWl8mlgaSwN+kEMzJs1eaGJpLA3EcTCOxuIgTgM84CCeZhyNTROnQRprPzRxHIyjieGBBnFWDs0YHPg0MTzQIM7KoRmDg73QxPBAA/E042hsmjhtcEEFpmFdUFjYef8AAA5ZSURBVLQZMhW4uAIz8KoKTMP65/K5q4I14gI1FPOn5ilNvDnKY0+NF5MTHjW+vX61vnh7kmNfq8anQXksDuI4/GT8sdw01nzBOhBn5dCOrS8mJ8iDOCuHto7n08TkBBqIp8nZauI0KI/FB99UYBrWPxfIiwd6scngBxxcwKexNOCDOA54wEE8jaUBP+AQZ/GAh59q8htrLziksTiI44EGcXEc0lgcxPFAg7g4DmksDuJ4oEGcxYEf8JDG/lSTbxzYCw54wEE8jaUBH8RxwAM++KYC07C+KdCEpwJTgeepwGs1rMfUrctRl6qt6N84Cuk+MdxqYmnsT8fLNw7Wy1k8WEMeu9XoaSwO/GAcjU1jacAPOFx6VmPh0vH2+NV4evtkceCD+jWepQFfHuABhzhbLosHeRBncfjJWe0xGDv4pgLTsL4p0GfYvUP4lD7irBf0x+EXiwP/IP35wsMf4fBbnC2XxYF/SPvzhYc/wuE38TT+Qfpg09iPz1/88Cl9rLn8j8Mvtjz2IP354gc5RHar0dNYHPjBOBq71ehpLA78YByNTWNpwAdxHPg04G81Og34AQdj0vhbTYwG/HAsN00uP+CDbyowDeuvBXKf0IuNLcoPcujsVqOnsTjwg3E0dqvR01gc+ME4GrvV6GksDvxgHI1NY2nADzisufytJp8G/ICDMWl8GqSxOPBDuexW2+biUB5rHI3FgU8DPOAgnsbfamI04AccjEnjbzUxGvADDsYEfLBUYBrWUoyD64Xir1bAejmKh0Pan684axzRiw+HS8abx9hgToizOKy5/K225vKDPDAmrb2umpg84Ac5NDat8fQ0Fgd+MI72Ta0+5MsDfmg8m8bKA37AYc3lbzX5NOAHHIxJ66yrJiYP+EEOjU1rPD2NxUGuD30AHywVmIa1FONM17fwZ6ZO2gtWQMN4wW2/x5anYf31OWtGweVp0TQ2TRyHNH4QP6aniZebxqaxOPADDnEWD3g4V7OXU7nip+YUf/R467UnFgd+wCHO4gEP52r3Pqv9uMSH9jT2swLTsD4L8Wm8WPrUxo8sn/Kf/z15epp4Gp9+zng5co05NV5MHvBD49k0c8lbNTEa8IMcGpv23XjxU7ni5oTyWBzEceDTjq1PlxPk0IxJ49PE0lga8IMcGpt27/HmP7WWuD1BeSwO9ioH8HfA2WechvXPpfIjQSgaZ49pX+nHco9pl4w3j3EBhziLAz/gIY09V/tJ7rE5f2O8fVg34BBnceAHPKSx52o/yT025zq++Fvbd29Y/hSDXgR8l52wXoTioVzxtF5Y54wv99h4seZkW4sf5NDXtdLY8lh5wA9yaOt4e6GJlcfSQBwHObRj4+lyAg6Xjm+tY+PFWoe1DvCDHNq61zS2PFYeHFtrHS8u79rx5rBuwMH8adagDT4r8M4Ny4vBi2P91OazLGOmAlOBZ6zAOzcsz8PFJvBfFbPv21bAH2S3nXFmu1kF3rlhdbnJVlDf+vdXc9aL0DS2XHEcjKOzOIjTAA+tJ55mnDyxNJYG/CCHZkwanyaWxtKAH+TQjEmzF5pYGksDcRyMo7E4iNMADziIpxlHY9PEaZDG2g9NHAfjaGJ4oEGclUMzBgc+TQwPNIizcmjG4GAvNDE80EA8zTgamyZOgzQWB3EcjKMNPivwzg3rswRjpgJTgVepwDs3LH96bS83V43fcyyPTRPHoR8jVo1frpxwLDeNLY991Pj2+tX64vYDcuxr1fg0kBNwEE/7yfhjuWlsc7LWAX6QQzu2vlh5rDw4lrtqfHnXjjeHdQMO5k+zBg3o/3lwVu1A3+vrnRuWy3YPP/Tk4+JbTSxNHA/pcfGtJpYmjof0OHtKE5MTcIizOPADHtLsZauJpYnjIT0uvtXE0sTxkB4X32piaeJ4SI+zpzQxOQGHOIvDuhYe5ID4VqOnieMhPS6+1cTSxPGQ7gMioKe9nX3nhvV2D3sOfFYF3rohnFWhX0x654blr1j4hBBcoHoMLB5oEGdxuHS8Nb4aT7dGwCHONp7FgS8P8IBDnC2XxYM8iLM4XHpWY+HS8fb41Xi6PQYc4i6vG8+m8+VBGosDP5TLprHygB9wuPSsxsKx8XSX8OBHQ/wt8VYNa/OEPfjgBSnMbjV6GosDPxhHY7caPY3FgR+Mo7FpLA34AYc1l7/V5NOAH3AwJo2/1cRowA/HctO2uTg0li2XxYEvD/CAQ5wtl8WDPIiL48Df6qsmJg/4AYc1l7/V5NOAH47lpm1zcWgsu+aKvT3epWH5Nj/00HEvCuDTWTzQIM7KobE48LcanQb8cCw3bZuLQ2PZclkc+PIADzjE2XJZPMiDOIvDmsvfamsuP8gDY9L4W02MBvxwLDdtm4tDY9lyWRz48gAPOIin8beaGA34AQdj0vhbTYwG/ICDMWn8rSZGe0u8S8PqUxe2B+0CM6wvjDSXn8dyj2n3GG8fx9ZKs6Yc4NNZPNAgzuKw5nbWVVtz+UHOV+Pp5bE48MM9xpvbOsAPOFgzjb/VxGjgNYIDDsbg8Ey1sre3wrs0rLd6qHPYj4+PKcIuK/AuDauLUbYH6XLTHQGk8YP4MT1NvNy0OCt+TE8TlwdpLB5wiLM48AMe0thzNXs5lStuPjiWJ35MTxM3FtL4QfyYniZebhqbxuLADzjEWTzg4VzNXk7lip+aU/xW45vnbey7NCw/94ceLu6TJODTvdBwSKPjQQ5NPI1PE9tq9DRWDs0YHPg0MTzQIM7KobE43Hu8+a0D/K/Wp8sJOBiTxqcd2z+9PFYOzRgc+DQxPNAgzsqhsTjce7z5rQP8r9anywk4GJPGpx3bP/3t8C4N6+0e7Bx4KrDHChxvWPs7qYtU6E8sJ8T/7+BAOouD+CH85wsPLmCJ4mnG0dg0cRqksafGi8kJxkKclUNb1+LTxOQEGsRZOTRjcGivYniQB+JpxtHYNHEapLE4iONgHI3FQZwGeLAfmniacTSxNJYG/CCHZkwanyaWxtKAH+TQjEmzF5pYGksDcRyMo7E4iNMADziIpxlHY9PEaW+Jd2lYXlzQJzxv+bDn0FOBV6/AuzQsdwCwXni++rOb/U8F3q4C79KwtpeYHjTNX3UA33LTWBzEaYAHjY8mnmYcjU0Tp0Eae2q8mJxgLMRZObR1LT5NTE6gQZyVQzPmXz4+PmjtVQwP8kA8zTgamyZOgzQWB3EcjKOxOIjTAA/2QxNPM44mlsbSgB/k0IxJ49PE0lga8IMcmjFp9kITS2NpII6DcTQWB3Ea4AEH8TTjaGyaOO0t8S4N6y0f7hx6KrC3Crxzw/KnlgtMcL/l2a4anwZywrHcNLa8a8ebx9rAD9agmX+riaWx8oAf5NDW8XyaWHksDcRxkLPVxGkgJ+AgnvaT8cdy09jmZK0D/CCHdmx9sfJYecAPcmjreD5NrDyWBuI4yNlq4jSQE3AQT2s8nQ/8t8U7NywX8F4AsL4AcBBPx0OaeBpLZ4M4DdJYHMTxQIM4iwM/4CGN/akm3ziwFxzwgIN4GksDPojjgAccxNNYGvBBHAc84CCextKAH3CIs3jAw081+Y21FxzSWBzE8UCDuDgOaSwO4niggb8WpJHR8Uvw8mPeuWG9/MObA7xVBXxg5N7srQ69Pew7Nyx/TccFJvRCYOmhesVZOXQvIBzSWDzIgzgrh3ZsPF1OwCHONp7FgS8PcHAuHPBQLpvGygN+wOHYXh8x3hpfrU9vnywO/NB4dqttc3EojzWOxuKBBnEWh3vUyrx+VPRM7QV/S7xzw/LgQw8f98IAfjoejmnlsuXxj+Ue08plG88ey01bc/l01jjg0wAPOIin8beaGA344Vhu2jYXh8ay5bI48OUBHnCIs+WyeJAHcRaHNZe/1dZcfpAHxqTxt5oYDfjhWG7aNheHxrJrrtjb450b1rGH735gRTlePEGczp7SxOQBPxhHY7caPY3FgR+Mo7FbjZ7G4sAPxtHYNJYG/IDDmsvfavJpwA84GJPG32piNOCHY7lp21wcGsuWy+LAlwd4wCHOlsviQR7EWRzWXP5WW3P5QR4YE/DBUoFpWEsxDq4XiotNcMl5kP588cMf4fBbnDXuIH2wOLg8/fj8hYdP6SPOGkdn8UCDOIvDmsvfamsuP8gDY9La66qJyQN+kENj0xpPT2Nx4AfjaGzatePNY07gBxzWtfhbTT4N+AEHY9La66qJyQN+kENj0xpPT2NxkOv1B3za4LMC07A+CzFmKjAVeP4KTMP66zNyZxBcnhZNY9PEcUjjB/Fjepp4uWlsGosDP+AQZ/GAh3M1ezmVK35qTvFHj7dee2Jx4Acc4iwe8PAX7UDoB/Pnix/ufVbruMQH/p8NzG9/q8A0rL/Vod+9QHwSA+4W0vEghy6exqeJbTV6GiuHZgwOfJoYHmgQZ+XQWBzuPd781gH+V+vT5QQcjEnj047tn14eK4dmDA58mhgeaBBn5dBYHO493vzWAf5X69PlBBzs1TjAB0sFpmEtxRh3KjAVeO4KTMN67ufzTLv7yQXwT3Kf6YyzlyevwF0a1pOfebZ3ugKajX8sbpvlkyyxVceP/ejiE641b/ypwE0qMA3rJmXc1STuUPxTJttDuWsRW3X8WMM6Nn4dN/5U4KIKTMO6qGwzaCowFfiNCkzD+o2q72nNOctU4IEVmIb1wGLPUlOBqcB1FZiGdV39ZvRUYCrwwApMw3pgsWepqcBrV+D3dz8N6/efwexgKjAVOLMC07DOLNSkTQWmAr9fgWlYv/8MZgdTganAmRWYhnVmoa5PmxmmAlOBayswDevaCs74qcBU4GEVmIb1sFLPQlOBqcC1FZiGdW0FZ/xU4J8rMMqdKjAN606FnWmnAlOB21dgGtbtazozTgWmAneqwDSsOxV2pp0KTAVuX4H/DwAA//9sB2hHAAAABklEQVQDAB9QlitZA9bLAAAAAElFTkSuQmCC",width:"248",height:"248",style:{mixBlendMode:"multiply"}})))}var i0="ai",s0="ai-wp-admin",Vs="ai/ai",a0="https://wordpress.org/plugins/ai/",Ys=Object.values(Fs()),c0=Ys.some(e=>e.type==="ai_provider"),af=[];for(let e of Ys)e.type==="ai_provider"&&e.authentication.method==="api_key"&&af.push(e.authentication.settingName);function cf(){let[e,t]=(0,wt.useState)(!1),[o,n]=(0,wt.useState)(!1),r=(0,wt.useRef)(null);(0,wt.useEffect)(()=>{o&&r.current?.focus()},[o]);let i=(0,wt.useRef)(Ys.some(S=>S.type==="ai_provider"&&S.authentication.method==="api_key"&&S.authentication.isConnected)).current,{pluginStatus:s,canInstallPlugins:a,canManagePlugins:d,hasConnectedProvider:c}=(0,ln.useSelect)(S=>{let x=S(Ws.store),E=!!x.canUser("create",{kind:"root",name:"plugin"}),T=x.getEntityRecord("root","site"),k=i||af.some(A=>!!T?.[A]),C=x.getEntityRecord("root","plugin",Vs);return x.hasFinishedResolution("getEntityRecord",["root","plugin",Vs])?C?{pluginStatus:C.status==="active"?"active":"inactive",canInstallPlugins:E,canManagePlugins:!0,hasConnectedProvider:k}:{pluginStatus:"not-installed",canInstallPlugins:E,canManagePlugins:E,hasConnectedProvider:k}:{pluginStatus:"checking",canInstallPlugins:E,canManagePlugins:void 0,hasConnectedProvider:k}},[]),{saveEntityRecord:l}=(0,ln.useDispatch)(Ws.store),{createSuccessNotice:f,createErrorNotice:p}=(0,ln.useDispatch)(rf.store),m=async()=>{t(!0);try{await l("root","plugin",{slug:i0,status:"active"},{throwOnError:!0}),n(!0),f((0,Xe.__)("AI plugin installed and activated successfully."),{id:"ai-plugin-install-success",type:"snackbar"})}catch{p((0,Xe.__)("Failed to install the AI plugin."),{id:"ai-plugin-install-error",type:"snackbar"})}finally{t(!1)}},u=async()=>{t(!0);try{await l("root","plugin",{plugin:Vs,status:"active"},{throwOnError:!0}),n(!0),f((0,Xe.__)("AI plugin activated successfully."),{id:"ai-plugin-activate-success",type:"snackbar"})}catch{p((0,Xe.__)("Failed to activate the AI plugin."),{id:"ai-plugin-activate-error",type:"snackbar"})}finally{t(!1)}};if(!c0||s==="checking"||s==="active"&&i&&!o||s==="inactive"&&d===!1)return null;let g=s==="active"&&!c,v=s==="active"&&c&&(!i||o),_=s==="not-installed"||s==="inactive",w=s==="not-installed"&&a===!1,y=()=>v?(0,Xe.__)("The AI plugin is ready to use. You can use it to generate featured images, alt text, titles, excerpts and more. Learn more"):g?(0,Xe.__)("The AI plugin is installed. Connect an AI provider below to generate featured images, alt text, titles, excerpts, and more. Learn more"):(0,Xe.__)("The AI plugin can use your AI connectors to generate featured images, alt text, titles, excerpts and more. Learn more"),b=()=>s==="not-installed"?{label:e?(0,Xe.__)("Installing\u2026"):(0,Xe.__)("Install the AI plugin"),disabled:e,onClick:e?void 0:m}:{label:e?(0,Xe.__)("Activating\u2026"):(0,Xe.__)("Activate the AI plugin"),disabled:e,onClick:e?void 0:u};return React.createElement("div",{className:"ai-plugin-callout"},React.createElement("div",{className:"ai-plugin-callout__content"},React.createElement("p",null,(0,wt.createInterpolateElement)(y(),{strong:React.createElement("strong",null),a:React.createElement(cn.ExternalLink,{href:a0})})),!w&&(_?React.createElement(cn.Button,{variant:"primary",size:"compact",isBusy:e,disabled:b().disabled,accessibleWhenDisabled:!0,onClick:b().onClick},b().label):React.createElement(cn.Button,{ref:r,variant:"secondary",size:"compact",href:(0,sf.addQueryArgs)("options-general.php",{page:s0})},(0,Xe.__)("Control features in the AI plugin")))),React.createElement(nf,null))}var{store:d0}=No(l0);of();function u0(){let e=$u(),{connectors:t,canInstallPlugins:o,isAiPluginInstalled:n}=(0,lf.useSelect)(c=>{let l=c(uf.store),f=l.getEntityRecord("root","plugin","ai/ai");return{connectors:No(c(d0)).getConnectors(),canInstallPlugins:l.canUser("create",{kind:"root",name:"plugin"}),isAiPluginInstalled:!!f}},[]),r=t.filter(c=>c.render),i=Array.from(new Set(t.filter(c=>c.type==="ai_provider").map(c=>c.plugin?.file?.split("/")[0]).filter(c=>!!c))).sort(),s=new Set(t.filter(c=>c.plugin?.isInstalled).map(c=>c.plugin?.file?.split("/")[0]).filter(c=>!!c));n&&s.add("ai");let a=["ai",...i].filter(c=>!s.has(c)),d=r.length===0;return React.createElement(Bs,{title:(0,Tt.__)("Connectors"),subTitle:(0,Tt.__)("All of your API keys and credentials are stored here and shared across plugins. Configure once and use everywhere.")},React.createElement("div",{className:`connectors-page${d?" connectors-page--empty":""}`},a.length>0&&(e||!o)&&React.createElement(tn.Root,{intent:"info",className:"connectors-page__file-mods-notice"},React.createElement(tn.Description,null,e?(0,Tt.__)("Plugins cannot be installed here due to your site configuration. Install them manually using your normal deployment workflow."):(0,Tt.__)("You do not have permission to install plugins. Please ask a site administrator to install them for you."))),d?React.createElement(dt.__experimentalVStack,{alignment:"center",spacing:3,style:{maxWidth:480}},React.createElement(dt.__experimentalVStack,{alignment:"center",spacing:2},React.createElement(dt.__experimentalHeading,{level:2,size:15},(0,Tt.__)("No connectors yet")),React.createElement(dt.__experimentalText,{size:12},(0,Tt.__)("Connectors appear here when you install plugins that use external services. Each plugin registers the API keys it needs, and you manage them all in one place."))),React.createElement(dt.Button,{variant:"secondary",href:"plugin-install.php",__next40pxDefaultSize:!0},(0,Tt.__)("Learn more"))):React.createElement(dt.__experimentalVStack,{spacing:3},React.createElement(cf,null),React.createElement(dt.__experimentalVStack,{spacing:3,role:"list"},t.map(c=>c.render?React.createElement(c.render,{key:c.slug,slug:c.slug,name:c.name,description:c.description,type:c.type,logo:c.logo,authentication:c.authentication,plugin:c.plugin}):null))),o&&!e&&React.createElement("p",null,(0,df.createInterpolateElement)((0,Tt.__)("If the connector you need is not listed, search the plugin directory to see if a connector is available."),{a:React.createElement("a",{href:"plugin-install.php?s=connector&tab=search&type=tag"})}))))}function f0(){return React.createElement(u0,null)}var p0=f0;export{p0 as stage}; +var wf=Object.create;var _r=Object.defineProperty;var vf=Object.getOwnPropertyDescriptor;var _f=Object.getOwnPropertyNames;var yf=Object.getPrototypeOf,xf=Object.prototype.hasOwnProperty;var Re=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),At=(e,t)=>{for(var o in t)_r(e,o,{get:t[o],enumerable:!0})},Rf=(e,t,o,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let r of _f(t))!xf.call(e,r)&&r!==o&&_r(e,r,{get:()=>t[r],enumerable:!(n=vf(t,r))||n.enumerable});return e};var h=(e,t,o)=>(o=e!=null?wf(yf(e)):{},Rf(t||!e||!e.__esModule?_r(o,"default",{value:e,enumerable:!0}):o,e));var Ot=Re((g0,Gs)=>{Gs.exports=window.wp.i18n});var de=Re((h0,Ks)=>{Ks.exports=window.wp.element});var z=Re((w0,qs)=>{qs.exports=window.React});var Q=Re((E0,$s)=>{$s.exports=window.ReactJSXRuntime});var Mt=Re((Ah,Ta)=>{Ta.exports=window.ReactDOM});var Mc=Re(Ic=>{"use strict";var wo=z();function Tm(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var km=typeof Object.is=="function"?Object.is:Tm,Pm=wo.useState,Cm=wo.useEffect,Am=wo.useLayoutEffect,Om=wo.useDebugValue;function Nm(e,t){var o=t(),n=Pm({inst:{value:o,getSnapshot:t}}),r=n[0].inst,i=n[1];return Am(function(){r.value=o,r.getSnapshot=t,ri(r)&&i({inst:r})},[e,o,t]),Cm(function(){return ri(r)&&i({inst:r}),e(function(){ri(r)&&i({inst:r})})},[e]),Om(o),o}function ri(e){var t=e.getSnapshot;e=e.value;try{var o=t();return!km(e,o)}catch{return!0}}function Lm(e,t){return t()}var Im=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?Lm:Nm;Ic.useSyncExternalStore=wo.useSyncExternalStore!==void 0?wo.useSyncExternalStore:Im});var ii=Re((w1,Bc)=>{"use strict";Bc.exports=Mc()});var zc=Re(Hc=>{"use strict";var Dn=z(),Mm=ii();function Bm(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var Hm=typeof Object.is=="function"?Object.is:Bm,zm=Mm.useSyncExternalStore,Dm=Dn.useRef,jm=Dn.useEffect,Fm=Dn.useMemo,Vm=Dn.useDebugValue;Hc.useSyncExternalStoreWithSelector=function(e,t,o,n,r){var i=Dm(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=Fm(function(){function d(m){if(!c){if(c=!0,l=m,m=n(m),r!==void 0&&s.hasValue){var u=s.value;if(r(u,m))return f=u}return f=m}if(u=f,Hm(l,m))return u;var g=n(m);return r!==void 0&&r(u,g)?(l=m,u):(l=m,f=g)}var c=!1,l,f,p=o===void 0?null:o;return[function(){return d(t())},p===null?void 0:function(){return d(p())}]},[t,o,n,r]);var a=zm(e,i[0],i[1]);return jm(function(){s.hasValue=!0,s.value=a},[a]),Vm(a),a}});var jc=Re((_1,Dc)=>{"use strict";Dc.exports=zc()});var $t=Re((X2,md)=>{md.exports=window.wp.primitives});var Rd=Re((g4,xd)=>{xd.exports=window.wp.theme});var Qi=Re((b4,Sd)=>{Sd.exports=window.wp.privateApis});var on=Re((q5,Au)=>{Au.exports=window.wp.components});var rn=Re((a3,zu)=>{zu.exports=window.wp.data});var mr=Re((c3,Du)=>{Du.exports=window.wp.coreData});var Hs=Re((u3,Fu)=>{Fu.exports=window.wp.notices});var Wu=Re((f3,Vu)=>{Vu.exports=window.wp.url});function Xs(e){var t,o,n="";if(typeof e=="string"||typeof e=="number")n+=e;else if(typeof e=="object")if(Array.isArray(e)){var r=e.length;for(t=0;te();function Y(e){let t=Se(kf).current;return t.next=e,Tf(t.effect),t.trampoline}function kf(){let e={next:void 0,callback:Pf,trampoline:(...t)=>e.callback?.(...t),effect:()=>{e.callback=e.next}};return e}function Pf(){}var Js=h(z(),1),Cf=()=>{},D=typeof document<"u"?Js.useLayoutEffect:Cf;var hn=h(z(),1),Af=hn.createContext(void 0);function so(){return hn.useContext(Af)?.direction??"ltr"}function Of(e,t){return function(n,...r){let i=new URL(e);return i.searchParams.set("code",n.toString()),r.forEach(s=>i.searchParams.append("args[]",s)),`${t} error #${n}; visit ${i} for the full message.`}}var Nf=Of("https://base-ui.com/production-error","Base UI"),Pe=Nf;var Wt=h(z(),1);function xr(e,t,o,n){let r=Se(ta).current;return Lf(r,e,t,o,n)&&oa(r,[e,t,o,n]),r.callback}function ea(e){let t=Se(ta).current;return If(t,e)&&oa(t,e),t.callback}function ta(){return{callback:null,cleanup:null,refs:[]}}function Lf(e,t,o,n,r){return e.refs[0]!==t||e.refs[1]!==o||e.refs[2]!==n||e.refs[3]!==r}function If(e,t){return e.refs.length!==t.length||e.refs.some((o,n)=>o!==t[n])}function oa(e,t){if(e.refs=t,t.every(o=>o==null)){e.callback=null;return}e.callback=o=>{if(e.cleanup&&(e.cleanup(),e.cleanup=null),o!=null){let n=Array(t.length).fill(null);for(let r=0;r{for(let r=0;r=e}function Rr(e){if(!ra.isValidElement(e))return null;let t=e,o=t.props;return(ao(19)?o?.ref:t.ref)??null}function Bo(e,t){if(e&&!t)return e;if(!e&&t)return t;if(e||t)return{...e,...t}}function Nt(){}var I0=Object.freeze([]),be=Object.freeze({});function ia(e,t){let o={};for(let n in e){let r=e[n];if(t?.hasOwnProperty(n)){let i=t[n](r);i!=null&&Object.assign(o,i);continue}r===!0?o[`data-${n.toLowerCase()}`]="":r&&(o[`data-${n.toLowerCase()}`]=r.toString())}return o}function sa(e,t){return typeof e=="function"?e(t):e}function aa(e,t){return typeof e=="function"?e(t):e}var Sr={};function ye(e,t,o,n,r){if(!o&&!n&&!r&&!e)return wn(t);let i=wn(e);return t&&(i=Ho(i,t)),o&&(i=Ho(i,o)),n&&(i=Ho(i,n)),r&&(i=Ho(i,r)),i}function ca(e){if(e.length===0)return Sr;if(e.length===1)return wn(e[0]);let t=wn(e[0]);for(let o=1;o=65&&r<=90&&(typeof t=="function"||typeof t>"u")}function Er(e){return typeof e=="function"}function da(e,t){return Er(e)?e(t):e??Sr}function zf(e,t){return t?e?(...o)=>{let n=o[0];if(fa(n)){let i=n;zo(i);let s=t(...o);return i.baseUIHandlerPrevented||e?.(...o),s}let r=t(...o);return e?.(...o),r}:ua(t):e}function ua(e){return e&&((...t)=>{let o=t[0];return fa(o)&&zo(o),e(...t)})}function zo(e){return e.preventBaseUIHandler=()=>{e.baseUIHandlerPrevented=!0},e}function Tr(e,t){return t?e?t+" "+e:t:e}function fa(e){return e!=null&&typeof e=="object"&&"nativeEvent"in e}var kr=h(z(),1);function Ce(e,t,o={}){let n=t.render,r=Df(t,o);if(o.enabled===!1)return null;let i=o.state??be;return Vf(e,n,r,i)}function Df(e,t={}){let{className:o,style:n,render:r}=e,{state:i=be,ref:s,props:a,stateAttributesMapping:d,enabled:c=!0}=t,l=c?sa(o,i):void 0,f=c?aa(n,i):void 0,p=c?ia(i,d):be,m=c&&a?jf(a):void 0,u=c?Bo(p,m)??{}:be;return typeof document<"u"&&(c?Array.isArray(s)?u.ref=ea([u.ref,Rr(r),...s]):u.ref=xr(u.ref,Rr(r),s):xr(null,null)),c?(l!==void 0&&(u.className=Tr(u.className,l)),f!==void 0&&(u.style=Bo(u.style,f)),u):be}function jf(e){return Array.isArray(e)?ca(e):ye(void 0,e)}var Ff=Symbol.for("react.lazy");function Vf(e,t,o,n){if(t){if(typeof t=="function")return t(o,n);let r=ye(o,t.props);r.ref=o.ref;let i=t;return i?.$$typeof===Ff&&(i=Wt.Children.toArray(t)[0]),Wt.cloneElement(i,r)}if(e&&typeof e=="string")return Wf(e,o);throw new Error(Pe(8))}function Wf(e,t){return e==="button"?(0,kr.createElement)("button",{type:"button",...t,key:t.key}):e==="img"?(0,kr.createElement)("img",{alt:"",...t,key:t.key}):Wt.createElement(e,t)}var vn=h(z(),1);var pa=0;function Yf(e,t="mui"){let[o,n]=vn.useState(e),r=e||o;return vn.useEffect(()=>{o==null&&(pa+=1,n(`${t}-${pa}`))},[o,t]),r}var ma=Mo.useId;function Lt(e,t){if(ma!==void 0){let o=ma();return e??(t?`${t}-${o}`:o)}return Yf(e,t)}function ga(e){return Lt(e,"base-ui")}var U={};At(U,{cancelOpen:()=>wp,chipRemovePress:()=>ep,clearPress:()=>$f,closePress:()=>Qf,closeWatcher:()=>up,decrementPress:()=>np,disabled:()=>_p,drag:()=>gp,escapeKey:()=>dp,focusOut:()=>lp,imperativeAction:()=>Rp,incrementPress:()=>op,initial:()=>xp,inputBlur:()=>sp,inputChange:()=>rp,inputClear:()=>ip,inputPaste:()=>ap,inputPress:()=>cp,itemPress:()=>Zf,keyboard:()=>pp,linkPress:()=>Jf,listNavigation:()=>fp,missing:()=>yp,none:()=>Uf,outsidePress:()=>qf,pointer:()=>mp,scrub:()=>hp,siblingOpen:()=>vp,swipe:()=>Sp,trackPress:()=>tp,triggerFocus:()=>Kf,triggerHover:()=>Xf,triggerPress:()=>Gf,wheel:()=>bp,windowResize:()=>Ep});var Uf="none",Gf="trigger-press",Xf="trigger-hover",Kf="trigger-focus",qf="outside-press",Zf="item-press",Qf="close-press",Jf="link-press",$f="clear-press",ep="chip-remove-press",tp="track-press",op="increment-press",np="decrement-press",rp="input-change",ip="input-clear",sp="input-blur",ap="input-paste",cp="input-press",lp="focus-out",dp="escape-key",up="close-watcher",fp="list-navigation",pp="keyboard",mp="pointer",gp="drag",bp="wheel",hp="scrub",wp="cancel-open",vp="sibling-open",_p="disabled",yp="missing",xp="initial",Rp="imperative-action",Sp="swipe",Ep="window-resize";function ee(e,t,o,n){let r=!1,i=!1,s=n??be;return{reason:e,event:t??new Event("base-ui"),cancel(){r=!0},allowPropagation(){i=!0},get isCanceled(){return r},get isPropagationAllowed(){return i},trigger:o,...s}}var Cr=h(z(),1);var ba=h(z(),1),Tp=[];function co(e){ba.useEffect(e,Tp)}var _n=null,ah=globalThis.requestAnimationFrame,Pr=class{callbacks=[];callbacksCount=0;nextId=1;startId=1;isScheduled=!1;tick=t=>{this.isScheduled=!1;let o=this.callbacks,n=this.callbacksCount;if(this.callbacks=[],this.callbacksCount=0,this.startId=this.nextId,n>0)for(let r=0;r=this.callbacks.length||(this.callbacks[o]=null,this.callbacksCount-=1)}},yn=new Pr,ft=class e{static create(){return new e}static request(t){return yn.request(t)}static cancel(t){return yn.cancel(t)}currentId=_n;request(t){this.cancel(),this.currentId=yn.request(()=>{this.currentId=_n,t()})}cancel=()=>{this.currentId!==_n&&(yn.cancel(this.currentId),this.currentId=_n)};disposeEffect=()=>this.cancel};function lo(){let e=Se(ft.create).current;return co(e.disposeEffect),e}function ha(e,t=!1,o=!1){let[n,r]=Cr.useState(e&&t?"idle":void 0),[i,s]=Cr.useState(e);return e&&!i&&(s(!0),r("starting")),!e&&i&&n!=="ending"&&!o&&r("ending"),!e&&!i&&n==="ending"&&r(void 0),D(()=>{if(!e&&i&&n!=="ending"&&o){let a=ft.request(()=>{r("ending")});return()=>{ft.cancel(a)}}},[e,i,n,o]),D(()=>{if(!e||t)return;let a=ft.request(()=>{r(void 0)});return()=>{ft.cancel(a)}},[t,e]),D(()=>{if(!e||!t)return;e&&i&&n!=="idle"&&r("starting");let a=ft.request(()=>{r("idle")});return()=>{ft.cancel(a)}},[t,e,i,n]),{mounted:i,setMounted:s,transitionStatus:n}}var Yt=(function(e){return e.startingStyle="data-starting-style",e.endingStyle="data-ending-style",e})({}),kp={[Yt.startingStyle]:""},Pp={[Yt.endingStyle]:""},wa={transitionStatus(e){return e==="starting"?kp:e==="ending"?Pp:null}};var po=h(z(),1);function xn(){return typeof window<"u"}function Gt(e){return Rn(e)?(e.nodeName||"").toLowerCase():"#document"}function ge(e){var t;return(e==null||(t=e.ownerDocument)==null?void 0:t.defaultView)||window}function ot(e){var t;return(t=(Rn(e)?e.ownerDocument:e.document)||window.document)==null?void 0:t.documentElement}function Rn(e){return xn()?e instanceof Node||e instanceof ge(e).Node:!1}function V(e){return xn()?e instanceof Element||e instanceof ge(e).Element:!1}function we(e){return xn()?e instanceof HTMLElement||e instanceof ge(e).HTMLElement:!1}function uo(e){return!xn()||typeof ShadowRoot>"u"?!1:e instanceof ShadowRoot||e instanceof ge(e).ShadowRoot}function fo(e){let{overflow:t,overflowX:o,overflowY:n,display:r}=Ae(e);return/auto|scroll|overlay|hidden|clip/.test(t+n+o)&&r!=="inline"&&r!=="contents"}function va(e){return/^(table|td|th)$/.test(Gt(e))}function Do(e){try{if(e.matches(":popover-open"))return!0}catch{}try{return e.matches(":modal")}catch{return!1}}var Cp=/transform|translate|scale|rotate|perspective|filter/,Ap=/paint|layout|strict|content/,Ut=e=>!!e&&e!=="none",Ar;function Sn(e){let t=V(e)?Ae(e):e;return Ut(t.transform)||Ut(t.translate)||Ut(t.scale)||Ut(t.rotate)||Ut(t.perspective)||!En()&&(Ut(t.backdropFilter)||Ut(t.filter))||Cp.test(t.willChange||"")||Ap.test(t.contain||"")}function _a(e){let t=tt(e);for(;we(t)&&!nt(t);){if(Sn(t))return t;if(Do(t))return null;t=tt(t)}return null}function En(){return Ar==null&&(Ar=typeof CSS<"u"&&CSS.supports&&CSS.supports("-webkit-backdrop-filter","none")),Ar}function nt(e){return/^(html|body|#document)$/.test(Gt(e))}function Ae(e){return ge(e).getComputedStyle(e)}function jo(e){return V(e)?{scrollLeft:e.scrollLeft,scrollTop:e.scrollTop}:{scrollLeft:e.scrollX,scrollTop:e.scrollY}}function tt(e){if(Gt(e)==="html")return e;let t=e.assignedSlot||e.parentNode||uo(e)&&e.host||ot(e);return uo(t)?t.host:t}function ya(e){let t=tt(e);return nt(t)?e.ownerDocument?e.ownerDocument.body:e.body:we(t)&&fo(t)?t:ya(t)}function It(e,t,o){var n;t===void 0&&(t=[]),o===void 0&&(o=!0);let r=ya(e),i=r===((n=e.ownerDocument)==null?void 0:n.body),s=ge(r);if(i){let a=Tn(s);return t.concat(s,s.visualViewport||[],fo(r)?r:[],a&&o?It(a):[])}else return t.concat(r,It(r,[],o))}function Tn(e){return e.parent&&Object.getPrototypeOf(e.parent)?e.frameElement:null}var kn=h(z(),1),Op=kn.createContext(void 0);function xa(e=!1){let t=kn.useContext(Op);if(t===void 0&&!e)throw new Error(Pe(16));return t}var Ra=h(z(),1);function Sa(e){let{focusableWhenDisabled:t,disabled:o,composite:n=!1,tabIndex:r=0,isNativeButton:i}=e,s=n&&t!==!1,a=n&&t===!1;return{props:Ra.useMemo(()=>{let c={onKeyDown(l){o&&t&&l.key!=="Tab"&&l.preventDefault()}};return n||(c.tabIndex=r,!i&&o&&(c.tabIndex=t?r:-1)),(i&&(t||s)||!i&&o)&&(c["aria-disabled"]=o),i&&(!t||a)&&(c.disabled=o),c},[n,o,t,s,a,i,r])}}function Ea(e={}){let{disabled:t=!1,focusableWhenDisabled:o,tabIndex:n=0,native:r=!0,composite:i}=e,s=po.useRef(null),a=xa(!0),d=i??a!==void 0,{props:c}=Sa({focusableWhenDisabled:o,disabled:t,composite:d,tabIndex:n,isNativeButton:r}),l=po.useCallback(()=>{let m=s.current;Or(m)&&d&&t&&c.disabled===void 0&&m.disabled&&(m.disabled=!1)},[t,c.disabled,d]);D(l,[l]);let f=po.useCallback((m={})=>{let{onClick:u,onMouseDown:g,onKeyUp:v,onKeyDown:_,onPointerDown:w,...y}=m;return ye({onClick(b){if(t){b.preventDefault();return}u?.(b)},onMouseDown(b){t||g?.(b)},onKeyDown(b){if(t||(zo(b),_?.(b),b.baseUIHandlerPrevented))return;let S=b.target===b.currentTarget,x=b.currentTarget,E=Or(x),T=!r&&Np(x),k=S&&(r?E:!T),C=b.key==="Enter",j=b.key===" ",A=x.getAttribute("role"),L=A?.startsWith("menuitem")||A==="option"||A==="gridcell";if(S&&d&&j){if(b.defaultPrevented&&L)return;b.preventDefault(),T||r&&E?(x.click(),b.preventBaseUIHandler()):k&&(u?.(b),b.preventBaseUIHandler());return}k&&(!r&&(j||C)&&b.preventDefault(),!r&&C&&u?.(b))},onKeyUp(b){if(!t){if(zo(b),v?.(b),b.target===b.currentTarget&&r&&d&&Or(b.currentTarget)&&b.key===" "){b.preventDefault();return}b.baseUIHandlerPrevented||b.target===b.currentTarget&&!r&&!d&&b.key===" "&&u?.(b)}},onPointerDown(b){if(t){b.preventDefault();return}w?.(b)}},r?{type:"button"}:{role:"button"},c,y)},[t,c,d,r]),p=Y(m=>{s.current=m,l()});return{getButtonProps:f,buttonRef:p}}function Or(e){return we(e)&&e.tagName==="BUTTON"}function Np(e){return!!(e?.tagName==="A"&&e?.href)}function re(e,t,o,n){return e.addEventListener(t,o,n),()=>{e.removeEventListener(t,o,n)}}function ze(e){let t=Se(Lp,e).current;return t.next=e,D(t.effect),t}function Lp(e){let t={current:e,next:e,effect:()=>{t.current=t.next}};return t}function xe(e){return e?.ownerDocument||document}var Ca=h(z(),1);var Pa=h(Mt(),1);function ka(e){return e==null?e:"current"in e?e.current:e}function mo(e,t=!1,o=!0){let n=lo();return Y((r,i=null)=>{n.cancel();let s=ka(e);if(s==null)return;let a=s,d=()=>{Pa.flushSync(r)};if(typeof a.getAnimations!="function"||globalThis.BASE_UI_ANIMATIONS_DISABLED){r();return}function c(){Promise.all(a.getAnimations().map(l=>l.finished)).then(()=>{i?.aborted||d()}).catch(()=>{if(o){i?.aborted||d();return}let l=a.getAnimations();!i?.aborted&&l.length>0&&l.some(f=>f.pending||f.playState!=="finished")&&c()})}if(t){let l=Yt.startingStyle;if(!a.hasAttribute(l)){n.request(c);return}let f=new MutationObserver(()=>{a.hasAttribute(l)||(f.disconnect(),c())});f.observe(a,{attributes:!0,attributeFilter:[l]}),i?.addEventListener("abort",()=>f.disconnect(),{once:!0});return}n.request(c)})}function Pn(e){let{enabled:t=!0,open:o,ref:n,onComplete:r}=e,i=Y(r),s=mo(n,o,!1);Ca.useEffect(()=>{if(!t)return;let a=new AbortController;return s(i,a.signal),()=>{a.abort()}},[t,o,i,s])}var Aa=h(z(),1);function Oa(e){let t=Aa.useRef(!0);t.current&&(t.current=!1,e())}var xt={};At(xt,{engine:()=>Br,env:()=>zr,os:()=>Ir,screenReader:()=>Hr});var Ir={};At(Ir,{android:()=>Ia,apple:()=>Lr,ios:()=>Nr,linux:()=>zp,mac:()=>Ma,windows:()=>Hp});function Ip(){return typeof navigator>"u"?{userAgent:"",platform:"",maxTouchPoints:0}:{userAgent:navigator.userAgent,platform:navigator.platform??"",maxTouchPoints:navigator.maxTouchPoints??0}}var{userAgent:Mp,platform:Bp,maxTouchPoints:Na}=Ip(),Xt=Mp.toLowerCase(),Kt=Bp.toLowerCase();var Nr=/^i(os$|p)/.test(Kt)||Kt==="macintel"&&Na>1,La="android",Ia=Kt===La||Xt.includes(La),Ma=!Nr&&Kt.startsWith("mac"),Hp=Kt.startsWith("win"),zp=!Ia&&/^(linux|chrome os)/.test(Kt),Lr=Ma||Nr;var Br={};At(Br,{blink:()=>jp,gecko:()=>Dp,webkit:()=>Mr});var Mr=typeof CSS<"u"&&!!CSS.supports?.("-webkit-backdrop-filter:none"),Dp=!Mr&&Xt.includes("firefox"),jp=!Mr&&Xt.includes("chrom");var Hr={};At(Hr,{voiceOver:()=>Fp});var Fp=Lr;var zr={};At(zr,{jsdom:()=>Vp});var Vp=/jsdom|happydom/.test(Xt);var Fo=0,Ye=class e{static create(){return new e}currentId=Fo;start(t,o){this.clear(),this.currentId=setTimeout(()=>{this.currentId=Fo,o()},t)}isStarted(){return this.currentId!==Fo}clear=()=>{this.currentId!==Fo&&(clearTimeout(this.currentId),this.currentId=Fo)};disposeEffect=()=>this.clear};function rt(){let e=Se(Ye.create).current;return co(e.disposeEffect),e}var Oe=h(z(),1);function Ba(e){return"nativeEvent"in e}function Rt(e,t){let o=["mouse","pen"];return t||o.push("",void 0),o.includes(e)}function Ha(e){let t=e.type;return t==="click"||t==="mousedown"||t==="keydown"||t==="keyup"}var Dr="data-base-ui-focusable";var jr="input:not([type='hidden']):not([disabled]),[contenteditable]:not([contenteditable='false']),textarea:not([disabled])";function Cn(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}function ie(e,t){if(!e||!t)return!1;let o=t.getRootNode?.();if(e.contains(t))return!0;if(o&&uo(o)){let n=t;for(;n;){if(e===n)return!0;n=n.parentNode||n.host}}return!1}function Me(e){return"composedPath"in e?e.composedPath()[0]:e.target}function Bt(e,t){if(!V(e))return!1;let o=e;if(t.hasElement(o))return!o.hasAttribute("data-trigger-disabled");for(let[,n]of t.entries())if(ie(n,o))return!n.hasAttribute("data-trigger-disabled");return!1}function An(e,t){if(t==null)return!1;if("composedPath"in e)return e.composedPath().includes(t);let o=e;return o.target!=null&&t.contains(o.target)}function za(e){return e.matches("html,body")}function Da(e){return we(e)&&e.matches(jr)}function Fr(e){return e?.closest(`button,a[href],[role="button"],select,[tabindex]:not([tabindex="-1"]),${jr}`)!=null}function ja(e){if(!e||xt.env.jsdom)return!0;try{return e.matches(":focus-visible")}catch{return!0}}function Wp(e,t){return t!=null&&!Rt(t)?0:typeof e=="function"?e():e}function St(e,t,o){let n=Wp(e,o);return typeof n=="number"?n:n?.[t]}function Vr(e){return typeof e=="function"?e():e}function On(e,t){return t||e==="click"||e==="mousedown"}function Fa(e){return e?.includes("mouse")&&e!=="mousedown"}var Va=h(Q(),1),Wa=Oe.createContext({hasProvider:!1,timeoutMs:0,delayRef:{current:0},initialDelayRef:{current:0},timeout:new Ye,currentIdRef:{current:null},currentContextRef:{current:null}});function Yp(e,t){e.current=t.current}function Wr(e){let{children:t,delay:o,timeoutMs:n=0}=e,r=Oe.useRef(o),i=Oe.useRef(o),s=Oe.useRef(null),a=Oe.useRef(null),d=rt();return D(()=>{if(i.current=o,!s.current){r.current=o;return}r.current={open:St(r.current,"open"),close:St(o,"close")}},[o,s,r,i]),(0,Va.jsx)(Wa.Provider,{value:Oe.useMemo(()=>({hasProvider:!0,delayRef:r,initialDelayRef:i,currentIdRef:s,timeoutMs:n,currentContextRef:a,timeout:d}),[n,d]),children:t})}function Yr(e,t={open:!1}){let{open:o}=t,n="rootStore"in e?e.rootStore:e,r=n.useState("floatingId"),i=Oe.useContext(Wa),{currentIdRef:s,delayRef:a,timeoutMs:d,initialDelayRef:c,currentContextRef:l,hasProvider:f,timeout:p}=i,[m,u]=Oe.useState(!1),g=Oe.useRef(o),v=Oe.useRef(!1);return D(()=>{g.current=o},[o]),D(()=>()=>{v.current=!0},[]),D(()=>{function _(){v.current||u(!1),l.current?.setIsInstantPhase(!1),s.current=null,l.current=null,a.current=c.current,p.clear()}if(s.current&&!o&&s.current===r){if(u(!1),d){let w=r;return p.start(d,()=>{n.select("open")||s.current&&s.current!==w||_()}),()=>{(g.current||s.current!==w)&&p.clear()}}_()}},[o,r,s,a,d,c,l,p,n]),D(()=>{if(!o)return;let _=l.current,w=s.current;p.clear(),l.current={onOpenChange:n.setOpen,setIsInstantPhase:u},s.current=r,a.current={open:0,close:St(c.current,"close")},w!==null&&w!==r?(u(!0),_?.setIsInstantPhase(!0),_?.onOpenChange(!1,ee(U.none))):(u(!1),_?.setIsInstantPhase(!1))},[o,r,n,s,a,c,l,p]),D(()=>()=>{if(s.current===r){if(l.current=null,!g.current)return;s.current=null,Yp(a,c),p.clear()}},[l,s,a,r,c,p]),Oe.useMemo(()=>({hasProvider:f,delayRef:a,isInstantPhase:m}),[f,a,m])}function it(...e){return()=>{for(let t=0;t({x:e,y:e}),Up={left:"right",right:"left",bottom:"top",top:"bottom"};function Yo(e,t,o){return Be(e,Ht(t,o))}function at(e,t){return typeof e=="function"?e(t):e}function Ee(e){return e.split("-")[0]}function ct(e){return e.split("-")[1]}function Ln(e){return e==="x"?"y":"x"}function Uo(e){return e==="y"?"height":"width"}function De(e){let t=e[0];return t==="t"||t==="b"?"y":"x"}function Go(e){return Ln(De(e))}function Xa(e,t,o){o===void 0&&(o=!1);let n=ct(e),r=Go(e),i=Uo(r),s=r==="x"?n===(o?"end":"start")?"right":"left":n==="start"?"bottom":"top";return t.reference[i]>t.floating[i]&&(s=Vo(s)),[s,Vo(s)]}function Ka(e){let t=Vo(e);return[Nn(e),t,Nn(t)]}function Nn(e){return e.includes("start")?e.replace("start","end"):e.replace("end","start")}var Ya=["left","right"],Ua=["right","left"],Gp=["top","bottom"],Xp=["bottom","top"];function Kp(e,t,o){switch(e){case"top":case"bottom":return o?t?Ua:Ya:t?Ya:Ua;case"left":case"right":return t?Gp:Xp;default:return[]}}function qa(e,t,o,n){let r=ct(e),i=Kp(Ee(e),o==="start",n);return r&&(i=i.map(s=>s+"-"+r),t&&(i=i.concat(i.map(Nn)))),i}function Vo(e){let t=Ee(e);return Up[t]+e.slice(t.length)}function qp(e){return{top:0,right:0,bottom:0,left:0,...e}}function In(e){return typeof e!="number"?qp(e):{top:e,right:e,bottom:e,left:e}}function qt(e){let{x:t,y:o,width:n,height:r}=e;return{width:n,height:r,top:o,left:t,right:t+n,bottom:o+r,x:t,y:o}}function Et(e,t,o=!0){return e.filter(r=>r.parentId===t).flatMap(r=>[...!o||r.context?.open?[r]:[],...Et(e,r.id,o)])}function go(e){return`data-base-ui-${e}`}var Ue=h(z(),1),Ja=h(Mt(),1);var Za={style:{transition:"none"}};var Zp="data-base-ui-swipe-ignore",Qp="data-swipe-ignore",ww=`[${Zp}]`,vw=`[${Qp}]`;var Qa={fallbackAxisSide:"end"};var $a=h(Q(),1),Jp=Ue.createContext(null),$p=()=>Ue.useContext(Jp),em=go("portal");function Ur(e={}){let{ref:t,container:o,componentProps:n=be,elementProps:r}=e,i=Lt(),a=$p()?.portalNode,[d,c]=Ue.useState(null),[l,f]=Ue.useState(null),p=Y(v=>{v!==null&&f(v)}),m=Ue.useRef(null);D(()=>{if(o===null){m.current&&(m.current=null,f(null),c(null));return}if(i==null)return;let v=(o&&(Rn(o)?o:o.current))??a??document.body;if(v==null){m.current&&(m.current=null,f(null),c(null));return}m.current!==v&&(m.current=v,f(null),c(v))},[o,a,i]);let u=Ce("div",n,{ref:[t,p],props:[{id:i,[em]:""},r]});return{portalNode:l,portalSubtree:d&&u?Ja.createPortal(u,d):null}}var Zt=h(z(),1);function ec(){let e=new Map;return{emit(t,o){e.get(t)?.forEach(n=>n(o))},on(t,o){e.has(t)||e.set(t,new Set),e.get(t).add(o)},off(t,o){e.get(t)?.delete(o)}}}var tm=h(Q(),1),om=Zt.createContext(null),nm=Zt.createContext(null),bo=()=>Zt.useContext(om)?.id||null,Dt=e=>{let t=Zt.useContext(nm);return e??t};var je=h(z(),1);function rm(e,t){let o=null,n=null,r=!1;return{contextElement:e||void 0,getBoundingClientRect(){let i=e?.getBoundingClientRect()||{width:0,height:0,x:0,y:0},s=t.axis==="x"||t.axis==="both",a=t.axis==="y"||t.axis==="both",d=["mouseenter","mousemove"].includes(t.dataRef.current.openEvent?.type||"")&&t.pointerType!=="touch",c=i.width,l=i.height,f=i.x,p=i.y;return o==null&&t.x&&s&&(o=i.x-t.x),n==null&&t.y&&a&&(n=i.y-t.y),f-=o||0,p-=n||0,c=0,l=0,!r||d?(c=t.axis==="y"?i.width:0,l=t.axis==="x"?i.height:0,f=s&&t.x!=null?t.x:f,p=a&&t.y!=null?t.y:p):r&&!d&&(l=t.axis==="x"?i.height:l,c=t.axis==="y"?i.width:c),r=!0,{width:c,height:l,x:f,y:p,top:p,right:f+c,bottom:p+l,left:f}}}}function tc(e){return e!=null&&e.clientX!=null}function Gr(e,t={}){let{enabled:o=!0,axis:n="both"}=t,r="rootStore"in e?e.rootStore:e,i=r.useState("open"),s=r.useState("floatingElement"),a=r.useState("domReferenceElement"),d=r.context.dataRef,c=je.useRef(!1),l=je.useRef(null),[f,p]=je.useState(),[m,u]=je.useState([]),g=Y(b=>{r.set("positionReference",b)}),v=Y((b,S,x)=>{c.current||d.current.openEvent&&!tc(d.current.openEvent)||r.set("positionReference",rm(x??a,{x:b,y:S,axis:n,dataRef:d,pointerType:f}))}),_=Y(b=>{i?l.current||(v(b.clientX,b.clientY,b.currentTarget),u([])):v(b.clientX,b.clientY,b.currentTarget)}),w=Rt(f)?s:i;je.useEffect(()=>{if(!o){g(a);return}if(!w)return;function b(){l.current?.(),l.current=null}let S=ge(s);function x(E){let T=Me(E);ie(s,T)?b():v(E.clientX,E.clientY)}return!d.current.openEvent||tc(d.current.openEvent)?l.current=re(S,"mousemove",x):g(a),b},[w,o,s,d,a,r,v,g,m]),je.useEffect(()=>()=>{r.set("positionReference",null)},[r]),je.useEffect(()=>{o&&!s&&(c.current=!1)},[o,s]),je.useEffect(()=>{!o&&i&&(c.current=!0)},[o,i]);let y=je.useMemo(()=>{function b(S){p(S.pointerType)}return{onPointerDown:b,onPointerEnter:b,onMouseMove:_,onMouseEnter:_}},[_]);return je.useMemo(()=>o?{reference:y,trigger:y}:{},[o,y])}var Fe=h(z(),1);function im(){return!1}function sm(e){return{escapeKey:typeof e=="boolean"?e:e?.escapeKey??!1,outsidePress:typeof e=="boolean"?e:e?.outsidePress??!0}}function Xr(e,t={}){let{enabled:o=!0,escapeKey:n=!0,outsidePress:r=!0,outsidePressEvent:i="sloppy",referencePress:s=im,bubbles:a,externalTree:d}=t,c="rootStore"in e?e.rootStore:e,l=c.useState("open"),f=c.useState("floatingElement"),{dataRef:p}=c.context,m=Dt(d),u=Y(typeof r=="function"?r:()=>!1),g=typeof r=="function"?u:r,v=g!==!1,_=Y(()=>i),{escapeKey:w,outsidePress:y}=sm(a),b=Fe.useRef(!1),S=Fe.useRef(!1),x=Fe.useRef(!1),E=Fe.useRef(!1),T=Fe.useRef(""),k=Fe.useRef(null),C=rt(),j=rt(),A=Y(()=>{j.clear(),p.current.insideReactTree=!1}),L=Y(W=>{let oe=p.current.floatingContext?.nodeId;return(m?Et(m.nodesRef.current,oe):[]).some(se=>se.context?.open&&!se.context.dataRef.current[W])}),I=Y(W=>An(W,c.select("floatingElement"))||An(W,c.select("domReferenceElement"))),R=Y(W=>{s()&&c.setOpen(!1,ee(U.triggerPress,W.nativeEvent))}),N=Y(W=>{if(!l||!o||!n||W.key!=="Escape"||E.current||!w&&L("__escapeKeyBubbles"))return;let oe=Ba(W)?W.nativeEvent:W,te=ee(U.escapeKey,oe);c.setOpen(!1,te),te.isCanceled||W.preventDefault(),!w&&!te.isPropagationAllowed&&W.stopPropagation()}),H=Y(()=>{p.current.insideReactTree=!0,j.start(0,A)}),P=Y(W=>{if(!l||!o||W.button!==0)return;let oe=Me(W.nativeEvent);ie(c.select("floatingElement"),oe)&&(b.current||(b.current=!0,S.current=!1))}),O=Y(W=>{!l||!o||(W.defaultPrevented||W.nativeEvent.defaultPrevented)&&b.current&&(S.current=!0)});Fe.useEffect(()=>{if(!l||!o)return;p.current.__escapeKeyBubbles=w,p.current.__outsidePressBubbles=y;let W=new Ye,oe=new Ye;function te(){W.clear(),E.current=!0}function se(){W.start(xt.engine.webkit?5:0,()=>{E.current=!1})}function G(){x.current=!0,oe.start(0,()=>{x.current=!1})}function K(){b.current=!1,S.current=!1}function J(){let B=T.current,F=B==="pen"||!B?"mouse":B,he=_(),ke=typeof he=="function"?he():he;return typeof ke=="string"?ke:ke[F]}function ne(B){let F=J();return F==="intentional"&&B.type!=="click"||F==="sloppy"&&B.type==="click"}function me(B){let F=p.current.floatingContext?.nodeId,he=m&&Et(m.nodesRef.current,F).some(ke=>An(B,ke.context?.elements.floating));return I(B)||he}function le(B){if(ne(B)){B.type!=="click"&&!I(B)&&(oe.clear(),x.current=!1),A();return}if(p.current.insideReactTree){A();return}let F=Me(B),he=`[${go("inert")}]`,ke=V(F)?F.getRootNode():null,kt=Array.from((uo(ke)?ke:xe(c.select("floatingElement"))).querySelectorAll(he)),Lo=c.context.triggerElements;if(F&&(Lo.hasElement(F)||Lo.hasMatchingElement(We=>ie(We,F))))return;let _t=V(F)?F:null;for(;_t&&!nt(_t);){let We=tt(_t);if(nt(We)||!V(We))break;_t=We}if(!(kt.length&&V(F)&&!za(F)&&!ie(F,c.select("floatingElement"))&&kt.every(We=>!ie(_t,We)))){if(we(F)&&!("touches"in B)){let We=nt(F),Pt=Ae(F),Ct=/auto|scroll/,un=We||Ct.test(Pt.overflowX),fn=We||Ct.test(Pt.overflowY),pn=un&&F.clientWidth>0&&F.scrollWidth>F.clientWidth,mn=fn&&F.clientHeight>0&&F.scrollHeight>F.clientHeight,gn=Pt.direction==="rtl",ae=mn&&(gn?B.offsetX<=F.offsetWidth-F.clientWidth:B.offsetX>F.clientWidth),Ie=pn&&B.offsetY>F.clientHeight;if(ae||Ie)return}if(!me(B)){if(J()==="intentional"&&x.current){oe.clear(),x.current=!1;return}typeof g=="function"&&!g(B)||L("__outsidePressBubbles")||(c.setOpen(!1,ee(U.outsidePress,B)),A())}}}function X(B){J()!=="sloppy"||B.pointerType==="touch"||!c.select("open")||!o||I(B)||le(B)}function pe(B){if(J()!=="sloppy"||!c.select("open")||!o||I(B))return;let F=B.touches[0];F&&(k.current={startTime:Date.now(),startX:F.clientX,startY:F.clientY,dismissOnTouchEnd:!1,dismissOnMouseDown:!0},C.start(1e3,()=>{k.current&&(k.current.dismissOnTouchEnd=!1,k.current.dismissOnMouseDown=!1)}))}function ue(B,F){let he=Me(B);if(!he)return;let ke=re(he,B.type,()=>{F(B),ke()})}function vt(B){T.current="touch",ue(B,pe)}function Te(B){C.clear(),B.type==="pointerdown"&&(T.current=B.pointerType),!(B.type==="mousedown"&&k.current&&!k.current.dismissOnMouseDown)&&ue(B,F=>{F.type==="pointerdown"?X(F):le(F)})}function Ve(B){if(!b.current)return;let F=S.current;if(K(),J()==="intentional"){if(B.type==="pointercancel"){F&&G();return}if(!me(B)){if(F){G();return}typeof g=="function"&&!g(B)||(oe.clear(),x.current=!0,A())}}}function Ke(B){if(J()!=="sloppy"||!k.current||I(B))return;let F=B.touches[0];if(!F)return;let he=Math.abs(F.clientX-k.current.startX),ke=Math.abs(F.clientY-k.current.startY),kt=Math.sqrt(he*he+ke*ke);kt>5&&(k.current.dismissOnTouchEnd=!0),kt>10&&(le(B),C.clear(),k.current=null)}function He(B){ue(B,Ke)}function no(B){J()!=="sloppy"||!k.current||I(B)||(k.current.dismissOnTouchEnd&&le(B),C.clear(),k.current=null)}function dn(B){ue(B,no)}let _e=xe(f),ro=it(n&&it(re(_e,"keydown",N),re(_e,"compositionstart",te),re(_e,"compositionend",se)),v&&it(re(_e,"click",Te,!0),re(_e,"pointerdown",Te,!0),re(_e,"pointerup",Ve,!0),re(_e,"pointercancel",Ve,!0),re(_e,"mousedown",Te,!0),re(_e,"mouseup",Ve,!0),re(_e,"touchstart",vt,!0),re(_e,"touchmove",He,!0),re(_e,"touchend",dn,!0)));return()=>{ro(),W.clear(),oe.clear(),K(),x.current=!1}},[p,f,n,v,g,l,o,w,y,N,A,_,L,I,m,c,C]),Fe.useEffect(A,[g,A]);let M=Fe.useMemo(()=>({onKeyDown:N,onPointerDown:R,onClick:R}),[N,R]),Z=Fe.useMemo(()=>({onKeyDown:N,onPointerDown:O,onMouseDown:O,onClickCapture:H,onMouseDownCapture(W){H(),P(W)},onPointerDownCapture(W){H(),P(W)},onMouseUpCapture:H,onTouchEndCapture:H,onTouchMoveCapture:H}),[N,H,P,O]);return Fe.useMemo(()=>o?{reference:M,floating:Z,trigger:M}:{},[o,M,Z])}var Ne=h(z(),1);function oc(e,t,o){let{reference:n,floating:r}=e,i=De(t),s=Go(t),a=Uo(s),d=Ee(t),c=i==="y",l=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2,p=n[a]/2-r[a]/2,m;switch(d){case"top":m={x:l,y:n.y-r.height};break;case"bottom":m={x:l,y:n.y+n.height};break;case"right":m={x:n.x+n.width,y:f};break;case"left":m={x:n.x-r.width,y:f};break;default:m={x:n.x,y:n.y}}switch(ct(t)){case"start":m[s]-=p*(o&&c?-1:1);break;case"end":m[s]+=p*(o&&c?-1:1);break}return m}async function ic(e,t){var o;t===void 0&&(t={});let{x:n,y:r,platform:i,rects:s,elements:a,strategy:d}=e,{boundary:c="clippingAncestors",rootBoundary:l="viewport",elementContext:f="floating",altBoundary:p=!1,padding:m=0}=at(t,e),u=In(m),v=a[p?f==="floating"?"reference":"floating":f],_=qt(await i.getClippingRect({element:(o=await(i.isElement==null?void 0:i.isElement(v)))==null||o?v:v.contextElement||await(i.getDocumentElement==null?void 0:i.getDocumentElement(a.floating)),boundary:c,rootBoundary:l,strategy:d})),w=f==="floating"?{x:n,y:r,width:s.floating.width,height:s.floating.height}:s.reference,y=await(i.getOffsetParent==null?void 0:i.getOffsetParent(a.floating)),b=await(i.isElement==null?void 0:i.isElement(y))?await(i.getScale==null?void 0:i.getScale(y))||{x:1,y:1}:{x:1,y:1},S=qt(i.convertOffsetParentRelativeRectToViewportRelativeRect?await i.convertOffsetParentRelativeRectToViewportRelativeRect({elements:a,rect:w,offsetParent:y,strategy:d}):w);return{top:(_.top-S.top+u.top)/b.y,bottom:(S.bottom-_.bottom+u.bottom)/b.y,left:(_.left-S.left+u.left)/b.x,right:(S.right-_.right+u.right)/b.x}}var am=50,sc=async(e,t,o)=>{let{placement:n="bottom",strategy:r="absolute",middleware:i=[],platform:s}=o,a=s.detectOverflow?s:{...s,detectOverflow:ic},d=await(s.isRTL==null?void 0:s.isRTL(t)),c=await s.getElementRects({reference:e,floating:t,strategy:r}),{x:l,y:f}=oc(c,n,d),p=n,m=0,u={};for(let g=0;gI<=0)){var j,A;let I=(((j=i.flip)==null?void 0:j.index)||0)+1,R=E[I];if(R&&(!(f==="alignment"?w!==De(R):!1)||C.every(P=>De(P.placement)===w?P.overflows[0]>0:!0)))return{data:{index:I,overflows:C},reset:{placement:R}};let N=(A=C.filter(H=>H.overflows[0]<=0).sort((H,P)=>H.overflows[1]-P.overflows[1])[0])==null?void 0:A.placement;if(!N)switch(m){case"bestFit":{var L;let H=(L=C.filter(P=>{if(x){let O=De(P.placement);return O===w||O==="y"}return!0}).map(P=>[P.placement,P.overflows.filter(O=>O>0).reduce((O,M)=>O+M,0)]).sort((P,O)=>P[1]-O[1])[0])==null?void 0:L[0];H&&(N=H);break}case"initialPlacement":N=a;break}if(r!==N)return{reset:{placement:N}}}return{}}}};function nc(e,t){return{top:e.top-t.height,right:e.right-t.width,bottom:e.bottom-t.height,left:e.left-t.width}}function rc(e){return Ga.some(t=>e[t]>=0)}var cc=function(e){return e===void 0&&(e={}),{name:"hide",options:e,async fn(t){let{rects:o,platform:n}=t,{strategy:r="referenceHidden",...i}=at(e,t);switch(r){case"referenceHidden":{let s=await n.detectOverflow(t,{...i,elementContext:"reference"}),a=nc(s,o.reference);return{data:{referenceHiddenOffsets:a,referenceHidden:rc(a)}}}case"escaped":{let s=await n.detectOverflow(t,{...i,altBoundary:!0}),a=nc(s,o.floating);return{data:{escapedOffsets:a,escaped:rc(a)}}}default:return{}}}}};var lc=new Set(["left","top"]);async function cm(e,t){let{placement:o,platform:n,elements:r}=e,i=await(n.isRTL==null?void 0:n.isRTL(r.floating)),s=Ee(o),a=ct(o),d=De(o)==="y",c=lc.has(s)?-1:1,l=i&&d?-1:1,f=at(t,e),{mainAxis:p,crossAxis:m,alignmentAxis:u}=typeof f=="number"?{mainAxis:f,crossAxis:0,alignmentAxis:null}:{mainAxis:f.mainAxis||0,crossAxis:f.crossAxis||0,alignmentAxis:f.alignmentAxis};return a&&typeof u=="number"&&(m=a==="end"?u*-1:u),d?{x:m*l,y:p*c}:{x:p*c,y:m*l}}var dc=function(e){return e===void 0&&(e=0),{name:"offset",options:e,async fn(t){var o,n;let{x:r,y:i,placement:s,middlewareData:a}=t,d=await cm(t,e);return s===((o=a.offset)==null?void 0:o.placement)&&(n=a.arrow)!=null&&n.alignmentOffset?{}:{x:r+d.x,y:i+d.y,data:{...d,placement:s}}}}},uc=function(e){return e===void 0&&(e={}),{name:"shift",options:e,async fn(t){let{x:o,y:n,placement:r,platform:i}=t,{mainAxis:s=!0,crossAxis:a=!1,limiter:d={fn:_=>{let{x:w,y}=_;return{x:w,y}}},...c}=at(e,t),l={x:o,y:n},f=await i.detectOverflow(t,c),p=De(Ee(r)),m=Ln(p),u=l[m],g=l[p];if(s){let _=m==="y"?"top":"left",w=m==="y"?"bottom":"right",y=u+f[_],b=u-f[w];u=Yo(y,u,b)}if(a){let _=p==="y"?"top":"left",w=p==="y"?"bottom":"right",y=g+f[_],b=g-f[w];g=Yo(y,g,b)}let v=d.fn({...t,[m]:u,[p]:g});return{...v,data:{x:v.x-o,y:v.y-n,enabled:{[m]:s,[p]:a}}}}}},fc=function(e){return e===void 0&&(e={}),{options:e,fn(t){let{x:o,y:n,placement:r,rects:i,middlewareData:s}=t,{offset:a=0,mainAxis:d=!0,crossAxis:c=!0}=at(e,t),l={x:o,y:n},f=De(r),p=Ln(f),m=l[p],u=l[f],g=at(a,t),v=typeof g=="number"?{mainAxis:g,crossAxis:0}:{mainAxis:0,crossAxis:0,...g};if(d){let y=p==="y"?"height":"width",b=i.reference[p]-i.floating[y]+v.mainAxis,S=i.reference[p]+i.reference[y]-v.mainAxis;mS&&(m=S)}if(c){var _,w;let y=p==="y"?"width":"height",b=lc.has(Ee(r)),S=i.reference[f]-i.floating[y]+(b&&((_=s.offset)==null?void 0:_[f])||0)+(b?0:v.crossAxis),x=i.reference[f]+i.reference[y]+(b?0:((w=s.offset)==null?void 0:w[f])||0)-(b?v.crossAxis:0);ux&&(u=x)}return{[p]:m,[f]:u}}}},pc=function(e){return e===void 0&&(e={}),{name:"size",options:e,async fn(t){var o,n;let{placement:r,rects:i,platform:s,elements:a}=t,{apply:d=()=>{},...c}=at(e,t),l=await s.detectOverflow(t,c),f=Ee(r),p=ct(r),m=De(r)==="y",{width:u,height:g}=i.floating,v,_;f==="top"||f==="bottom"?(v=f,_=p===(await(s.isRTL==null?void 0:s.isRTL(a.floating))?"start":"end")?"left":"right"):(_=f,v=p==="end"?"top":"bottom");let w=g-l.top-l.bottom,y=u-l.left-l.right,b=Ht(g-l[v],w),S=Ht(u-l[_],y),x=!t.middlewareData.shift,E=b,T=S;if((o=t.middlewareData.shift)!=null&&o.enabled.x&&(T=y),(n=t.middlewareData.shift)!=null&&n.enabled.y&&(E=w),x&&!p){let C=Be(l.left,0),j=Be(l.right,0),A=Be(l.top,0),L=Be(l.bottom,0);m?T=u-2*(C!==0||j!==0?C+j:Be(l.left,l.right)):E=g-2*(A!==0||L!==0?A+L:Be(l.top,l.bottom))}await d({...t,availableWidth:T,availableHeight:E});let k=await s.getDimensions(a.floating);return u!==k.width||g!==k.height?{reset:{rects:!0}}:{}}}};function hc(e){let t=Ae(e),o=parseFloat(t.width)||0,n=parseFloat(t.height)||0,r=we(e),i=r?e.offsetWidth:o,s=r?e.offsetHeight:n,a=zt(o)!==i||zt(n)!==s;return a&&(o=i,n=s),{width:o,height:n,$:a}}function qr(e){return V(e)?e:e.contextElement}function ho(e){let t=qr(e);if(!we(t))return st(1);let o=t.getBoundingClientRect(),{width:n,height:r,$:i}=hc(t),s=(i?zt(o.width):o.width)/n,a=(i?zt(o.height):o.height)/r;return(!s||!Number.isFinite(s))&&(s=1),(!a||!Number.isFinite(a))&&(a=1),{x:s,y:a}}var lm=st(0);function wc(e){let t=ge(e);return!En()||!t.visualViewport?lm:{x:t.visualViewport.offsetLeft,y:t.visualViewport.offsetTop}}function dm(e,t,o){return t===void 0&&(t=!1),!o||t&&o!==ge(e)?!1:t}function Qt(e,t,o,n){t===void 0&&(t=!1),o===void 0&&(o=!1);let r=e.getBoundingClientRect(),i=qr(e),s=st(1);t&&(n?V(n)&&(s=ho(n)):s=ho(e));let a=dm(i,o,n)?wc(i):st(0),d=(r.left+a.x)/s.x,c=(r.top+a.y)/s.y,l=r.width/s.x,f=r.height/s.y;if(i){let p=ge(i),m=n&&V(n)?ge(n):n,u=p,g=Tn(u);for(;g&&n&&m!==u;){let v=ho(g),_=g.getBoundingClientRect(),w=Ae(g),y=_.left+(g.clientLeft+parseFloat(w.paddingLeft))*v.x,b=_.top+(g.clientTop+parseFloat(w.paddingTop))*v.y;d*=v.x,c*=v.y,l*=v.x,f*=v.y,d+=y,c+=b,u=ge(g),g=Tn(u)}}return qt({width:l,height:f,x:d,y:c})}function Mn(e,t){let o=jo(e).scrollLeft;return t?t.left+o:Qt(ot(e)).left+o}function vc(e,t){let o=e.getBoundingClientRect(),n=o.left+t.scrollLeft-Mn(e,o),r=o.top+t.scrollTop;return{x:n,y:r}}function um(e){let{elements:t,rect:o,offsetParent:n,strategy:r}=e,i=r==="fixed",s=ot(n),a=t?Do(t.floating):!1;if(n===s||a&&i)return o;let d={scrollLeft:0,scrollTop:0},c=st(1),l=st(0),f=we(n);if((f||!f&&!i)&&((Gt(n)!=="body"||fo(s))&&(d=jo(n)),f)){let m=Qt(n);c=ho(n),l.x=m.x+n.clientLeft,l.y=m.y+n.clientTop}let p=s&&!f&&!i?vc(s,d):st(0);return{width:o.width*c.x,height:o.height*c.y,x:o.x*c.x-d.scrollLeft*c.x+l.x+p.x,y:o.y*c.y-d.scrollTop*c.y+l.y+p.y}}function fm(e){return Array.from(e.getClientRects())}function pm(e){let t=ot(e),o=jo(e),n=e.ownerDocument.body,r=Be(t.scrollWidth,t.clientWidth,n.scrollWidth,n.clientWidth),i=Be(t.scrollHeight,t.clientHeight,n.scrollHeight,n.clientHeight),s=-o.scrollLeft+Mn(e),a=-o.scrollTop;return Ae(n).direction==="rtl"&&(s+=Be(t.clientWidth,n.clientWidth)-r),{width:r,height:i,x:s,y:a}}var mc=25;function mm(e,t){let o=ge(e),n=ot(e),r=o.visualViewport,i=n.clientWidth,s=n.clientHeight,a=0,d=0;if(r){i=r.width,s=r.height;let l=En();(!l||l&&t==="fixed")&&(a=r.offsetLeft,d=r.offsetTop)}let c=Mn(n);if(c<=0){let l=n.ownerDocument,f=l.body,p=getComputedStyle(f),m=l.compatMode==="CSS1Compat"&&parseFloat(p.marginLeft)+parseFloat(p.marginRight)||0,u=Math.abs(n.clientWidth-f.clientWidth-m);u<=mc&&(i-=u)}else c<=mc&&(i+=c);return{width:i,height:s,x:a,y:d}}function gm(e,t){let o=Qt(e,!0,t==="fixed"),n=o.top+e.clientTop,r=o.left+e.clientLeft,i=we(e)?ho(e):st(1),s=e.clientWidth*i.x,a=e.clientHeight*i.y,d=r*i.x,c=n*i.y;return{width:s,height:a,x:d,y:c}}function gc(e,t,o){let n;if(t==="viewport")n=mm(e,o);else if(t==="document")n=pm(ot(e));else if(V(t))n=gm(t,o);else{let r=wc(e);n={x:t.x-r.x,y:t.y-r.y,width:t.width,height:t.height}}return qt(n)}function _c(e,t){let o=tt(e);return o===t||!V(o)||nt(o)?!1:Ae(o).position==="fixed"||_c(o,t)}function bm(e,t){let o=t.get(e);if(o)return o;let n=It(e,[],!1).filter(a=>V(a)&&Gt(a)!=="body"),r=null,i=Ae(e).position==="fixed",s=i?tt(e):e;for(;V(s)&&!nt(s);){let a=Ae(s),d=Sn(s);!d&&a.position==="fixed"&&(r=null),(i?!d&&!r:!d&&a.position==="static"&&!!r&&(r.position==="absolute"||r.position==="fixed")||fo(s)&&!d&&_c(e,s))?n=n.filter(l=>l!==s):r=a,s=tt(s)}return t.set(e,n),n}function hm(e){let{element:t,boundary:o,rootBoundary:n,strategy:r}=e,s=[...o==="clippingAncestors"?Do(t)?[]:bm(t,this._c):[].concat(o),n],a=gc(t,s[0],r),d=a.top,c=a.right,l=a.bottom,f=a.left;for(let p=1;p{s(!1,1e-7)},1e3)}E===1&&!xc(c,e.getBoundingClientRect())&&s(),b=!1}try{o=new IntersectionObserver(S,{...y,root:r.ownerDocument})}catch{o=new IntersectionObserver(S,y)}o.observe(e)}return s(!0),i}function Xo(e,t,o,n){n===void 0&&(n={});let{ancestorScroll:r=!0,ancestorResize:i=!0,elementResize:s=typeof ResizeObserver=="function",layoutShift:a=typeof IntersectionObserver=="function",animationFrame:d=!1}=n,c=qr(e),l=r||i?[...c?It(c):[],...t?It(t):[]]:[];l.forEach(_=>{r&&_.addEventListener("scroll",o,{passive:!0}),i&&_.addEventListener("resize",o)});let f=c&&a?xm(c,o):null,p=-1,m=null;s&&(m=new ResizeObserver(_=>{let[w]=_;w&&w.target===c&&m&&t&&(m.unobserve(t),cancelAnimationFrame(p),p=requestAnimationFrame(()=>{var y;(y=m)==null||y.observe(t)})),o()}),c&&!d&&m.observe(c),t&&m.observe(t));let u,g=d?Qt(e):null;d&&v();function v(){let _=Qt(e);g&&!xc(g,_)&&o(),g=_,u=requestAnimationFrame(v)}return o(),()=>{var _;l.forEach(w=>{r&&w.removeEventListener("scroll",o),i&&w.removeEventListener("resize",o)}),f?.(),(_=m)==null||_.disconnect(),m=null,d&&cancelAnimationFrame(u)}}var Rc=dc;var Sc=uc,Ec=ac,Tc=pc,kc=cc;var Pc=fc,Bn=(e,t,o)=>{let n=new Map,r={platform:Zr,...o},i={...r.platform,_c:n};return sc(e,t,{...r,platform:i})};var ve=h(z(),1),Ac=h(z(),1),Oc=h(Mt(),1),Sm=typeof document<"u",Em=function(){},Hn=Sm?Ac.useLayoutEffect:Em;function zn(e,t){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(typeof e=="function"&&e.toString()===t.toString())return!0;let o,n,r;if(e&&t&&typeof e=="object"){if(Array.isArray(e)){if(o=e.length,o!==t.length)return!1;for(n=o;n--!==0;)if(!zn(e[n],t[n]))return!1;return!0}if(r=Object.keys(e),o=r.length,o!==Object.keys(t).length)return!1;for(n=o;n--!==0;)if(!{}.hasOwnProperty.call(t,r[n]))return!1;for(n=o;n--!==0;){let i=r[n];if(!(i==="_owner"&&e.$$typeof)&&!zn(e[i],t[i]))return!1}return!0}return e!==e&&t!==t}function Nc(e){return typeof window>"u"?1:(e.ownerDocument.defaultView||window).devicePixelRatio||1}function Cc(e,t){let o=Nc(e);return Math.round(t*o)/o}function Qr(e){let t=ve.useRef(e);return Hn(()=>{t.current=e}),t}function Lc(e){e===void 0&&(e={});let{placement:t="bottom",strategy:o="absolute",middleware:n=[],platform:r,elements:{reference:i,floating:s}={},transform:a=!0,whileElementsMounted:d,open:c}=e,[l,f]=ve.useState({x:0,y:0,strategy:o,placement:t,middlewareData:{},isPositioned:!1}),[p,m]=ve.useState(n);zn(p,n)||m(n);let[u,g]=ve.useState(null),[v,_]=ve.useState(null),w=ve.useCallback(P=>{P!==x.current&&(x.current=P,g(P))},[]),y=ve.useCallback(P=>{P!==E.current&&(E.current=P,_(P))},[]),b=i||u,S=s||v,x=ve.useRef(null),E=ve.useRef(null),T=ve.useRef(l),k=d!=null,C=Qr(d),j=Qr(r),A=Qr(c),L=ve.useCallback(()=>{if(!x.current||!E.current)return;let P={placement:t,strategy:o,middleware:p};j.current&&(P.platform=j.current),Bn(x.current,E.current,P).then(O=>{let M={...O,isPositioned:A.current!==!1};I.current&&!zn(T.current,M)&&(T.current=M,Oc.flushSync(()=>{f(M)}))})},[p,t,o,j,A]);Hn(()=>{c===!1&&T.current.isPositioned&&(T.current.isPositioned=!1,f(P=>({...P,isPositioned:!1})))},[c]);let I=ve.useRef(!1);Hn(()=>(I.current=!0,()=>{I.current=!1}),[]),Hn(()=>{if(b&&(x.current=b),S&&(E.current=S),b&&S){if(C.current)return C.current(b,S,L);L()}},[b,S,L,C,k]);let R=ve.useMemo(()=>({reference:x,floating:E,setReference:w,setFloating:y}),[w,y]),N=ve.useMemo(()=>({reference:b,floating:S}),[b,S]),H=ve.useMemo(()=>{let P={position:o,left:0,top:0};if(!N.floating)return P;let O=Cc(N.floating,l.x),M=Cc(N.floating,l.y);return a?{...P,transform:"translate("+O+"px, "+M+"px)",...Nc(N.floating)>=1.5&&{willChange:"transform"}}:{position:o,left:O,top:M}},[o,a,N.floating,l.x,l.y]);return ve.useMemo(()=>({...l,update:L,refs:R,elements:N,floatingStyles:H}),[l,L,R,N,H])}var Jr=(e,t)=>{let o=Rc(e);return{name:o.name,fn:o.fn,options:[e,t]}},$r=(e,t)=>{let o=Sc(e);return{name:o.name,fn:o.fn,options:[e,t]}},ei=(e,t)=>({fn:Pc(e).fn,options:[e,t]}),ti=(e,t)=>{let o=Ec(e);return{name:o.name,fn:o.fn,options:[e,t]}},oi=(e,t)=>{let o=Tc(e);return{name:o.name,fn:o.fn,options:[e,t]}};var ni=(e,t)=>{let o=kc(e);return{name:o.name,fn:o.fn,options:[e,t]}};var _o=h(z(),1),qc=h(Mt(),1);var Xc=h(z(),1);var q=(e,t,o,n,r,i,...s)=>{if(s.length>0)throw new Error(Pe(1));let a;if(e&&t&&o&&n&&r&&i)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f),g=n(d,c,l,f),v=r(d,c,l,f);return i(p,m,u,g,v,c,l,f)};else if(e&&t&&o&&n&&r)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f),g=n(d,c,l,f);return r(p,m,u,g,c,l,f)};else if(e&&t&&o&&n)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f),u=o(d,c,l,f);return n(p,m,u,c,l,f)};else if(e&&t&&o)a=(d,c,l,f)=>{let p=e(d,c,l,f),m=t(d,c,l,f);return o(p,m,c,l,f)};else if(e&&t)a=(d,c,l,f)=>{let p=e(d,c,l,f);return t(p,c,l,f)};else if(e)a=e;else throw new Error("Missing arguments");return a};var Uc=h(z(),1),li=h(ii(),1),Gc=h(jc(),1);var Fc=h(z(),1);var si=[],ai;function Vc(){return ai}function Wc(e){si.push(e)}function ci(e){let t=(o,n)=>{let r=Se(Wm).current,i;try{ai=r;for(let s of si)s.before(r);i=e(o,n);for(let s of si)s.after(r);r.didInitialize=!0}finally{ai=void 0}return i};return t.displayName=e.displayName||e.name,t}function Yc(e){return Fc.forwardRef(ci(e))}function Wm(){return{didInitialize:!1}}var Ym=ao(19),Um=Ym?Xm:Km;function jn(e,t,o,n,r){return Um(e,t,o,n,r)}function Gm(e,t,o,n,r){let i=Uc.useCallback(()=>t(e.getSnapshot(),o,n,r),[e,t,o,n,r]);return(0,li.useSyncExternalStore)(e.subscribe,i,i)}Wc({before(e){e.syncIndex=0,e.didInitialize||(e.syncTick=1,e.syncHooks=[],e.didChangeStore=!0,e.getSnapshot=()=>{let t=!1;for(let o=0;o0&&(e.didChangeStore&&(e.didChangeStore=!1,e.subscribe=t=>{let o=new Set;for(let r of e.syncHooks)o.add(r.store);let n=[];for(let r of o)n.push(r.subscribe(t));return()=>{for(let r of n)r()}}),(0,li.useSyncExternalStore)(e.subscribe,e.getSnapshot,e.getSnapshot))}});function Xm(e,t,o,n,r){let i=Vc();if(!i)return Gm(e,t,o,n,r);let s=i.syncIndex;i.syncIndex+=1;let a;return i.didInitialize?(a=i.syncHooks[s],(a.store!==e||a.selector!==t||!Object.is(a.a1,o)||!Object.is(a.a2,n)||!Object.is(a.a3,r))&&(a.store!==e&&(i.didChangeStore=!0),a.store=e,a.selector=t,a.a1=o,a.a2=n,a.a3=r,a.value=t(e.getSnapshot(),o,n,r))):(a={store:e,selector:t,a1:o,a2:n,a3:r,value:t(e.getSnapshot(),o,n,r)},i.syncHooks.push(a)),a.value}function Km(e,t,o,n,r){return(0,Gc.useSyncExternalStoreWithSelector)(e.subscribe,e.getSnapshot,e.getSnapshot,i=>t(i,o,n,r))}var Fn=class{constructor(t){this.state=t,this.listeners=new Set,this.updateTick=0}subscribe=t=>(this.listeners.add(t),()=>{this.listeners.delete(t)});getSnapshot=()=>this.state;setState(t){if(this.state===t)return;this.state=t,this.updateTick+=1;let o=this.updateTick;for(let n of this.listeners){if(o!==this.updateTick)return;n(t)}}update(t){for(let o in t)if(!Object.is(this.state[o],t[o])){this.setState({...this.state,...t});return}}set(t,o){Object.is(this.state[t],o)||this.setState({...this.state,[t]:o})}notifyAll(){let t={...this.state};this.setState(t)}use(t,o,n,r){return jn(this,t,o,n,r)}};var Jt=h(z(),1);var vo=class extends Fn{constructor(t,o={},n){super(t),this.context=o,this.selectors=n}useSyncedValue(t,o){Jt.useDebugValue(t);let n=this;D(()=>{n.state[t]!==o&&n.set(t,o)},[n,t,o])}useSyncedValueWithCleanup(t,o){let n=this;D(()=>(n.state[t]!==o&&n.set(t,o),()=>{n.set(t,void 0)}),[n,t,o])}useSyncedValues(t){let o=this,n=Object.values(t);D(()=>{o.update(t)},[o,...n])}useControlledProp(t,o){Jt.useDebugValue(t);let n=this,r=o!==void 0;D(()=>{r&&!Object.is(n.state[t],o)&&n.setState({...n.state,[t]:o})},[n,t,o,r])}select(t,o,n,r){let i=this.selectors[t];return i(this.state,o,n,r)}useState(t,o,n,r){return Jt.useDebugValue(t),jn(this,this.selectors[t],o,n,r)}useContextCallback(t,o){Jt.useDebugValue(t);let n=Y(o??Nt);this.context[t]=n}useStateSetter(t){let o=Jt.useRef(void 0);return o.current===void 0&&(o.current=n=>{this.set(t,n)}),o.current}observe(t,o){let n;typeof t=="function"?n=t:n=this.selectors[t];let r=n(this.state);return o(r,r,this),this.subscribe(i=>{let s=n(i);if(!Object.is(r,s)){let a=r;r=s,o(s,a,this)}})}};var qm={open:q(e=>e.open),transitionStatus:q(e=>e.transitionStatus),domReferenceElement:q(e=>e.domReferenceElement),referenceElement:q(e=>e.positionReference??e.referenceElement),floatingElement:q(e=>e.floatingElement),floatingId:q(e=>e.floatingId)},pt=class extends vo{constructor(t){let{syncOnly:o,nested:n,onOpenChange:r,triggerElements:i,...s}=t;super({...s,positionReference:s.referenceElement,domReferenceElement:s.referenceElement},{onOpenChange:r,dataRef:{current:{}},events:ec(),nested:n,triggerElements:i},qm),this.syncOnly=o}syncOpenEvent=(t,o)=>{(!t||!this.state.open||o!=null&&Ha(o))&&(this.context.dataRef.current.openEvent=t?o:void 0)};dispatchOpenChange=(t,o)=>{this.syncOpenEvent(t,o.event);let n={open:t,reason:o.reason,nativeEvent:o.event,nested:this.context.nested,triggerElement:o.trigger};this.context.events.emit("openchange",n)};setOpen=(t,o)=>{if(this.syncOnly){this.context.onOpenChange?.(t,o);return}this.dispatchOpenChange(t,o),this.context.onOpenChange?.(t,o)}};function Kc(e){let{popupStore:t,treatPopupAsFloatingElement:o=!1,floatingRootContext:n,floatingId:r,nested:i,onOpenChange:s}=e,a=t.useState("open"),d=t.useState("activeTriggerElement"),c=t.useState(o?"popupElement":"positionerElement"),l=t.context.triggerElements,f=s,p=Xc.useRef(null);n===void 0&&p.current===null&&(p.current=new pt({open:a,transitionStatus:void 0,referenceElement:d,floatingElement:c,triggerElements:l,onOpenChange:f,floatingId:r,syncOnly:!0,nested:i}));let m=n??p.current;return t.useSyncedValue("floatingId",r),D(()=>{let u={open:a,floatingId:r,referenceElement:d,floatingElement:c};V(d)&&(u.domReferenceElement=d),m.state.positionReference===m.state.referenceElement&&(u.positionReference=d),m.update(u)},[a,r,d,c,m]),m.context.onOpenChange=f,m.context.nested=i,m}var Zc={tabIndex:-1,[Dr]:""};function Qc(e,t,o=!1){let n=Lt(),r=bo()!=null,i=_o.useRef(null);e===void 0&&i.current===null&&(i.current=t(n,r));let s=e??i.current;return Kc({popupStore:s,treatPopupAsFloatingElement:o,floatingRootContext:s.state.floatingRootContext,floatingId:n,nested:r,onOpenChange:s.setOpen}),{store:s,internalStore:i.current}}function Zm(e,t){let o=_o.useRef(null),n=_o.useRef(null);return _o.useCallback(r=>{if(e===void 0)return;let i=!1;if(o.current!==null){let s=o.current,a=n.current,d=t.context.triggerElements.getById(s);a&&d===a&&(t.context.triggerElements.delete(s),i=!0),o.current=null,n.current=null}if(r!==null&&(o.current=e,n.current=r,t.context.triggerElements.add(e,r),i=!0),i){let s=t.context.triggerElements.size;t.select("open")&&t.state.triggerCount!==s&&t.set("triggerCount",s)}},[t,e])}function Qm(e,t,o,n=!1){t?e.preventUnmountingOnClose=!1:n&&(e.preventUnmountingOnClose=!0);let r=o?.id??null;(r||t)&&(e.activeTriggerId=r,e.activeTriggerElement=o??null)}function Jm(e){let t=!1;return e.preventUnmountOnClose=()=>{t=!0},()=>t}function Jc(e,t,o,n={}){let r=o.reason,i=r===U.triggerHover,s=t&&r===U.triggerFocus,a=!t&&(r===U.triggerPress||r===U.escapeKey),d=Jm(o);if(e.context.onOpenChange?.(t,o),o.isCanceled)return;n.onBeforeDispatch?.(),e.state.floatingRootContext.dispatchOpenChange(t,o);let c=()=>{let l={...n.extraState,open:t};s?l.instantType="focus":a?l.instantType="dismiss":i&&(l.instantType=void 0),Qm(l,t,o.trigger,d()),e.update(l)};i?qc.flushSync(c):c()}function $c(e,t,o,n){Oa(()=>{t===void 0&&e.state.open===!1&&o&&(e.state={...e.state,open:!0,activeTriggerId:n,preventUnmountingOnClose:!1})})}function el(e,t,o,n){let r=o.useState("isMountedByTrigger",e),i=Zm(e,o),s=Y(a=>{if(i(a),!a)return;let d=o.select("open"),c=o.select("activeTriggerId");if(c===e){o.update({activeTriggerElement:a,...d?n:null});return}c==null&&d&&o.update({activeTriggerId:e,activeTriggerElement:a,...n})});return D(()=>{r&&o.update({activeTriggerElement:t.current,...n})},[r,o,t,...Object.values(n)]),{registerTrigger:s,isMountedByThisTrigger:r}}function tl(e,t={}){let{closeOnActiveTriggerUnmount:o=!1}=t,n=e.useState("open"),r=e.useState("triggerCount");D(()=>{if(!n){e.state.triggerCount!==0&&e.set("triggerCount",0);return}let i=e.context.triggerElements.size,s={};e.state.triggerCount!==i&&(s.triggerCount=i);let a=e.select("activeTriggerId"),d=null;if(a){let c=e.context.triggerElements.getById(a);c?c!==e.state.activeTriggerElement&&(s.activeTriggerElement=c):d=a}if(!d&&!a&&i===1){let c=e.context.triggerElements.entries().next();if(!c.done){let[l,f]=c.value;s.activeTriggerId=l,s.activeTriggerElement=f}}(s.triggerCount!==void 0||s.activeTriggerId!==void 0||s.activeTriggerElement!==void 0)&&e.update(s),d&&o&&queueMicrotask(()=>{if(e.select("open")&&e.select("activeTriggerId")===d&&!e.context.triggerElements.getById(d)){let c=ee(U.none);e.setOpen(!1,c),c.isCanceled||e.update({activeTriggerId:null,activeTriggerElement:null})}})},[n,e,r,o])}function ol(e,t,o){let{mounted:n,setMounted:r,transitionStatus:i}=ha(e),s=t.useState("preventUnmountingOnClose"),a=e?!1:s;t.useSyncedValues({mounted:n,transitionStatus:i,preventUnmountingOnClose:a});let d=Y(()=>{r(!1),t.update({activeTriggerId:null,activeTriggerElement:null,mounted:!1,preventUnmountingOnClose:!1}),o?.(),t.context.onOpenChangeComplete?.(!1)});return Pn({enabled:n&&!e&&!a,open:e,ref:t.context.popupRef,onComplete(){e||d()}}),{forceUnmount:d,transitionStatus:i}}function nl(e,t){e.useSyncedValues(t),D(()=>()=>{e.update({activeTriggerProps:be,inactiveTriggerProps:be,popupProps:be})},[e])}var jt=class{constructor(){this.elementsSet=new Set,this.idMap=new Map}add(t,o){let n=this.idMap.get(t);n!==o&&(n!==void 0&&this.elementsSet.delete(n),this.elementsSet.add(o),this.idMap.set(t,o))}delete(t){let o=this.idMap.get(t);o&&(this.elementsSet.delete(o),this.idMap.delete(t))}hasElement(t){return this.elementsSet.has(t)}hasMatchingElement(t){for(let o of this.elementsSet)if(t(o))return!0;return!1}getById(t){return this.idMap.get(t)}entries(){return this.idMap.entries()}elements(){return this.elementsSet.values()}get size(){return this.idMap.size}};function rl(){return new pt({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:new jt,floatingId:void 0,syncOnly:!1,nested:!1,onOpenChange:void 0})}function sl(){return{open:!1,openProp:void 0,mounted:!1,transitionStatus:void 0,floatingRootContext:rl(),floatingId:void 0,triggerCount:0,preventUnmountingOnClose:!1,payload:void 0,activeTriggerId:null,activeTriggerElement:null,triggerIdProp:void 0,popupElement:null,positionerElement:null,activeTriggerProps:be,inactiveTriggerProps:be,popupProps:be}}function al(e,t,o=!1){return new pt({open:!1,transitionStatus:void 0,floatingElement:null,referenceElement:null,triggerElements:e,floatingId:t,syncOnly:!0,nested:o,onOpenChange:void 0})}var Ko=q(e=>e.triggerIdProp??e.activeTriggerId),di=q(e=>e.openProp??e.open),il=q(e=>(e.popupElement?.id??e.floatingId)||void 0);function cl(e,t){return t!==void 0&&di(e)&&Ko(e)===t}function $m(e,t){return cl(e,t)?!0:t!==void 0&&di(e)&&Ko(e)==null&&e.triggerCount===1}var ll={open:di,mounted:q(e=>e.mounted),transitionStatus:q(e=>e.transitionStatus),floatingRootContext:q(e=>e.floatingRootContext),triggerCount:q(e=>e.triggerCount),preventUnmountingOnClose:q(e=>e.preventUnmountingOnClose),payload:q(e=>e.payload),activeTriggerId:Ko,activeTriggerElement:q(e=>e.mounted?e.activeTriggerElement:null),popupId:il,isTriggerActive:q((e,t)=>t!==void 0&&Ko(e)===t),isOpenedByTrigger:q((e,t)=>cl(e,t)),isMountedByTrigger:q((e,t)=>t!==void 0&&Ko(e)===t&&e.mounted),triggerProps:q((e,t)=>t?e.activeTriggerProps:e.inactiveTriggerProps),triggerPopupId:q((e,t)=>$m(e,t)?il(e):void 0),popupProps:q(e=>e.popupProps),popupElement:q(e=>e.popupElement),positionerElement:q(e=>e.positionerElement)};function dl(e){let{open:t=!1,onOpenChange:o,elements:n={}}=e,r=Lt(),i=bo()!=null,s=Se(()=>new pt({open:t,transitionStatus:void 0,onOpenChange:o,referenceElement:n.reference??null,floatingElement:n.floating??null,triggerElements:new jt,floatingId:r,syncOnly:!1,nested:i})).current;return D(()=>{let a={open:t,floatingId:r};n.reference!==void 0&&(a.referenceElement=n.reference,a.domReferenceElement=V(n.reference)?n.reference:null),n.floating!==void 0&&(a.floatingElement=n.floating),s.update(a)},[t,r,n.reference,n.floating,s]),s.context.onOpenChange=o,s.context.nested=i,s}function ui(e={}){let{nodeId:t,externalTree:o}=e,n=dl(e),r=e.rootContext||n,i=r.useState("referenceElement"),s=r.useState("floatingElement"),a=r.useState("domReferenceElement"),d=r.useState("open"),c=r.useState("floatingId"),[l,f]=Ne.useState(null),[p,m]=Ne.useState(void 0),[u,g]=Ne.useState(void 0),v=Ne.useRef(null),_=Dt(o),w=Ne.useMemo(()=>({reference:i,floating:s,domReference:a}),[i,s,a]),y=Lc({...e,elements:{...w,...l&&{reference:l}}}),b=V(p)?p:null,S=u===void 0?r.state.floatingElement:u;r.useSyncedValue("referenceElement",p??null),r.useSyncedValue("domReferenceElement",p===void 0?a:b),r.useSyncedValue("floatingElement",S);let x=Ne.useCallback(A=>{let L=V(A)?{getBoundingClientRect:()=>A.getBoundingClientRect(),getClientRects:()=>A.getClientRects(),contextElement:A}:A;f(L),y.refs.setReference(L)},[y.refs]),E=Ne.useCallback(A=>{(V(A)||A===null)&&(v.current=A,m(A)),(V(y.refs.reference.current)||y.refs.reference.current===null||A!==null&&!V(A))&&y.refs.setReference(A)},[y.refs,m]),T=Ne.useCallback(A=>{g(A),y.refs.setFloating(A)},[y.refs]),k=Ne.useMemo(()=>({...y.refs,setReference:E,setFloating:T,setPositionReference:x,domReference:v}),[y.refs,E,T,x]),C=Ne.useMemo(()=>({...y.elements,domReference:a}),[y.elements,a]),j=Ne.useMemo(()=>({...y,dataRef:r.context.dataRef,open:d,onOpenChange:r.setOpen,events:r.context.events,floatingId:c,refs:k,elements:C,nodeId:t,rootStore:r}),[y,k,C,t,r,d,c]);return D(()=>{a&&(v.current=a)},[a]),D(()=>{r.context.dataRef.current.floatingContext=j;let A=_?.nodesRef.current.find(L=>L.id===t);A&&(A.context=j)}),Ne.useMemo(()=>({...y,context:j,refs:k,elements:C,rootStore:r}),[y,k,C,j,r])}var mt=h(z(),1);var fi=xt.os.mac&&xt.engine.webkit;function pi(e,t={}){let{enabled:o=!0,delay:n}=t,r="rootStore"in e?e.rootStore:e,{events:i,dataRef:s}=r.context,a=mt.useRef(!1),d=mt.useRef(null),c=mt.useRef(!0),l=rt();mt.useEffect(()=>{let p=r.select("domReferenceElement");if(!o)return;let m=ge(p);function u(){let _=r.select("domReferenceElement");!r.select("open")&&we(_)&&_===Cn(xe(_))&&(a.current=!0)}function g(){c.current=!0}function v(){c.current=!1}return it(re(m,"blur",u),fi&&re(m,"keydown",g,!0),fi&&re(m,"pointerdown",v,!0))},[r,o]),mt.useEffect(()=>{if(!o)return;function p(m){if(m.reason===U.triggerPress||m.reason===U.escapeKey){let u=r.select("domReferenceElement");V(u)&&(d.current=u,a.current=!0)}}return i.on("openchange",p),()=>{i.off("openchange",p)}},[i,o,r]);let f=mt.useMemo(()=>{function p(){a.current=!1,d.current=null}return{onMouseLeave(){p()},onFocus(m){let u=m.currentTarget;if(a.current){if(d.current===u)return;p()}let g=Me(m.nativeEvent);if(V(g)){if(fi&&!m.relatedTarget){if(!c.current&&!Da(g))return}else if(!ja(g))return}let v=Bt(m.relatedTarget,r.context.triggerElements),{nativeEvent:_,currentTarget:w}=m,y=typeof n=="function"?n():n;if(r.select("open")&&v||y===0||y===void 0){r.setOpen(!0,ee(U.triggerFocus,_,w));return}l.start(y,()=>{a.current||r.setOpen(!0,ee(U.triggerFocus,_,w))})},onBlur(m){p();let u=m.relatedTarget,g=m.nativeEvent,v=V(u)&&u.hasAttribute(go("focus-guard"))&&u.getAttribute("data-type")==="outside";l.start(0,()=>{let _=r.select("domReferenceElement"),w=Cn(xe(_));!u&&w===_||ie(s.current.floatingContext?.refs.floating.current,w)||ie(_,w)||v||Bt(u??w,r.context.triggerElements)||r.setOpen(!1,ee(U.triggerFocus,g))})}}},[s,n,r,l]);return mt.useMemo(()=>o?{reference:f,trigger:f}:{},[o,f])}var gi=h(z(),1);var mi=class e{constructor(){this.pointerType=void 0,this.interactedInside=!1,this.handler=void 0,this.blockMouseMove=!0,this.performedPointerEventsMutation=!1,this.pointerEventsScopeElement=null,this.pointerEventsReferenceElement=null,this.pointerEventsFloatingElement=null,this.restTimeoutPending=!1,this.openChangeTimeout=new Ye,this.restTimeout=new Ye,this.handleCloseOptions=void 0}static create(){return new e}dispose=()=>{this.openChangeTimeout.clear(),this.restTimeout.clear()};disposeEffect=()=>this.dispose},Vn=new WeakMap;function yo(e){if(!e.performedPointerEventsMutation)return;let t=e.pointerEventsScopeElement;t&&Vn.get(t)===e&&(e.pointerEventsScopeElement?.style.removeProperty("pointer-events"),e.pointerEventsReferenceElement?.style.removeProperty("pointer-events"),e.pointerEventsFloatingElement?.style.removeProperty("pointer-events"),Vn.delete(t)),e.performedPointerEventsMutation=!1,e.pointerEventsScopeElement=null,e.pointerEventsReferenceElement=null,e.pointerEventsFloatingElement=null}function Wn(e,t){let{scopeElement:o,referenceElement:n,floatingElement:r}=t,i=Vn.get(o);i&&i!==e&&yo(i),yo(e),e.performedPointerEventsMutation=!0,e.pointerEventsScopeElement=o,e.pointerEventsReferenceElement=n,e.pointerEventsFloatingElement=r,Vn.set(o,e),o.style.pointerEvents="none",n.style.pointerEvents="auto",r.style.pointerEvents="auto"}function xo(e){let t=e.context.dataRef.current,o=Se(()=>t.hoverInteractionState??mi.create()).current;return t.hoverInteractionState||(t.hoverInteractionState=o),co(t.hoverInteractionState.disposeEffect),t.hoverInteractionState}function bi(e,t={}){let{enabled:o=!0,closeDelay:n=0,nodeId:r}=t,i="rootStore"in e?e.rootStore:e,s=i.useState("open"),a=i.useState("floatingElement"),d=i.useState("domReferenceElement"),{dataRef:c}=i.context,l=Dt(),f=bo(),p=xo(i),m=rt(),u=Y(()=>On(c.current.openEvent?.type,p.interactedInside)),g=Y(()=>Fa(c.current.openEvent?.type)),v=Y(()=>{yo(p)});D(()=>{s||(p.pointerType=void 0,p.restTimeoutPending=!1,p.interactedInside=!1,v())},[s,p,v]),gi.useEffect(()=>v,[v]),D(()=>{if(o&&s&&p.handleCloseOptions?.blockPointerEvents&&g()&&V(d)&&a){let _=d,w=a,y=xe(a),b=l?.nodesRef.current.find(T=>T.id===f)?.context?.elements.floating;b&&(b.style.pointerEvents="");let S=p.pointerEventsScopeElement!==w?p.pointerEventsScopeElement:null,x=b!==w?b:null,E=p.handleCloseOptions?.getScope?.()??S??x??_.closest("[data-rootownerid]")??y.body;return Wn(p,{scopeElement:E,referenceElement:_,floatingElement:w}),()=>{v()}}},[o,s,d,a,p,g,l,f,v]),gi.useEffect(()=>{if(!o)return;function _(){return!!(l&&f&&Et(l.nodesRef.current,f).length>0)}function w(T){let k=St(n,"close",p.pointerType),C=()=>{i.setOpen(!1,ee(U.triggerHover,T)),l?.events.emit("floating.closed",T)};k?p.openChangeTimeout.start(k,C):(p.openChangeTimeout.clear(),C())}function y(T){let k=Me(T);if(!Fr(k)){p.interactedInside=!1;return}p.interactedInside=k?.closest("[aria-haspopup]")!=null}function b(){p.openChangeTimeout.clear(),m.clear(),l?.events.off("floating.closed",x),v()}function S(T){if(_()&&l){l.events.on("floating.closed",x);return}if(Bt(T.relatedTarget,i.context.triggerElements))return;let k=c.current.floatingContext?.nodeId??r,C=T.relatedTarget;if(!(l&&k&&V(C)&&Et(l.nodesRef.current,k,!1).some(A=>ie(A.context?.elements.floating,C)))){if(p.handler){p.handler(T);return}v(),g()&&!u()&&w(T)}}function x(T){!l||!f||_()||m.start(0,()=>{l.events.off("floating.closed",x),i.setOpen(!1,ee(U.triggerHover,T)),l.events.emit("floating.closed",T)})}let E=a;return it(E&&re(E,"mouseenter",b),E&&re(E,"mouseleave",S),E&&re(E,"pointerdown",y,!0),()=>{l?.events.off("floating.closed",x)})},[o,a,i,c,n,r,g,u,v,p,l,f,m])}var Ft=h(z(),1),ul=h(Mt(),1);var eg={current:null};function hi(e,t={}){let{enabled:o=!0,delay:n=0,handleClose:r=null,mouseOnly:i=!1,restMs:s=0,move:a=!0,triggerElementRef:d=eg,externalTree:c,isActiveTrigger:l=!0,getHandleCloseContext:f,isClosing:p,shouldOpen:m}=t,u="rootStore"in e?e.rootStore:e,{dataRef:g,events:v}=u.context,_=Dt(c),w=xo(u),y=Ft.useRef(!1),b=ze(r),S=ze(n),x=ze(s),E=ze(o),T=ze(m),k=ze(p),C=Y(()=>On(g.current.openEvent?.type,w.interactedInside)),j=Y(()=>T.current?.()!==!1),A=Y((R,N,H)=>{let P=u.context.triggerElements;if(P.hasElement(N))return!R||!ie(R,N);if(!V(H))return!1;let O=H;return P.hasMatchingElement(M=>ie(M,O))&&(!R||!ie(R,O))}),L=Y(()=>{if(!w.handler)return;xe(u.select("domReferenceElement")).removeEventListener("mousemove",w.handler),w.handler=void 0}),I=Y(()=>{yo(w)});return l&&(w.handleCloseOptions=b.current?.__options),Ft.useEffect(()=>L,[L]),Ft.useEffect(()=>{if(!o)return;function R(N){N.open?y.current=!1:(y.current=N.reason===U.triggerHover,L(),w.openChangeTimeout.clear(),w.restTimeout.clear(),w.blockMouseMove=!0,w.restTimeoutPending=!1)}return v.on("openchange",R),()=>{v.off("openchange",R)}},[o,v,w,L]),Ft.useEffect(()=>{if(!o)return;function R(O,M=!0){let Z=St(S.current,"close",w.pointerType);Z?w.openChangeTimeout.start(Z,()=>{u.setOpen(!1,ee(U.triggerHover,O)),_?.events.emit("floating.closed",O)}):M&&(w.openChangeTimeout.clear(),u.setOpen(!1,ee(U.triggerHover,O)),_?.events.emit("floating.closed",O))}let N=d.current??(l?u.select("domReferenceElement"):null);if(!V(N))return;function H(O){if(w.openChangeTimeout.clear(),w.blockMouseMove=!1,i&&!Rt(w.pointerType))return;let M=Vr(x.current),Z=St(S.current,"open",w.pointerType),W=Me(O),oe=O.currentTarget??null,te=u.select("domReferenceElement"),se=oe;if(V(W)&&!u.context.triggerElements.hasElement(W)){for(let ue of u.context.triggerElements.elements())if(ie(ue,W)){se=ue;break}}V(oe)&&V(te)&&!u.context.triggerElements.hasElement(oe)&&ie(oe,te)&&(se=te);let G=se==null?!1:A(te,se,W),K=u.select("open"),J=k.current?.()??u.select("transitionStatus")==="ending",ne=!K&&J&&y.current,me=!G&&V(se)&&V(te)&&ie(te,se)&&ne,le=M>0&&!Z,X=G&&(K||ne)||me,pe=!K||G;if(X){j()&&u.setOpen(!0,ee(U.triggerHover,O,se));return}le||(Z?w.openChangeTimeout.start(Z,()=>{pe&&j()&&u.setOpen(!0,ee(U.triggerHover,O,se))}):pe&&j()&&u.setOpen(!0,ee(U.triggerHover,O,se)))}function P(O){if(C()){I();return}L();let M=u.select("domReferenceElement"),Z=xe(M);w.restTimeout.clear(),w.restTimeoutPending=!1;let W=g.current.floatingContext??f?.();if(Bt(O.relatedTarget,u.context.triggerElements))return;if(b.current&&W){u.select("open")||w.openChangeTimeout.clear();let te=d.current;w.handler=b.current({...W,tree:_,x:O.clientX,y:O.clientY,onClose(){I(),L(),E.current&&!C()&&te===u.select("domReferenceElement")&&R(O,!0)}}),Z.addEventListener("mousemove",w.handler),w.handler(O);return}(w.pointerType!=="touch"||!ie(u.select("floatingElement"),O.relatedTarget))&&R(O)}return a?it(re(N,"mousemove",H,{once:!0}),re(N,"mouseenter",H),re(N,"mouseleave",P)):it(re(N,"mouseenter",H),re(N,"mouseleave",P))},[L,I,g,S,u,o,b,w,l,A,C,i,a,x,d,_,E,f,k,j]),Ft.useMemo(()=>{if(!o)return;function R(N){w.pointerType=N.pointerType}return{onPointerDown:R,onPointerEnter:R,onMouseMove(N){let{nativeEvent:H}=N,P=N.currentTarget,O=u.select("domReferenceElement"),M=u.select("open"),Z=A(O,P,N.target);if(i&&!Rt(w.pointerType))return;if(M&&Z&&w.handleCloseOptions?.blockPointerEvents){let te=u.select("floatingElement");if(te){let se=w.handleCloseOptions?.getScope?.()??P.ownerDocument.body;Wn(w,{scopeElement:se,referenceElement:P,floatingElement:te})}}let W=Vr(x.current);if(M&&!Z||W===0||!Z&&w.restTimeoutPending&&N.movementX**2+N.movementY**2<2)return;w.restTimeout.clear();function oe(){if(w.restTimeoutPending=!1,C())return;let te=u.select("open");!w.blockMouseMove&&(!te||Z)&&j()&&u.setOpen(!0,ee(U.triggerHover,H,P))}w.pointerType==="touch"?ul.flushSync(()=>{oe()}):Z&&M?oe():(w.restTimeoutPending=!0,w.restTimeout.start(W,oe))}}},[o,w,C,A,i,u,x,j])}var fl=.1,tg=fl*fl,ce=.5;function Yn(e,t,o,n,r,i){return n>=t!=i>=t&&e<=(r-o)*(t-n)/(i-n)+o}function Un(e,t,o,n,r,i,s,a,d,c){let l=!1;return Yn(e,t,o,n,r,i)&&(l=!l),Yn(e,t,r,i,s,a)&&(l=!l),Yn(e,t,s,a,d,c)&&(l=!l),Yn(e,t,d,c,o,n)&&(l=!l),l}function og(e,t,o){return e>=o.x&&e<=o.x+o.width&&t>=o.y&&t<=o.y+o.height}function Gn(e,t,o,n,r,i){let s=Math.min(o,r),a=Math.max(o,r),d=Math.min(n,i),c=Math.max(n,i);return e>=s&&e<=a&&t>=d&&t<=c}function wi(e={}){let{blockPointerEvents:t=!1}=e,o=new Ye,n=({x:r,y:i,placement:s,elements:a,onClose:d,nodeId:c,tree:l})=>{let f=s?.split("-")[0],p=!1,m=null,u=null,g=typeof performance<"u"?performance.now():0;function v(w,y){let b=performance.now(),S=b-g;if(m===null||u===null||S===0)return m=w,u=y,g=b,!1;let x=w-m,E=y-u,T=x*x+E*E,k=S*S*tg;return m=w,u=y,g=b,T0)}function L(){A()||_()}if(A())return;let I=b.getBoundingClientRect(),R=S.getBoundingClientRect(),N=r>R.right-R.width/2,H=i>R.bottom-R.height/2,P=R.width>I.width,O=R.height>I.height,M=(P?I:R).left,Z=(P?I:R).right,W=(O?I:R).top,oe=(O?I:R).bottom;if(f==="top"&&i>=I.bottom-1||f==="bottom"&&i<=I.top+1||f==="left"&&r>=I.right-1||f==="right"&&r<=I.left+1){L();return}let te=!1;switch(f){case"top":te=Gn(x,E,M,I.top+1,Z,R.bottom-1);break;case"bottom":te=Gn(x,E,M,R.top+1,Z,I.bottom-1);break;case"left":te=Gn(x,E,R.right-1,oe,I.left+1,W);break;case"right":te=Gn(x,E,I.right-1,oe,R.left+1,W);break;default:}if(te)return;if(p&&!og(x,E,I)){L();return}if(!k&&v(x,E)){L();return}let se=!1;switch(f){case"top":{let G=P?ce/2:ce*4,K=P||N?r+G:r-G,J=P?r-G:N?r+G:r-G,ne=i+ce+1,me=N||P?R.bottom-ce:R.top,le=N?P?R.bottom-ce:R.top:R.bottom-ce;se=Un(x,E,K,ne,J,ne,R.left,me,R.right,le);break}case"bottom":{let G=P?ce/2:ce*4,K=P||N?r+G:r-G,J=P?r-G:N?r+G:r-G,ne=i-ce,me=N||P?R.top+ce:R.bottom,le=N?P?R.top+ce:R.bottom:R.top+ce;se=Un(x,E,K,ne,J,ne,R.left,me,R.right,le);break}case"left":{let G=O?ce/2:ce*4,K=O||H?i+G:i-G,J=O?i-G:H?i+G:i-G,ne=r+ce+1,me=H||O?R.right-ce:R.left,le=H?O?R.right-ce:R.left:R.right-ce;se=Un(x,E,me,R.top,le,R.bottom,ne,K,ne,J);break}case"right":{let G=O?ce/2:ce*4,K=O||H?i+G:i-G,J=O?i-G:H?i+G:i-G,ne=r-ce,me=H||O?R.left+ce:R.right,le=H?O?R.left+ce:R.right:R.left+ce;se=Un(x,E,ne,K,ne,J,me,R.top,le,R.bottom);break}default:}se?p||o.start(40,L):L()}};return n.__options={...e,blockPointerEvents:t},n}var vi=(function(e){return e.open="data-open",e.closed="data-closed",e[e.startingStyle=Yt.startingStyle]="startingStyle",e[e.endingStyle=Yt.endingStyle]="endingStyle",e.anchorHidden="data-anchor-hidden",e.side="data-side",e.align="data-align",e})({}),qo=(function(e){return e.popupOpen="data-popup-open",e.pressed="data-pressed",e})({}),ng={[qo.popupOpen]:""},B_={[qo.popupOpen]:"",[qo.pressed]:""},rg={[vi.open]:""},ig={[vi.closed]:""},sg={[vi.anchorHidden]:""},pl={open(e){return e?ng:null}};var Ro={open(e){return e?rg:ig},anchorHidden(e){return e?sg:null}};function ml(e){return ao(19)?e:e?"true":void 0}var Ge=h(z(),1);var ag=e=>({name:"arrow",options:e,async fn(t){let{x:o,y:n,placement:r,rects:i,platform:s,elements:a,middlewareData:d}=t,{element:c,padding:l=0,offsetParent:f="real"}=at(e,t)||{};if(c==null)return{};let p=In(l),m={x:o,y:n},u=Go(r),g=Uo(u),v=await s.getDimensions(c),_=u==="y",w=_?"top":"left",y=_?"bottom":"right",b=_?"clientHeight":"clientWidth",S=i.reference[g]+i.reference[u]-m[u]-i.floating[g],x=m[u]-i.reference[u],E=f==="real"?await s.getOffsetParent?.(c):a.floating,T=a.floating[b]||i.floating[g];(!T||!await s.isElement?.(E))&&(T=a.floating[b]||i.floating[g]);let k=S/2-x/2,C=T/2-v[g]/2-1,j=Math.min(p[w],C),A=Math.min(p[y],C),L=j,I=T-v[g]-A,R=T/2-v[g]/2+k,N=Yo(L,R,I),H=!d.arrow&&ct(r)!=null&&R!==N&&i.reference[g]/2-(R({...ag(e),options:[e,t]});var cg=ni().fn,bl={name:"hide",async fn(e){let{width:t,height:o,x:n,y:r}=e.rects.reference,i=t===0&&o===0&&n===0&&r===0;return{data:{referenceHidden:(await cg(e)).data?.referenceHidden||i}}}};var Zo={sideX:"left",sideY:"top"},hl={name:"adaptiveOrigin",async fn(e){let{x:t,y:o,rects:{floating:n},elements:{floating:r},platform:i,strategy:s,placement:a}=e,d=ge(r),c=d.getComputedStyle(r);if(!(c.transitionDuration!=="0s"&&c.transitionDuration!==""))return{x:t,y:o,data:Zo};let f=await i.getOffsetParent?.(r),p={width:0,height:0};if(s==="fixed"&&d?.visualViewport)p={width:d.visualViewport.width,height:d.visualViewport.height};else if(f===d){let w=xe(r);p={width:w.documentElement.clientWidth,height:w.documentElement.clientHeight}}else await i.isElement?.(f)&&(p=await i.getDimensions(f));let m=Ee(a),u=t,g=o;m==="left"&&(u=p.width-(t+n.width)),m==="top"&&(g=p.height-(o+n.height));let v=m==="left"?"right":Zo.sideX,_=m==="top"?"bottom":Zo.sideY;return{x:u,y:g,data:{sideX:v,sideY:_}}}};function _l(e,t,o){let n=e==="inline-start"||e==="inline-end";return{top:"top",right:n?o?"inline-start":"inline-end":"right",bottom:"bottom",left:n?o?"inline-end":"inline-start":"left"}[t]}function wl(e,t,o){let{rects:n,placement:r}=e;return{side:_l(t,Ee(r),o),align:ct(r)||"center",anchor:{width:n.reference.width,height:n.reference.height},positioner:{width:n.floating.width,height:n.floating.height}}}function yl(e){let{anchor:t,positionMethod:o="absolute",side:n="bottom",sideOffset:r=0,align:i="center",alignOffset:s=0,collisionBoundary:a,collisionPadding:d=5,sticky:c=!1,arrowPadding:l=5,disableAnchorTracking:f=!1,inline:p,keepMounted:m=!1,floatingRootContext:u,mounted:g,collisionAvoidance:v,shiftCrossAxis:_=!1,nodeId:w,adaptiveOrigin:y,lazyFlip:b=!1,externalTree:S}=e,[x,E]=Ge.useState(null);!g&&x!==null&&E(null);let T=v.side||"flip",k=v.align||"flip",C=v.fallbackAxisSide||"end",j=typeof t=="function"?t:void 0,A=Y(j),L=j?A:t,I=ze(t),R=ze(g),H=so()==="rtl",P=x||{top:"top",right:"right",bottom:"bottom",left:"left","inline-end":H?"left":"right","inline-start":H?"right":"left"}[n],O=i==="center"?P:`${P}-${i}`,M=d,Z=1,W=n==="bottom"?Z:0,oe=n==="top"?Z:0,te=n==="right"?Z:0,se=n==="left"?Z:0;typeof M=="number"?M={top:M+W,right:M+se,bottom:M+oe,left:M+te}:M&&(M={top:(M.top||0)+W,right:(M.right||0)+se,bottom:(M.bottom||0)+oe,left:(M.left||0)+te});let G={boundary:a==="clipping-ancestors"?"clippingAncestors":a,padding:M},K=Ge.useRef(null),J=ze(r),ne=ze(s),me=typeof r!="function"?r:0,le=typeof s!="function"?s:0,X=[];p&&X.push(p),X.push(Jr(ae=>{let Ie=wl(ae,n,H),ut=typeof J.current=="function"?J.current(Ie):J.current,qe=typeof ne.current=="function"?ne.current(Ie):ne.current;return{mainAxis:ut,crossAxis:qe,alignmentAxis:qe}},[me,le,H,n]));let pe=k==="none"&&T!=="shift",ue=!pe&&(c||_||T==="shift"),vt=T==="none"?null:ti({...G,padding:{top:M.top+Z,right:M.right+Z,bottom:M.bottom+Z,left:M.left+Z},mainAxis:!_&&T==="flip",crossAxis:k==="flip"?"alignment":!1,fallbackAxisSideDirection:C}),Te=pe?null:$r(ae=>{let Ie=xe(ae.elements.floating).documentElement;return{...G,rootBoundary:_?{x:0,y:0,width:Ie.clientWidth,height:Ie.clientHeight}:void 0,mainAxis:k!=="none",crossAxis:ue,limiter:c||_?void 0:ei(ut=>{if(!K.current)return{};let{width:qe,height:yt}=K.current.getBoundingClientRect(),et=De(Ee(ut.placement)),Vt=et==="y"?qe:yt,io=et==="y"?M.left+M.right:M.top+M.bottom;return{offset:Vt/2+io/2}})}},[G,c,_,M,k]);T==="shift"||k==="shift"||i==="center"?X.push(Te,vt):X.push(vt,Te),X.push(oi({...G,apply({elements:{floating:ae},availableWidth:Ie,availableHeight:ut,rects:qe}){if(!R.current)return;let yt=ae.style;yt.setProperty("--available-width",`${Ie}px`),yt.setProperty("--available-height",`${ut}px`);let et=ge(ae).devicePixelRatio||1,{x:Vt,y:io,width:bn,height:br}=qe.reference,hr=(Math.round((Vt+bn)*et)-Math.round(Vt*et))/et,wr=(Math.round((io+br)*et)-Math.round(io*et))/et;yt.setProperty("--anchor-width",`${hr}px`),yt.setProperty("--anchor-height",`${wr}px`)}}),gl(ae=>({element:K.current||xe(ae.elements.floating).createElement("div"),padding:l,offsetParent:"floating"}),[l]),{name:"transformOrigin",fn(ae){let{elements:Ie,middlewareData:ut,placement:qe,rects:yt,y:et}=ae,Vt=Ee(qe),io=De(Vt),bn=K.current,br=ut.arrow?.x||0,hr=ut.arrow?.y||0,wr=bn?.clientWidth||0,ff=bn?.clientHeight||0,vr=br+wr/2,Us=hr+ff/2,pf=Math.abs(ut.shift?.y||0),mf=yt.reference.height/2,Io=typeof r=="function"?r(wl(ae,n,H)):r,gf=pf>Io,bf={top:`${vr}px calc(100% + ${Io}px)`,bottom:`${vr}px ${-Io}px`,left:`calc(100% + ${Io}px) ${Us}px`,right:`${-Io}px ${Us}px`}[Vt],hf=`${vr}px ${yt.reference.y+mf-et}px`;return Ie.floating.style.setProperty("--transform-origin",ue&&io==="y"&&gf?hf:bf),{}}},bl,y),D(()=>{!g&&u&&u.update({referenceElement:null,floatingElement:null,domReferenceElement:null,positionReference:null})},[g,u]);let Ve=Ge.useMemo(()=>({elementResize:!f&&typeof ResizeObserver<"u",layoutShift:!f&&typeof IntersectionObserver<"u"}),[f]),{refs:Ke,elements:He,x:no,y:dn,middlewareData:_e,update:ro,placement:B,context:F,isPositioned:he,floatingStyles:ke}=ui({rootContext:u,open:m?g:void 0,placement:O,middleware:X,strategy:o,whileElementsMounted:m?void 0:(...ae)=>Xo(...ae,Ve),nodeId:w,externalTree:S}),{sideX:kt,sideY:Lo}=_e.adaptiveOrigin||Zo,_t=he?o:"fixed",We=Ge.useMemo(()=>{let ae=y?{position:_t,[kt]:no,[Lo]:dn}:{position:_t,...ke};return he||(ae.opacity=0),ae},[y,_t,kt,no,Lo,dn,ke,he]),Pt=Ge.useRef(null);D(()=>{if(!g)return;let ae=I.current,Ie=typeof ae=="function"?ae():ae,qe=(vl(Ie)?Ie.current:Ie)||null||null;qe!==Pt.current&&(Ke.setPositionReference(qe),Pt.current=qe)},[g,Ke,L,I]),Ge.useEffect(()=>{if(!g)return;let ae=I.current;typeof ae!="function"&&vl(ae)&&ae.current!==Pt.current&&(Ke.setPositionReference(ae.current),Pt.current=ae.current)},[g,Ke,L,I]),Ge.useEffect(()=>{if(m&&g&&He.reference&&He.floating)return Xo(He.reference,He.floating,ro,Ve)},[m,g,He,ro,Ve]);let Ct=Ee(B),un=_l(n,Ct,H),fn=ct(B)||"center",pn=!!_e.hide?.referenceHidden;D(()=>{b&&g&&he&&E(Ct)},[b,g,he,Ct]);let mn=Ge.useMemo(()=>({position:"absolute",top:_e.arrow?.y,left:_e.arrow?.x}),[_e.arrow]),gn=_e.arrow?.centerOffset!==0;return Ge.useMemo(()=>({positionerStyles:We,arrowStyles:mn,arrowRef:K,arrowUncentered:gn,side:un,align:fn,physicalSide:Ct,anchorHidden:pn,refs:Ke,context:F,isPositioned:he,update:ro}),[We,mn,K,gn,un,fn,Ct,pn,Ke,F,he,ro])}function vl(e){return e!=null&&"current"in e}function Xn(e){return e==="starting"?Za:be}function xl(e,t,{styles:o,transitionStatus:n,props:r,refs:i,hidden:s,inert:a=!1}){let d={...o};return a&&(d.pointerEvents="none"),Ce("div",e,{state:t,ref:i,props:[{role:"presentation",hidden:s,style:d},Xn(n),r],stateAttributesMapping:Ro})}var Rl=h(z(),1);var _i=Rl.forwardRef(function(t,o){let{render:n,className:r,disabled:i=!1,focusableWhenDisabled:s=!1,nativeButton:a=!0,style:d,...c}=t,{getButtonProps:l,buttonRef:f}=Ea({disabled:i,focusableWhenDisabled:s,native:a});return Ce("button",t,{state:{disabled:i},ref:[o,f],props:[c,l]})});var Le=h(z(),1),Cl=h(Mt(),1);var Sl=h(z(),1);function El(e){let[t,o]=Sl.useState({current:e,previous:null});return e!==t.current&&o({current:e,previous:t.current}),t.previous}var So=h(z(),1);function yi(e){let t=Ae(e),o=parseFloat(t.width)||0,n=parseFloat(t.height)||0,r=we(e),i=r?e.offsetWidth:o,s=r?e.offsetHeight:n;return(zt(o)!==i||zt(n)!==s)&&(o=i,n=s),{width:o,height:n}}function kl(e){let{popupElement:t,positionerElement:o,content:n,mounted:r,onMeasureLayout:i,onMeasureLayoutComplete:s,side:a,direction:d}=e,c=mo(t,!0,!1),l=lo(),f=So.useRef(null),p=So.useRef(!0),m=So.useRef(Nt),u=Y(i),g=Y(s),v=So.useMemo(()=>{let _=a==="top",w=a==="left";return d==="rtl"?(_=_||a==="inline-end",w=w||a==="inline-end"):(_=_||a==="inline-start",w=w||a==="inline-start"),_?{position:"absolute",[a==="top"?"bottom":"top"]:"0",[w?"right":"left"]:"0"}:be},[a,d]);D(()=>{if(!r){m.current=Nt,p.current=!0,f.current=null;return}if(!t||!o)return;m.current=Tl(t,v),xi(t,"auto");let _=qn(t,"position","static"),w=qn(t,"transform","none"),y=qn(t,"scale","1"),b=Tl(o,{"--available-width":"max-content","--available-height":"max-content"});function S(){_(),w(),b()}function x(){S(),y()}if(u?.(),p.current||f.current===null){Kn(o,"max-content");let C=yi(t);return f.current=C,Kn(o,C),x(),g?.(null,C),p.current=!1,()=>{m.current(),m.current=Nt}}Kn(o,"max-content");let E=f.current,T=yi(t);f.current=T,xi(t,E),x(),g?.(E,T),Kn(o,T);let k=new AbortController;return l.request(()=>{xi(t,T),c(()=>{t.style.setProperty("--popup-width","auto"),t.style.setProperty("--popup-height","auto")},k.signal)}),()=>{k.abort(),l.cancel(),m.current(),m.current=Nt}},[n,t,o,c,l,r,u,g,v])}function qn(e,t,o){let n=e.style.getPropertyValue(t);return e.style.setProperty(t,o),()=>{e.style.setProperty(t,n)}}function Tl(e,t){let o=[];for(let[n,r]of Object.entries(t))o.push(qn(e,n,r));return o.length?()=>{o.forEach(n=>n())}:Nt}function xi(e,t){let o=t==="auto"?"auto":`${t.width}px`,n=t==="auto"?"auto":`${t.height}px`;e.style.setProperty("--popup-width",o),e.style.setProperty("--popup-height",n)}function Kn(e,t){let o=t==="max-content"?"max-content":`${t.width}px`,n=t==="max-content"?"max-content":`${t.height}px`;e.style.setProperty("--positioner-width",o),e.style.setProperty("--positioner-height",n)}var Eo=h(Q(),1);function Al(e){let{store:t,side:o,cssVars:n,children:r}=e,i=so(),s=t.useState("activeTriggerElement"),a=t.useState("activeTriggerId"),d=t.useState("open"),c=t.useState("payload"),l=t.useState("mounted"),f=t.useState("popupElement"),p=t.useState("positionerElement"),m=El(d?s:null),u=ug(a,c),g=Le.useRef(null),[v,_]=Le.useState(null),[w,y]=Le.useState(null),b=Le.useRef(null),S=Le.useRef(null),x=mo(b,!0,!1),E=lo(),[T,k]=Le.useState(null),[C,j]=Le.useState(!1);D(()=>(t.set("hasViewport",!0),()=>{t.set("hasViewport",!1)}),[t]);let A=Y(()=>{b.current?.style.setProperty("animation","none"),b.current?.style.setProperty("transition","none"),S.current?.style.setProperty("display","none")}),L=Y(P=>{b.current?.style.removeProperty("animation"),b.current?.style.removeProperty("transition"),S.current?.style.removeProperty("display"),P&&k(P)}),I=Le.useRef(null);D(()=>{(!d||!l)&&(I.current=null)},[d,l]),D(()=>{if(s&&m&&s!==m&&I.current!==s&&g.current){_(g.current),j(!0);let P=dg(m,s);y(P),E.request(()=>{Cl.flushSync(()=>{j(!1)}),x(()=>{_(null),k(null),g.current=null})}),I.current=s}},[s,m,v,x,E]),D(()=>{let P=b.current;if(!P)return;let O=xe(P).createElement("div");for(let M of Array.from(P.childNodes))O.appendChild(M.cloneNode(!0));g.current=O});let R=v!=null,N;R?N=(0,Eo.jsxs)(Le.Fragment,{children:[(0,Eo.jsx)("div",{"data-previous":!0,inert:ml(!0),ref:S,style:{...T?{[n.popupWidth]:`${T.width}px`,[n.popupHeight]:`${T.height}px`}:null,position:"absolute"},"data-ending-style":C?void 0:""},"previous"),(0,Eo.jsx)("div",{"data-current":!0,ref:b,"data-starting-style":C?"":void 0,children:r},u)]}):N=(0,Eo.jsx)("div",{"data-current":!0,ref:b,children:r},u),D(()=>{let P=S.current;!P||!v||P.replaceChildren(...Array.from(v.childNodes))},[v]),kl({popupElement:f,positionerElement:p,mounted:l,content:c,onMeasureLayout:A,onMeasureLayoutComplete:L,side:o,direction:i});let H={activationDirection:lg(w),transitioning:R};return{children:N,state:H}}function lg(e){if(e)return`${Pl(e.horizontal,5,"right","left")} ${Pl(e.vertical,5,"down","up")}`}function Pl(e,t,o,n){return e>t?o:e<-t?n:""}function dg(e,t){let o=e.getBoundingClientRect(),n=t.getBoundingClientRect(),r={x:o.left+o.width/2,y:o.top+o.height/2},i={x:n.left+n.width/2,y:n.top+n.height/2};return{horizontal:i.x-r.x,vertical:i.y-r.y}}function ug(e,t){let[o,n]=Le.useState(0),r=Le.useRef(e),i=Le.useRef(t),s=Le.useRef(!1);return D(()=>{let a=r.current,d=i.current,c=e!==a,l=t!==d;c?(n(f=>f+1),s.current=!l):s.current&&l&&(n(f=>f+1),s.current=!1),r.current=e,i.current=t},[e,t]),`${e??"current"}-${o}`}var Zn=h(z(),1),Ol=h(Mt(),1);var Nl=h(Q(),1),Ll=Zn.forwardRef(function(t,o){let{children:n,container:r,className:i,render:s,style:a,...d}=t,{portalNode:c,portalSubtree:l}=Ur({container:r,ref:o,componentProps:t,elementProps:d});return!l&&!c?null:(0,Nl.jsxs)(Zn.Fragment,{children:[l,c&&Ol.createPortal(n,c)]})});var Qe={};At(Qe,{Arrow:()=>ql,Handle:()=>Qo,Popup:()=>Xl,Portal:()=>Wl,Positioner:()=>Ul,Provider:()=>Zl,Root:()=>Ml,Trigger:()=>jl,Viewport:()=>$l,createHandle:()=>ed});var gt=h(z(),1);var Qn=h(z(),1),Ri=Qn.createContext(void 0);function Ze(e){let t=Qn.useContext(Ri);if(t===void 0&&!e)throw new Error(Pe(72));return t}var Il=h(z(),1);var fg={...ll,disabled:q(e=>e.disabled),instantType:q(e=>e.instantType),isInstantPhase:q(e=>e.isInstantPhase),trackCursorAxis:q(e=>e.trackCursorAxis),disableHoverablePopup:q(e=>e.disableHoverablePopup),lastOpenChangeReason:q(e=>e.openChangeReason),closeOnClick:q(e=>e.closeOnClick),closeDelay:q(e=>e.closeDelay),hasViewport:q(e=>e.hasViewport)},To=class e extends vo{constructor(t,o,n=!1){let r=new jt,i={...pg(),...t};i.floatingRootContext=al(r,o,n),super(i,{popupRef:Il.createRef(),onOpenChange:void 0,onOpenChangeComplete:void 0,triggerElements:r},fg)}setOpen=(t,o)=>{Jc(this,t,o,{extraState:{openChangeReason:o.reason}})};cancelPendingOpen(t){this.state.floatingRootContext.dispatchOpenChange(!1,ee(U.triggerPress,t))}static useStore(t,o){return Qc(t,(r,i)=>new e(o,r,i)).store}};function pg(){return{...sl(),disabled:!1,instantType:void 0,isInstantPhase:!1,trackCursorAxis:"none",disableHoverablePopup:!1,openChangeReason:null,closeOnClick:!0,closeDelay:0,hasViewport:!1}}var Jn=h(Q(),1),Ml=ci(function(t){let{disabled:o=!1,defaultOpen:n=!1,open:r,disableHoverablePopup:i=!1,trackCursorAxis:s="none",actionsRef:a,onOpenChange:d,onOpenChangeComplete:c,handle:l,triggerId:f,defaultTriggerId:p=null,children:m}=t,u=To.useStore(l?.store,{open:n,openProp:r,activeTriggerId:p,triggerIdProp:f});$c(u,r,n,p),u.useControlledProp("openProp",r),u.useControlledProp("triggerIdProp",f),u.useContextCallback("onOpenChange",d),u.useContextCallback("onOpenChangeComplete",c);let g=u.useState("open"),v=!o&&g,_=u.useState("activeTriggerId"),w=u.useState("mounted"),y=u.useState("payload");u.useSyncedValues({trackCursorAxis:s,disableHoverablePopup:i}),u.useSyncedValue("disabled",o),tl(u,{closeOnActiveTriggerUnmount:!0});let{forceUnmount:b,transitionStatus:S}=ol(v,u),x=u.useState("isInstantPhase"),E=u.useState("instantType"),T=u.useState("lastOpenChangeReason"),k=gt.useRef(null);D(()=>{g&&o&&u.setOpen(!1,ee(U.disabled))},[g,o,u]),D(()=>{S==="ending"&&T===U.none||S!=="ending"&&x?(E!=="delay"&&(k.current=E),u.set("instantType","delay")):k.current!==null&&(u.set("instantType",k.current),k.current=null)},[S,x,T,E,u]),D(()=>{v&&_==null&&u.set("payload",void 0)},[u,_,v]);let C=gt.useCallback(()=>{u.setOpen(!1,ee(U.imperativeAction))},[u]);gt.useImperativeHandle(a,()=>({unmount:b,close:C}),[b,C]);let j=v||w||!o&&s!=="none";return(0,Jn.jsxs)(Ri.Provider,{value:u,children:[j&&(0,Jn.jsx)(mg,{store:u,disabled:o,trackCursorAxis:s}),typeof m=="function"?m({payload:y}):m]})});function mg({store:e,disabled:t,trackCursorAxis:o}){let n=e.useState("floatingRootContext"),r=Xr(n,{enabled:!t,referencePress:()=>e.select("closeOnClick")}),i=Gr(n,{enabled:!t&&o!=="none",axis:o==="none"?void 0:o}),s=gt.useMemo(()=>ye(i.reference,r.reference),[i.reference,r.reference]),a=gt.useMemo(()=>ye(i.trigger,r.trigger),[i.trigger,r.trigger]),d=gt.useMemo(()=>ye(Zc,i.floating,r.floating),[i.floating,r.floating]);return nl(e,{activeTriggerProps:s,inactiveTriggerProps:a,popupProps:d}),null}var er=h(z(),1);var $n=h(z(),1),Si=$n.createContext(void 0);function Bl(){return $n.useContext(Si)}var Hl=(function(e){return e[e.popupOpen=qo.popupOpen]="popupOpen",e.triggerDisabled="data-trigger-disabled",e})({});var Dl="data-base-ui-tooltip-trigger";function zl(e){if("composedPath"in e){let o=e.composedPath();for(let n=0;ng.select("transitionStatus")==="ending",shouldOpen(){return!O.current}}),G=pi(y,{enabled:!R}).reference,K=X=>{let pe=O.current,ue=zl(X),vt=te(ue),Te=b.current,Ve=Te&&ue&&ie(Te,ue);if(vt&&g.select("open")&&g.select("lastOpenChangeReason")===U.triggerHover){g.setOpen(!1,ee(U.triggerHover,X));return}if(pe&&!vt&&Ve&&!N.current&&!g.select("open")&&Te&&Rt(Z.current)){let Ke=()=>{!O.current&&!N.current&&!g.select("open")&&g.setOpen(!0,ee(U.triggerHover,X,Te))},He=W();He===0?(M.clear(),Ke()):M.start(He,Ke)}},J=g.useState("triggerProps",T);return Ce("button",t,{state:{open:w},ref:[o,E,b],props:[se,G,T||H!=="none"?J:void 0,{onMouseOver(X){K(X.nativeEvent)},onFocus(X){oe(zl(X.nativeEvent))&&X.preventBaseUIHandler()},onMouseLeave(){O.current=!1,M.clear(),Z.current=void 0},onPointerEnter(X){Z.current=X.pointerType},onPointerDown(X){Z.current=X.pointerType,g.set("closeOnClick",l),l&&!g.select("open")&&g.cancelPendingOpen(X.nativeEvent)},onClick(X){l&&!g.select("open")&&g.cancelPendingOpen(X.nativeEvent)},id:v,[Hl.triggerDisabled]:R?"":void 0,[Dl]:R?void 0:""},m],stateAttributesMapping:pl})});var Vl=h(z(),1);var tr=h(z(),1),Ei=tr.createContext(void 0);function Fl(){let e=tr.useContext(Ei);if(e===void 0)throw new Error(Pe(70));return e}var Ti=h(Q(),1),Wl=Vl.forwardRef(function(t,o){let{keepMounted:n=!1,...r}=t;return Ze().useState("mounted")||n?(0,Ti.jsx)(Ei.Provider,{value:n,children:(0,Ti.jsx)(Ll,{ref:o,...r})}):null});var nr=h(z(),1);var or=h(z(),1),ki=or.createContext(void 0);function ko(){let e=or.useContext(ki);if(e===void 0)throw new Error(Pe(71));return e}var Yl=h(Q(),1),Ul=nr.forwardRef(function(t,o){let{render:n,className:r,anchor:i,positionMethod:s="absolute",side:a="top",align:d="center",sideOffset:c=0,alignOffset:l=0,collisionBoundary:f="clipping-ancestors",collisionPadding:p=5,arrowPadding:m=5,sticky:u=!1,disableAnchorTracking:g=!1,collisionAvoidance:v=Qa,style:_,...w}=t,y=Ze(),b=Fl(),S=y.useState("open"),x=y.useState("mounted"),E=y.useState("trackCursorAxis"),T=y.useState("disableHoverablePopup"),k=y.useState("floatingRootContext"),C=y.useState("instantType"),j=y.useState("transitionStatus"),A=y.useState("hasViewport"),L=yl({anchor:i,positionMethod:s,floatingRootContext:k,mounted:x,side:a,sideOffset:c,align:d,alignOffset:l,collisionBoundary:f,collisionPadding:p,sticky:u,arrowPadding:m,disableAnchorTracking:g,keepMounted:b,collisionAvoidance:v,adaptiveOrigin:A?hl:void 0}),I=nr.useMemo(()=>({open:S,side:L.side,align:L.align,anchorHidden:L.anchorHidden,instant:E!=="none"?"tracking-cursor":C}),[S,L.side,L.align,L.anchorHidden,E,C]),R=xl(t,I,{styles:L.positionerStyles,transitionStatus:j,props:w,refs:[o,y.useStateSetter("positionerElement")],hidden:!x,inert:!S||E==="both"||T});return(0,Yl.jsx)(ki.Provider,{value:L,children:R})});var Gl=h(z(),1);var bg={...Ro,...wa},Xl=Gl.forwardRef(function(t,o){let{render:n,className:r,style:i,...s}=t,a=Ze(),{side:d,align:c}=ko(),l=a.useState("open"),f=a.useState("instantType"),p=a.useState("transitionStatus"),m=a.useState("popupProps"),u=a.useState("floatingRootContext"),g=a.useState("disabled"),v=a.useState("closeDelay");Pn({open:l,ref:a.context.popupRef,onComplete(){l&&a.context.onOpenChangeComplete?.(!0)}}),bi(u,{enabled:!g,closeDelay:v});let _=a.useStateSetter("popupElement");return Ce("div",t,{state:{open:l,side:d,align:c,instant:f,transitionStatus:p},ref:[o,a.context.popupRef,_],props:[m,Xn(p),s],stateAttributesMapping:bg})});var Kl=h(z(),1);var ql=Kl.forwardRef(function(t,o){let{render:n,className:r,style:i,...s}=t,a=Ze(),{arrowRef:d,side:c,align:l,arrowUncentered:f,arrowStyles:p}=ko(),m=a.useState("open"),u=a.useState("instantType");return Ce("div",t,{state:{open:m,side:c,align:l,uncentered:f,instant:u},ref:[o,d],props:[{style:p,"aria-hidden":!0},s],stateAttributesMapping:Ro})});var Pi=h(z(),1);var Ci=h(Q(),1),Zl=function(t){let{delay:o,closeDelay:n,timeout:r=400}=t,i=Pi.useMemo(()=>({delay:o,closeDelay:n}),[o,n]),s=Pi.useMemo(()=>({open:o,close:n}),[o,n]);return(0,Ci.jsx)(Si.Provider,{value:i,children:(0,Ci.jsx)(Wr,{delay:s,timeoutMs:r,children:t.children})})};var Jl=h(z(),1);var Ql=(function(e){return e.popupWidth="--popup-width",e.popupHeight="--popup-height",e})({});var hg={activationDirection:e=>e?{"data-activation-direction":e}:null},$l=Jl.forwardRef(function(t,o){let{render:n,className:r,style:i,children:s,...a}=t,d=Ze(),c=ko(),l=d.useState("instantType"),{children:f,state:p}=Al({store:d,side:c.side,cssVars:Ql,children:s}),m={activationDirection:p.activationDirection,transitioning:p.transitioning,instant:l};return Ce("div",t,{state:m,ref:o,props:[a,{children:f}],stateAttributesMapping:hg})});var Qo=class{constructor(){this.store=new To}open(t){let o=t?this.store.context.triggerElements.getById(t):void 0;if(t&&!o)throw new Error(Pe(81,t));this.store.setOpen(!0,ee(U.imperativeAction,void 0,o))}close(){this.store.setOpen(!1,ee(U.imperativeAction,void 0,void 0))}get isOpen(){return this.store.select("open")}};function ed(){return new Qo}function bt(e){return Ce(e.defaultTagName??"div",e,e)}var nd=h(de(),1),Ai="data-wp-hash";function Oi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&vg(document)),e.__wpStyleRuntime}function wg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ai}]`))if(o.getAttribute(Ai)===t)return!0;return!1}function rd(e,t,o){if(!e.head)return;let n=Oi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(wg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ai,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function vg(e){let t=Oi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)rd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function id(e,t){let o=Oi();o.styles.set(e,t);for(let n of o.documents.keys())rd(n,e,t)}typeof process>"u",id("a495f9d138",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._83ed8a8da5dd50ea__text{margin:0}._14437cfb77831647__heading-2xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-2xl,32px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-2xl,32px);--_gcd-p-line-height:var(--wpds-typography-line-height-2xl,40px);font-size:var(--wpds-typography-font-size-2xl,32px);line-height:var(--wpds-typography-line-height-2xl,40px)}._14437cfb77831647__heading-2xl,._3c78b7fa9b4072dd__heading-xl{font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-emphasis,600)}._3c78b7fa9b4072dd__heading-xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-p-line-height:var(--wpds-typography-line-height-md,24px);font-size:var(--wpds-typography-font-size-xl,20px);line-height:var(--wpds-typography-line-height-md,24px)}.aa58f227716bcde2__heading-lg{--_gcd-heading-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-lg,15px)}.aa58f227716bcde2__heading-lg,.fc4da56d8dfe52c4__heading-md{font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-emphasis,600);line-height:var(--wpds-typography-line-height-sm,20px)}.fc4da56d8dfe52c4__heading-md{--_gcd-heading-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-md,13px)}.a9b78c7c82e8dff7__heading-sm{--_gcd-heading-font-size:var(--wpds-typography-font-size-xs,11px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-emphasis,600);--_gcd-p-font-size:var(--wpds-typography-font-size-xs,11px);--_gcd-p-line-height:var(--wpds-typography-line-height-xs,16px);font-family:var(--wpds-typography-font-family-heading,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-xs,11px);font-weight:var(--wpds-typography-font-weight-emphasis,600);line-height:var(--wpds-typography-line-height-xs,16px);text-transform:uppercase}._305ff559e52180d5__body-xl{--_gcd-heading-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-xl,20px);--_gcd-p-line-height:var(--wpds-typography-line-height-xl,32px);font-size:var(--wpds-typography-font-size-xl,20px);line-height:var(--wpds-typography-line-height-xl,32px)}._305ff559e52180d5__body-xl,.ca1aa3fc2029e958__body-lg{font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-default,400)}.ca1aa3fc2029e958__body-lg{--_gcd-heading-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-lg,15px);--_gcd-p-line-height:var(--wpds-typography-line-height-md,24px);font-size:var(--wpds-typography-font-size-lg,15px);line-height:var(--wpds-typography-line-height-md,24px)}._131101940be12424__body-md{--_gcd-heading-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-md,13px);--_gcd-p-line-height:var(--wpds-typography-line-height-sm,20px);font-size:var(--wpds-typography-font-size-md,13px);line-height:var(--wpds-typography-line-height-sm,20px)}._0e8d87a42c1f75fa__body-sm,._131101940be12424__body-md{font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-weight:var(--wpds-typography-font-weight-default,400)}._0e8d87a42c1f75fa__body-sm{--_gcd-heading-font-size:var(--wpds-typography-font-size-sm,12px);--_gcd-heading-font-weight:var(--wpds-typography-font-weight-default,400);--_gcd-p-font-size:var(--wpds-typography-font-size-sm,12px);--_gcd-p-line-height:var(--wpds-typography-line-height-xs,16px);font-size:var(--wpds-typography-font-size-sm,12px);line-height:var(--wpds-typography-line-height-xs,16px)}}}');var td={text:"_83ed8a8da5dd50ea__text","heading-2xl":"_14437cfb77831647__heading-2xl","heading-xl":"_3c78b7fa9b4072dd__heading-xl","heading-lg":"aa58f227716bcde2__heading-lg","heading-md":"fc4da56d8dfe52c4__heading-md","heading-sm":"a9b78c7c82e8dff7__heading-sm","body-xl":"_305ff559e52180d5__body-xl","body-lg":"ca1aa3fc2029e958__body-lg","body-md":"_131101940be12424__body-md","body-sm":"_0e8d87a42c1f75fa__body-sm"};typeof process>"u",id("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var od={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},Je=(0,nd.forwardRef)(function({variant:t="body-md",render:o,className:n,...r},i){return bt({render:o,defaultTagName:"span",ref:i,props:ye(r,{className:$(td.text,od.heading,od.p,td[t],n)})})});var ld=h(Q(),1),Ni="data-wp-hash";function Li(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&yg(document)),e.__wpStyleRuntime}function _g(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ni}]`))if(o.getAttribute(Ni)===t)return!0;return!1}function cd(e,t,o){if(!e.head)return;let n=Li(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(_g(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ni,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function yg(e){let t=Li();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)cd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function xg(e,t){let o=Li();o.styles.set(e,t);for(let n of o.documents.keys())cd(n,e,t)}typeof process>"u",xg("9db2873e7f","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._96e6251aad1a6136__badge{border-radius:var(--wpds-border-radius-lg,8px);padding-block:var(--wpds-dimension-padding-xs,4px);padding-inline:var(--wpds-dimension-padding-sm,8px)}._99f7158cb520f750__is-high-intent{background-color:var(--wpds-color-background-surface-error,#f6e6e3);color:var(--wpds-color-foreground-content-error,#470000)}.c20ebef2365bc8b7__is-medium-intent{background-color:var(--wpds-color-background-surface-warning,#fde6be);color:var(--wpds-color-foreground-content-warning,#2e1900)}._365e1626c6202e52__is-low-intent{background-color:var(--wpds-color-background-surface-caution,#fee995);color:var(--wpds-color-foreground-content-caution,#281d00)}._33f8198127ddf4ef__is-stable-intent{background-color:var(--wpds-color-background-surface-success,#c6f7cd);color:var(--wpds-color-foreground-content-success,#002900)}._04c1aca8fc449412__is-informational-intent{background-color:var(--wpds-color-background-surface-info,#deebfa);color:var(--wpds-color-foreground-content-info,#001b4f)}._90726e69d495ec19__is-draft-intent{background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);color:var(--wpds-color-foreground-content-neutral,#1e1e1e)}._898f4a544993bd39__is-none-intent{background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral,#dbdbdb);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);padding-block:calc(var(--wpds-dimension-padding-xs, 4px) - var(--wpds-border-width-xs, 1px));padding-inline:calc(var(--wpds-dimension-padding-sm, 8px) - var(--wpds-border-width-xs, 1px))}}}");var sd={badge:"_96e6251aad1a6136__badge","is-high-intent":"_99f7158cb520f750__is-high-intent","is-medium-intent":"c20ebef2365bc8b7__is-medium-intent","is-low-intent":"_365e1626c6202e52__is-low-intent","is-stable-intent":"_33f8198127ddf4ef__is-stable-intent","is-informational-intent":"_04c1aca8fc449412__is-informational-intent","is-draft-intent":"_90726e69d495ec19__is-draft-intent","is-none-intent":"_898f4a544993bd39__is-none-intent"},Ii=(0,ad.forwardRef)(function({intent:t="none",className:o,...n},r){return(0,ld.jsx)(Je,{ref:r,className:$(sd.badge,sd[`is-${t}-intent`],o),...n,variant:"body-sm"})});var rr=h(de(),1),dd=h(Ot(),1),fd=h(Q(),1);import{speak as Rg}from"@wordpress/a11y";var Mi="data-wp-hash";function Bi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Eg(document)),e.__wpStyleRuntime}function Sg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Mi}]`))if(o.getAttribute(Mi)===t)return!0;return!1}function ud(e,t,o){if(!e.head)return;let n=Bi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Sg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Mi,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Eg(e){let t=Bi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)ud(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function ir(e,t){let o=Bi();o.styles.set(e,t);for(let n of o.documents.keys())ud(n,e,t)}typeof process>"u",ir("b74f1ac304",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._97b0fc33c028be1a__button,.abbb272e2ce49bd6__is-unstyled{appearance:none;padding:0}._97b0fc33c028be1a__button{--wp-ui-button-font-weight:var(--wpds-typography-font-weight-emphasis,600);--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-strong,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-strong-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 93%,#000));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand-strong,#fff);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-strong-active,#fff);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-strong-disabled,#8d8d8d);--wp-ui-button-padding-block:var(--wpds-dimension-padding-xs,4px);--wp-ui-button-padding-inline:var(--wpds-dimension-padding-md,12px);--wp-ui-button-height:var(--wpds-dimension-size-lg,40px);--wp-ui-button-aspect-ratio:auto;--wp-ui-button-font-size:var(--wpds-typography-font-size-md,13px);--wp-ui-button-min-width:calc(4ch + var(--wp-ui-button-padding-inline)*2);--wp-ui-button-icon-margin:calc((var(--wpds-dimension-size-2xs, 16px) - var(--wpds-dimension-size-sm, 24px))/2);--wp-ui-button-border-color:var(--wp-ui-button-background-color);--wp-ui-button-border-color-active:var(--wp-ui-button-background-color-active);--wp-ui-button-border-color-disabled:var(--wp-ui-button-background-color-disabled);--_gcd-button-font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);--_gcd-button-font-size:var(--wp-ui-button-font-size);--_gcd-button-font-weight:var(--wp-ui-button-font-weight);align-items:center;aspect-ratio:var(--wp-ui-button-aspect-ratio);background-clip:border-box;background-color:var(--wp-ui-button-background-color);border-color:var(--wp-ui-button-border-color);border-radius:var(--wpds-border-radius-sm,2px);border-style:solid;border-width:1px;color:var(--wp-ui-button-foreground-color);display:inline-flex;font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wp-ui-button-font-size);font-weight:var(--wp-ui-button-font-weight);gap:var(--wpds-dimension-gap-sm,8px);justify-content:center;line-height:var(--wpds-typography-line-height-sm,20px);max-width:100%;min-height:var(--wp-ui-button-height);min-width:var(--wp-ui-button-min-width);overflow-wrap:anywhere;padding-block:var(--wp-ui-button-padding-block);padding-inline:var(--wp-ui-button-padding-inline);position:relative;text-align:center;text-decoration:none;&:not([data-disabled]){cursor:var(--wpds-cursor-control,pointer)}@media not (prefers-reduced-motion){transition:color .1s ease-out;*{transition:opacity .1s ease-out}}&[href]{cursor:pointer}[href]{color:inherit;text-decoration:inherit}&:not([data-disabled]):is(:hover,:active,:focus){background-color:var(--wp-ui-button-background-color-active);border-color:var(--wp-ui-button-border-color-active);color:var(--wp-ui-button-foreground-color-active)}&[data-disabled]:not(._914b42f315c0e580__is-loading){background-color:var(--wp-ui-button-background-color-disabled);border-color:var(--wp-ui-button-border-color-disabled);color:var(--wp-ui-button-foreground-color-disabled);@media (forced-colors:active){border-bottom-color:GrayText;border-left-color:GrayText;border-right-color:GrayText;border-top-color:GrayText;color:GrayText}}&:before{aspect-ratio:1;border:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid;border-block-end-color:transparent;border-block-start-color:var(--wp-ui-button-foreground-color);border-inline-end-color:var(--wp-ui-button-foreground-color);border-inline-start-color:transparent;border-radius:50%;box-sizing:border-box;content:"";display:block;height:var(--wp-ui-button-font-size);inset-inline-start:50%;opacity:0;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);@media not (prefers-reduced-motion){transition:opacity .1s ease-out}@media (forced-colors:active){border-block-end-style:none;border-bottom-color:ButtonText;border-inline-start-style:none;border-left-color:ButtonText;border-right-color:ButtonText;border-top-color:ButtonText}}}._908205475f9f2a92__is-small{--wp-ui-button-padding-block:0px;--wp-ui-button-padding-inline:var(--wpds-dimension-padding-sm,8px);--wp-ui-button-height:var(--wpds-dimension-size-sm,24px)}._9f6fc6553aeb36fe__icon{margin:var(--wp-ui-button-icon-margin)}.dd460c965226cc77__is-brand{&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 85%,#000));--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-brand-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000)}}.e722a8f96726aa99__is-neutral{&.ad0619a3217c6a5b__is-minimal[aria-pressed=true],&.b50b3358c5fb4d0b__is-solid{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-strong,#2d2d2d);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-strong-active,#1e1e1e);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral-strong,#f0f0f0);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-strong-active,#f0f0f0);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-strong-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d);--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-neutral-active,#6e6e6e);--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-neutral-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000)}}.abbb272e2ce49bd6__is-unstyled{background:none;border:none;min-width:unset}.cf59cf1b69629838__is-compact{--wp-ui-button-height:var(--wpds-dimension-size-md,32px)}._914b42f315c0e580__is-loading:not(.abbb272e2ce49bd6__is-unstyled){color:transparent;&:not([data-disabled]):is(:hover,:active,:focus){color:transparent}@media (forced-colors:active){color:ButtonFace}*{opacity:0}&:before{opacity:1;transition-delay:.05s;@media not (prefers-reduced-motion){animation:_5a1d53da6f830c8d__loading-animation 1s linear infinite}}}}@keyframes _5a1d53da6f830c8d__loading-animation{0%{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(1turn)}}}');var Jo={button:"_97b0fc33c028be1a__button","is-unstyled":"abbb272e2ce49bd6__is-unstyled","is-loading":"_914b42f315c0e580__is-loading","is-small":"_908205475f9f2a92__is-small",icon:"_9f6fc6553aeb36fe__icon","is-brand":"dd460c965226cc77__is-brand","is-outline":"_62d5a778b7b258ee__is-outline","is-minimal":"ad0619a3217c6a5b__is-minimal","is-neutral":"e722a8f96726aa99__is-neutral","is-solid":"b50b3358c5fb4d0b__is-solid","is-compact":"cf59cf1b69629838__is-compact","loading-animation":"_5a1d53da6f830c8d__loading-animation"};typeof process>"u",ir("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var Tg={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",ir("da99a163ac","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus{outline:none}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active){@include mixins.focus-ring()}}}");var kg={"outset-ring--focus":"_08e8a2e44959f892__outset-ring--focus","outset-ring--focus-visible":"d0541bc9dd9dc7b6__outset-ring--focus-visible","outset-ring--focus-within":"cd83dfc2126a0846__outset-ring--focus-within","outset-ring--focus-within-visible":"c5cb3ee4bddaa8e4__outset-ring--focus-within-visible","outset-ring--focus-parent-visible":"ecadb9e080e2dfa5__outset-ring--focus-parent-visible","outset-ring--focus-except-active":"e25b2bdd7aa21721__outset-ring--focus-except-active","outset-ring--focus-within-except-active":"_970d04df7376df67__outset-ring--focus-within-except-active"};typeof process>"u",ir("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var Pg={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},pd=(0,rr.forwardRef)(function({tone:t="brand",variant:o="solid",size:n="default",className:r,focusableWhenDisabled:i=!0,disabled:s,loading:a,loadingAnnouncement:d=(0,dd.__)("Loading"),children:c,...l},f){let p=$(Pg.button,Tg["box-sizing"],kg["outset-ring--focus-except-active"],o!=="unstyled"&&Jo.button,Jo[`is-${t}`],Jo[`is-${o}`],Jo[`is-${n}`],a&&Jo["is-loading"],r);return(0,rr.useEffect)(()=>{a&&d&&Rg(d)},[a,d]),(0,fd.jsx)(_i,{ref:f,className:p,focusableWhenDisabled:i,disabled:s??a,...l,children:c})});var wd=h(de(),1);var gd=h(de(),1),bd=h($t(),1),hd=h(Q(),1),eo=(0,gd.forwardRef)(function({icon:t,size:o=24,...n},r){return(0,hd.jsx)(bd.SVG,{ref:r,...t.props,...n,width:o,height:o})});var _d=h(Q(),1),Hi="data-wp-hash";function zi(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ag(document)),e.__wpStyleRuntime}function Cg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Hi}]`))if(o.getAttribute(Hi)===t)return!0;return!1}function vd(e,t,o){if(!e.head)return;let n=zi(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Cg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Hi,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ag(e){let t=zi();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)vd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Og(e,t){let o=zi();o.styles.set(e,t);for(let n of o.documents.keys())vd(n,e,t)}typeof process>"u",Og("b74f1ac304",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._97b0fc33c028be1a__button,.abbb272e2ce49bd6__is-unstyled{appearance:none;padding:0}._97b0fc33c028be1a__button{--wp-ui-button-font-weight:var(--wpds-typography-font-weight-emphasis,600);--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-strong,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-strong-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 93%,#000));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand-strong,#fff);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-strong-active,#fff);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-strong-disabled,#8d8d8d);--wp-ui-button-padding-block:var(--wpds-dimension-padding-xs,4px);--wp-ui-button-padding-inline:var(--wpds-dimension-padding-md,12px);--wp-ui-button-height:var(--wpds-dimension-size-lg,40px);--wp-ui-button-aspect-ratio:auto;--wp-ui-button-font-size:var(--wpds-typography-font-size-md,13px);--wp-ui-button-min-width:calc(4ch + var(--wp-ui-button-padding-inline)*2);--wp-ui-button-icon-margin:calc((var(--wpds-dimension-size-2xs, 16px) - var(--wpds-dimension-size-sm, 24px))/2);--wp-ui-button-border-color:var(--wp-ui-button-background-color);--wp-ui-button-border-color-active:var(--wp-ui-button-background-color-active);--wp-ui-button-border-color-disabled:var(--wp-ui-button-background-color-disabled);--_gcd-button-font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);--_gcd-button-font-size:var(--wp-ui-button-font-size);--_gcd-button-font-weight:var(--wp-ui-button-font-weight);align-items:center;aspect-ratio:var(--wp-ui-button-aspect-ratio);background-clip:border-box;background-color:var(--wp-ui-button-background-color);border-color:var(--wp-ui-button-border-color);border-radius:var(--wpds-border-radius-sm,2px);border-style:solid;border-width:1px;color:var(--wp-ui-button-foreground-color);display:inline-flex;font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wp-ui-button-font-size);font-weight:var(--wp-ui-button-font-weight);gap:var(--wpds-dimension-gap-sm,8px);justify-content:center;line-height:var(--wpds-typography-line-height-sm,20px);max-width:100%;min-height:var(--wp-ui-button-height);min-width:var(--wp-ui-button-min-width);overflow-wrap:anywhere;padding-block:var(--wp-ui-button-padding-block);padding-inline:var(--wp-ui-button-padding-inline);position:relative;text-align:center;text-decoration:none;&:not([data-disabled]){cursor:var(--wpds-cursor-control,pointer)}@media not (prefers-reduced-motion){transition:color .1s ease-out;*{transition:opacity .1s ease-out}}&[href]{cursor:pointer}[href]{color:inherit;text-decoration:inherit}&:not([data-disabled]):is(:hover,:active,:focus){background-color:var(--wp-ui-button-background-color-active);border-color:var(--wp-ui-button-border-color-active);color:var(--wp-ui-button-foreground-color-active)}&[data-disabled]:not(._914b42f315c0e580__is-loading){background-color:var(--wp-ui-button-background-color-disabled);border-color:var(--wp-ui-button-border-color-disabled);color:var(--wp-ui-button-foreground-color-disabled);@media (forced-colors:active){border-bottom-color:GrayText;border-left-color:GrayText;border-right-color:GrayText;border-top-color:GrayText;color:GrayText}}&:before{aspect-ratio:1;border:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid;border-block-end-color:transparent;border-block-start-color:var(--wp-ui-button-foreground-color);border-inline-end-color:var(--wp-ui-button-foreground-color);border-inline-start-color:transparent;border-radius:50%;box-sizing:border-box;content:"";display:block;height:var(--wp-ui-button-font-size);inset-inline-start:50%;opacity:0;pointer-events:none;position:absolute;top:50%;transform:translate(-50%,-50%);@media not (prefers-reduced-motion){transition:opacity .1s ease-out}@media (forced-colors:active){border-block-end-style:none;border-bottom-color:ButtonText;border-inline-start-style:none;border-left-color:ButtonText;border-right-color:ButtonText;border-top-color:ButtonText}}}._908205475f9f2a92__is-small{--wp-ui-button-padding-block:0px;--wp-ui-button-padding-inline:var(--wpds-dimension-padding-sm,8px);--wp-ui-button-height:var(--wpds-dimension-size-sm,24px)}._9f6fc6553aeb36fe__icon{margin:var(--wp-ui-button-icon-margin)}.dd460c965226cc77__is-brand{&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-brand-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-brand,var(--wp-admin-theme-color,#3858e9));--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 85%,#000));--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-brand-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal{--wp-ui-button-background-color:var(--wpds-color-background-interactive-brand-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-brand-weak-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 12%,#fff));--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-brand-weak-disabled,#0000)}}.e722a8f96726aa99__is-neutral{&.ad0619a3217c6a5b__is-minimal[aria-pressed=true],&.b50b3358c5fb4d0b__is-solid{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-strong,#2d2d2d);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-strong-active,#1e1e1e);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-strong-disabled,#e6e6e6);--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral-strong,#f0f0f0);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-strong-active,#f0f0f0);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-strong-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline,&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-foreground-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);--wp-ui-button-foreground-color-active:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);--wp-ui-button-foreground-color-disabled:var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d)}&._62d5a778b7b258ee__is-outline{--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000);--wp-ui-button-border-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d);--wp-ui-button-border-color-active:var(--wpds-color-stroke-interactive-neutral-active,#6e6e6e);--wp-ui-button-border-color-disabled:var(--wpds-color-stroke-interactive-neutral-disabled,#dbdbdb)}&.ad0619a3217c6a5b__is-minimal:not([aria-pressed=true]){--wp-ui-button-background-color:var(--wpds-color-background-interactive-neutral-weak,#0000);--wp-ui-button-background-color-active:var(--wpds-color-background-interactive-neutral-weak-active,#ededed);--wp-ui-button-background-color-disabled:var(--wpds-color-background-interactive-neutral-weak-disabled,#0000)}}.abbb272e2ce49bd6__is-unstyled{background:none;border:none;min-width:unset}.cf59cf1b69629838__is-compact{--wp-ui-button-height:var(--wpds-dimension-size-md,32px)}._914b42f315c0e580__is-loading:not(.abbb272e2ce49bd6__is-unstyled){color:transparent;&:not([data-disabled]):is(:hover,:active,:focus){color:transparent}@media (forced-colors:active){color:ButtonFace}*{opacity:0}&:before{opacity:1;transition-delay:.05s;@media not (prefers-reduced-motion){animation:_5a1d53da6f830c8d__loading-animation 1s linear infinite}}}}@keyframes _5a1d53da6f830c8d__loading-animation{0%{transform:translate(-50%,-50%) rotate(0deg)}to{transform:translate(-50%,-50%) rotate(1turn)}}}');var Ng={button:"_97b0fc33c028be1a__button","is-unstyled":"abbb272e2ce49bd6__is-unstyled","is-loading":"_914b42f315c0e580__is-loading","is-small":"_908205475f9f2a92__is-small",icon:"_9f6fc6553aeb36fe__icon","is-brand":"dd460c965226cc77__is-brand","is-outline":"_62d5a778b7b258ee__is-outline","is-minimal":"ad0619a3217c6a5b__is-minimal","is-neutral":"e722a8f96726aa99__is-neutral","is-solid":"b50b3358c5fb4d0b__is-solid","is-compact":"cf59cf1b69629838__is-compact","loading-animation":"_5a1d53da6f830c8d__loading-animation"},Di=(0,wd.forwardRef)(function({className:t,icon:o,...n},r){return(0,_d.jsx)(eo,{ref:r,icon:o,className:$(Ng.icon,t),size:24,...n})});Di.displayName="Button.Icon";var sr=Object.assign(pd,{Icon:Di});var ar=h($t(),1),ji=h(Q(),1),Fi=(0,ji.jsx)(ar.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,ji.jsx)(ar.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm-.75 12v-1.5h1.5V16h-1.5Zm0-8v5h1.5V8h-1.5Z"})});var cr=h($t(),1),Vi=h(Q(),1),Wi=(0,Vi.jsx)(cr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Vi.jsx)(cr.Path,{d:"M12 13.06l3.712 3.713 1.061-1.06L13.061 12l3.712-3.712-1.06-1.06L12 10.938 8.288 7.227l-1.061 1.06L10.939 12l-3.712 3.712 1.06 1.061L12 13.061z"})});var lr=h($t(),1),Yi=h(Q(),1),Ui=(0,Yi.jsx)(lr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Yi.jsx)(lr.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M12.218 5.377a.25.25 0 0 0-.436 0l-7.29 12.96a.25.25 0 0 0 .218.373h14.58a.25.25 0 0 0 .218-.372l-7.29-12.96Zm-1.743-.735c.669-1.19 2.381-1.19 3.05 0l7.29 12.96a1.75 1.75 0 0 1-1.525 2.608H4.71a1.75 1.75 0 0 1-1.525-2.608l7.29-12.96ZM12.75 17.46h-1.5v-1.5h1.5v1.5Zm-1.5-3h1.5v-5h-1.5v5Z"})});var dr=h($t(),1),Gi=h(Q(),1),Xi=(0,Gi.jsx)(dr.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Gi.jsx)(dr.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M5.5 12a6.5 6.5 0 1 0 13 0 6.5 6.5 0 0 0-13 0ZM12 4a8 8 0 1 0 0 16 8 8 0 0 0 0-16Zm.75 4v1.5h-1.5V8h1.5Zm0 8v-5h-1.5v5h1.5Z"})});var ur=h($t(),1),Ki=h(Q(),1),qi=(0,Ki.jsx)(ur.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",fill:"currentColor",children:(0,Ki.jsx)(ur.Path,{fillRule:"evenodd",clipRule:"evenodd",d:"M12 18.5a6.5 6.5 0 1 1 0-13 6.5 6.5 0 0 1 0 13ZM4 12a8 8 0 1 1 16 0 8 8 0 0 1-16 0Zm11.53-1.47-1.06-1.06L11 12.94l-1.47-1.47-1.06 1.06L11 15.06l4.53-4.53Z"})});var yd=h(de(),1);function Zi(e,t,o){return(0,yd.cloneElement)(e??t,{children:o})}var Lg=h(Rd(),1);var Ed=h(Qi(),1),{lock:h4,unlock:Td}=(0,Ed.__dangerousOptInToUnstableAPIsOnlyForCoreModules)("I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.","@wordpress/ui");function Ig(){let e=Lg;if(e.ThemeProvider)return e.ThemeProvider;if(!e.privateApis)throw new Error("@wordpress/ui: @wordpress/theme must expose `ThemeProvider` or `privateApis.ThemeProvider`.");return Td(e.privateApis).ThemeProvider}var kd=Ig();var Pd=h(de(),1),Ji="data-wp-hash";function $i(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Bg(document)),e.__wpStyleRuntime}function Mg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ji}]`))if(o.getAttribute(Ji)===t)return!0;return!1}function Cd(e,t,o){if(!e.head)return;let n=$i(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Mg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ji,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Bg(e){let t=$i();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Cd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Hg(e,t){let o=$i();o.styles.set(e,t);for(let n of o.documents.keys())Cd(n,e,t)}typeof process>"u",Hg("32aba35fe1","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._19ce0419607e1896__stack{display:flex}}}");var zg={stack:"_19ce0419607e1896__stack"},Dg={xs:"var(--wpds-dimension-gap-xs, 4px)",sm:"var(--wpds-dimension-gap-sm, 8px)",md:"var(--wpds-dimension-gap-md, 12px)",lg:"var(--wpds-dimension-gap-lg, 16px)",xl:"var(--wpds-dimension-gap-xl, 24px)","2xl":"var(--wpds-dimension-gap-2xl, 32px)","3xl":"var(--wpds-dimension-gap-3xl, 40px)"},Po=(0,Pd.forwardRef)(function({direction:t,gap:o,align:n,justify:r,wrap:i,render:s,...a},d){let c={gap:o&&Dg[o],alignItems:n,justifyContent:r,flexDirection:t,flexWrap:i};return bt({render:s,ref:d,props:ye(a,{style:c,className:zg.stack})})});var Kd=h(de(),1);var Vd=h(de(),1);var Id=h(de(),1);var ts="data-wp-hash";function os(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Fg(document)),e.__wpStyleRuntime}function jg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ts}]`))if(o.getAttribute(ts)===t)return!0;return!1}function Od(e,t,o){if(!e.head)return;let n=os(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(jg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ts,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Fg(e){let t=os();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Od(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Vg(e,t){let o=os();o.styles.set(e,t);for(let n of o.documents.keys())Od(n,e,t)}typeof process>"u",Vg("be37f31c1e","._11fc52b637ff8a7e__slot{inset:0;isolation:isolate;pointer-events:none;position:fixed;z-index:1000000003}@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._11fc52b637ff8a7e__slot>*{pointer-events:auto}}}");var Ad={slot:"_11fc52b637ff8a7e__slot"},Nd="data-wp-compat-overlay-slot";function Wg(){return typeof document>"u"?null:document}function Yg(){let e;try{e=window.top?.wp}catch{}let t=e??window.wp;return typeof t?.components=="object"&&t.components!==null}var ht=null;function es(e){return e.setAttribute("aria-hidden","false"),e}function Ug(e){let t=e.createElement("div");return t.setAttribute(Nd,""),Ad.slot&&t.classList.add(Ad.slot),e.body.appendChild(t),t}function Ld(){if(typeof window>"u"||!Yg()&&window.__wpUiCompatOverlaySlotEnabled!==!0)return;let e=Wg();if(!e||!e.body)return;if(ht&&ht.ownerDocument===e&&ht.isConnected)return es(ht);let t=e.querySelector(`[${Nd}]`);return t instanceof HTMLDivElement?(ht=es(t),ht):(ht?.isConnected&&ht.remove(),ht=es(Ug(e)),ht)}var Md=h(Q(),1),Bd=(0,Id.forwardRef)(function({container:t,...o},n){return(0,Md.jsx)(Qe.Portal,{container:t??Ld(),...o,ref:n})});var Hd=h(de(),1),jd=h(Q(),1),ns="data-wp-hash";function rs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Xg(document)),e.__wpStyleRuntime}function Gg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ns}]`))if(o.getAttribute(ns)===t)return!0;return!1}function zd(e,t,o){if(!e.head)return;let n=rs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Gg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ns,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Xg(e){let t=rs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)zd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Dd(e,t){let o=rs();o.styles.set(e,t);for(let n of o.documents.keys())zd(n,e,t)}typeof process>"u",Dd("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var Kg={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",Dd("19fcc06039",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._480b748dd3510e64__positioner{z-index:var(--wp-ui-tooltip-z-index,initial)}._50096b232db7709d__popup{--_wp-ui-elevation-sm:0 1px 2px rgba(0,0,0,.05),0 2px 3px rgba(0,0,0,.04),0 6px 6px rgba(0,0,0,.03),0 8px 8px rgba(0,0,0,.02);background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border-radius:var(--wpds-border-radius-md,4px);box-shadow:var(--_wp-ui-elevation-sm);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-sm,12px);line-height:1.4;padding:var(--wpds-dimension-padding-xs,4px) var(--wpds-dimension-padding-sm,8px);@media (forced-colors:active){border-bottom-color:CanvasText;border-bottom-style:solid;border-bottom-width:1px;border-left-color:CanvasText;border-left-style:solid;border-left-width:1px;border-right-color:CanvasText;border-right-style:solid;border-right-width:1px;border-top-color:CanvasText;border-top-style:solid;border-top-width:1px}}}}');var qg={positioner:"_480b748dd3510e64__positioner",popup:"_50096b232db7709d__popup"},Fd=(0,Hd.forwardRef)(function({align:t="center",className:o,side:n="top",sideOffset:r=4,...i},s){return(0,jd.jsx)(Qe.Positioner,{ref:s,align:t,side:n,sideOffset:r,...i,className:$(Kg["box-sizing"],qg.positioner,o)})});var $o=h(Q(),1),is="data-wp-hash";function ss(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Qg(document)),e.__wpStyleRuntime}function Zg(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${is}]`))if(o.getAttribute(is)===t)return!0;return!1}function Wd(e,t,o){if(!e.head)return;let n=ss(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Zg(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(is,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Qg(e){let t=ss();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Wd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Jg(e,t){let o=ss();o.styles.set(e,t);for(let n of o.documents.keys())Wd(n,e,t)}typeof process>"u",Jg("19fcc06039",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._480b748dd3510e64__positioner{z-index:var(--wp-ui-tooltip-z-index,initial)}._50096b232db7709d__popup{--_wp-ui-elevation-sm:0 1px 2px rgba(0,0,0,.05),0 2px 3px rgba(0,0,0,.04),0 6px 6px rgba(0,0,0,.03),0 8px 8px rgba(0,0,0,.02);background-color:var(--wpds-color-background-surface-neutral-strong,#fff);border-radius:var(--wpds-border-radius-md,4px);box-shadow:var(--_wp-ui-elevation-sm);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);font-family:var(--wpds-typography-font-family-body,-apple-system,system-ui,"Segoe UI","Roboto","Oxygen-Sans","Ubuntu","Cantarell","Helvetica Neue",sans-serif);font-size:var(--wpds-typography-font-size-sm,12px);line-height:1.4;padding:var(--wpds-dimension-padding-xs,4px) var(--wpds-dimension-padding-sm,8px);@media (forced-colors:active){border-bottom-color:CanvasText;border-bottom-style:solid;border-bottom-width:1px;border-left-color:CanvasText;border-left-style:solid;border-left-width:1px;border-right-color:CanvasText;border-right-style:solid;border-right-width:1px;border-top-color:CanvasText;border-top-style:solid;border-top-width:1px}}}}');var $g={positioner:"_480b748dd3510e64__positioner",popup:"_50096b232db7709d__popup"},eb={background:"#1e1e1e"},as=(0,Vd.forwardRef)(function({portal:t,positioner:o,children:n,className:r,...i},s){let a=(0,$o.jsx)(kd,{color:eb,children:(0,$o.jsx)(Qe.Popup,{ref:s,className:$($g.popup,r),...i,children:n})}),d=Zi(o,(0,$o.jsx)(Fd,{}),a);return Zi(t,(0,$o.jsx)(Bd,{}),d)});var Yd=h(de(),1),Ud=h(Q(),1),cs=(0,Yd.forwardRef)(function(t,o){return(0,Ud.jsx)(Qe.Trigger,{ref:o,...t})});var Gd=h(Q(),1);function ls(e){return(0,Gd.jsx)(Qe.Root,{...e})}var lt=h(Q(),1),ds="data-wp-hash";function us(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&nb(document)),e.__wpStyleRuntime}function ob(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ds}]`))if(o.getAttribute(ds)===t)return!0;return!1}function qd(e,t,o){if(!e.head)return;let n=us(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ob(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ds,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function nb(e){let t=us();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)qd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function rb(e,t){let o=us();o.styles.set(e,t);for(let n of o.documents.keys())qd(n,e,t)}typeof process>"u",rb("c5cdafb1bc","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer compositions{._28cfdc260e755391__icon-button{--wp-ui-button-aspect-ratio:1;--wp-ui-button-padding-inline:0px;--wp-ui-button-min-width:unset}.f1c70d719989a85a__icon{margin:-1px}}}");var Xd={"icon-button":"_28cfdc260e755391__icon-button",icon:"f1c70d719989a85a__icon"},fs=(0,Kd.forwardRef)(function({label:t,className:o,children:n,disabled:r,focusableWhenDisabled:i=!0,icon:s,size:a,shortcut:d,positioner:c,...l},f){let p=$(Xd["icon-button"],o);return(0,lt.jsxs)(ls,{children:[(0,lt.jsx)(cs,{ref:f,disabled:r&&!i,render:(0,lt.jsx)(sr,{...l,size:a,"aria-label":t,"aria-keyshortcuts":d?.ariaKeyShortcut,disabled:r,focusableWhenDisabled:i}),className:p,children:(0,lt.jsx)(eo,{icon:s,size:24,className:Xd.icon})}),(0,lt.jsxs)(as,{positioner:c,children:[t,d&&(0,lt.jsxs)(lt.Fragment,{children:[" ",(0,lt.jsx)("span",{"aria-hidden":"true",children:d.displayShortcut})]})]})]})});var Zd=h(de(),1),Qd=h(Ot(),1),Co=h(Q(),1),ps="data-wp-hash";function ms(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&sb(document)),e.__wpStyleRuntime}function ib(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ps}]`))if(o.getAttribute(ps)===t)return!0;return!1}function Jd(e,t,o){if(!e.head)return;let n=ms(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ib(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ps,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function sb(e){let t=ms();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Jd(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function pr(e,t){let o=ms();o.styles.set(e,t);for(let n of o.documents.keys())Jd(n,e,t)}typeof process>"u",pr("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var ab={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",pr("da99a163ac","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._08e8a2e44959f892__outset-ring--focus:focus,.c5cb3ee4bddaa8e4__outset-ring--focus-within-visible:focus-within:has(:focus-visible),.cd83dfc2126a0846__outset-ring--focus-within:focus-within,.d0541bc9dd9dc7b6__outset-ring--focus-visible:focus-visible,:focus-visible .ecadb9e080e2dfa5__outset-ring--focus-parent-visible{--_gcd-a-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));--_gcd-div-outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px)) solid var(--wpds-color-stroke-focus,var(--wp-admin-theme-color,#3858e9));outline-offset:var(--wpds-border-width-focus,var(--wp-admin-border-width-focus,2px))}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within,.e25b2bdd7aa21721__outset-ring--focus-except-active:focus{outline:none}._970d04df7376df67__outset-ring--focus-within-except-active:focus-within:not(:has(:active)),.e25b2bdd7aa21721__outset-ring--focus-except-active:focus:not(:active){@include mixins.focus-ring()}}}");var cb={"outset-ring--focus":"_08e8a2e44959f892__outset-ring--focus","outset-ring--focus-visible":"d0541bc9dd9dc7b6__outset-ring--focus-visible","outset-ring--focus-within":"cd83dfc2126a0846__outset-ring--focus-within","outset-ring--focus-within-visible":"c5cb3ee4bddaa8e4__outset-ring--focus-within-visible","outset-ring--focus-parent-visible":"ecadb9e080e2dfa5__outset-ring--focus-parent-visible","outset-ring--focus-except-active":"e25b2bdd7aa21721__outset-ring--focus-except-active","outset-ring--focus-within-except-active":"_970d04df7376df67__outset-ring--focus-within-except-active"};typeof process>"u",pr("e8e6a9be37",'@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{.d4250949359b05ce__link{text-decoration-thickness:from-font;text-underline-offset:.2em}.c6055659b8e2cd2c__is-brand,.c6055659b8e2cd2c__is-brand:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9));color:var(--wpds-color-foreground-interactive-brand,var(--wp-admin-theme-color,#3858e9))}.c6055659b8e2cd2c__is-brand:active,.c6055659b8e2cd2c__is-brand:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000));color:var(--wpds-color-foreground-interactive-brand-active,color-mix(in oklch,var(--wp-admin-theme-color,#3858e9) 52%,#000))}._92e0dfcaeee15b88__is-neutral,._92e0dfcaeee15b88__is-neutral:visited{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral,#1e1e1e);text-decoration-color:var(--wpds-color-stroke-interactive-neutral,#8d8d8d)}._92e0dfcaeee15b88__is-neutral:active,._92e0dfcaeee15b88__is-neutral:hover{--_gcd-a-color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e);color:var(--wpds-color-foreground-interactive-neutral-active,#1e1e1e)}.cf122a9bf1035d42__is-unstyled{--_gcd-a-color:inherit;color:inherit;text-decoration:none}._0cb411afac4c86c7__link-icon{display:inline-block;font-weight:var(--wpds-typography-font-weight-default,400);line-height:1;margin-inline-start:var(--wpds-dimension-padding-xs,4px);text-decoration:none}._0cb411afac4c86c7__link-icon:after{content:"\\2197"}._0cb411afac4c86c7__link-icon:dir(rtl):after{content:"\\2196"}}}');var fr={link:"d4250949359b05ce__link","is-brand":"c6055659b8e2cd2c__is-brand","is-neutral":"_92e0dfcaeee15b88__is-neutral","is-unstyled":"cf122a9bf1035d42__is-unstyled","link-icon":"_0cb411afac4c86c7__link-icon"};typeof process>"u",pr("af6d9984a6","._6defc79820e382c6__button{box-sizing:var(--_gcd-button-box-sizing,border-box);font-family:var(--_gcd-button-font-family,inherit);font-size:var(--_gcd-button-font-size,inherit);font-weight:var(--_gcd-button-font-weight,inherit)}.d2cff2e5dea83bd1__input{box-sizing:var(--_gcd-input-box-sizing,border-box);font-family:var(--_gcd-input-font-family,inherit);font-size:var(--_gcd-input-font-size,inherit);font-weight:var(--_gcd-input-font-weight,inherit);margin:var(--_gcd-input-margin,0);&:is(textarea,[type=text],[type=password],[type=color],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){background-color:var(--_gcd-input-background-color,transparent);border:var(--_gcd-input-border,none);border-radius:var(--_gcd-input-border-radius,0);box-shadow:var(--_gcd-input-box-shadow,0 0 0 transparent);color:var(--_gcd-input-color,var(--wpds-color-foreground-interactive-neutral,#1e1e1e));&:focus{border-color:var(--_gcd-input-border-color-focus,var(--wp-admin-theme-color));box-shadow:var(--_gcd-input-box-shadow-focus,none);outline:var(--_gcd-input-outline-focus,none)}&:disabled{background:var(--_gcd-input-background-disabled,transparent);border-color:var(--_gcd-input-border-color-disabled,transparent);box-shadow:var(--_gcd-input-box-shadow-disabled,none);color:var(--_gcd-input-color-disabled,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}&::placeholder{color:var(--_gcd-input-placeholder-color,var(--wpds-color-foreground-interactive-neutral-disabled,#8d8d8d))}}&:is(textarea,[type=text],[type=password],[type=date],[type=datetime],[type=datetime-local],[type=email],[type=month],[type=number],[type=search],[type=tel],[type=time],[type=url],[type=week]){line-height:var(--_gcd-input-line-height,inherit);min-height:var(--_gcd-input-min-height,auto);padding:var(--_gcd-input-padding,0)}}._547d86373d02e108__textarea{box-sizing:var(--_gcd-textarea-box-sizing,border-box);overflow:var(--_gcd-textarea-overflow,auto);resize:var(--_gcd-textarea-resize,block)}._8c15fd0ed9f28ba4__div{outline:var(--_gcd-div-outline,0 solid transparent)}p._43cec3e1eec1066d__p{font-size:var(--_gcd-p-font-size,13px);line-height:var(--_gcd-p-line-height,1.5);margin:var(--_gcd-p-margin,0)}:is(h1,h2,h3,h4,h5,h6).e97669c6d9a38497__heading{color:var(--_gcd-heading-color,var(--wpds-color-foreground-content-neutral,#1e1e1e));font-size:var(--_gcd-heading-font-size,inherit);font-weight:var(--_gcd-heading-font-weight,var(--wpds-typography-font-weight-emphasis,600));margin:var(--_gcd-heading-margin,0)}._2c0831b0499dbd6e__a,._2c0831b0499dbd6e__a:is(:hover,:focus,:active){border-radius:var(--_gcd-a-border-radius,0);box-shadow:var(--_gcd-a-box-shadow,none);color:var(--_gcd-a-color,inherit);outline:var(--_gcd-a-outline,0 solid transparent);transition:var(--_gcd-a-transition,none)}");var lb={button:"_6defc79820e382c6__button",input:"d2cff2e5dea83bd1__input",textarea:"_547d86373d02e108__textarea",div:"_8c15fd0ed9f28ba4__div",p:"_43cec3e1eec1066d__p",heading:"e97669c6d9a38497__heading",a:"_2c0831b0499dbd6e__a"},en=(0,Zd.forwardRef)(function({children:t,variant:o="default",tone:n="brand",openInNewTab:r=!1,render:i,className:s,...a},d){return bt({render:i,defaultTagName:"a",ref:d,props:ye(a,{className:$(lb.a,ab["box-sizing"],cb["outset-ring--focus-except-active"],o!=="unstyled"&&fr.link,o!=="unstyled"&&fr[`is-${n}`],o==="unstyled"&&fr["is-unstyled"],s),target:r?"_blank":void 0,children:(0,Co.jsxs)(Co.Fragment,{children:[t,r&&(0,Co.jsx)("span",{className:fr["link-icon"],role:"img","aria-label":(0,Qd.__)("(opens in a new tab)")})]})})})});var tn={};At(tn,{ActionButton:()=>xu,ActionLink:()=>Eu,Actions:()=>fu,CloseIcon:()=>hu,Description:()=>lu,Root:()=>tu,Title:()=>iu});var Ao=h(de(),1);import{speak as db}from"@wordpress/a11y";var Oo=h(Q(),1),bs="data-wp-hash";function hs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&fb(document)),e.__wpStyleRuntime}function ub(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${bs}]`))if(o.getAttribute(bs)===t)return!0;return!1}function $d(e,t,o){if(!e.head)return;let n=hs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(ub(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(bs,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function fb(e){let t=hs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)$d(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function eu(e,t){let o=hs();o.styles.set(e,t);for(let n of o.documents.keys())$d(n,e,t)}typeof process>"u",eu("10f3806643","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer utilities{._336cd3e4e743482f__box-sizing{box-sizing:border-box;*,:after,:before{box-sizing:inherit}}}}");var pb={"box-sizing":"_336cd3e4e743482f__box-sizing"};typeof process>"u",eu("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var gs={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},mb={neutral:null,info:Xi,warning:Fi,success:qi,error:Ui};function gb(e){return e==="error"?"assertive":"polite"}function bb(e){if(e){if(typeof e=="string")return e;try{return(0,Ao.renderToString)(e)}catch{return}}}function hb(e,t){let o=bb(e);(0,Ao.useEffect)(()=>{o&&db(o,t)},[o,t])}var tu=(0,Ao.forwardRef)(function({intent:t="neutral",children:o,icon:n,spokenMessage:r=o,politeness:i=gb(t),render:s,...a},d){hb(r,i);let c=n===null?null:n??mb[t],l=$(gs.notice,gs[`is-${t}`],pb["box-sizing"]);return bt({defaultTagName:"div",render:s,ref:d,props:ye({className:l,children:(0,Oo.jsxs)(Oo.Fragment,{children:[o,c&&(0,Oo.jsx)(eo,{className:gs.icon,icon:c})]})},a)})});var ou=h(de(),1);var ru=h(Q(),1),ws="data-wp-hash";function vs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&vb(document)),e.__wpStyleRuntime}function wb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${ws}]`))if(o.getAttribute(ws)===t)return!0;return!1}function nu(e,t,o){if(!e.head)return;let n=vs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(wb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(ws,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function vb(e){let t=vs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)nu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function _b(e,t){let o=vs();o.styles.set(e,t);for(let n of o.documents.keys())nu(n,e,t)}typeof process>"u",_b("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var yb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},iu=(0,ou.forwardRef)(function({className:t,...o},n){return(0,ru.jsx)(Je,{ref:n,variant:"heading-md",className:$(yb.title,t),...o})});var su=h(de(),1);var cu=h(Q(),1),_s="data-wp-hash";function ys(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Rb(document)),e.__wpStyleRuntime}function xb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${_s}]`))if(o.getAttribute(_s)===t)return!0;return!1}function au(e,t,o){if(!e.head)return;let n=ys(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(xb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(_s,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Rb(e){let t=ys();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)au(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Sb(e,t){let o=ys();o.styles.set(e,t);for(let n of o.documents.keys())au(n,e,t)}typeof process>"u",Sb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Eb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},lu=(0,su.forwardRef)(function({className:t,...o},n){return(0,cu.jsx)(Je,{ref:n,variant:"body-md",className:$(Eb.description,t),...o})});var du=h(de(),1);var xs="data-wp-hash";function Rs(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&kb(document)),e.__wpStyleRuntime}function Tb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${xs}]`))if(o.getAttribute(xs)===t)return!0;return!1}function uu(e,t,o){if(!e.head)return;let n=Rs(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Tb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(xs,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function kb(e){let t=Rs();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)uu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Pb(e,t){let o=Rs();o.styles.set(e,t);for(let n of o.documents.keys())uu(n,e,t)}typeof process>"u",Pb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Cb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},fu=(0,du.forwardRef)(function({render:t,...o},n){return bt({defaultTagName:"div",render:t,ref:n,props:ye({className:Cb.actions},o)})});var pu=h(de(),1),mu=h(Ot(),1);var bu=h(Q(),1),Ss="data-wp-hash";function Es(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ob(document)),e.__wpStyleRuntime}function Ab(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ss}]`))if(o.getAttribute(Ss)===t)return!0;return!1}function gu(e,t,o){if(!e.head)return;let n=Es(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Ab(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ss,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ob(e){let t=Es();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)gu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Nb(e,t){let o=Es();o.styles.set(e,t);for(let n of o.documents.keys())gu(n,e,t)}typeof process>"u",Nb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var Lb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},hu=(0,pu.forwardRef)(function({className:t,icon:o=Wi,label:n=(0,mu.__)("Dismiss"),...r},i){return(0,bu.jsx)(fs,{...r,ref:i,className:$(Lb["close-icon"],t),variant:"minimal",size:"small",tone:"neutral",icon:o,label:n})});var vu=h(de(),1);var yu=h(Q(),1),Ts="data-wp-hash";function ks(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Mb(document)),e.__wpStyleRuntime}function Ib(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ts}]`))if(o.getAttribute(Ts)===t)return!0;return!1}function _u(e,t,o){if(!e.head)return;let n=ks(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Ib(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ts,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Mb(e){let t=ks();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)_u(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Bb(e,t){let o=ks();o.styles.set(e,t);for(let n of o.documents.keys())_u(n,e,t)}typeof process>"u",Bb("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var wu={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},xu=(0,vu.forwardRef)(function({className:t,loading:o,loadingAnnouncement:n,variant:r,...i},s){return(0,yu.jsx)(sr,{...i,...o!==void 0?{loading:o,loadingAnnouncement:n??""}:{},ref:s,size:"compact",tone:"neutral",variant:r,className:$(wu["action-button"],wu[`is-action-button-${r}`],t)})});var Ru=h(de(),1);var Cs=h(Q(),1),Ps="data-wp-hash";function As(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&zb(document)),e.__wpStyleRuntime}function Hb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Ps}]`))if(o.getAttribute(Ps)===t)return!0;return!1}function Su(e,t,o){if(!e.head)return;let n=As(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Hb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Ps,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function zb(e){let t=As();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Su(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Db(e,t){let o=As();o.styles.set(e,t);for(let n of o.documents.keys())Su(n,e,t)}typeof process>"u",Db("726c480820","@layer wp-ui{@layer utilities, components, compositions, overrides;@layer components{._4145abab73d17514__notice{--icon-height:var(--wpds-dimension-size-sm,24px);--text-vertical-padding:calc((var(--icon-height) - var(--wpds-typography-line-height-sm, 20px))/2);--wp-ui-notice-background-color:var(--wpds-color-background-surface-neutral-weak,#f4f4f4);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-neutral,#dbdbdb);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-neutral,#1e1e1e);align-items:start;background-color:var(--wp-ui-notice-background-color);border:1px solid var(--wp-ui-notice-border-color);border-radius:var(--wpds-border-radius-lg,8px);container-type:inline-size;display:grid;grid-template-columns:auto 1fr auto;padding:var(--wpds-dimension-padding-md,12px)}.d0a25570cb528528__icon{color:var(--wp-ui-notice-decorative-icon-color);grid-column:1;grid-row:1;margin-inline-end:var(--wpds-dimension-gap-xs,4px)}._1904b570a89bb815__description,.b5397fb9d05389e3__title{color:var(--wp-ui-notice-text-color);grid-column:2;padding-block:var(--text-vertical-padding)}._1904b570a89bb815__description{text-wrap:pretty}._0a1270dcdd79c031__actions{display:flex;flex-wrap:wrap;gap:var(--wpds-dimension-gap-md,12px);grid-column:2}._4145abab73d17514__notice:has(._1904b570a89bb815__description) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions{margin-block-start:var(--wpds-dimension-gap-sm,8px)}._983740ab855c4e09__action-button{flex-shrink:0}.d329e7416d368d31__action-link{flex-shrink:0;&:not(:first-child){margin-inline-start:var(--wpds-dimension-gap-xs,4px)}&:not(:last-child){margin-inline-end:var(--wpds-dimension-gap-xs,4px)}}._487e6a5c1375f7dc__close-icon{grid-column:3;grid-row:1;margin-inline-start:var(--wpds-dimension-gap-xs,4px)}._531c140826094795__is-info{--wp-ui-notice-background-color:var(--wpds-color-background-surface-info-weak,#f3f9ff);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-info,#a9c6e7);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-info,#001b4f);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-info-weak,#006bd7)}.ae2e1004697cce95__is-warning{--wp-ui-notice-background-color:var(--wpds-color-background-surface-warning-weak,#fff7e1);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-warning,#e1bc7c);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-warning,#2e1900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-warning-weak,#926300)}._2e614a76af494837__is-success{--wp-ui-notice-background-color:var(--wpds-color-background-surface-success-weak,#ebffed);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-success,#94d29e);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-success,#002900);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-success-weak,#008030)}.af00331ae17a0065__is-error{--wp-ui-notice-background-color:var(--wpds-color-background-surface-error-weak,#fff6f5);--wp-ui-notice-border-color:var(--wpds-color-stroke-surface-error,#dab1aa);--wp-ui-notice-text-color:var(--wpds-color-foreground-content-error,#470000);--wp-ui-notice-decorative-icon-color:var(--wpds-color-foreground-content-error-weak,#cc1818)}@container (max-width: 320px){._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._0a1270dcdd79c031__actions,._4145abab73d17514__notice:has(.b5397fb9d05389e3__title) ._1904b570a89bb815__description{grid-column:1/3}}}@layer compositions{.d329e7416d368d31__action-link{margin-block:auto}._487e6a5c1375f7dc__close-icon,._983740ab855c4e09__action-button:is(._8ddb8fb33fbf3d38__is-action-button-outline,._77bbde495a8a0af3__is-action-button-minimal){--wp-ui-button-background-color-active:color-mix(in srgb,transparent 50%,var(--wpds-color-background-interactive-neutral-weak-active,#ededed))}}}");var jb={notice:"_4145abab73d17514__notice",icon:"d0a25570cb528528__icon",title:"b5397fb9d05389e3__title",description:"_1904b570a89bb815__description",actions:"_0a1270dcdd79c031__actions","action-button":"_983740ab855c4e09__action-button","action-link":"d329e7416d368d31__action-link","close-icon":"_487e6a5c1375f7dc__close-icon","is-info":"_531c140826094795__is-info","is-warning":"ae2e1004697cce95__is-warning","is-success":"_2e614a76af494837__is-success","is-error":"af00331ae17a0065__is-error","is-action-button-outline":"_8ddb8fb33fbf3d38__is-action-button-outline","is-action-button-minimal":"_77bbde495a8a0af3__is-action-button-minimal"},Eu=(0,Ru.forwardRef)(function({className:t,render:o,...n},r){return(0,Cs.jsx)(Je,{ref:r,className:$(jb["action-link"],t),...n,variant:"body-md",render:(0,Cs.jsx)(en,{tone:"neutral",variant:"default",render:o})})});var Tu=h(de(),1),ku=h(Q(),1),Pu=(0,Tu.forwardRef)(({children:e,className:t,ariaLabel:o,as:n="div",...r},i)=>(0,ku.jsx)(n,{ref:i,className:$("admin-ui-navigable-region",t),"aria-label":o,role:"region",tabIndex:"-1",...r,children:e}));Pu.displayName="NavigableRegion";var Cu=Pu;var Ou=h(on(),1),{Fill:Nu,Slot:Lu}=(0,Ou.createSlotFill)("SidebarToggle");var $e=h(Q(),1),Os="data-wp-hash";function Ns(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Vb(document)),e.__wpStyleRuntime}function Fb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Os}]`))if(o.getAttribute(Os)===t)return!0;return!1}function Iu(e,t,o){if(!e.head)return;let n=Ns(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Fb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Os,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Vb(e){let t=Ns();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Iu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Wb(e,t){let o=Ns();o.styles.set(e,t);for(let n of o.documents.keys())Iu(n,e,t)}typeof process>"u",Wb("ddd9aab364","._956b6df0898efed0__page{text-wrap:pretty;background-color:var(--wpds-color-background-surface-neutral,#fcfcfc);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);display:flex;flex-flow:column;height:100%;position:relative;z-index:1}._0625b55e82a0d93d__header{background:var(--wpds-color-background-surface-neutral-strong,#fff);border-block-end:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral-weak,#f0f0f0);inset-block-start:0;padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px);position:sticky;z-index:1}.a43c44d5ae28b2e8__header-content{min-height:var(--wpds-dimension-size-md,32px)}.b7cb5b9daf3a3b25__header-actions{flex-shrink:0}._8113be94e7caf73c__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._9a776c7f70996f61__header-visual{display:grid;flex-shrink:0;grid-template-columns:1fr;grid-template-rows:1fr;height:var(--wpds-dimension-size-sm,24px);width:var(--wpds-dimension-size-sm,24px);>*{grid-column:1/-1;grid-row:1/-1;max-height:100%;max-width:100%}}.d5e0920cd15d35bc__sidebar-toggle-slot:empty{display:none}._60fea2f6bf5319cd__header-subtitle{color:var(--wpds-color-foreground-content-neutral-weak,#707070);padding-block-end:var(--wpds-dimension-padding-xs,4px)}.be5e57d029ec4036__content{display:flex;flex-direction:column;flex-grow:1;overflow:auto;&._128806d0b26e3a50__has-padding{padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px)}}");var to={page:"_956b6df0898efed0__page",header:"_0625b55e82a0d93d__header","header-content":"a43c44d5ae28b2e8__header-content","header-actions":"b7cb5b9daf3a3b25__header-actions","header-title":"_8113be94e7caf73c__header-title","header-visual":"_9a776c7f70996f61__header-visual","sidebar-toggle-slot":"d5e0920cd15d35bc__sidebar-toggle-slot","header-subtitle":"_60fea2f6bf5319cd__header-subtitle",content:"be5e57d029ec4036__content","has-padding":"_128806d0b26e3a50__has-padding"};function Mu({headingLevel:e=1,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,actions:s,showSidebarToggle:a=!0}){let d=`h${e}`;return(0,$e.jsxs)(Po,{direction:"column",className:to.header,children:[(0,$e.jsxs)(Po,{className:to["header-content"],direction:"row",gap:"sm",justify:"space-between",children:[(0,$e.jsxs)(Po,{direction:"row",gap:"sm",align:"center",justify:"start",children:[a&&(0,$e.jsx)(Lu,{bubblesVirtually:!0,className:to["sidebar-toggle-slot"]}),n&&(0,$e.jsx)("div",{className:to["header-visual"],"aria-hidden":"true",children:n}),r&&(0,$e.jsx)(Je,{className:to["header-title"],render:(0,$e.jsx)(d,{}),variant:"heading-lg",children:r}),t,o]}),s&&(0,$e.jsx)(Po,{align:"center",className:to["header-actions"],direction:"row",gap:"sm",children:s})]}),i&&(0,$e.jsx)(Je,{render:(0,$e.jsx)("p",{}),variant:"body-md",className:to["header-subtitle"],children:i})]})}var nn=h(Q(),1),Is="data-wp-hash";function Ms(){let e=globalThis;return e.__wpStyleRuntime||(e.__wpStyleRuntime={documents:new Map,styles:new Map,injectedStyles:new WeakMap},typeof document<"u"&&Ub(document)),e.__wpStyleRuntime}function Yb(e,t){if(!e.head)return!1;for(let o of e.head.querySelectorAll(`style[${Is}]`))if(o.getAttribute(Is)===t)return!0;return!1}function Bu(e,t,o){if(!e.head)return;let n=Ms(),r=n.injectedStyles.get(e);if(r||(r=new Set,n.injectedStyles.set(e,r)),r.has(t))return;if(Yb(e,t)){r.add(t);return}let i=e.createElement("style");i.setAttribute(Is,t),i.appendChild(e.createTextNode(o)),e.head.appendChild(i),r.add(t)}function Ub(e){let t=Ms();t.documents.set(e,(t.documents.get(e)??0)+1);for(let[o,n]of t.styles)Bu(e,o,n);return()=>{let o=t.documents.get(e);if(o!==void 0){if(o<=1){t.documents.delete(e);return}t.documents.set(e,o-1)}}}function Gb(e,t){let o=Ms();o.styles.set(e,t);for(let n of o.documents.keys())Bu(n,e,t)}typeof process>"u",Gb("ddd9aab364","._956b6df0898efed0__page{text-wrap:pretty;background-color:var(--wpds-color-background-surface-neutral,#fcfcfc);color:var(--wpds-color-foreground-content-neutral,#1e1e1e);display:flex;flex-flow:column;height:100%;position:relative;z-index:1}._0625b55e82a0d93d__header{background:var(--wpds-color-background-surface-neutral-strong,#fff);border-block-end:var(--wpds-border-width-xs,1px) solid var(--wpds-color-stroke-surface-neutral-weak,#f0f0f0);inset-block-start:0;padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px);position:sticky;z-index:1}.a43c44d5ae28b2e8__header-content{min-height:var(--wpds-dimension-size-md,32px)}.b7cb5b9daf3a3b25__header-actions{flex-shrink:0}._8113be94e7caf73c__header-title{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._9a776c7f70996f61__header-visual{display:grid;flex-shrink:0;grid-template-columns:1fr;grid-template-rows:1fr;height:var(--wpds-dimension-size-sm,24px);width:var(--wpds-dimension-size-sm,24px);>*{grid-column:1/-1;grid-row:1/-1;max-height:100%;max-width:100%}}.d5e0920cd15d35bc__sidebar-toggle-slot:empty{display:none}._60fea2f6bf5319cd__header-subtitle{color:var(--wpds-color-foreground-content-neutral-weak,#707070);padding-block-end:var(--wpds-dimension-padding-xs,4px)}.be5e57d029ec4036__content{display:flex;flex-direction:column;flex-grow:1;overflow:auto;&._128806d0b26e3a50__has-padding{padding:var(--wpds-dimension-padding-lg,16px) var(--wpds-dimension-padding-2xl,24px)}}");var Ls={page:"_956b6df0898efed0__page",header:"_0625b55e82a0d93d__header","header-content":"a43c44d5ae28b2e8__header-content","header-actions":"b7cb5b9daf3a3b25__header-actions","header-title":"_8113be94e7caf73c__header-title","header-visual":"_9a776c7f70996f61__header-visual","sidebar-toggle-slot":"d5e0920cd15d35bc__sidebar-toggle-slot","header-subtitle":"_60fea2f6bf5319cd__header-subtitle",content:"be5e57d029ec4036__content","has-padding":"_128806d0b26e3a50__has-padding"};function Hu({headingLevel:e,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,children:s,className:a,actions:d,ariaLabel:c,hasPadding:l=!1,showSidebarToggle:f=!0}){let p=$(Ls.page,a);return(0,nn.jsxs)(Cu,{className:p,ariaLabel:c??(typeof r=="string"?r:""),children:[(r||t||o||d||n)&&(0,nn.jsx)(Mu,{headingLevel:e,breadcrumbs:t,badges:o,visual:n,title:r,subTitle:i,actions:d,showSidebarToggle:f}),l?(0,nn.jsx)("div",{className:$(Ls.content,Ls["has-padding"]),children:s}):s]})}Hu.SidebarToggleFill=Nu;var Bs=Hu;var dt=h(on()),lf=h(rn()),df=h(de()),Tt=h(Ot()),uf=h(mr());import{privateApis as l0}from"@wordpress/connectors";var ju=h(Qi()),{lock:l3,unlock:No}=(0,ju.__dangerousOptInToUnstableAPIsOnlyForCoreModules)("I acknowledge private features are not for use in themes or plugins and doing so will break in the next version of WordPress.","@wordpress/routes");if(typeof document<"u"&&!document.head.querySelector("style[data-wp-hash='09e9b056ea']")){let e=document.createElement("style");e.setAttribute("data-wp-hash","09e9b056ea"),e.appendChild(document.createTextNode(".connectors-page{box-sizing:border-box;margin:0 auto;max-width:680px;padding:24px;width:100%}.connectors-page .components-item{background:#fff;border:1px solid #ddd;border-radius:8px;overflow:hidden;padding:20px;scroll-margin-top:120px}.connectors-page .connector-settings__error{color:#cc1818}.connectors-page .connector-settings .components-text-control__input{font-family:monospace;scroll-margin-top:120px}.connectors-page__file-mods-notice{margin-bottom:16px}.connectors-page--empty{align-items:center;display:flex;flex-direction:column;flex-grow:1;gap:32px;justify-content:center;text-align:center}.connectors-page .ai-plugin-callout{background-color:#e7d4e4;background-image:radial-gradient(ellipse 70% 120% at 18% 115%,rgba(202,158,198,.75) 0,rgba(202,158,198,0) 60%),radial-gradient(ellipse 55% 110% at 92% -15%,rgba(208,175,217,.7) 0,rgba(208,175,217,0) 65%),radial-gradient(ellipse 40% 85% at 58% -10%,rgba(170,130,184,.45) 0,rgba(170,130,184,0) 70%);border-radius:8px;overflow:hidden;padding:24px;padding-inline-end:150px;position:relative}[dir=rtl] .connectors-page .ai-plugin-callout{background-image:radial-gradient(ellipse 70% 120% at 82% 115%,rgba(202,158,198,.75) 0,rgba(202,158,198,0) 60%),radial-gradient(ellipse 55% 110% at 8% -15%,rgba(208,175,217,.7) 0,rgba(208,175,217,0) 65%),radial-gradient(ellipse 40% 85% at 42% -10%,rgba(170,130,184,.45) 0,rgba(170,130,184,0) 70%)}.connectors-page .ai-plugin-callout__content{align-items:flex-start;display:flex;flex-direction:column;gap:12px;padding-top:2px}.connectors-page .ai-plugin-callout__content p{font-size:13px;line-height:20px;margin:0}.connectors-page .ai-plugin-callout__decoration{height:110px;inset-inline-end:16px;position:absolute;top:12px;width:110px}.connectors-page>p{color:#949494}@media (max-width:680px){.connectors-page .ai-plugin-callout{padding:12px;padding-inline-end:100px}.connectors-page .ai-plugin-callout__decoration{height:75px;inset-inline-end:8px;top:8px;width:75px}}@media (max-width:480px){.connectors-page{padding:8px}.connectors-page .ai-plugin-callout{padding-inline-end:130px}.connectors-page .components-item{padding:12px}.connectors-page .components-item>.components-v-stack>.components-h-stack:first-child svg{height:32px;width:32px}.connectors-page .components-item>.components-v-stack>.components-h-stack:first-child>.components-h-stack:last-child{align-items:flex-end;flex-direction:column}}")),document.head.appendChild(e)}var cn=h(on()),Ws=h(mr()),ln=h(rn()),wt=h(de()),Xe=h(Ot()),rf=h(Hs()),sf=h(Wu());var gr=h(on()),js=h(de()),Qu=h(rn()),oo=h(Ot());import{__experimentalRegisterConnector as Xb,__experimentalConnectorItem as Zu,__experimentalDefaultConnectorSettings as Kb,__experimentalApplicationPasswordConnectorSettings as qb,privateApis as Zb}from"@wordpress/connectors";var zs=h(mr()),an=h(rn()),sn=h(de()),fe=h(Ot()),Yu=h(Hs());function Ds({file:e,settingName:t,connectorName:o,isInstalled:n,isActivated:r,keySource:i="none",initialIsConnected:s=!1}){let[a,d]=(0,sn.useState)(!1),[c,l]=(0,sn.useState)(!1),[f,p]=(0,sn.useState)(s),[m,u]=(0,sn.useState)(null),g=e?.replace(/\.php$/,""),v=g?.includes("/")?g.split("/")[0]:g,{derivedPluginStatus:_,canManagePlugins:w,currentApiKey:y,currentUsername:b,hasStoredCredentials:S,hasResolvedSettings:x,canInstallPlugins:E}=(0,an.useSelect)(K=>{let J=K(zs.store),me=J.getEntityRecord("root","site")?.[t],le=typeof me=="string"?me:"",X=typeof me=="object"&&me!==null?me:void 0,pe=X!==void 0?!!X.username&&!!X.password:!!le,ue=J.hasFinishedResolution("getEntityRecord",["root","site"]),vt=!!J.canUser("create",{kind:"root",name:"plugin"}),Te={currentApiKey:le,currentUsername:X?.username??"",hasStoredCredentials:pe,hasResolvedSettings:ue,canInstallPlugins:vt};if(!e)return{...Te,derivedPluginStatus:ue?"active":"checking",canManagePlugins:void 0};let Ve=J.getEntityRecord("root","plugin",g);if(!J.hasFinishedResolution("getEntityRecord",["root","plugin",g]))return{...Te,derivedPluginStatus:"checking",canManagePlugins:void 0};if(Ve){let no=Ve.status==="active"||Ve.status==="network-active";return{...Te,derivedPluginStatus:no?"active":"inactive",canManagePlugins:!0}}let He="not-installed";return r?He="active":n&&(He="inactive"),{...Te,derivedPluginStatus:He,canManagePlugins:!1}},[e,g,t,n,r]),T=m??_,k=w,C=T==="active"&&f||m==="active"&&S,{saveEntityRecord:j,invalidateResolution:A}=(0,an.useDispatch)(zs.store),{createSuccessNotice:L,createErrorNotice:I}=(0,an.useDispatch)(Yu.store),R=K=>j("root","site",{[t]:K},{throwOnError:!0}),N=()=>{L((0,fe.sprintf)((0,fe.__)("%s connected successfully."),o),{id:"connector-connect-success",type:"snackbar"})},H=()=>{L((0,fe.sprintf)((0,fe.__)("%s disconnected."),o),{id:"connector-disconnect-success",type:"snackbar"})},P=()=>{I((0,fe.sprintf)((0,fe.__)("Failed to disconnect %s."),o),{id:"connector-disconnect-error",type:"snackbar"})},O=async()=>{if(v){l(!0);try{await j("root","plugin",{slug:v,status:"active"},{throwOnError:!0}),u("active"),A("getEntityRecord",["root","site"]),d(!0),L((0,fe.sprintf)((0,fe.__)("Plugin for %s installed and activated successfully."),o),{id:"connector-plugin-install-success",type:"snackbar"})}catch{I((0,fe.sprintf)((0,fe.__)("Failed to install plugin for %s."),o),{id:"connector-plugin-install-error",type:"snackbar"})}finally{l(!1)}}},M=async()=>{if(e){l(!0);try{await j("root","plugin",{plugin:g,status:"active"},{throwOnError:!0}),u("active"),A("getEntityRecord",["root","site"]),d(!0),L((0,fe.sprintf)((0,fe.__)("Plugin for %s activated successfully."),o),{id:"connector-plugin-activate-success",type:"snackbar"})}catch{I((0,fe.sprintf)((0,fe.__)("Failed to activate plugin for %s."),o),{id:"connector-plugin-activate-error",type:"snackbar"})}finally{l(!1)}}};return{pluginStatus:T,canInstallPlugins:E,canActivatePlugins:k,isExpanded:a,setIsExpanded:d,isBusy:c,isConnected:C,currentApiKey:y,currentUsername:b,hasResolvedSettings:x,keySource:i,handleButtonClick:()=>{if(T==="not-installed"){if(E===!1)return;O()}else if(T==="inactive"){if(k===!1)return;M()}else d(!a)},getButtonLabel:()=>{if(c)return T==="not-installed"?(0,fe.__)("Installing\u2026"):(0,fe.__)("Activating\u2026");if(a)return(0,fe.__)("Cancel");if(C)return(0,fe.__)("Edit");switch(T){case"checking":return(0,fe.__)("Checking\u2026");case"not-installed":return(0,fe.__)("Install");case"inactive":return(0,fe.__)("Activate");case"active":return(0,fe.__)("Set up")}},saveApiKey:async K=>{let J=y;try{let le=(await R(K))?.[t];if(K&&(le===J||!le))throw new Error("It was not possible to connect to the provider using this key.");p(!0),N()}catch(ne){throw console.error("Failed to save API key:",ne),ne}},removeApiKey:async()=>{try{await R(""),p(!1),H()}catch(K){console.error("Failed to remove API key:",K),P()}},saveCredentials:async({username:K,applicationPassword:J})=>{try{let le=(await R({username:K,password:J}))?.[t];if(!le?.username||!le?.password)throw new Error((0,fe.__)("It was not possible to save these credentials."));p(!0),N()}catch(ne){throw console.error("Failed to save credentials:",ne),ne}},removeCredentials:async()=>{try{await R({username:"",password:""}),p(!1),H()}catch(K){console.error("Failed to remove credentials:",K),P()}}}}var Uu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 24 24",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.872zm16.5963 3.8558L13.1038 8.364l2.0201-1.1685a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.4043-.6813zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z",fill:"currentColor"})),Gu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 32 32",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M6.2 21.024L12.416 17.536L12.52 17.232L12.416 17.064H12.112L11.072 17L7.52 16.904L4.44 16.776L1.456 16.616L0.704 16.456L0 15.528L0.072 15.064L0.704 14.64L1.608 14.72L3.608 14.856L6.608 15.064L8.784 15.192L12.008 15.528H12.52L12.592 15.32L12.416 15.192L12.28 15.064L9.176 12.96L5.816 10.736L4.056 9.456L3.104 8.808L2.624 8.2L2.416 6.872L3.28 5.92L4.44 6L4.736 6.08L5.912 6.984L8.424 8.928L11.704 11.344L12.184 11.744L12.376 11.608L12.4 11.512L12.184 11.152L10.4 7.928L8.496 4.648L7.648 3.288L7.424 2.472C7.344 2.136 7.288 1.856 7.288 1.512L8.272 0.176L8.816 0L10.128 0.176L10.68 0.656L11.496 2.52L12.816 5.456L14.864 9.448L15.464 10.632L15.784 11.728L15.904 12.064H16.112V11.872L16.28 9.624L16.592 6.864L16.896 3.312L17 2.312L17.496 1.112L18.48 0.464L19.248 0.832L19.88 1.736L19.792 2.32L19.416 4.76L18.68 8.584L18.2 11.144H18.48L18.8 10.824L20.096 9.104L22.272 6.384L23.232 5.304L24.352 4.112L25.072 3.544H26.432L27.432 5.032L26.984 6.568L25.584 8.344L24.424 9.848L22.76 12.088L21.72 13.88L21.816 14.024L22.064 14L25.824 13.2L27.856 12.832L30.28 12.416L31.376 12.928L31.496 13.448L31.064 14.512L28.472 15.152L25.432 15.76L20.904 16.832L20.848 16.872L20.912 16.952L22.952 17.144L23.824 17.192H25.96L29.936 17.488L30.976 18.176L31.6 19.016L31.496 19.656L29.896 20.472L27.736 19.96L22.696 18.76L20.968 18.328H20.728V18.472L22.168 19.88L24.808 22.264L28.112 25.336L28.28 26.096L27.856 26.696L27.408 26.632L24.504 24.448L23.384 23.464L20.848 21.328H20.68V21.552L21.264 22.408L24.352 27.048L24.512 28.472L24.288 28.936L23.488 29.216L22.608 29.056L20.8 26.52L18.936 23.664L17.432 21.104L17.248 21.208L16.36 30.768L15.944 31.256L14.984 31.624L14.184 31.016L13.76 30.032L14.184 28.088L14.696 25.552L15.112 23.536L15.488 21.032L15.712 20.2L15.696 20.144L15.512 20.168L13.624 22.76L10.752 26.64L8.48 29.072L7.936 29.288L6.992 28.8L7.08 27.928L7.608 27.152L10.752 23.152L12.648 20.672L13.872 19.24L13.864 19.032H13.792L5.44 24.456L3.952 24.648L3.312 24.048L3.392 23.064L3.696 22.744L6.208 21.016L6.2 21.024Z",fill:"#D97757"})),Xu=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 32 32",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M0 4C0 1.79086 1.79086 0 4 0H28C30.2091 0 32 1.79086 32 4V28C32 30.2091 30.2091 32 28 32H4C1.79086 32 0 30.2091 0 28V4Z",fill:"#F0F0F0"}),React.createElement("path",{d:"M14.5 8V12H17.5V8H19V12H20.5C20.7652 12 21.0196 12.1054 21.2071 12.2929C21.3946 12.4804 21.5 12.7348 21.5 13V17L18.5 21V23C18.5 23.2652 18.3946 23.5196 18.2071 23.7071C18.0196 23.8946 17.7652 24 17.5 24H14.5C14.2348 24 13.9804 23.8946 13.7929 23.7071C13.6054 23.5196 13.5 23.2652 13.5 23V21L10.5 17V13C10.5 12.7348 10.6054 12.4804 10.7929 12.2929C10.9804 12.1054 11.2348 12 11.5 12H13V8H14.5ZM15 20.5V22.5H17V20.5L20 16.5V13.5H12V16.5L15 20.5Z",fill:"#949494"})),Ku=()=>React.createElement("svg",{width:"40",height:"40",viewBox:"0 0 44 44",fill:"none",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("rect",{width:"44",height:"44",fill:"#357B49",rx:"6"}),React.createElement("path",{fill:"#fff",fillRule:"evenodd",d:"m29.746 28.31-6.392-16.797c-.152-.397-.305-.672-.789-.675-.673 0-1.408.611-1.746 1.316l-7.378 16.154c-.072.16-.143.311-.214.454-.5.995-1.045 1.546-2.357 1.626a.399.399 0 0 0-.16.033l-.01.004a.399.399 0 0 0-.23.392v.01c0 .054.01.106.03.155l.004.01a.416.416 0 0 0 .394.252h6.212a.417.417 0 0 0 .307-.12.416.416 0 0 0 .124-.305.398.398 0 0 0-.105-.302.399.399 0 0 0-.294-.127c-.757 0-2.197-.062-2.197-1.164.02-.318.103-.63.245-.916l1.399-3.152c.52-1.163 1.654-1.163 2.572-1.163h5.843c.023 0 .044 0 .062.003.13.014.16.081.214.242l1.534 4.07a2.857 2.857 0 0 1 .216 1.04c0 .054-.003.104-.01.153-.09.726-.831.887-1.49.887a.4.4 0 0 0-.294.127l-.007.008-.007.008a.401.401 0 0 0-.092.286v.01c0 .054.01.106.03.155l.005.01a.42.42 0 0 0 .395.252h7.011a.413.413 0 0 0 .279-.13.412.412 0 0 0 .11-.297.387.387 0 0 0-.09-.294.388.388 0 0 0-.277-.135c-1.448-.122-2.295-.643-2.847-2.08Zm-11.985-5.844 2.847-6.304c.361-.728.659-1.486.889-2.265 0-.06.03-.092.06-.092s.061.032.061.091c.02.122.045.247.073.374.197.888.584 1.878.914 2.723l.176.453 1.684 4.529a.927.927 0 0 1 .092.4.473.473 0 0 1-.009.094c-.041.202-.228.272-.602.272h-6.063c-.122 0-.184-.03-.184-.092a.36.36 0 0 1 .062-.183Zm17.107-.721c0 .786-.446 1.231-1.25 1.231-.806 0-1.125-.409-1.125-1.034 0-.786.465-1.231 1.25-1.231.785 0 1.125.427 1.125 1.034ZM9.629 23.002c.803 0 1.25-.447 1.25-1.231 0-.607-.343-1.036-1.128-1.036-.785 0-1.25.447-1.25 1.231 0 .625.325 1.036 1.128 1.036Z",clipRule:"evenodd"})),qu=()=>React.createElement("svg",{width:"40",height:"40",style:{flex:"none",lineHeight:1},viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg","aria-hidden":"true"},React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"#3186FF"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-0)"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-1)"}),React.createElement("path",{d:"M20.616 10.835a14.147 14.147 0 01-4.45-3.001 14.111 14.111 0 01-3.678-6.452.503.503 0 00-.975 0 14.134 14.134 0 01-3.679 6.452 14.155 14.155 0 01-4.45 3.001c-.65.28-1.318.505-2.002.678a.502.502 0 000 .975c.684.172 1.35.397 2.002.677a14.147 14.147 0 014.45 3.001 14.112 14.112 0 013.679 6.453.502.502 0 00.975 0c.172-.685.397-1.351.677-2.003a14.145 14.145 0 013.001-4.45 14.113 14.113 0 016.453-3.678.503.503 0 000-.975 13.245 13.245 0 01-2.003-.678z",fill:"url(#lobe-icons-gemini-fill-2)"}),React.createElement("defs",null,React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-0",x1:"7",x2:"11",y1:"15.5",y2:"12"},React.createElement("stop",{stopColor:"#08B962"}),React.createElement("stop",{offset:"1",stopColor:"#08B962",stopOpacity:"0"})),React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-1",x1:"8",x2:"11.5",y1:"5.5",y2:"11"},React.createElement("stop",{stopColor:"#F94543"}),React.createElement("stop",{offset:"1",stopColor:"#F94543",stopOpacity:"0"})),React.createElement("linearGradient",{gradientUnits:"userSpaceOnUse",id:"lobe-icons-gemini-fill-2",x1:"3.5",x2:"17.5",y1:"13.5",y2:"12"},React.createElement("stop",{stopColor:"#FABC12"}),React.createElement("stop",{offset:".46",stopColor:"#FABC12",stopOpacity:"0"}))));var{store:Qb}=No(Zb);function Ju(){try{return JSON.parse(document.getElementById("wp-script-module-data-options-connectors-wp-admin")?.textContent??"{}")}catch{return{}}}function Fs(){return Ju().connectors??{}}function $u(){return!!Ju().isFileModDisabled}var Jb={google:qu,openai:Uu,anthropic:Gu,akismet:Ku};function $b(e,t){if(t)return React.createElement("img",{src:t,alt:"",width:40,height:40});let o=Jb[e];return React.createElement(o||Xu,null)}var e0=()=>React.createElement("span",{style:{color:"#345b37",backgroundColor:"#eff8f0",padding:"4px 12px",borderRadius:"2px",fontSize:"13px",fontWeight:"var(--wpds-typography-font-weight-emphasis)",whiteSpace:"nowrap"}},(0,oo.__)("Connected")),t0=({slug:e})=>React.createElement(en,{href:(0,oo.sprintf)((0,oo.__)("https://wordpress.org/plugins/%s/"),e),openInNewTab:!0},(0,oo.__)("Learn more")),o0=()=>React.createElement(Ii,null,(0,oo.__)("Not available"));function ef({isConnected:e,showUnavailableBadge:t,pluginSlug:o,isExpanded:n,isBusy:r,pluginStatus:i,actionButtonRef:s,handleButtonClick:a,getButtonLabel:d}){return React.createElement(gr.__experimentalHStack,{spacing:3,expanded:!1},e&&React.createElement(e0,null),t&&(o?React.createElement(t0,{slug:o}):React.createElement(o0,null)),!t&&React.createElement(gr.Button,{ref:s,variant:n||e?"tertiary":"secondary",size:"compact",onClick:a,disabled:i==="checking"||r,isBusy:r,accessibleWhenDisabled:!0},d()))}function tf(e){let t=e?.replace(/\.php$/,"");return t?.includes("/")?t.split("/")[0]:t}function n0({name:e,description:t,logo:o,authentication:n,plugin:r}){let i=n?.method==="api_key"?n:void 0,s=i?.settingName??"",a=i?.credentialsUrl??void 0,d=tf(r?.file),{pluginStatus:c,canInstallPlugins:l,canActivatePlugins:f,isExpanded:p,setIsExpanded:m,isBusy:u,isConnected:g,currentApiKey:v,hasResolvedSettings:_,keySource:w,handleButtonClick:y,getButtonLabel:b,saveApiKey:S,removeApiKey:x}=Ds({file:r?.file,settingName:s,connectorName:e,isInstalled:r?.isInstalled,isActivated:r?.isActivated,keySource:i?.keySource,initialIsConnected:i?.isConnected}),E=w==="env"||w==="constant",T=c==="not-installed"&&l===!1||c==="inactive"&&f===!1,k=(0,js.useRef)(null);return React.createElement(Zu,{className:d?`connector-item--${d}`:void 0,logo:o,name:e,description:t,actionArea:React.createElement(ef,{isConnected:g,showUnavailableBadge:T,pluginSlug:d,isExpanded:p,isBusy:u,pluginStatus:c,actionButtonRef:k,handleButtonClick:y,getButtonLabel:b})},p&&c==="active"&&_&&React.createElement(Kb,{key:g?"connected":"setup",initialValue:E?"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022":v,helpUrl:a,readOnly:g||E,keySource:w,onRemove:E?void 0:async()=>{await x(),k.current?.focus()},onSave:async C=>{await S(C),m(!1),k.current?.focus()}}))}function r0({name:e,description:t,logo:o,authentication:n,plugin:r}){let i=n?.method==="application_password"?n:void 0,s=i?.settingName??"",a=i?.credentialsUrl??void 0,d=tf(r?.file),{pluginStatus:c,canInstallPlugins:l,canActivatePlugins:f,isExpanded:p,setIsExpanded:m,isBusy:u,isConnected:g,currentUsername:v,hasResolvedSettings:_,keySource:w,handleButtonClick:y,getButtonLabel:b,saveCredentials:S,removeCredentials:x}=Ds({file:r?.file,settingName:s,connectorName:e,isInstalled:r?.isInstalled,isActivated:r?.isActivated,keySource:i?.keySource,initialIsConnected:i?.isConnected}),E=w==="env"||w==="constant",T=(0,js.useRef)(null),k=c==="not-installed"&&l===!1||c==="inactive"&&f===!1;return React.createElement(Zu,{className:d?`connector-item--${d}`:void 0,logo:o,name:e,description:t,actionArea:React.createElement(ef,{isConnected:g,showUnavailableBadge:k,pluginSlug:d,isExpanded:p,isBusy:u,pluginStatus:c,actionButtonRef:T,handleButtonClick:y,getButtonLabel:b})},p&&c==="active"&&_&&React.createElement(qb,{key:g?"connected":"setup",initialUsername:E?"\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022":v,helpUrl:a,readOnly:g||E,keySource:w,onRemove:E?void 0:async()=>{await x(),T.current?.focus()},onSave:async C=>{await S(C),m(!1),T.current?.focus()}}))}function of(){let e=Fs(),t=o=>o.replace(/[^a-z0-9-_]/gi,"-");for(let[o,n]of Object.entries(e)){if(o==="akismet"&&!n.plugin?.isInstalled)continue;let{authentication:r}=n,i=t(o),s={name:n.name,description:n.description,type:n.type,logo:$b(o,n.logoUrl),authentication:r,plugin:n.plugin},a=No((0,Qu.select)(Qb)).getConnector(i);r.method==="api_key"&&!a?.render?s.render=n0:r.method==="application_password"&&!a?.render&&(s.render=r0),Xb(i,s)}}function nf(){return React.createElement("div",{className:"ai-plugin-callout__decoration","aria-hidden":"true"},React.createElement("svg",{viewBox:"0 0 248 248",xmlns:"http://www.w3.org/2000/svg",xmlnsXlink:"http://www.w3.org/1999/xlink",focusable:"false",style:{width:"100%",height:"100%"}},React.createElement("image",{href:"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAYAAAB5fY51AAAQAElEQVR4AezdC3ojWW5tYflOzPbIbI/M9sh8+WdrdZ+KpiiKL5FB5KedwN7AeSFIpHRYmfX/PubXVGAqMBV4kQpMw3qRBzXbnApMBT4+pmHNq2AqMBV4mQpMw3qZR3X9RmeGqcCrV2Aa1qs/wdn/VOCNKjAN640e9hx1KvDqFZiG9epPcPY/FThWgZ1q07B2+mDnWFOBPVZgGtYen+qcaSqw0wpMw9rpg51jTQX2WIFpWMee6mhTganAU1ZgGtZTPpbZ1FRgKnCsAtOwjlVltKnAVOApKzAN6ykfy2zqcRWYlV6pAtOwXulpzV6nAm9egWlYb/4CmONPBV6pAtOwXulpve9e//Nw9P/7xL8d7Hy9aQWubFhvWrU59qMr8D+HBcPBna93rcA0rHd98q91bs3q3w9bBv7Bna93rMA0rHd86nPmqcCLVmAa1os+uF/Y9m8u6Q7rvw8bgLnDOhTiXb+mYb3rk3+tc//rYbsaVTjQP18amct4+h9hftt3BaZh7fv57v107rNg7+ec831WYBrWZyHGPHUF/vewu//6xNqg+HMRfyjMrb+edb5pWM/6ZGZfawX86Bc0qTU2/htVYBrWGz3sOepU4NUrMA3r1Z/g7H8q8EYVmIZ1h4c9U04FpgL3qcA0rPvUdWadCkwF7lCBaVh3KOpMORWYCtynAtOw7lPXmfVdKjDnfGgFpmE9tNyz2FRgKnBNBaZhXVO9GTsVmAo8tALTsB5a7llsKjAVuKYCv9uwrtn5jJ0KTAXergLTsN7ukc+BpwKvW4FpWK/77GbnU4G3q8A0rLd75L914Fl3KnB9BaZhXV/DmWEqMBV4UAWmYT2o0LPMVGAqcH0FpmFdX8OZYSowFfhrBe7GpmHdrbQz8VRgKnDrCkzDunVFZ76pwFTgbhWYhnW30s7EU4GpwK0rMA3r1hW9fr6ZYSowFfiiAtOwvijMyFOBqcDzVWAa1vM9k9nRVGAq8EUFpmF9UZiRpwKPqMCs8bMKTMP6Wb0meyowFfjFCkzD+sXiz9JTganAzyowDetn9ZrsqcBU4Bcr8NIN6xfrNktPBaYCv1CBaVi/UPRZciowFbisAtOwLqvbjJoKTAV+oQLTsH6h6LPkBRWYIVOBQwWmYR2KMF9TganAa1RgGtZrPKfZ5VRgKnCowDSsQxHmayowFXimCny9l2lYX9dmIlOBqcCTVWAa1pM9kNnOVGAq8HUFpmF9XZuJTAWmAk9WgWlYT/ZArt/OzDAV2G8FpmHt99nOyaYCu6vANKzdPdK7HOjfDrP+9yf4B/fP138efoeDma+pwP0rMA3r/jXewwqaVFjP8x8HAmIHd74eXIG3W24a1ts98pse+H8Os8HBzNdU4P4VmIZ1/xrvYQU/9v3L4SCwNqh/P2iwagdpvqYC96nANKz71HVmnQpMBe5QgXduWHco526n9B3W9tJ91fi7Pfwc7HkqMA3reZ7FM+/kXw+bc7EeDvTPV1z8jzC/TQXuWYFpWPes7sw9FZgK3LQC07BuWs7dTva/h5P91ye6YGfT2EP4eb9mZ/uowDSsfTzHe5/CHVXQqKzHbjX6YCpwtwpMw7pbaX808f8dsoN7oQOdr6nAVGBbgWlY24o8hvvEzXcnp1YTl3cq51ExTdRe7GldE6ev2vhTgbtV4KyGdbfV33diDeC7T9bE5T1LlezFntb94PRVG38qcLcKTMO6W2lPTuy/GPdfiJfED+6G6Lg8/m/Dnuxne7lOe5Y9/naNZv0HVGAa1gOKfMYSGkI4I/1XUp59f79SlFn0sRWYhvXYereaex/3PyunQT9iiePlPMbOKlOBJ67ANKzfeTiakvufVsdDmjgtPnYq8PYVmIb1Oy8B9z7uf06tLi7vVM7EpgJvVYFpWM/xuF1mB3dFz7Gr2cXOK/B6x5uG9RzPzH1VeI4dzS6mAk9YgWlYT/hQZktTganA8QpMwzpel1GnAlOBJ6zANKyLH8oMnApMBR5dgWlYj674rDcVmApcXIFpWBeXbgZOBaYCj67ANKxHV3zWe8UKzJ6fpALTsJ7kQcw2pgJTge8rMA3r+xpNxlRgKvAkFZiG9SQPYrYxFZgKfF+BRzSs73cxGVOBqcBU4IwKTMM6o0iTMhWYCjxHBaZhPcdzmF1MBaYCZ1RgGtYZRXrSFP9Wln/gD/htEwd/mTqNT4Nyj2ny+7/3sDgYh4NxNBYHcdrH4Tc8HOifL/E044hsmjgN0tj2Ko6DcfLE8EADcfmAg1w64IMXrcA0rNd5cN6Y3njrjnE4pvkHANP58iCNxQO+B3x11v84HA6c9+DO1ytWYBrW6zw1/6Df/FtZlz8vtYPLZ5iRv16BaVi//gjO3sD2zYb7F0mB30Q4aHBpfBqU68cjHPjl4iHNPy5oDljH4yBeLh7SxNN+Mr7cY+PFmpNtLf52/2suv9yx11TgF8ZOw/qFor/gkt7kKzrCJZox9xzf3GN3WIFpWK/xUN27hHbsuyIXyyBGZ/FAgzgrh7aO59PE5AQaiKfJ2WriNCiPPZabxsqBa8ebw9rAD9agmX+r0QcvVoFpWK/xwLzxvOFcGq87pof0OHtKE5MDLqpxwAMO4mksDfggjgMecBBPY2lsEKdBGouDOB5oEGdx4Ac8pLFpY1+sAtOwfuuBXb+uN/H1s9x2hm0zWH/8u+1KM9tbVmAa1ms8dj/SuEh2odyOXUSHtTGksadyjZETjuWm/e/BKc+4A/1g09iPw69j2kH+OHe8XHMF89GOjaeXx+LAD41nt5rcwYtVYBrWiz2wZbvehBoZ8IVYPNAgzuKw5vK32prLD8dy08xRHosDP5TLbrVtLg7lscbRWDzQIM7isObyaYMXrMA0rBd8aN9s2Y9lodQ4m/ZK1r7Duu80Np0f0n7ZzvK3qsA0rFtV8vHzeFP6r9+Bbwesy/lAgzgrh8YaC+t3I3SclRdoEGflbDU6TYwfaBBn5Ww1fN2nPB820ECcZiweaLDmyqGBcSunDV6sAtOwXuyBPWC73tTe9NulaNuLfhqsuY1nV13eOeONMRb4t4Q93HK+mevBFZiG9eCC33i5ay+S3efAui3fibjc3+o06625OH3VjKOZZ9V9aCB/1XC5q2YczTyrfq7vgt5YWMc076qN/2IVeIGG9WIVfdx2vSG9CaFVaRpDSI+zcuisxgDrHMXYFfLhO018m0eDrY6D2AoapNmjvUN7FcdDueLyQU762B1UYBrWDh7iHGEq8C4VmIa1vyfdJbTvNDqdi/Ww3g3JgfKe1TpT+2+/zpHGtne6HEgbu5MKTMPayYNcjuENC9sL7iXl765LaPi78MvOLZZ3dmc65/y3WG/meGAFpmE9sNhPuJQ7HhffT7i1i7fkTODy/eJJZuBzVmAa1nM+l2t21SW0S+fm4Qdv5lV/hR+dNNXt/p0jje1M6a9wrvY89swKTMM6s1AvnuZNHF7xKO092xnibNrYF6nAJduchnVJ1Z57jO8sQjt1aR3c8aS/inWe7f6dI43tLPSQNnYnFZiGtZMHuRzDhTOsl869gdkl9cOna7Bqz+g7i72H9hhnV00DU4O0sTupwDSsnTzIOcZU4B0qMA3rRZ/yiW27gAYX1aXxw3rf0wV9ec9qfeJ3bP9pbHv346NzqUHa2J1UYBrWTh7kcgwNKSR7E4e0V7LtnXU2e2fxQBvsvALTsHb+gD+P544nfEovZdo7u24cD6s+/k4rMA1rfw/WJTq4eO50/OANvtXjz2pdoLd/31HZp3OksTQQx1n89TEn+HsFpmH9vRRv6XjTw94O70w+Wdzbud7+PNOw9vcScLcDLqq/O52Lafgu75Xizu5M60X8K+1/9nqiAtOwThTnRUPerLD+SORTs+AN3dH4EH9W6zztv3PZdxrb3ukhbexOKrD/hrWTBzXHmApMBT4+pmHt71Xgwhn6TsQJXcIH9zs04AP/meE87b9z2Xca2/7pciBt7E4qMA1rJw9yOYY3LJxz6awRwDL85V1n96niOed/+cO+2wGmYb3bE//reXd21/PncJ3pnA8d/gyY316nAtOwXudZnbvTfzkkgovqg/vnix+8of+Ih9/SDu5Tf/nEr722fzaN7QDp8yNhFdmRnYa1o4d54ijexOFE2tOG2nu2jcbZtLE7rsA0rP09XN9ZhE7nniq440l/Fes82/07Rxr7KmeZfV5RgaVhXTHLDH2mCrhwhvXS2Zs7rHutEazaM/rO0v7Z9sgPac7kU8NpYlVkR3Ya1o4e5hzlLxWYS/e/lGMfZBrWPp7jeoouqNl0fljve3w3sl5Yl/9sVvM5tv80tj07kw8d2LSxO6nANKydPMjlGN6omhIk0wLt1dDe2c7F4uHVzjT7vaAC07AuKNoLDumeh33B7X/Yd/hYfqWxizzuXiswDWt/T9aFM6yXzvywvrnTnr0KPkRor76jsl/nSGNpII6z+GBHFZiGtaOHecFRvOnhgqFPPcSZfLL41Jt81Ob2tM40rD09zb+dxd0OuKj+m/L17y7c4euM14v4zsqZ1ov41zvF7PhoBaZhHS3LS4verOCN20F8ahY0s3Q+xJ/VOk/771z2ncauexeDVRt/BxWYhrWDhzhHmAq8SwWmYX3zpF8w7MIZ+k7EEVzCB/c7NOAD/5nhPO2/c9l3Gtv+6XIgbexOKjANaycPcjmGNyycc+msEcAy/OVdZ/ep4jnnf/nDvtsBpmG92xP/63nd88Bf1ddmzgPnfOjw2id9w91Pw9rfQ3cBDS6qOx0/eDNv9fizWp/4bffvHGlse0//+Y+EzTD2aSswDetpH81NN+ZNHG468YMma+/Zlo2zaWN3XIFpWPt7uL6zCJ0uzrrjSX+Utaa1gW9dFg+0r7Dm8strLJs2dscVmIa1v4frwhnWS2c8rCf26Rqs2j381mZrOCwO617pPghg24uckM6mseVqXs5kjrSxO6nA7RrWTgoyx3iaCmhIT7OZ2chzVGAa1nM8h1vuwgV1aN44u973uJyH8u5lfWJnbWh9Fg+tTXeJ7jultGPjxRrL4mCcM5kDH+yoAtOwdvQwP4/iDQve+J/SBx4+fuFXa7Pti8WBf2pbckK5bBp7avzEdlKBaVg7eZDfHMOPV+Gb1HPCP85pbbbB/BXpx+xXeV/px+YYbQcVmIa1g4e4OYILZ1gvnfnBm7wh8mDVil1jfcezzulSvPXFzC2eJk4DcTqLgzgN0tfxdHkgjrP4YEcVmIa1o4f5w6N4w/9wyFnp5tVgzkr+Iskc6yeHX6R9KV87/suJJ/C7FZiG9bv1v8fq7nbARfWp+eW4rIZTeT+NmdeFN/vTsfKNsyfAf4prx/90vb3nP9X5pmE91eO4yWY0C1h/JPKpWfCGbiE5sGrFrrHb+eyn9a1nbjZNnAbGirE4iJcrRhNPY2lAl8Pigx1VYBrWjh7mHGUqsPcKTMPa3xN24Qy+y+h0LtaD+x06Kwfwe8Ia9gTWtRaLgzjtK8hpoPtu7gAAEABJREFU/+Uan8Y2li4H0sbupALTsO77IH9jdm9YOOfS2uU4yL/3Xq0B6zo4nLPXddwp33zOdMs5T603sQdWYBrWA4s9Sz2kAu6u4LsPHR6ymVnkthWYhnXbej7DbC6gwUV1++EHb2Y6Kw/4tHvBj2fWgdZi29N3nwiKl2ucfbJpLA3SrYkPdlSBaVg7epgnjuJNHE6kPTzUnthTi4uvKPeYVuzhdha8fwWmYd2/xo9ewR0OrN9h8INYe+JD/FmtPR7bfxr7rHuffd2wAtOwbljMJ5nKJ2qwXjq7hA5tUxOQB/z0Z7TtnW2vLB7at+blU0PnShu7kwpMw9rJg5xjTAXeoQJP07DeodgPOqML6tCSx+56aC6rgV/uM1qf+NkjrPvDQ7rvsJxJDdLG7qQC07B28iCXY3jDgjdysjdwWHU+lPes1nnaP98+7TuNpQUxiI/dSQWmYe3kQX5zDPc94ZvUpwy3d3bdIB5WffydVmAa1v4erAtnWC+d+cEb3KlZecCnPQY/X8XFevvvOyx7TmObVRxn08bupALTsHbyIOcYf6mAZrZ+SvqX4JDXrcA0rNd9dl/t3N0NuKj+Kocux8U04HvBXs+1l+dz1TmmYV1Vvqcc7AIa1h+J/JWY4A3dxuXAqhV7Jus87d9+7c2e01ga0OWw+OBXK3Dbxadh3baeM9tUYCpwxwpMw7pjcR8wtbsaaCm+S/SQHmflpL+K9R2Ti3Ro/6zzhM4iJ8hJH7uDCkzDeu2H2Bvz0lNoBHDp+EeO03zCqXXLYU/lTewFKzAN66kf2rebc08D3yZ+kaBZXTP+i2lHngrcpwLTsO5T10fN6jIaWk/zwUN6nJWTzm457dmgsdo7tF8WD+05zspJH7uDCkzD2sFD3BzBmzQUirNpr2btPbT3OHtKKzb2xSswDet1H6A7Gt95AL+T4CFNPKTtwXZOtvPwgzNv9VUr9gx29nBGBaZhnVGkJ03xxvNXVoBvmyweaEC/9oLePM8EZ+qc63/Vnsa2Xw0MB+PSx75YBaZhvdgDm+1OBd65AtOwXvfpu7cJ6ynS2HTfYbiEhrQ9WH+tKHQe515Bx8vj0wYvWIG9NKwXLP3VW/bG04BAQzLhqtFpQQzir26dxbmB33mcO6SJywN++tgXq8A0rBd7YMt23cWERf5IYz/u+Mv8K1rqmFbsEfbY+se0R+xl1rhxBaZh3bigd5rOhfn2r6B4E9LBdw6WXjU67RZo3tYxZ5p1XGbTAA84GNf+jaMBH/iXwFhzs41vbTadxUF+uXScTRv7xBWYhvXED+fJtuZNvX4ad4vtmVMT+dFcS7Lxa7NcQme5144/a5FJul0FpmHdrpb3nMm/beXuBe65zqm5u7Q+lXMqZu+w5vjuZv2nYdbYOb753Fex5+Rvc6x/zfjtfMPvXIFpWHcu8I2m743lzdWUNG924NO9cfFAuwXMaw22+fDWWfeVxq65cmCdo/il1lywjrduKLbulb/ml7Nq4z9pBaZhPemDmW1NBaYCHx8fmyJMw9oU5AmoexXfBbBtpwtrNl2O+x9IK/8aay5Y57CGtcG6YiwO4jTAAw7iacbRrEGHNPq1MJc5oblop9Zfcxsz9gkrMA3r+R6KS2Twhv5ud3JCubg3aPyn1nhvYPanY3+abw245WW+ucwJ3+1HTvgud+JPUIFpWE/wEDZb6IJ9I59N3cnA2QM2ica6YGc3oaFTgd+twDSs363/sdV9d+Rymi2OhxqJ+FYr/285sZ9ZY829jtLAtmvJSRMvP41NE8fB/HQWB3HaLWAuc0LzrXu1Lp2VE2iDJ6/ANKwnf0Cf2/PmCp/SH5PG/hHu9Jv5V7TMJZoxp8YXu9SaP6xzpLHp/JA29okrMA3r+R6O7wZCu4uz7lzS+RC/hbVGaD5rpPHpbBpLA37AYc3lbzX5tHvBmtYAfuvgIU08jZ8+9gkqMA3rdx+CNwS0C74L95AeZ9PkuhwHfvq11hqhueJsa7E4uOg+lntMM47OGgvrePqtz2RO6wB/uz6dBvyAvwjeY5vTsH73OXvzwLFd+FHlmH5P7au93HPNY3PbBxyLjfbGFZiG9bsPvx891l1oVODTwnQ8rFoXxmLp11qX1qG57MUakMYP4sf0NPFy0+Ks+Kr7L9XVJu1aa43OxG8+fkizl2O5xcf+YgWmYf1i8Y8s7c1TE1rfsGmsnIbyIX6tNZd1Q/Ph1gY+XS4OaXQ84CCexqd9NV7s1rCWdYFvfrY9sTSQE/DBE1VgGtafh/FUv/lRKLSxOJt2L2uN0Bpx9pj2lX4q15gV5T7SHlv/mPbIPc1aJyowDetEce4c8qf4uX9dxCV08IZqa3yIX2vN1Tps87mExsG+6WuuOA3kBBzE04yjsWniNDA/ncVvAWtVa745WesEGsRZOTTg33JP5hz8sALTsH5YsCdL9yaCJ9vWVdvxiaEzsVdNdOPBmirceNqZ7icVmIb1k2rdNtcdSrh0Zn/iw6Xjn3GcS291YW+5P3PCpXO6iF/vui6dZ8ZdUYFpWFcU78qh3jzeAFDTofmELLREnJWTfmtrbmuE5rfHtPbKpomXm8amieNgHJ3FQZwGdJzFbwHnMifwzclaO9AgzsqhAR/4g1+qwDSsXyr8LDsVmAr8vALTsH5es0tGuJPxHQM0nu9iF8TpLB5oEGfl0G453lzmNLc1Ag3E0+RsNXEalMfiII7DT8Yfy01jzResA3FWDu3Y+mJygjyIs3Jo63g+bfALFfhpw/qFLe5iSZe1sF4k870hQgeNs6c0MTkBhziLAz/gIc1etppYmjge0uPiW00sTRwP6XHxrSaWJo6H9Dh7ShOTE3CIszjwAx7S7CVt7IMrMA3rwQWf5aYCU4HLKzAN6/La/WSky16XuGzj+tSJ1mUui4dy46wcuh9NcEhj8SAP4qwc2jreXmhicgINxNPk0I6Np5fH4nDp+NY6Nl7MGsE6EGfl0Na9prFygjyIs3Jo63h7oQ1+oQLTsH6h6J9LejOs+JQ/ztU+Dr/OzT2Wdxj+cUz/u/bxj1+rxi/CD+dq8s/NPZZ3yXjzGBdwiLM48AMe0ti0sQ+uwDSsxxTcn9DBXYhV2a1GT2Nx4AfjaOxWo6exOPCDcTQ2jaUBP+Cw5vK3mnwa8AMOxqTxaZDG4sAP5bJbbZuLQ3mscTQWBz4N8IBDnC2XxYM8iLP44M4VmIZ15wJ/Tu/CPXxKH3HWG4LO4oEGcRaHNZe/1dZcfpAHxqR1kbxqYvKAH+TQ2LTG09NYOV9p3uRy4KvxxoKc0JxsGisP+AGHNZe/1eTTgB9wMCbtu73KH9ypAtOw7lTYN53WG/tNj/7ix36R7U/DesyDcu+xwqr+6kkaHtLYn2ryjQs4xFkc+MFeaJDG4iCOAw78IL7VitHFV06Ls+I0wAMO4luNnsbiwA84xFk84OFczV7KdQEf0sbesQLTsO5Y3GVqnziFZD8SpfHp3jxpLA34QQ6NTbv3ePOfWkvcnqA8FgdxHPi0Y/unywlyaMak8WliaSwN+EEOjU271XjzmivggztXYBrWnQv8Ob0flcKn9BHPfnz+irOf0gc/fCy/0thkfjiliZXH4sAPOMSzNIizOPADDvEsDeIsDvyAQzxLgziLAz/gIY39qSbfuIBDnMUHd67ANKxbFPgfc3jh9u8u+ZO3iL/mEeTQXeJuNbE0Vh7wgxya+beaWBorD/hBDm0dby80sfJYGojjIId2bDxdTsDh0vGtdWy8WOuw1gF+kENb95rGlsfKA36QQ1vH2wtNrDyWFsTyx96wAtOwbljMmWoq8FkBDUyT+6RjblWBaVi3quQ/5nFfEv6hjvdOFfC3GrwG3unMDznrNKzbltmLtMtdfrN7AYd0eWn9aSyWxp4ab4wc4Mu9dLy9nBovbh1oLRYHceMBDziIpxlHY9PEaZDGOg9NHAfjaGJ4oEGclUMzBgc+TQwPNIizcmjG4P/y8fFhLzSxNJa2Qnzl49+gAtOwblDEmWIqMBV4TAWmYV1XZ5er0Cz+JHZ/Afx0PJQvvtXE0thHjbcXa321vrj9gBy5q8angZyAg3jaT8Yfy01jm5O1DvCDHNqx9cXKY+UBP8ihreP5NLHyWBqI4yCHNrhRBaZhXV5IL0Yvyj41aiY6rH+FAw/liaex6fxwShMrj8WBH3CIs3jAwV62Gj1NHA/pcfGtJpYmjof0uPhWE0sTx0N6nD2lickJOMRZHPgBD2n2stXE0sRxSBt7owo8uGHdaNfPM417ivW/fH6enc1OpgI7rMA0rMsfqmblAtaPAM1C669qsOn8IIeu0W01epq5cUhjG8/iwJcHOPxkvHxjgR9wOLZXa5bHygN+wOHS8db4ajy9dVgc+KHx7Fbb5uJQHmscjcUDDeIsDny1B+NogxtVYBrWjQr5OY0XqAYG/E/5Aw8fn7/ibLksDvzP1A88fHz+Ek/jk9mtRk9jcTiWu2prLj/I+Wo8vTwWB364x3hzWwf4AQdrpvG3mhgN+AEHY9L4W02MBuIBH9ywAtOwLi+mOwovVOCbicUDDeKsHBqLA58GeMAhzpbL4sCXB3jAIc6Wy+JBHsRZHNZc/lZbc/kA8sAYHPhbjU4DfjiWm7bNxaGxbLksDnx5gAcc4my5LB7kQZzFYc3lb7U1V2zwgwpMw/pBsTapLtvD+sJMc/nakDT2mHZs/Fe5jTdGDvDpLB5oEGdxWHPb66qtufwg56vx9PJYHPjhHuPNbR3gBxysmcbfamI04AccjEm7Za3MPfhBBaZh/aBYkzoVmAr8bgWmYV1efxfJ27uKOCve7HhIE99qYmksDvyAQ5zFAx7O1ezlVK74qTnFHz3eeu2JxYEfcIizeMDDudotz9qaL28fdYBpWJdX2l2ET4KAbyYvfhzS6HiQQxNP49PE0lga8IMcGpt27/HmP7WWuD1BeSwO4jjwacf2T5cT5NCMSePTxNJYGvCDHBqbdu/x5j+1lrg9DS6owDSsC4r2OcS9xopP+eMSzZiPz1/88Cl9xNmP5RcekuPsKU1MTsAhzuLAX0GDSzRjjAV+wCHO4sBfQYNztZ/kHpvz0vHmMhb4AR9cUIFpWOcVzZ+K/qt2thEuYWnghUgXx0GcBngoV3yriaWxxgI/yKGta6Wx5bHygB/k0Nbx9kITK4+lgTgOcmjHxtPlBBwuHd9ax8aLtQ5rHeAHObR1r2lseaw84Ac5tHW8vdDEymNpII6DHNqx8fTBDyswDeu8gvlkyIuPPW/ED7Im9a0r4B98fOsC/OTw07DOq5aLVvcg7HkjJmsqcF4Fjv3TNOeNfMOsaVjnPXTf0rtIZRuBe7FBOouDeLl40Pjo4mnG0cTSWBrwgxyaMWl8mlgaSwN+kEMzJs1eaGJpLA3EcTCOxuIgTgM84CCeZhyNTROnQRprPzRxHIyjieGBBnFWDs0YHPg0MTzQIM7KoRmDg73QxPBAA/E042hsmjhtcEEFpmFdUFjYef8AAA5ZSURBVLQZMhW4uAIz8KoKTMP65/K5q4I14gI1FPOn5ilNvDnKY0+NF5MTHjW+vX61vnh7kmNfq8anQXksDuI4/GT8sdw01nzBOhBn5dCOrS8mJ8iDOCuHto7n08TkBBqIp8nZauI0KI/FB99UYBrWPxfIiwd6scngBxxcwKexNOCDOA54wEE8jaUBP+AQZ/GAh59q8htrLziksTiI44EGcXEc0lgcxPFAg7g4DmksDuJ4oEGcxYEf8JDG/lSTbxzYCw54wEE8jaUBH8RxwAM++KYC07C+KdCEpwJTgeepwGs1rMfUrctRl6qt6N84Cuk+MdxqYmnsT8fLNw7Wy1k8WEMeu9XoaSwO/GAcjU1jacAPOFx6VmPh0vH2+NV4evtkceCD+jWepQFfHuABhzhbLosHeRBncfjJWe0xGDv4pgLTsL4p0GfYvUP4lD7irBf0x+EXiwP/IP35wsMf4fBbnC2XxYF/SPvzhYc/wuE38TT+Qfpg09iPz1/88Cl9rLn8j8Mvtjz2IP354gc5RHar0dNYHPjBOBq71ehpLA78YByNTWNpwAdxHPg04G81Og34AQdj0vhbTYwG/HAsN00uP+CDbyowDeuvBXKf0IuNLcoPcujsVqOnsTjwg3E0dqvR01gc+ME4GrvV6GksDvxgHI1NY2nADzisufytJp8G/ICDMWl8GqSxOPBDuexW2+biUB5rHI3FgU8DPOAgnsbfamI04AccjEnjbzUxGvADDsYEfLBUYBrWUoyD64Xir1bAejmKh0Pan684axzRiw+HS8abx9hgToizOKy5/K225vKDPDAmrb2umpg84Ac5NDat8fQ0Fgd+MI72Ta0+5MsDfmg8m8bKA37AYc3lbzX5NOAHHIxJ66yrJiYP+EEOjU1rPD2NxUGuD30AHywVmIa1FONM17fwZ6ZO2gtWQMN4wW2/x5anYf31OWtGweVp0TQ2TRyHNH4QP6aniZebxqaxOPADDnEWD3g4V7OXU7nip+YUf/R467UnFgd+wCHO4gEP52r3Pqv9uMSH9jT2swLTsD4L8Wm8WPrUxo8sn/Kf/z15epp4Gp9+zng5co05NV5MHvBD49k0c8lbNTEa8IMcGpv23XjxU7ni5oTyWBzEceDTjq1PlxPk0IxJ49PE0lga8IMcGpt27/HmP7WWuD1BeSwO9ioH8HfA2WechvXPpfIjQSgaZ49pX+nHco9pl4w3j3EBhziLAz/gIY09V/tJ7rE5f2O8fVg34BBnceAHPKSx52o/yT025zq++Fvbd29Y/hSDXgR8l52wXoTioVzxtF5Y54wv99h4seZkW4sf5NDXtdLY8lh5wA9yaOt4e6GJlcfSQBwHObRj4+lyAg6Xjm+tY+PFWoe1DvCDHNq61zS2PFYeHFtrHS8u79rx5rBuwMH8adagDT4r8M4Ny4vBi2P91OazLGOmAlOBZ6zAOzcsz8PFJvBfFbPv21bAH2S3nXFmu1kF3rlhdbnJVlDf+vdXc9aL0DS2XHEcjKOzOIjTAA+tJ55mnDyxNJYG/CCHZkwanyaWxtKAH+TQjEmzF5pYGksDcRyMo7E4iNMADziIpxlHY9PEaZDG2g9NHAfjaGJ4oEGclUMzBgc+TQwPNIizcmjG4GAvNDE80EA8zTgamyZOgzQWB3EcjKMNPivwzg3rswRjpgJTgVepwDs3LH96bS83V43fcyyPTRPHoR8jVo1frpxwLDeNLY991Pj2+tX64vYDcuxr1fg0kBNwEE/7yfhjuWlsc7LWAX6QQzu2vlh5rDw4lrtqfHnXjjeHdQMO5k+zBg3o/3lwVu1A3+vrnRuWy3YPP/Tk4+JbTSxNHA/pcfGtJpYmjof0OHtKE5MTcIizOPADHtLsZauJpYnjIT0uvtXE0sTxkB4X32piaeJ4SI+zpzQxOQGHOIvDuhYe5ID4VqOnieMhPS6+1cTSxPGQ7gMioKe9nX3nhvV2D3sOfFYF3rohnFWhX0x654blr1j4hBBcoHoMLB5oEGdxuHS8Nb4aT7dGwCHONp7FgS8P8IBDnC2XxYM8iLM4XHpWY+HS8fb41Xi6PQYc4i6vG8+m8+VBGosDP5TLprHygB9wuPSsxsKx8XSX8OBHQ/wt8VYNa/OEPfjgBSnMbjV6GosDPxhHY7caPY3FgR+Mo7FpLA34AYc1l7/V5NOAH3AwJo2/1cRowA/HctO2uTg0li2XxYEvD/CAQ5wtl8WDPIiL48Df6qsmJg/4AYc1l7/V5NOAH47lpm1zcWgsu+aKvT3epWH5Nj/00HEvCuDTWTzQIM7KobE48LcanQb8cCw3bZuLQ2PZclkc+PIADzjE2XJZPMiDOIvDmsvfamsuP8gDY9L4W02MBvxwLDdtm4tDY9lyWRz48gAPOIin8beaGA34AQdj0vhbTYwG/ICDMWn8rSZGe0u8S8PqUxe2B+0CM6wvjDSXn8dyj2n3GG8fx9ZKs6Yc4NNZPNAgzuKw5nbWVVtz+UHOV+Pp5bE48MM9xpvbOsAPOFgzjb/VxGjgNYIDDsbg8Ey1sre3wrs0rLd6qHPYj4+PKcIuK/AuDauLUbYH6XLTHQGk8YP4MT1NvNy0OCt+TE8TlwdpLB5wiLM48AMe0thzNXs5lStuPjiWJ35MTxM3FtL4QfyYniZebhqbxuLADzjEWTzg4VzNXk7lip+aU/xW45vnbey7NCw/94ceLu6TJODTvdBwSKPjQQ5NPI1PE9tq9DRWDs0YHPg0MTzQIM7KobE43Hu8+a0D/K/Wp8sJOBiTxqcd2z+9PFYOzRgc+DQxPNAgzsqhsTjce7z5rQP8r9anywk4GJPGpx3bP/3t8C4N6+0e7Bx4KrDHChxvWPs7qYtU6E8sJ8T/7+BAOouD+CH85wsPLmCJ4mnG0dg0cRqksafGi8kJxkKclUNb1+LTxOQEGsRZOTRjcGivYniQB+JpxtHYNHEapLE4iONgHI3FQZwGeLAfmniacTSxNJYG/CCHZkwanyaWxtKAH+TQjEmzF5pYGksDcRyMo7E4iNMADziIpxlHY9PEaW+Jd2lYXlzQJzxv+bDn0FOBV6/AuzQsdwCwXni++rOb/U8F3q4C79KwtpeYHjTNX3UA33LTWBzEaYAHjY8mnmYcjU0Tp0Eae2q8mJxgLMRZObR1LT5NTE6gQZyVQzPmXz4+PmjtVQwP8kA8zTgamyZOgzQWB3EcjKOxOIjTAA/2QxNPM44mlsbSgB/k0IxJ49PE0lga8IMcmjFp9kITS2NpII6DcTQWB3Ea4AEH8TTjaGyaOO0t8S4N6y0f7hx6KrC3Crxzw/KnlgtMcL/l2a4anwZywrHcNLa8a8ebx9rAD9agmX+riaWx8oAf5NDW8XyaWHksDcRxkLPVxGkgJ+AgnvaT8cdy09jmZK0D/CCHdmx9sfJYecAPcmjreD5NrDyWBuI4yNlq4jSQE3AQT2s8nQ/8t8U7NywX8F4AsL4AcBBPx0OaeBpLZ4M4DdJYHMTxQIM4iwM/4CGN/akm3ziwFxzwgIN4GksDPojjgAccxNNYGvBBHAc84CCextKAH3CIs3jAw081+Y21FxzSWBzE8UCDuDgOaSwO4niggb8WpJHR8Uvw8mPeuWG9/MObA7xVBXxg5N7srQ69Pew7Nyx/TccFJvRCYOmhesVZOXQvIBzSWDzIgzgrh3ZsPF1OwCHONp7FgS8PcHAuHPBQLpvGygN+wOHYXh8x3hpfrU9vnywO/NB4dqttc3EojzWOxuKBBnEWh3vUyrx+VPRM7QV/S7xzw/LgQw8f98IAfjoejmnlsuXxj+Ue08plG88ey01bc/l01jjg0wAPOIin8beaGA344Vhu2jYXh8ay5bI48OUBHnCIs+WyeJAHcRaHNZe/1dZcfpAHxqTxt5oYDfjhWG7aNheHxrJrrtjb450b1rGH735gRTlePEGczp7SxOQBPxhHY7caPY3FgR+Mo7FbjZ7G4sAPxtHYNJYG/IDDmsvfavJpwA84GJPG32piNOCHY7lp21wcGsuWy+LAlwd4wCHOlsviQR7EWRzWXP5WW3P5QR4YE/DBUoFpWEsxDq4XiotNcMl5kP588cMf4fBbnDXuIH2wOLg8/fj8hYdP6SPOGkdn8UCDOIvDmsvfamsuP8gDY9La66qJyQN+kENj0xpPT2Nx4AfjaGzatePNY07gBxzWtfhbTT4N+AEHY9La66qJyQN+kENj0xpPT2NxkOv1B3za4LMC07A+CzFmKjAVeP4KTMP66zNyZxBcnhZNY9PEcUjjB/Fjepp4uWlsGosDP+AQZ/GAh3M1ezmVK35qTvFHj7dee2Jx4Acc4iwe8PAX7UDoB/Pnix/ufVbruMQH/p8NzG9/q8A0rL/Vod+9QHwSA+4W0vEghy6exqeJbTV6GiuHZgwOfJoYHmgQZ+XQWBzuPd781gH+V+vT5QQcjEnj047tn14eK4dmDA58mhgeaBBn5dBYHO493vzWAf5X69PlBBzs1TjAB0sFpmEtxRh3KjAVeO4KTMN67ufzTLv7yQXwT3Kf6YyzlyevwF0a1pOfebZ3ugKajX8sbpvlkyyxVceP/ejiE641b/ypwE0qMA3rJmXc1STuUPxTJttDuWsRW3X8WMM6Nn4dN/5U4KIKTMO6qGwzaCowFfiNCkzD+o2q72nNOctU4IEVmIb1wGLPUlOBqcB1FZiGdV39ZvRUYCrwwApMw3pgsWepqcBrV+D3dz8N6/efwexgKjAVOLMC07DOLNSkTQWmAr9fgWlYv/8MZgdTganAmRWYhnVmoa5PmxmmAlOBayswDevaCs74qcBU4GEVmIb1sFLPQlOBqcC1FZiGdW0FZ/xU4J8rMMqdKjAN606FnWmnAlOB21dgGtbtazozTgWmAneqwDSsOxV2pp0KTAVuX4H/DwAA//9sB2hHAAAABklEQVQDAB9QlitZA9bLAAAAAElFTkSuQmCC",width:"248",height:"248",style:{mixBlendMode:"multiply"}})))}var i0="ai",s0="ai-wp-admin",Vs="ai/ai",a0="https://wordpress.org/plugins/ai/",Ys=Object.values(Fs()),c0=Ys.some(e=>e.type==="ai_provider"),af=[];for(let e of Ys)e.type==="ai_provider"&&e.authentication.method==="api_key"&&af.push(e.authentication.settingName);function cf(){let[e,t]=(0,wt.useState)(!1),[o,n]=(0,wt.useState)(!1),r=(0,wt.useRef)(null);(0,wt.useEffect)(()=>{o&&r.current?.focus()},[o]);let i=(0,wt.useRef)(Ys.some(S=>S.type==="ai_provider"&&S.authentication.method==="api_key"&&S.authentication.isConnected)).current,{pluginStatus:s,canInstallPlugins:a,canManagePlugins:d,hasConnectedProvider:c}=(0,ln.useSelect)(S=>{let x=S(Ws.store),E=!!x.canUser("create",{kind:"root",name:"plugin"}),T=x.getEntityRecord("root","site"),k=i||af.some(A=>!!T?.[A]),C=x.getEntityRecord("root","plugin",Vs);return x.hasFinishedResolution("getEntityRecord",["root","plugin",Vs])?C?{pluginStatus:C.status==="active"?"active":"inactive",canInstallPlugins:E,canManagePlugins:!0,hasConnectedProvider:k}:{pluginStatus:"not-installed",canInstallPlugins:E,canManagePlugins:E,hasConnectedProvider:k}:{pluginStatus:"checking",canInstallPlugins:E,canManagePlugins:void 0,hasConnectedProvider:k}},[]),{saveEntityRecord:l}=(0,ln.useDispatch)(Ws.store),{createSuccessNotice:f,createErrorNotice:p}=(0,ln.useDispatch)(rf.store),m=async()=>{t(!0);try{await l("root","plugin",{slug:i0,status:"active"},{throwOnError:!0}),n(!0),f((0,Xe.__)("AI plugin installed and activated successfully."),{id:"ai-plugin-install-success",type:"snackbar"})}catch{p((0,Xe.__)("Failed to install the AI plugin."),{id:"ai-plugin-install-error",type:"snackbar"})}finally{t(!1)}},u=async()=>{t(!0);try{await l("root","plugin",{plugin:Vs,status:"active"},{throwOnError:!0}),n(!0),f((0,Xe.__)("AI plugin activated successfully."),{id:"ai-plugin-activate-success",type:"snackbar"})}catch{p((0,Xe.__)("Failed to activate the AI plugin."),{id:"ai-plugin-activate-error",type:"snackbar"})}finally{t(!1)}};if(!c0||s==="checking"||s==="active"&&i&&!o||s==="inactive"&&d===!1)return null;let g=s==="active"&&!c,v=s==="active"&&c&&(!i||o),_=s==="not-installed"||s==="inactive",w=s==="not-installed"&&a===!1,y=()=>v?(0,Xe.__)("The AI plugin is ready to use. You can use it to generate featured images, alt text, titles, excerpts and more. Learn more"):g?(0,Xe.__)("The AI plugin is installed. Connect an AI provider below to generate featured images, alt text, titles, excerpts, and more. Learn more"):(0,Xe.__)("The AI plugin can use your AI connectors to generate featured images, alt text, titles, excerpts and more. Learn more"),b=()=>s==="not-installed"?{label:e?(0,Xe.__)("Installing\u2026"):(0,Xe.__)("Install the AI plugin"),disabled:e,onClick:e?void 0:m}:{label:e?(0,Xe.__)("Activating\u2026"):(0,Xe.__)("Activate the AI plugin"),disabled:e,onClick:e?void 0:u};return React.createElement("div",{className:"ai-plugin-callout"},React.createElement("div",{className:"ai-plugin-callout__content"},React.createElement("p",null,(0,wt.createInterpolateElement)(y(),{strong:React.createElement("strong",null),a:React.createElement(cn.ExternalLink,{href:a0})})),!w&&(_?React.createElement(cn.Button,{variant:"primary",size:"compact",isBusy:e,disabled:b().disabled,accessibleWhenDisabled:!0,onClick:b().onClick},b().label):React.createElement(cn.Button,{ref:r,variant:"secondary",size:"compact",href:(0,sf.addQueryArgs)("options-general.php",{page:s0})},(0,Xe.__)("Control features in the AI plugin")))),React.createElement(nf,null))}var{store:d0}=No(l0);of();function u0(){let e=$u(),{connectors:t,canInstallPlugins:o,isAiPluginInstalled:n}=(0,lf.useSelect)(c=>{let l=c(uf.store),f=l.getEntityRecord("root","plugin","ai/ai");return{connectors:No(c(d0)).getConnectors(),canInstallPlugins:l.canUser("create",{kind:"root",name:"plugin"}),isAiPluginInstalled:!!f}},[]),r=t.filter(c=>c.render),i=Array.from(new Set(t.filter(c=>c.type==="ai_provider").map(c=>c.plugin?.file?.split("/")[0]).filter(c=>!!c))).sort(),s=new Set(t.filter(c=>c.plugin?.isInstalled).map(c=>c.plugin?.file?.split("/")[0]).filter(c=>!!c));n&&s.add("ai");let a=["ai",...i].filter(c=>!s.has(c)),d=r.length===0;return React.createElement(Bs,{title:(0,Tt.__)("Connectors"),subTitle:(0,Tt.__)("All of your API keys and credentials are stored here and shared across plugins. Configure once and use everywhere.")},React.createElement("div",{className:`connectors-page${d?" connectors-page--empty":""}`},a.length>0&&(e||!o)&&React.createElement(tn.Root,{intent:"info",className:"connectors-page__file-mods-notice"},React.createElement(tn.Description,null,e?(0,Tt.__)("Plugins cannot be installed here due to your site configuration. Install them manually using your normal deployment workflow."):(0,Tt.__)("You do not have permission to install plugins. Please ask a site administrator to install them for you."))),d?React.createElement(dt.__experimentalVStack,{alignment:"center",spacing:3,style:{maxWidth:480}},React.createElement(dt.__experimentalVStack,{alignment:"center",spacing:2},React.createElement(dt.__experimentalHeading,{level:2,size:15},(0,Tt.__)("No connectors yet")),React.createElement(dt.__experimentalText,{size:12},(0,Tt.__)("Connectors appear here when you install plugins that use external services. Each plugin registers the API keys it needs, and you manage them all in one place."))),React.createElement(dt.Button,{variant:"secondary",href:"plugin-install.php",__next40pxDefaultSize:!0},(0,Tt.__)("Learn more"))):React.createElement(dt.__experimentalVStack,{spacing:3},React.createElement(cf,null),React.createElement(dt.__experimentalVStack,{spacing:3,role:"list"},t.map(c=>c.render?React.createElement(c.render,{key:c.slug,slug:c.slug,name:c.name,description:c.description,type:c.type,logo:c.logo,authentication:c.authentication,plugin:c.plugin}):null))),o&&!e&&React.createElement("p",null,(0,df.createInterpolateElement)((0,Tt.__)("If the connector you need is not listed, search the plugin directory to see if a connector is available."),{a:React.createElement("a",{href:"plugin-install.php?s=connector&tab=search&type=tag"})}))))}function f0(){return React.createElement(u0,null)}var p0=f0;export{p0 as stage}; /*! Bundled license information: use-sync-external-store/cjs/use-sync-external-store-shim.production.js: diff --git a/src/wp-includes/theme.json b/src/wp-includes/theme.json index df48a061af01e..1cd9dfa120e89 100644 --- a/src/wp-includes/theme.json +++ b/src/wp-includes/theme.json @@ -319,6 +319,7 @@ "radius": true }, "dimensions": { + "width": true, "dimensionSizes": [ { "name": "25%", From 312b034308cc2b8d222534a6f7d74a71294d6fff Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Wed, 5 Aug 2026 12:59:21 +0000 Subject: [PATCH 131/138] Coding Standards: Correct alignment of assignment operators. This resolves a WPCS warning: {{{ Equals sign not aligned with surrounding assignments }}} Follow-up to [62590], [62838]. Props Soean. See #64897. git-svn-id: https://develop.svn.wordpress.org/trunk@63027 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/class-wp-users-list-table.php | 2 +- src/wp-includes/pluggable.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wp-admin/includes/class-wp-users-list-table.php b/src/wp-admin/includes/class-wp-users-list-table.php index dd54b200bafaf..1212c2db531e5 100644 --- a/src/wp-admin/includes/class-wp-users-list-table.php +++ b/src/wp-admin/includes/class-wp-users-list-table.php @@ -635,7 +635,7 @@ public function single_row( $user_object, $style = '', $role = '', $numposts = 0 if ( $primary === $column_name ) { $row .= $this->row_actions( $actions ); } - $tag = ( $primary === $column_name ) ? 'th' : 'td'; + $tag = ( $primary === $column_name ) ? 'th' : 'td'; $row .= ""; } } diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index e1c43540c8cb8..c7694e4cf8d11 100644 --- a/src/wp-includes/pluggable.php +++ b/src/wp-includes/pluggable.php @@ -2376,7 +2376,7 @@ function wp_new_user_notification( $user_id, $deprecated = null, $notify = '' ) $switched_locale = switch_to_user_locale( $user_id ); - $message = __( 'To set your password, visit the following address:' ) . "\r\n\r\n"; + $message = __( 'To set your password, visit the following address:' ) . "\r\n\r\n"; /* * Since some user login names end in a period, this could produce ambiguous URLs that From 2768106d9c32a529a368ea801e34982ff0252753 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 5 Aug 2026 13:03:06 +0000 Subject: [PATCH 132/138] Tests: Add unit tests for `wp_privacy_exports_url()`. This adds coverage for the personal data exports directory URL, verifying both the default location under the uploads directory and that the filter of the same name can override it. Developed in: https://github.com/WordPress/wordpress-develop/pull/5551 Follow-up to [63025]. Props desrosj, masteradhoc, mindctrl, pbearne, wildworks. Fixes #59709. git-svn-id: https://develop.svn.wordpress.org/trunk@63028 602fd350-edb4-49c9-b593-d223f7449a82 --- .../tests/functions/wpPrivacyExportsUrl.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/phpunit/tests/functions/wpPrivacyExportsUrl.php diff --git a/tests/phpunit/tests/functions/wpPrivacyExportsUrl.php b/tests/phpunit/tests/functions/wpPrivacyExportsUrl.php new file mode 100644 index 0000000000000..6891640d172b0 --- /dev/null +++ b/tests/phpunit/tests/functions/wpPrivacyExportsUrl.php @@ -0,0 +1,40 @@ +assertSame( trailingslashit( $upload_dir['baseurl'] ) . 'wp-personal-data-exports/', wp_privacy_exports_url() ); + } + + /** + * @ticket 59709 + */ + public function test_wp_privacy_exports_url_filtered() { + add_filter( 'wp_privacy_exports_url', array( $this, 'filter_wp_privacy_exports_url' ) ); + + $upload_dir = wp_upload_dir(); + $expected_url = trailingslashit( $upload_dir['baseurl'] ) . 'filtered-exports/'; + $actual_url = wp_privacy_exports_url(); + $this->assertSame( $expected_url, $actual_url ); + } + + /** + * Filters the personal data exports directory URL for tests. + * + * @param string $exports_url Default exports directory URL. + * @return string Filtered exports directory URL. + */ + public function filter_wp_privacy_exports_url( $exports_url ) { + return str_replace( 'wp-personal-data-exports/', 'filtered-exports/', $exports_url ); + } +} From 462a0507dd2d1350339a67ca6cca0bbd1860458a Mon Sep 17 00:00:00 2001 From: Joe Dolson Date: Wed, 5 Aug 2026 13:19:30 +0000 Subject: [PATCH 133/138] Media: Fix positioning of active spinner. Two positioning issues: on desktop, the active spinner appeared off screen, generating a scrollbar in the media toolbar. In the attachment details modal, the spinner overlapped with the `Saved` confirmation. On desktop, limit some positioning assignments to only apply with the media modal. In the attachment details, apply `display: flex` to prevent overlapping. Developed in https://github.com/WordPress/wordpress-develop/pull/12797 Props afercia, rcorrales, joedolson. Fixes #65778. git-svn-id: https://develop.svn.wordpress.org/trunk@63029 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/css/media-views.css | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index 227be604f7852..6748a50f00c57 100644 --- a/src/wp-includes/css/media-views.css +++ b/src/wp-includes/css/media-views.css @@ -364,9 +364,9 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { grid-area: 2 / 2 / 3 / 3; } -.media-toolbar-secondary > .spinner { +.media-modal .media-toolbar-secondary > .spinner { position: absolute; - left: calc( 100% + 2px ); + right: -30px; top: 50%; margin: 0; } @@ -1855,6 +1855,7 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { text-align: right; text-transform: none; font-weight: 400; + display: flex; } .attachment-details .settings-save-status .spinner { @@ -2842,7 +2843,7 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { float: right; } - .media-frame .media-toolbar-secondary .spinner { + .media-modal .media-frame .media-toolbar-secondary .spinner { top: calc( 50% - 8px ); } @@ -2877,7 +2878,7 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { bottom: -60px; } - .media-frame .media-toolbar-secondary .spinner { + .media-modal .media-frame .media-toolbar-secondary .spinner { top: 0; } @@ -2900,13 +2901,9 @@ select#media-attachment-filters ~ select#media-attachment-date-filters { position: unset; } - .media-frame .media-toolbar-secondary .spinner { - position: absolute; - top: 0; + .media-modal .media-frame .media-toolbar-secondary .spinner { bottom: 0; margin: auto; - left: calc( 100% + 2px ); - right: 0; z-index: 9; } From b9de76505ec2139156ee6d8aa269eb8868d0f65e Mon Sep 17 00:00:00 2001 From: Sergey Biryukov Date: Wed, 5 Aug 2026 13:52:42 +0000 Subject: [PATCH 134/138] I18N: Move trailing spaces out of translatable strings. Follow-up to [6873], [10888], [31059]. Props khokansardar, jorbin, audrasjb, rcorrales, SergeyBiryukov. See #64899. git-svn-id: https://develop.svn.wordpress.org/trunk@63030 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/category-template.php | 2 +- src/wp-includes/pluggable.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/wp-includes/category-template.php b/src/wp-includes/category-template.php index cd8304f24fdc0..76409d0832f2e 100644 --- a/src/wp-includes/category-template.php +++ b/src/wp-includes/category-template.php @@ -1230,7 +1230,7 @@ function get_the_tag_list( $before = '', $sep = '', $after = '', $post_id = 0 ) */ function the_tags( $before = null, $sep = ', ', $after = '' ) { if ( null === $before ) { - $before = __( 'Tags: ' ); + $before = __( 'Tags:' ) . ' '; } $the_tags = get_the_tag_list( $before, $sep, $after ); diff --git a/src/wp-includes/pluggable.php b/src/wp-includes/pluggable.php index c7694e4cf8d11..b283844836b83 100644 --- a/src/wp-includes/pluggable.php +++ b/src/wp-includes/pluggable.php @@ -2090,7 +2090,7 @@ function wp_notify_moderator( $comment_id ) { $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n"; /* translators: %s: Trackback/pingback/comment author URL. */ $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n"; - $notify_message .= __( 'Trackback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n"; + $notify_message .= sprintf( __( 'Trackback excerpt: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n"; break; case 'pingback': @@ -2101,7 +2101,7 @@ function wp_notify_moderator( $comment_id ) { $notify_message .= sprintf( __( 'Website: %1$s (IP address: %2$s, %3$s)' ), $comment->comment_author, $comment->comment_author_IP, $comment_author_domain ) . "\r\n"; /* translators: %s: Trackback/pingback/comment author URL. */ $notify_message .= sprintf( __( 'URL: %s' ), $comment->comment_author_url ) . "\r\n"; - $notify_message .= __( 'Pingback excerpt: ' ) . "\r\n" . $comment_content . "\r\n\r\n"; + $notify_message .= sprintf( __( 'Pingback excerpt: %s' ), "\r\n" . $comment_content ) . "\r\n\r\n"; break; default: // Comments. From 884f5156ddd9e820bec0b8f6550cfb7f8aa53f99 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Wed, 5 Aug 2026 14:02:21 +0000 Subject: [PATCH 135/138] Upgrade/Install: Add removed icon files to `$_old_files`. This adds the icon files removed during the 7.1 release to the `$_old_files` list. Follow up to [62738], [62739]. Props courane01, wiildworks. Fixes #65489. See #65813. git-svn-id: https://develop.svn.wordpress.org/trunk@63031 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/update-core.php | 244 ++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php index 89589c2ed384e..ce3eb82bc9e71 100644 --- a/src/wp-admin/includes/update-core.php +++ b/src/wp-admin/includes/update-core.php @@ -900,6 +900,250 @@ // 7.0.2 'wp-includes/collaboration', 'wp-includes/collaboration.php', + // 7.1 + 'wp-includes/images/icon-library/accordion-heading.svg', + 'wp-includes/images/icon-library/accordion-item.svg', + 'wp-includes/images/icon-library/accordion.svg', + 'wp-includes/images/icon-library/add-card.svg', + 'wp-includes/images/icon-library/add-submenu.svg', + 'wp-includes/images/icon-library/add-template.svg', + 'wp-includes/images/icon-library/align-center.svg', + 'wp-includes/images/icon-library/align-justify.svg', + 'wp-includes/images/icon-library/align-left.svg', + 'wp-includes/images/icon-library/align-none.svg', + 'wp-includes/images/icon-library/align-right.svg', + 'wp-includes/images/icon-library/archive.svg', + 'wp-includes/images/icon-library/aspect-ratio.svg', + 'wp-includes/images/icon-library/background.svg', + 'wp-includes/images/icon-library/backup.svg', + 'wp-includes/images/icon-library/bell-unread.svg', + 'wp-includes/images/icon-library/border.svg', + 'wp-includes/images/icon-library/box.svg', + 'wp-includes/images/icon-library/breadcrumbs.svg', + 'wp-includes/images/icon-library/brush.svg', + 'wp-includes/images/icon-library/bug.svg', + 'wp-includes/images/icon-library/button.svg', + 'wp-includes/images/icon-library/buttons.svg', + 'wp-includes/images/icon-library/cancel-circle-filled.svg', + 'wp-includes/images/icon-library/caption.svg', + 'wp-includes/images/icon-library/caution-filled.svg', + 'wp-includes/images/icon-library/classic.svg', + 'wp-includes/images/icon-library/close-small.svg', + 'wp-includes/images/icon-library/close.svg', + 'wp-includes/images/icon-library/cloud-download.svg', + 'wp-includes/images/icon-library/cloud-upload.svg', + 'wp-includes/images/icon-library/cloud.svg', + 'wp-includes/images/icon-library/code.svg', + 'wp-includes/images/icon-library/cog.svg', + 'wp-includes/images/icon-library/color.svg', + 'wp-includes/images/icon-library/column.svg', + 'wp-includes/images/icon-library/columns.svg', + 'wp-includes/images/icon-library/comment-author-avatar.svg', + 'wp-includes/images/icon-library/comment-author-name.svg', + 'wp-includes/images/icon-library/comment-content.svg', + 'wp-includes/images/icon-library/comment-edit-link.svg', + 'wp-includes/images/icon-library/comment-reply-link.svg', + 'wp-includes/images/icon-library/connection.svg', + 'wp-includes/images/icon-library/contents.svg', + 'wp-includes/images/icon-library/copy-small.svg', + 'wp-includes/images/icon-library/copy.svg', + 'wp-includes/images/icon-library/corner-all.svg', + 'wp-includes/images/icon-library/corner-bottom-left.svg', + 'wp-includes/images/icon-library/corner-bottom-right.svg', + 'wp-includes/images/icon-library/corner-top-left.svg', + 'wp-includes/images/icon-library/corner-top-right.svg', + 'wp-includes/images/icon-library/crop.svg', + 'wp-includes/images/icon-library/currency-dollar.svg', + 'wp-includes/images/icon-library/currency-euro.svg', + 'wp-includes/images/icon-library/currency-pound.svg', + 'wp-includes/images/icon-library/custom-link.svg', + 'wp-includes/images/icon-library/custom-post-type.svg', + 'wp-includes/images/icon-library/dashboard.svg', + 'wp-includes/images/icon-library/details.svg', + 'wp-includes/images/icon-library/drafts.svg', + 'wp-includes/images/icon-library/drag-handle.svg', + 'wp-includes/images/icon-library/filter.svg', + 'wp-includes/images/icon-library/flip-horizontal.svg', + 'wp-includes/images/icon-library/flip-vertical.svg', + 'wp-includes/images/icon-library/footer.svg', + 'wp-includes/images/icon-library/format-bold.svg', + 'wp-includes/images/icon-library/format-capitalize.svg', + 'wp-includes/images/icon-library/format-indent-rtl.svg', + 'wp-includes/images/icon-library/format-indent.svg', + 'wp-includes/images/icon-library/format-italic.svg', + 'wp-includes/images/icon-library/format-list-bullets-rtl.svg', + 'wp-includes/images/icon-library/format-list-bullets.svg', + 'wp-includes/images/icon-library/format-list-numbered-rtl.svg', + 'wp-includes/images/icon-library/format-list-numbered.svg', + 'wp-includes/images/icon-library/format-lowercase.svg', + 'wp-includes/images/icon-library/format-ltr.svg', + 'wp-includes/images/icon-library/format-outdent-rtl.svg', + 'wp-includes/images/icon-library/format-outdent.svg', + 'wp-includes/images/icon-library/format-rtl.svg', + 'wp-includes/images/icon-library/format-strikethrough.svg', + 'wp-includes/images/icon-library/format-underline.svg', + 'wp-includes/images/icon-library/format-uppercase.svg', + 'wp-includes/images/icon-library/full-height.svg', + 'wp-includes/images/icon-library/fullscreen.svg', + 'wp-includes/images/icon-library/funnel.svg', + 'wp-includes/images/icon-library/gift.svg', + 'wp-includes/images/icon-library/globe.svg', + 'wp-includes/images/icon-library/grid.svg', + 'wp-includes/images/icon-library/handle.svg', + 'wp-includes/images/icon-library/header.svg', + 'wp-includes/images/icon-library/heading-level-1.svg', + 'wp-includes/images/icon-library/heading-level-2.svg', + 'wp-includes/images/icon-library/heading-level-3.svg', + 'wp-includes/images/icon-library/heading-level-4.svg', + 'wp-includes/images/icon-library/heading-level-5.svg', + 'wp-includes/images/icon-library/heading-level-6.svg', + 'wp-includes/images/icon-library/help-filled.svg', + 'wp-includes/images/icon-library/home-button.svg', + 'wp-includes/images/icon-library/html.svg', + 'wp-includes/images/icon-library/inbox.svg', + 'wp-includes/images/icon-library/insert-after.svg', + 'wp-includes/images/icon-library/insert-before.svg', + 'wp-includes/images/icon-library/institution.svg', + 'wp-includes/images/icon-library/justify-bottom.svg', + 'wp-includes/images/icon-library/justify-center-vertical.svg', + 'wp-includes/images/icon-library/justify-center.svg', + 'wp-includes/images/icon-library/justify-left.svg', + 'wp-includes/images/icon-library/justify-right.svg', + 'wp-includes/images/icon-library/justify-space-between-vertical.svg', + 'wp-includes/images/icon-library/justify-space-between.svg', + 'wp-includes/images/icon-library/justify-stretch-vertical.svg', + 'wp-includes/images/icon-library/justify-stretch.svg', + 'wp-includes/images/icon-library/justify-top.svg', + 'wp-includes/images/icon-library/keyboard-close.svg', + 'wp-includes/images/icon-library/keyboard-return.svg', + 'wp-includes/images/icon-library/keyboard.svg', + 'wp-includes/images/icon-library/layout.svg', + 'wp-includes/images/icon-library/level-up.svg', + 'wp-includes/images/icon-library/lifesaver.svg', + 'wp-includes/images/icon-library/line-dashed.svg', + 'wp-includes/images/icon-library/line-dotted.svg', + 'wp-includes/images/icon-library/line-solid.svg', + 'wp-includes/images/icon-library/link-off.svg', + 'wp-includes/images/icon-library/link.svg', + 'wp-includes/images/icon-library/list-item.svg', + 'wp-includes/images/icon-library/list-view.svg', + 'wp-includes/images/icon-library/list.svg', + 'wp-includes/images/icon-library/lock-outline.svg', + 'wp-includes/images/icon-library/lock-small.svg', + 'wp-includes/images/icon-library/lock.svg', + 'wp-includes/images/icon-library/login.svg', + 'wp-includes/images/icon-library/loop.svg', + 'wp-includes/images/icon-library/math.svg', + 'wp-includes/images/icon-library/media-and-text.svg', + 'wp-includes/images/icon-library/media.svg', + 'wp-includes/images/icon-library/megaphone.svg', + 'wp-includes/images/icon-library/more.svg', + 'wp-includes/images/icon-library/move-to.svg', + 'wp-includes/images/icon-library/navigation-overlay.svg', + 'wp-includes/images/icon-library/navigation.svg', + 'wp-includes/images/icon-library/not-allowed.svg', + 'wp-includes/images/icon-library/not-found.svg', + 'wp-includes/images/icon-library/offline.svg', + 'wp-includes/images/icon-library/overlay-text.svg', + 'wp-includes/images/icon-library/page-break.svg', + 'wp-includes/images/icon-library/page.svg', + 'wp-includes/images/icon-library/pages.svg', + 'wp-includes/images/icon-library/pending.svg', + 'wp-includes/images/icon-library/percent.svg', + 'wp-includes/images/icon-library/pin-small.svg', + 'wp-includes/images/icon-library/pin.svg', + 'wp-includes/images/icon-library/plugins.svg', + 'wp-includes/images/icon-library/plus-circle-filled.svg', + 'wp-includes/images/icon-library/position-center.svg', + 'wp-includes/images/icon-library/position-left.svg', + 'wp-includes/images/icon-library/position-right.svg', + 'wp-includes/images/icon-library/post-author.svg', + 'wp-includes/images/icon-library/post-categories.svg', + 'wp-includes/images/icon-library/post-comments-count.svg', + 'wp-includes/images/icon-library/post-comments-form.svg', + 'wp-includes/images/icon-library/post-comments.svg', + 'wp-includes/images/icon-library/post-content.svg', + 'wp-includes/images/icon-library/post-date.svg', + 'wp-includes/images/icon-library/post-excerpt.svg', + 'wp-includes/images/icon-library/post-featured-image.svg', + 'wp-includes/images/icon-library/post-list.svg', + 'wp-includes/images/icon-library/post-terms.svg', + 'wp-includes/images/icon-library/post.svg', + 'wp-includes/images/icon-library/preformatted.svg', + 'wp-includes/images/icon-library/pull-left.svg', + 'wp-includes/images/icon-library/pull-right.svg', + 'wp-includes/images/icon-library/pullquote.svg', + 'wp-includes/images/icon-library/query-pagination-next.svg', + 'wp-includes/images/icon-library/query-pagination-numbers.svg', + 'wp-includes/images/icon-library/query-pagination-previous.svg', + 'wp-includes/images/icon-library/query-pagination.svg', + 'wp-includes/images/icon-library/redo.svg', + 'wp-includes/images/icon-library/remove-bug.svg', + 'wp-includes/images/icon-library/remove-submenu.svg', + 'wp-includes/images/icon-library/replace.svg', + 'wp-includes/images/icon-library/reset.svg', + 'wp-includes/images/icon-library/resize-corner-ne.svg', + 'wp-includes/images/icon-library/reusable-block.svg', + 'wp-includes/images/icon-library/rotate-left.svg', + 'wp-includes/images/icon-library/rotate-right.svg', + 'wp-includes/images/icon-library/row.svg', + 'wp-includes/images/icon-library/seen.svg', + 'wp-includes/images/icon-library/send.svg', + 'wp-includes/images/icon-library/separator.svg', + 'wp-includes/images/icon-library/shipping.svg', + 'wp-includes/images/icon-library/shortcode.svg', + 'wp-includes/images/icon-library/sidebar.svg', + 'wp-includes/images/icon-library/sides-all.svg', + 'wp-includes/images/icon-library/sides-axial.svg', + 'wp-includes/images/icon-library/sides-bottom.svg', + 'wp-includes/images/icon-library/sides-horizontal.svg', + 'wp-includes/images/icon-library/sides-left.svg', + 'wp-includes/images/icon-library/sides-right.svg', + 'wp-includes/images/icon-library/sides-top.svg', + 'wp-includes/images/icon-library/sides-vertical.svg', + 'wp-includes/images/icon-library/site-logo.svg', + 'wp-includes/images/icon-library/square.svg', + 'wp-includes/images/icon-library/stack.svg', + 'wp-includes/images/icon-library/stretch-full-width.svg', + 'wp-includes/images/icon-library/stretch-wide.svg', + 'wp-includes/images/icon-library/subscript.svg', + 'wp-includes/images/icon-library/superscript.svg', + 'wp-includes/images/icon-library/swatch.svg', + 'wp-includes/images/icon-library/tab.svg', + 'wp-includes/images/icon-library/table-column-after.svg', + 'wp-includes/images/icon-library/table-column-before.svg', + 'wp-includes/images/icon-library/table-column-delete.svg', + 'wp-includes/images/icon-library/table-of-contents.svg', + 'wp-includes/images/icon-library/table-row-after.svg', + 'wp-includes/images/icon-library/table-row-before.svg', + 'wp-includes/images/icon-library/table-row-delete.svg', + 'wp-includes/images/icon-library/tabs-menu-item.svg', + 'wp-includes/images/icon-library/tabs-menu.svg', + 'wp-includes/images/icon-library/tabs.svg', + 'wp-includes/images/icon-library/term-count.svg', + 'wp-includes/images/icon-library/term-description.svg', + 'wp-includes/images/icon-library/term-name.svg', + 'wp-includes/images/icon-library/text-color.svg', + 'wp-includes/images/icon-library/text-horizontal.svg', + 'wp-includes/images/icon-library/text-vertical.svg', + 'wp-includes/images/icon-library/thumbs-down.svg', + 'wp-includes/images/icon-library/thumbs-up.svg', + 'wp-includes/images/icon-library/time-to-read.svg', + 'wp-includes/images/icon-library/title.svg', + 'wp-includes/images/icon-library/tool.svg', + 'wp-includes/images/icon-library/trash.svg', + 'wp-includes/images/icon-library/trending-down.svg', + 'wp-includes/images/icon-library/trending-up.svg', + 'wp-includes/images/icon-library/typography.svg', + 'wp-includes/images/icon-library/undo.svg', + 'wp-includes/images/icon-library/ungroup.svg', + 'wp-includes/images/icon-library/unlock.svg', + 'wp-includes/images/icon-library/unseen.svg', + 'wp-includes/images/icon-library/update.svg', + 'wp-includes/images/icon-library/video.svg', + 'wp-includes/images/icon-library/widget.svg', + 'wp-includes/images/icon-library/word-count.svg', + 'wp-includes/images/icon-library/wordpress.svg', /* * Added back in 7.1. * From 2d97c2ee6986c3c6e36d540f5b39fef276c51990 Mon Sep 17 00:00:00 2001 From: Jonathan Desrosiers Date: Wed, 5 Aug 2026 14:27:59 +0000 Subject: [PATCH 136/138] Upgrade/Install: Correct `$_old_files` ordering for accuracy. The `wp-includes/js/dist/sync.js` and `wp-includes/js/dist/sync.min.js` files were removed in 7.0.2 and added to the `$_old_files` list (see [62778]), but they are present again in `trunk`. [62783] marked these files as reintroduced, but this comment should be moved above the file list added for 7.1. Follow up to [62777], [62783], [63031]. See #65813, #65325. git-svn-id: https://develop.svn.wordpress.org/trunk@63032 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-admin/includes/update-core.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/wp-admin/includes/update-core.php b/src/wp-admin/includes/update-core.php index ce3eb82bc9e71..664fec95298c6 100644 --- a/src/wp-admin/includes/update-core.php +++ b/src/wp-admin/includes/update-core.php @@ -900,6 +900,12 @@ // 7.0.2 'wp-includes/collaboration', 'wp-includes/collaboration.php', + /* + * Restored in WordPress 7.1. + * + * 'wp-includes/js/dist/sync.js', + * 'wp-includes/js/dist/sync.min.js', + */ // 7.1 'wp-includes/images/icon-library/accordion-heading.svg', 'wp-includes/images/icon-library/accordion-item.svg', @@ -1144,12 +1150,6 @@ 'wp-includes/images/icon-library/widget.svg', 'wp-includes/images/icon-library/word-count.svg', 'wp-includes/images/icon-library/wordpress.svg', - /* - * Added back in 7.1. - * - * 'wp-includes/js/dist/sync.js', - * 'wp-includes/js/dist/sync.min.js', - */ ); /** From d5b458991216f79f45a78f075badee6f6aaf7443 Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 5 Aug 2026 15:10:21 +0000 Subject: [PATCH 137/138] WordPress 7.1 RC 1. git-svn-id: https://develop.svn.wordpress.org/trunk@63033 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php index 121a44ba90167..c4720b37f947c 100644 --- a/src/wp-includes/version.php +++ b/src/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '7.1-beta4-62899-src'; +$wp_version = '7.1-RC1-src'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema. From 7b887ba4820e0ee87bbf3f14a0e8385b33f1a6fd Mon Sep 17 00:00:00 2001 From: Aki Hamano Date: Wed, 5 Aug 2026 15:32:55 +0000 Subject: [PATCH 138/138] Post WordPress 7.1 RC 1 version bump. git-svn-id: https://develop.svn.wordpress.org/trunk@63034 602fd350-edb4-49c9-b593-d223f7449a82 --- src/wp-includes/version.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wp-includes/version.php b/src/wp-includes/version.php index c4720b37f947c..985bfaf0bf868 100644 --- a/src/wp-includes/version.php +++ b/src/wp-includes/version.php @@ -16,7 +16,7 @@ * * @global string $wp_version */ -$wp_version = '7.1-RC1-src'; +$wp_version = '7.1-RC1-63034-src'; /** * Holds the WordPress DB revision, increments when changes are made to the WordPress DB schema.