Skip to content

Taxonomy: Add 's' as an alias of 'search' in WP_Term_Query - #11696

Open
wppoland wants to merge 3 commits into
WordPress:trunkfrom
wppoland:trac/51811
Open

wppoland wants to merge 3 commits into
WordPress:trunkfrom
wppoland:trac/51811

Conversation

@wppoland

@wppoland wppoland commented May 3, 2026 •

Copy link
Copy Markdown

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

WP_Query uses s as its canonical search parameter. To match this convention, this PR adds s to WP_Term_Query as a shorthand alias for search.

This PR registers s as a recognized argument and copies it onto search when search is not explicitly set, preserving precedence for the long form. It also re-resolves s after get_terms_args to support callbacks modifying $query->query_vars['s'] in pre_get_terms, and normalizes generate_cache_key() so equivalent queries share cache entries.

Tests cover:

  • s returns the same matches as search
  • search takes precedence when both are provided
  • s returns empty for non-matching input against populated taxonomies
  • s can be modified in pre_get_terms callbacks
  • s and search produce identical cache keys

Use of AI Tools

AI assistance: Yes
Tool(s): Antigravity IDE
Model(s): Gemini 2.5 Pro
Used for: Code analysis, conflict resolution, test suite updates, and patch verification. All changes were manually reviewed and tested locally.


This Pull Request is for code review only. Please keep all other discussion in the Trac ticket. Do not merge this Pull Request. See GitHub Pull Requests for Code Review in the Core Handbook for more details.

@github-actions

github-actions Bot commented May 3, 2026 •

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. You can also manually ask me to refresh this list by adding the props-bot label.

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

Props motylanogha, mukesh27, westonruter.

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

@github-actions

github-actions Bot commented May 3, 2026

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.

'term_taxonomy_id' => '',
'hierarchical' => true,
'search' => '',
's' => '',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add @since for new variable.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 99ea3e2: added @since 7.1.0 Introduced the 's' parameter as an alias of 'search'. to the constructor docblock, plus the @type string $s entry in the parameter list. Apologies for the delayed reply, the fix has been on the branch since May 10 but I never pinged the thread.

Comment on lines +1212 to +1213
* @ticket 51811
* @covers WP_Term_Query::parse_query

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @ticket 51811
* @covers WP_Term_Query::parse_query
* @ticket 51811
*
* @covers WP_Term_Query::parse_query

Update other tests as well

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in 99ea3e2: all three new tests now use the suggested format (@ticket 51811, blank line, @covers WP_Term_Query::parse_query). Ready for another look.

wppoland added a commit to wppoland/wordpress-develop that referenced this pull request May 10, 2026
Adds the `@since 7.1.0` line for the new `'s'` query var on `WP_Term_Query::__construct()`, and inserts a blank line between `@ticket` and `@covers` in the new test docblocks to match the file's existing convention (e.g. `test_query_cache`).

Follow-up to [WordPressGH-11696].
See #51811.
@wppoland

Copy link
Copy Markdown
Author

Rebased onto current trunk in 15c0dac. The branch had gone CONFLICTING.

The conflict was purely additive and in the test file only: trunk gained test_id_and_parent_fields_should_return_parent_ids_keyed_by_term_id() for #65817 at the same end-of-file position as the three tests here. Both sets are kept, neither was modified.

Verified after the rebase, PHP 8.3, single site:

  • tests/phpunit/tests/term/query.php: OK (46 tests, 112 assertions), which includes trunk's new id=>parent test alongside the three for this ticket.
  • phpcs on src/wp-includes/class-wp-term-query.php and the test file: 0 errors, 0 warnings.

Full CI is green: 153 check runs, 0 failures.

Also worth recording here that @Logicrays filed an independent reproduction on the ticket (comment:9) against 7.1-alpha-62606 on PHP 8.2: search returned 1 term, s returned all of them. That is the behaviour this PR fixes and it matches test_s_param_is_alias_for_search().

@westonruter westonruter left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment by Claude Opus 5

The alias itself reads correctly for the happy path: s is copied onto search only when search is empty, so the long form wins, and parse_query() remains idempotent. Six observations follow, four of them as inline comments.

get_terms() is missing a matching @since entry. get_terms() maintains its own changelog of introduced parameters (src/wp-includes/taxonomy.php:1304-1310, for example @since 4.2.0 Introduced 'name' and 'childless' parameters.) and is the primary public entry point for these arguments. As the patch stands, a developer reading get_terms() alone sees no mention of s. A matching @since 7.2.0 Introduced the 's' parameter as an alias of 'search'. line belongs there as well. That file is not currently touched by the diff, hence the note here rather than inline.

The premise stated in the PR description is not accurate. The description asserts that "WP_Query, WP_User_Query, and WP_Comment_Query all accept s as a shorthand alias for search". Neither src/wp-includes/class-wp-user-query.php nor src/wp-includes/class-wp-comment-query.php contains any handling of s; both accept search only. WP_Query is the sole class that uses s, and there s is the canonical name rather than an alias. The inline code comment ("matching WP_Query convention") is accurate, but the description overstates the consistency argument, which is worth correcting before a committer weighs it.

The three new tests were not executed as part of this review.

Re Core-51811.

Comment thread src/wp-includes/class-wp-term-query.php Outdated
* @since 5.1.0 Introduced the 'meta_compare_key' parameter.
* @since 5.3.0 Introduced the 'meta_type_key' parameter.
* @since 6.4.0 Introduced the 'cache_results' parameter.
* @since 7.1.0 Introduced the 's' parameter as an alias of 'search'.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment by Claude Opus 5

This should be 7.2.0. src/wp-includes/version.php currently holds $wp_version = '7.2-alpha-63166-src' and package.json is at 7.2.0, so 7.1 has already shipped without this parameter. As written, the parameter is documented as available in a release that does not contain it.

'term_taxonomy_id' => '',
'hierarchical' => true,
'search' => '',
's' => '',

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment by Claude Opus 5

Adding s to query_var_defaults carries two side effects beyond this diff, because that array is consumed by two other pieces of machinery.

1. get_terms() legacy-signature detection. The legacy ( $taxonomy, $args ) form is distinguished from the modern one by array_intersect_key( $term_query->query_var_defaults, (array) $_args ) (src/wp-includes/taxonomy.php:1357), with an empty intersection meaning "legacy". A new single-letter key now participates in that test. For a taxonomy registered under the name s, get_terms( 's' ) parses to array( 's' => '' ), which now intersects the defaults, so the call is no longer detected as legacy, taxonomy is never set, and terms from every taxonomy are returned instead of just that one. This is admittedly exotic, but it is a behavior change outside the diff and deserves at least a mention on the ticket.

2. Duplicate cache entries for equivalent queries. generate_cache_key() slices $args by array_keys( $this->query_var_defaults ), so s now forms part of the key. array( 'search' => 'foo' ) and array( 's' => 'foo' ) produce byte-identical SQL yet different cache keys, so each equivalent query stores and misses its own entry.

Unsetting s once it has been copied onto search — the same treatment generate_cache_key() already gives cache_results and update_term_meta_cache — would resolve the second point and keep the parsed query_vars canonical.

Comment on lines +267 to +270
// 's' is a shorthand alias for 'search', matching WP_Query convention.
if ( '' === $query['search'] && '' !== $query['s'] ) {
$query['search'] = $query['s'];
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment by Claude Opus 5

The alias is resolved here, but the documented extension points run afterward and neither of them re-resolves it: pre_get_terms fires at line 391 and the get_terms_args filter at line 434, both after parse_query() has completed.

Once s is documented as an alias of search, the following becomes a natural thing to write:

add_action(
    'pre_get_terms',
    static function ( $query ) {
        $query->query_vars['s'] = $_GET['s'];
    }
);

Setting search in that callback works; setting s is silently discarded and an unfiltered result set is returned, which is difficult to diagnose from the outside. There is precedent for handling this: meta_query is deliberately reparsed at line 674, with the comment "Reparse meta_query query_vars, in case they were modified in a 'pre_get_terms' callback." Resolving the alias a second time after get_terms_args, or else documenting that s is honored only at parse time, would close the gap.

Comment on lines +1318 to +1331
public function test_s_param_returns_empty_when_no_match() {
register_taxonomy( 'wptests_tax', 'post' );

$q = new WP_Term_Query(
array(
'taxonomy' => 'wptests_tax',
's' => 'absolutelynonexistentterm',
'hide_empty' => false,
'fields' => 'ids',
)
);

$this->assertEmpty( $q->terms, 'The s parameter should return empty for non-matching terms.' );
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Comment by Claude Opus 5

This test passes whether or not the feature works. wptests_tax is registered but no terms are created in it, so $q->terms comes back empty regardless of whether s is honored — reverting the entire patch leaves the assertion passing.

For the assertion to carry weight, a term whose name does not match absolutelynonexistentterm needs to exist in wptests_tax, so that an unhonored s — which falls through to "return everything" — actually fails the test.

Comment thread tests/phpstan/baselines/assign.propertyType.neon
@wppoland

Copy link
Copy Markdown
Author

Thank you for the thorough review and guidance @westonruter!

Addressed all points in 83d04fa:

  1. Target version: Updated @since tags to 7.2.0 in src/wp-includes/class-wp-term-query.php.
  2. get_terms() documentation: Added @since 7.2.0 Introduced the 's' parameter as an alias of 'search'. to the get_terms() docblock in src/wp-includes/taxonomy.php.
  3. Diff scope: Dropped the unrelated PHPStan baseline commit (6060be5101) and rebased cleanly onto current trunk.
  4. PR description accuracy: Corrected the PR description to remove reference to WP_User_Query and WP_Comment_Query, clarifying that this specifically matches the WP_Query convention.
  5. Cache key canonicalization: In WP_Term_Query::generate_cache_key(), unset $cache_args['s'] alongside cache_results and update_term_meta_cache, so equivalent queries using search and s produce identical cache keys and share cache hits.
  6. Hook support: In WP_Term_Query::get_terms(), re-resolved the s alias after get_terms_args to support callbacks modifying $query->query_vars['s'] in pre_get_terms or filters on get_terms_args.
  7. Test coverage:
    • Populated wptests_tax with an existing term in test_s_param_returns_empty_when_no_match() so it fails if s is unhonored.
    • Added test_s_param_can_be_set_in_pre_get_terms().
    • Added test_s_and_search_produce_identical_cache_key().

All 48 tests pass cleanly with 0 phpcs violations.

- Adds 's' as a shorthand alias for 'search' in WP_Term_Query, matching WP_Query convention.
- Re-resolves 's' alias in get_terms() after get_terms_args filter to honor callbacks setting 's'.
- Normalizes query vars in generate_cache_key() by unsetting 's' so equivalent queries share cache keys.
- Adds comprehensive unit tests covering alias resolution, precedence, non-matching terms, pre_get_terms callback, and shared cache key generation.

Props mukeshpanchal27, westonruter, wppoland.
Fixes #51811.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants