Opened 6 weeks ago
Last modified 6 weeks ago
#65411 new defect (bug)
Don’t let ?s= override singular URLs
| Reported by: | jonoaldersonwp | Owned by: | |
|---|---|---|---|
| Priority: | low | Milestone: | Awaiting Review |
| Component: | Rewrite Rules | Version: | |
| Severity: | normal | Keywords: | 2nd-opinion |
| Cc: | Focuses: | ui |
Description (last modified by )
When a post URL is shared from Twitter/X, the app may append a source-tracking parameter such as ?s=20.
For example, a valid post URL like https://www.example.com/some-article/ can become https://www.example.com/some-article/?s=20 (where 20 varies by device/location/context) when shared.
A visitor clicking that link expects to see the article. Instead, WordPress may treat s=20 as an internal search query. Depending on the site, theme, plugins, and rewrite state, this can load search results for 20, change the template context, or produce a 404 error.
That is a bad outcome for users, and often an expensive one for sites. Singular content is commonly cached. Search results and 404s often are not.
Broader issue
The s query var is a long-standing part of WordPress search behaviour, and URLs like https://www.example.com/?s=example and https://www.example.com/some-taxonomy/?s=filter (which filters the existing request) continue to work.
But s is also a very short, generic parameter. WordPress cannot assume that every external use of ?s= is intended to trigger site search.
Twitter/X is the clearest current example, but the same failure mode can occur whenever another platform, app, email client, CMS, analytics system, or sharing tool appends s to an otherwise valid WordPress URL.
A third-party tracking parameter should not be able to override a request that already resolves to a post, page, attachment, or other singular object.
Proposed change
Could WordPress prefer the resolved singular object when a request contains both /some-existing-post/ and ?s=<value>?
In practice: https://www.example.com/some-article/?s=20 should load the post at /some-article/, not a search results page for 20.
This should not remove or deprecate normal search URLs. URLs like https://www.example.com/?s=example and https://www.example.com/search/example/ should continue to behave as search results.
The change should apply only where the path portion of the request already resolves to a singular object.
Possible implementation direction
This may be best handled during request parsing or main query resolution.
At a high level:
- If the request path resolves to a singular object, do not let
sturn the main query into a search. - Preserve the raw
svalue in$_GETfor plugins and custom code that need to inspect it. - Ensure template selection, conditional tags, and canonical behaviour match the resolved singular object.
- Consider a filter for sites that intentionally use
?s=on singular URLs.
Compatibility considerations
Some sites may intentionally use ?s= on singular URLs for custom behaviour, for example:
https://www.example.com/product/example-product/?s=blue
For that reason, the safest approach may be to change only the main query interpretation, while preserving the raw request parameter.
It is also worth discussing whether this should apply to all s values, or only to values that look like third-party source identifiers, such as numeric values. Applying it consistently to all s values may be simpler and less surprising: if the path resolves to a singular object, the singular object wins.
Questions for discussion
- At what level should this be addressed (given that we can't rely on
is_search()etc)? - Should the rule apply to all
svalues, or only source-like values such as numbers? - Is a compatibility filter needed?
Why this belongs in Core
This is a Core routing and query interpretation issue, not a theme-specific or plugin-specific problem.
A valid shared URL to a singular object should not become a search or 404 because a third-party platform appended a generic s parameter. WordPress can make this more resilient by allowing the resolved singular path to take precedence over accidental search parameters.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)