Skip to content

Themes: Restore dynamic tabs in the Add Themes screen via install_themes_tabs - #15866

Open
robelsust wants to merge 2 commits into
WordPress:trunkfrom
robelsust:fix/65979-install-themes-tabs
Open

robelsust wants to merge 2 commits into
WordPress:trunkfrom
robelsust:fix/65979-install-themes-tabs

Conversation

@robelsust

Copy link
Copy Markdown

Trac ticket: https://core.trac.wordpress.org/ticket/65979

Description

Restores the install_themes_tabs filter in wp-admin/theme-install.php to allow registering, reordering, and filtering tabs in the Backbone-based theme installer, matching parity with install_plugins_tabs on the Add Plugins screen.

Background & Architecture

  • Prior to WordPress 3.8/3.9, the Add Themes screen was rendered via WP_Theme_Install_List_Table, which used the install_themes_tabs filter (introduced in 2.8.0).
  • When theme-install.php transitioned to a Backbone.js single-page application, the filter links (<ul class="filter-links">) were hardcoded to 'popular', 'new', 'block-themes', and 'favorites'. The DocBlock for install_themes_tabs was demoted to "for backward compatibility only, for the suppression of the upload tab".
  • Consequently, hosts, managed platforms, and custom repository plugins were forced into fragile DOM manipulation (jQuery('.filter-links').append(...)) to add custom tabs.
  • The server-side AJAX query infrastructure in wp-admin/includes/ajax-actions.php (wp_ajax_query_themes()) is already fully dynamic: any browse key automatically applies install_themes_table_api_args_{$browse} and passes $args directly to themes_api( 'query_themes', $args ).

Changes Made

  1. wp-admin/theme-install.php:

    • Defines the core tabs (popular, new, block-themes, favorites, and conditionally upload when the user has upload_themes capability) and runs apply_filters( 'install_themes_tabs', $tabs ) before wp_localize_script().
    • Computes $browse_tabs = array_diff_key( $tabs, array( 'upload' => true ) ); and derives $default_tab = ! empty( $browse_tabs ) ? (string) array_key_first( $browse_tabs ) : 'popular';.
    • Passes $default_tab to _wpThemeSettings.settings.defaultTab.
    • Renders the <ul class="filter-links"> list dynamically from $browse_tabs.
    • Preserves upload tab suppression via ! empty( $tabs['upload'] ) && current_user_can( 'upload_themes' ).
    • Parses both $_REQUEST['browse'] and $_REQUEST['tab'] for $tab.
  2. src/js/_enqueues/wp/theme.js:

    • Updates InstallerRouter and RunInstaller.init() to route to _wpThemeSettings.settings.defaultTab || 'popular' when visiting the base URL without query parameters.
    • Adds route 'theme-install.php?tab=:sort': 'sort' to support legacy ?tab= URLs alongside ?browse=.
    • Wraps the sort tab selector in $.escapeSelector( sort ) to safely handle custom tab keys with special characters.
  3. tests/phpunit/tests/theme/installThemesTabs.php:

    • Adds dedicated unit tests covering:
      • Default tabs for users with upload_themes capability.
      • Default tabs for users without upload_themes capability.
      • Registering custom tabs via install_themes_tabs.
      • Suppressing the upload tab via unset( $tabs['upload'] ).
      • Reordering tabs / changing the default active tab.
      • Fallback when browse tabs are empty.

Testing Instructions

  1. Run PHPUnit tests:
    vendor/bin/phpunit tests/phpunit/tests/theme/installThemesTabs.php
  2. In a test plugin or functions.php, add a custom tab:
    add_filter( 'install_themes_tabs', function( $tabs ) {
        $tabs['featured'] = 'Featured';
        return $tabs;
    } );
  3. Visit wp-admin/theme-install.php.
  4. Verify the "Featured" tab appears in the navigation links and clicking it navigates to ?browse=featured without errors.
  5. Filter args via install_themes_table_api_args_featured or themes_api and verify themes render correctly.

…emes_tabs`.

Re-enables the `install_themes_tabs` filter on `wp-admin/theme-install.php` to allow registering and filtering browse tabs in the Backbone-based theme installer, matching parity with `install_plugins_tabs`. Passes the default active tab to `_wpThemeSettings` for seamless Backbone routing, escapes the tab selector attribute, and adds support for legacy `?tab=:sort` URLs.

Props therssoftware, pbiron, audrasjb.
See #65979.
@github-actions

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs.

Core Committers: Use this line as a base for the props when committing in SVN:

Props therssoftware.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.


Props Bot commands

You can trigger Props Bot actions by commenting on this PR:

  • @propsbot add <username> to give props to a GitHub user. Requires write access.
  • @propsbot remove <username> to leave a user out of the props. Requires write access.
  • @propsbot refresh to refresh this list. Adding the props-bot label works too.

@github-actions

Copy link
Copy Markdown

Test using WordPress Playground

The changes in this pull request can previewed and tested using a WordPress Playground instance.

WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Some things to be aware of

  • All changes will be lost when closing a tab with a Playground instance.
  • All changes will be lost when refreshing the page.
  • A fresh instance is created each time the link below is clicked.
  • Every time this pull request is updated, a new ZIP file containing all changes is created. If changes are not reflected in the Playground instance,
    it's possible that the most recent build failed, or has not completed. Check the list of workflow runs to be sure.

For more details about these limitations and more, check out the Limitations page in the WordPress Playground documentation.

Test this pull request with WordPress Playground.

…est capabilities.

- Add missing <?php opening tag before upload button condition in src/wp-admin/theme-install.php, preventing plain-text code leak and fixing E2E theme upload tests.
- Grant super admin capabilities to the test admin user in multisite environments in tests/phpunit/tests/theme/installThemesTabs.php, resolving multisite test failures.

See #65979.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant