diff --git a/src/css/manage.scss b/src/css/manage.scss index f3a4a373..173c5596 100644 --- a/src/css/manage.scss +++ b/src/css/manage.scss @@ -137,6 +137,26 @@ #wpbody-content & .column-name { white-space: nowrap; /* prevents wrapping of snippet title */ } + + td.column-date, th.column-date { + white-space: nowrap; + inline-size: 130px; /* fixed column width */ + min-inline-size: 130px; + max-inline-size: 130px; + text-align: right; + padding-inline-start: 8px; + padding-inline-end: 8px; + overflow: hidden; + text-overflow: ellipsis; + } + + /* Ensure the name column can shrink/ellipsis instead of pushing the date. */ + td.column-name, th.column-name { + max-inline-size: calc(100% - 140px); + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } } td.column-description { diff --git a/src/php/admin-menus/class-import-menu.php b/src/php/admin-menus/class-import-menu.php index 3c3b2565..5c018342 100644 --- a/src/php/admin-menus/class-import-menu.php +++ b/src/php/admin-menus/class-import-menu.php @@ -128,30 +128,36 @@ protected function print_messages() { echo '

'; } - if ( isset( $_REQUEST['imported'] ) ) { - echo '

'; - - $imported = intval( $_REQUEST['imported'] ); - - if ( 0 === $imported ) { - esc_html_e( 'No snippets were imported.', 'code-snippets' ); - - } else { - /* translators: %d: amount of snippets imported */ - printf( - _n( - 'Successfully imported %d snippet.', - 'Successfully imported %d snippets.', - $imported, - 'code-snippets' - ), - '' . number_format_i18n( $imported ) . '', - ); - - printf( - ' %s', - esc_url( code_snippets()->get_menu_url( 'manage' ) ), - esc_html__( 'Have fun!', 'code-snippets' ) + if ( isset( $_REQUEST['imported'] ) ) { + echo '

'; + + $imported = intval( $_REQUEST['imported'] ); + + if ( 0 === $imported ) { + esc_html_e( 'No snippets were imported.', 'code-snippets' ); + + } else { + $imported_count = sprintf( '%s', esc_html( number_format_i18n( $imported ) ) ); + printf( + '%s', + wp_kses_post( + sprintf( + /* translators: %s: number of snippets imported. */ + _n( + 'Successfully imported %s snippet.', + 'Successfully imported %s snippets.', + $imported, + 'code-snippets' + ), + $imported_count + ) + ) + ); + + printf( + ' %s', + esc_url( code_snippets()->get_menu_url( 'manage' ) ), + esc_html__( 'Have fun!', 'code-snippets' ) ); } diff --git a/src/php/class-list-table.php b/src/php/class-list-table.php index 41ed1379..bdae02de 100644 --- a/src/php/class-list-table.php +++ b/src/php/class-list-table.php @@ -618,17 +618,21 @@ public function get_views(): array { continue 2; } - $shared_label_template = $this->is_network - ? _n_noop( + if ( $this->is_network ) { + /* translators: %s: total number of snippets shared with subsites. */ + $shared_label_template = _n_noop( 'Shared with Subsites (%s)', 'Shared with Subsites (%s)', 'code-snippets' - ) - : _n_noop( + ); + } else { + /* translators: %s: total number of network snippets. */ + $shared_label_template = _n_noop( 'Network Snippets (%s)', 'Network Snippets (%s)', 'code-snippets' ); + } $template = translate_nooped_plural( $shared_label_template, $count, 'code-snippets' ); break; @@ -663,16 +667,16 @@ public function get_views(): array { * @since 2.0 */ public function get_current_tags() { - global $snippets, $status; + global $code_snippets_snippets, $status; // If we're not viewing a snippets table, get all used tags instead. - if ( ! isset( $snippets, $status ) ) { + if ( ! isset( $code_snippets_snippets, $status ) ) { $tags = get_all_snippet_tags(); } else { $tags = array(); // Merge all tags into a single array. - foreach ( $snippets[ $status ] as $snippet ) { + foreach ( $code_snippets_snippets[ $status ] as $snippet ) { $tags = array_merge( $snippet->tags, $tags ); } @@ -1088,12 +1092,12 @@ public function prepare_items() { /** * Global variables. * - * @var string $status Current status view. - * @var array $snippets List of snippets for views. - * @var array $totals List of total items for views. - * @var string $s Current search term. + * @var string $status Current status view. + * @var array $code_snippets_snippets List of snippets for views. + * @var array $totals List of total items for views. + * @var string $s Current search term. */ - global $status, $snippets, $totals, $s; + global $status, $code_snippets_snippets, $totals, $s; wp_reset_vars( array( 'orderby', 'order', 's' ) ); @@ -1107,21 +1111,21 @@ public function prepare_items() { } $this->process_requested_actions(); - $snippets = array_fill_keys( $this->statuses, array() ); + $code_snippets_snippets = array_fill_keys( $this->statuses, array() ); $all_snippets = apply_filters( 'code_snippets/list_table/get_snippets', $this->fetch_shared_network_snippets( get_snippets() ) ); // Separate trashed snippets from the main collection - $snippets['trashed'] = array_filter( $all_snippets, function( $snippet ) { + $code_snippets_snippets['trashed'] = array_filter( $all_snippets, function( $snippet ) { return $snippet->is_trashed(); }); // Filter out trashed snippets from the 'all' collection - $snippets['all'] = array_filter( $all_snippets, function( $snippet ) { + $code_snippets_snippets['all'] = array_filter( $all_snippets, function( $snippet ) { return ! $snippet->is_trashed(); }); - foreach ( $snippets['all'] as $snippet ) { + foreach ( $code_snippets_snippets['all'] as $snippet ) { if ( $snippet->active ) { $this->active_by_condition[ $snippet->condition_id ][] = $snippet; } @@ -1131,16 +1135,16 @@ public function prepare_items() { $type = sanitize_key( wp_unslash( $_GET['type'] ?? '' ) ); if ( $type && 'all' !== $type ) { - $snippets['all'] = array_filter( - $snippets['all'], + $code_snippets_snippets['all'] = array_filter( + $code_snippets_snippets['all'], function ( Snippet $snippet ) use ( $type ) { return $type === $snippet->type; } ); // Filter trashed snippets by type - $snippets['trashed'] = array_filter( - $snippets['trashed'], + $code_snippets_snippets['trashed'] = array_filter( + $code_snippets_snippets['trashed'], function ( Snippet $snippet ) use ( $type ) { return $type === $snippet->type; } @@ -1148,13 +1152,13 @@ function ( Snippet $snippet ) use ( $type ) { } // Add scope tags to all snippets (including trashed). - foreach ( $snippets['all'] as $snippet ) { + foreach ( $code_snippets_snippets['all'] as $snippet ) { if ( 'global' !== $snippet->scope ) { $snippet->add_tag( $snippet->scope ); } } - foreach ( $snippets['trashed'] as $snippet ) { + foreach ( $code_snippets_snippets['trashed'] as $snippet ) { if ( 'global' !== $snippet->scope ) { $snippet->add_tag( $snippet->scope ); } @@ -1162,27 +1166,27 @@ function ( Snippet $snippet ) use ( $type ) { // Filter snippets by tag. if ( ! empty( $_GET['tag'] ) ) { - $snippets['all'] = array_filter( $snippets['all'], array( $this, 'tags_filter_callback' ) ); - $snippets['trashed'] = array_filter( $snippets['trashed'], array( $this, 'tags_filter_callback' ) ); + $code_snippets_snippets['all'] = array_filter( $code_snippets_snippets['all'], array( $this, 'tags_filter_callback' ) ); + $code_snippets_snippets['trashed'] = array_filter( $code_snippets_snippets['trashed'], array( $this, 'tags_filter_callback' ) ); } // Filter snippets based on search query. if ( $s ) { - $snippets['all'] = array_filter( $snippets['all'], array( $this, 'search_by_line_callback' ) ); - $snippets['trashed'] = array_filter( $snippets['trashed'], array( $this, 'search_by_line_callback' ) ); + $code_snippets_snippets['all'] = array_filter( $code_snippets_snippets['all'], array( $this, 'search_by_line_callback' ) ); + $code_snippets_snippets['trashed'] = array_filter( $code_snippets_snippets['trashed'], array( $this, 'search_by_line_callback' ) ); } if ( is_multisite() ) { - $snippets['shared_network'] = array_values( + $code_snippets_snippets['shared_network'] = array_values( array_filter( - $snippets['all'], + $code_snippets_snippets['all'], static function ( Snippet $snippet ) { return $snippet->shared_network; } ) ); } else { - $snippets['shared_network'] = array(); + $code_snippets_snippets['shared_network'] = array(); } // Clear recently activated snippets older than a week. @@ -1205,20 +1209,20 @@ static function ( Snippet $snippet ) { * * @var Snippet $snippet */ - foreach ( $snippets['all'] as $snippet ) { + foreach ( $code_snippets_snippets['all'] as $snippet ) { // Skip trashed snippets (they're already in their own section) if ( $snippet->is_trashed() ) { continue; } if ( $snippet->active || $this->is_condition_active( $snippet ) ) { - $snippets['active'][] = $snippet; + $code_snippets_snippets['active'][] = $snippet; } else { - $snippets['inactive'][] = $snippet; + $code_snippets_snippets['inactive'][] = $snippet; // Was the snippet recently deactivated? if ( isset( $recently_activated[ $snippet->id ] ) ) { - $snippets['recently_activated'][] = $snippet; + $code_snippets_snippets['recently_activated'][] = $snippet; } } } @@ -1228,16 +1232,16 @@ static function ( Snippet $snippet ) { function ( $section_snippets ) { return count( $section_snippets ); }, - $snippets + $code_snippets_snippets ); // If the current status is empty, default to all. - if ( empty( $snippets[ $status ] ) ) { + if ( empty( $code_snippets_snippets[ $status ] ) ) { $status = 'all'; } // Get the current data. - $data = $snippets[ $status ]; + $data = $code_snippets_snippets[ $status ]; // Decide how many records per page to show by getting the user's setting in the Screen Options panel. $sort_by = $this->screen->get_option( 'per_page', 'option' ); diff --git a/src/php/cloud/class-cloud-search-list-table.php b/src/php/cloud/class-cloud-search-list-table.php index af1051c7..db8040f0 100644 --- a/src/php/cloud/class-cloud-search-list-table.php +++ b/src/php/cloud/class-cloud-search-list-table.php @@ -173,11 +173,11 @@ public function display_rows() { echo ''; ?> - -

-
+ + +

process_description( $item->description ) ); ?>

diff --git a/src/php/front-end/mce-strings.php b/src/php/front-end/mce-strings.php index 58ceef03..6395637f 100644 --- a/src/php/front-end/mce-strings.php +++ b/src/php/front-end/mce-strings.php @@ -9,6 +9,7 @@ use _WP_Editors; +/* phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound */ /** * Variable types. * @@ -53,3 +54,4 @@ $strings = [ _WP_Editors::$mce_locale => [ 'code_snippets' => $strings ] ]; /** $strings is used by outer file. @noinspection PhpUnusedLocalVariableInspection */ $strings = 'tinyMCE.addI18n(' . wp_json_encode( $strings ) . ');'; +/* phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound */ diff --git a/src/php/load.php b/src/php/load.php index de46e383..a3b37470 100644 --- a/src/php/load.php +++ b/src/php/load.php @@ -50,15 +50,15 @@ // Since Imposter rewrites namespaces to Code_Snippets\Vendor\*, we need to remove the original PSR-4 // mappings that Composer generates so other plugins can load their own copies of these libraries. if ( $code_snippets_autoloader instanceof \Composer\Autoload\ClassLoader ) { - $prefixes = $code_snippets_autoloader->getPrefixesPsr4(); - $our_prefix = 'Code_Snippets\\Vendor\\'; + $code_snippets_prefixes = $code_snippets_autoloader->getPrefixesPsr4(); + $code_snippets_vendor_prefix = 'Code_Snippets\\Vendor\\'; - foreach ( $prefixes as $namespace => $paths ) { + foreach ( $code_snippets_prefixes as $code_snippets_namespace => $code_snippets_paths ) { // Remove any non-Code_Snippets namespace that has a corresponding prefixed version - if ( strpos( $namespace, $our_prefix ) === false ) { - $prefixed_namespace = $our_prefix . $namespace; - if ( isset( $prefixes[ $prefixed_namespace ] ) ) { - $code_snippets_autoloader->setPsr4( $namespace, [] ); + if ( strpos( $code_snippets_namespace, $code_snippets_vendor_prefix ) === false ) { + $code_snippets_prefixed_namespace = $code_snippets_vendor_prefix . $code_snippets_namespace; + if ( isset( $code_snippets_prefixes[ $code_snippets_prefixed_namespace ] ) ) { + $code_snippets_autoloader->setPsr4( $code_snippets_namespace, [] ); } } } diff --git a/src/php/settings/class-version-switch.php b/src/php/settings/class-version-switch.php index b2486e1c..c1ef11e7 100644 --- a/src/php/settings/class-version-switch.php +++ b/src/php/settings/class-version-switch.php @@ -230,17 +230,18 @@ public static function handle_version_switch( string $target_version ): array { return self::create_error_response( $install_result->get_error_message() ); } - if ( $install_result ) { - delete_transient( VERSION_CACHE_KEY ); + if ( $install_result ) { + delete_transient( VERSION_CACHE_KEY ); - return [ - 'success' => true, - 'message' => sprintf( __( 'Successfully switched to version %s. Please refresh the page to see changes.', 'code-snippets' ), $target_version ), - ]; - } + return [ + 'success' => true, + /* translators: %s: the version number that was switched to. */ + 'message' => sprintf( __( 'Successfully switched to version %s. Please refresh the page to see changes.', 'code-snippets' ), $target_version ), + ]; + } - return self::handle_installation_failure( $target_version, $validation['download_url'], $install_result ); - } + return self::handle_installation_failure( $target_version, $validation['download_url'], $install_result ); + } public static function render_version_switch_field( array $args ): void { $current_version = self::get_current_version(); @@ -291,7 +292,7 @@ public static function render_version_switch_field( array $args ): void { public static function ajax_switch_version(): void { if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'code_snippets_version_switch' ) ) { - wp_die( __( 'Security check failed.', 'code-snippets' ) ); + wp_die( esc_html__( 'Security check failed.', 'code-snippets' ) ); } if ( ! current_user_can( 'update_plugins' ) ) { @@ -329,7 +330,7 @@ public static function render_refresh_versions_field( array $args ): void { public static function ajax_refresh_versions(): void { if ( ! wp_verify_nonce( $_POST['nonce'] ?? '', 'code_snippets_refresh_versions' ) ) { - wp_die( __( 'Security check failed.', 'code-snippets' ) ); + wp_die( esc_html__( 'Security check failed.', 'code-snippets' ) ); } if ( ! current_user_can( 'manage_options' ) ) { diff --git a/src/php/views/import.php b/src/php/views/import.php index 902d4409..f4548ea7 100644 --- a/src/php/views/import.php +++ b/src/php/views/import.php @@ -18,7 +18,8 @@ return; } -$max_size_bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() ); +// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Core hook name expected by WordPress importers. +$code_snippets_max_size_bytes = apply_filters( 'import_upload_size_limit', wp_max_upload_size() ); ?>

@@ -40,18 +41,18 @@

-

- All Snippets page to activate the imported snippets.', 'code-snippets' ); - $url = esc_url( code_snippets()->get_menu_url( 'manage' ) ); - - echo wp_kses( - sprintf( $text, $url ), - array( - 'a' => array( - 'href' => array(), - 'target' => array(), +

+ All Snippets page to activate the imported snippets.', 'code-snippets' ); + $code_snippets_manage_url = esc_url( code_snippets()->get_menu_url( 'manage' ) ); + + echo wp_kses( + sprintf( $code_snippets_import_notice, $code_snippets_manage_url ), + array( + 'a' => array( + 'href' => array(), + 'target' => array(), ), ) ); @@ -98,17 +99,17 @@

-

- - - - - -

-
+

+ + + + + +

+ __( 'All Snippets', 'code-snippets' ) ], Plugin::get_types() ); -$current_type = $this->get_current_type(); +$code_snippets_types = array_merge( [ 'all' => __( 'All Snippets', 'code-snippets' ) ], Plugin::get_types() ); +$code_snippets_current_type = $this->get_current_type(); if ( false !== strpos( code_snippets()->version, 'beta' ) ) { echo '

'; @@ -54,9 +54,9 @@ print_messages(); ?>

diff --git a/src/php/views/partials/cloud-search.php b/src/php/views/partials/cloud-search.php index 078399ed..9674e890 100644 --- a/src/php/views/partials/cloud-search.php +++ b/src/php/views/partials/cloud-search.php @@ -14,8 +14,8 @@ * @var Manage_Menu $this */ -$search_query = isset( $_REQUEST['cloud_search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['cloud_search'] ) ) : ''; -$cloud_select = sanitize_key( wp_unslash( $_REQUEST['cloud_select'] ?? '' ) ); +$code_snippets_search_query = isset( $_REQUEST['cloud_search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['cloud_search'] ) ) : ''; +$code_snippets_cloud_select = sanitize_key( wp_unslash( $_REQUEST['cloud_select'] ?? '' ) ); ?> @@ -30,32 +30,32 @@
- ', esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['type'] ) ) ) ); + + + ', esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['type'] ) ) ) ); } ?>

-
-
- - +
+
+ + - @@ -68,7 +68,7 @@ cloud_search_list_table->display(); } diff --git a/src/php/views/partials/list-table-notices.php b/src/php/views/partials/list-table-notices.php index c3d34561..56becfc7 100644 --- a/src/php/views/partials/list-table-notices.php +++ b/src/php/views/partials/list-table-notices.php @@ -21,14 +21,14 @@ */ if ( defined( 'CODE_SNIPPETS_SAFE_MODE' ) && CODE_SNIPPETS_SAFE_MODE ) { ?> -
-

- - CODE_SNIPPETS_SAFE_MODE', 'wp-config.php' ); - ?> +

+

+ + CODE_SNIPPETS_SAFE_MODE', 'wp-config.php' ); + ?> @@ -42,9 +42,9 @@ return; } -$result = sanitize_key( $_REQUEST['result'] ); +$code_snippets_result = sanitize_key( $_REQUEST['result'] ); -$result_messages = [ +$code_snippets_result_messages = [ 'executed' => __( 'Snippet executed.', 'code-snippets' ), 'activated' => __( 'Snippet activated.', 'code-snippets' ), 'activated-multi' => __( 'Selected snippets activated.', 'code-snippets' ), @@ -62,43 +62,45 @@ ]; // Add undo link for single snippet trash action -if ( 'deleted' === $result && ! empty( $_REQUEST['ids'] ) ) { - $deleted_ids = sanitize_text_field( $_REQUEST['ids'] ); - $undo_url = wp_nonce_url( +if ( 'deleted' === $code_snippets_result && ! empty( $_REQUEST['ids'] ) ) { + $code_snippets_deleted_ids = sanitize_text_field( $_REQUEST['ids'] ); + $code_snippets_undo_url = wp_nonce_url( add_query_arg( array( 'action' => 'restore', - 'ids' => $deleted_ids + 'ids' => $code_snippets_deleted_ids ) ), 'bulk-snippets' ); - $result_messages['deleted'] = sprintf( + $code_snippets_result_messages['deleted'] = sprintf( + /* translators: %s: URL to undo snippet deletion. */ __( 'Snippet trashed. Undo', 'code-snippets' ), - esc_url( $undo_url ) + esc_url( $code_snippets_undo_url ) ); } // Add undo link for bulk snippet trash action -if ( 'deleted-multi' === $result && ! empty( $_REQUEST['ids'] ) ) { - $deleted_ids = sanitize_text_field( $_REQUEST['ids'] ); - $undo_url = wp_nonce_url( +if ( 'deleted-multi' === $code_snippets_result && ! empty( $_REQUEST['ids'] ) ) { + $code_snippets_deleted_ids = sanitize_text_field( $_REQUEST['ids'] ); + $code_snippets_undo_url = wp_nonce_url( add_query_arg( array( 'action' => 'restore', - 'ids' => $deleted_ids + 'ids' => $code_snippets_deleted_ids ) ), 'bulk-snippets' ); - $result_messages['deleted-multi'] = sprintf( + $code_snippets_result_messages['deleted-multi'] = sprintf( + /* translators: %s: URL to undo snippet deletion. */ __( 'Selected snippets trashed. Undo', 'code-snippets' ), - esc_url( $undo_url ) + esc_url( $code_snippets_undo_url ) ); } -$result_messages = apply_filters( 'code_snippets/manage/result_messages', $result_messages ); +$code_snippets_result_messages = apply_filters( 'code_snippets/manage/result_messages', $code_snippets_result_messages ); -if ( isset( $result_messages[ $result ] ) ) { - $result_kses = [ +if ( isset( $code_snippets_result_messages[ $code_snippets_result ] ) ) { + $code_snippets_result_kses = [ 'strong' => [], 'a' => [ 'href' => [], @@ -107,6 +109,6 @@ printf( '

%s

', - wp_kses( $result_messages[ $result ], $result_kses ) + wp_kses( $code_snippets_result_messages[ $code_snippets_result ], $code_snippets_result_kses ) ); } diff --git a/src/php/views/welcome.php b/src/php/views/welcome.php index 05316134..e72014e0 100644 --- a/src/php/views/welcome.php +++ b/src/php/views/welcome.php @@ -18,9 +18,9 @@ return; } -$hero = $this->api->get_hero_item(); +$code_snippets_hero = $this->api->get_hero_item(); -$changelog_sections = [ +$code_snippets_changelog_sections = [ 'Added' => [ 'title' => __( 'New features', 'code-snippets' ), 'icon' => 'lightbulb', @@ -39,7 +39,7 @@ ], ]; -$plugin_types = [ +$code_snippets_plugin_types = [ 'core' => __( 'Core', 'code-snippets' ), 'pro' => __( 'Pro', 'code-snippets' ), ]; @@ -78,50 +78,50 @@ class="csp-link-">
-
-

📰

-
- -
- -

-
-
-
- <?php esc_attr_e( 'Latest news image', 'code-snippets' ); ?>); -
-
+
+

📰

+
+ +
+ +

+
+
+
+ <?php esc_attr_e( 'Latest news image', 'code-snippets' ); ?>); +
+
-
- -

-
-
- api->get_changelog() as $version => $version_changes ) { ?> -

-
- $section ) { - if ( empty( $version_changes[ $section_key ] ) ) { - continue; - } - ?> -

- - -

-
    - $type_label ) { - if ( empty( $version_changes[ $section_key ][ $plugin_type ] ) ) { - continue; - } +
    + +

    +
    +
    + api->get_changelog() as $version => $version_changes ) { ?> +

    +
    + $section ) { + if ( empty( $version_changes[ $section_key ] ) ) { + continue; + } + ?> +

    + + +

    +
      + $type_label ) { + if ( empty( $version_changes[ $section_key ][ $plugin_type ] ) ) { + continue; + } foreach ( $version_changes[ $section_key ][ $plugin_type ] as $change ) { ?> diff --git a/tests/e2e/auth.setup.ts b/tests/e2e/auth.setup.ts index 59a5c39c..63d56d1b 100644 --- a/tests/e2e/auth.setup.ts +++ b/tests/e2e/auth.setup.ts @@ -12,8 +12,25 @@ setup('authenticate', async ({ page }) => { await page.click('#wp-submit') - await page.waitForURL(/wp-admin/) - await page.waitForSelector('#wpbody-content, #adminmenu') + // If WordPress shows the DB upgrade interstitial it includes a link to + // `upgrade.php`. In that case navigate back to `/wp-admin` (the upgrade + // process is handled by the environment) and then wait for the admin UI. + const upgradeLink = page.locator('a[href*="upgrade.php"]') + if (0 < await upgradeLink.count()) { + // Click the upgrade link to reach the upgrade interstitial page. + await upgradeLink.first().click() + + // If the interstitial shows an "Update WordPress Database" action, click it. + const updateBtn = page.locator('a:has-text("Update WordPress Database")') + if (0 < await updateBtn.count()) { + await updateBtn.first().click() + } + // Give the upgrade process more time to complete and the admin UI to load. + await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: 120000 }) + } else { + // Normal path: wait for admin UI. + await page.waitForSelector('#wpbody-content, #adminmenu', { timeout: 60000 }) + } await expect(page.locator('#adminmenu')).toBeVisible() diff --git a/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-active-darwin.png b/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-active-darwin.png new file mode 100644 index 00000000..ac04337d Binary files /dev/null and b/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-active-darwin.png differ diff --git a/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-inactive-darwin.png b/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-inactive-darwin.png new file mode 100644 index 00000000..18de391b Binary files /dev/null and b/tests/e2e/code-snippets-list.spec.ts-snapshots/snippet-row-inactive-darwin.png differ