[wp-trac] [WordPress Trac] #65072: Registering a query_var called 'preview_nonce' stops previews from working.
WordPress Trac
noreply at wordpress.org
Tue Apr 14 12:39:42 UTC 2026
#65072: Registering a query_var called 'preview_nonce' stops previews from working.
--------------------------+-----------------------------
Reporter: dsas | Owner: dsas
Type: defect (bug) | Status: assigned
Priority: normal | Milestone: Awaiting Review
Component: Query | Version:
Severity: normal | Keywords:
Focuses: |
--------------------------+-----------------------------
**Summary**
The static front page fallback in WP_Query::get_posts()
[https://github.com/WordPress/wordpress-
develop/blob/aa72dfed4432cfd875f77d2c475f772c6623cae5/src/wp-includes
/class-wp-query.php#L2042 line ~2042] sets `is_page = true` and `is_home =
false`, but does not update `is_singular`. This causes the query to
generate incorrect SQL — using `post_type = 'post'` instead of `post_type
= 'page'` — and return zero results.
The equivalent check in `parse_query()` ([https://github.com/WordPress
/wordpress-develop/blob/aa72dfed4432cfd875f77d2c475f772c6623cae5/src/wp-
includes/class-wp-query.php#L1057 line ~1057]) correctly maintains the
invariant by [https://github.com/WordPress/wordpress-
develop/blob/aa72dfed4432cfd875f77d2c475f772c6623cae5/src/wp-includes
/class-wp-query.php#L1135 recalculating is_singular at line 1135]. The
`get_posts()` backstop does not.
**How to trigger**
The backstop fires when `parse_query()` fails to detect the static front
page because $this->query contains unexpected public query vars (anything
not in the allowlist of preview, page, paged, cpage). This can happen when
a plugin registers a query var that collides with a parameter WordPress
core uses in preview URLs — for example, registering preview_nonce as a
public query var.
**Steps to reproduce**
1. Register preview_nonce as a public query var: `add_filter(
'query_vars', function ( $vars ) { $vars[] = 'preview_nonce'; return
$vars; } );`
2. Set a static front page in Settings → Reading
3. Visit /?preview_id=<page_id>&preview_nonce=<valid_nonce>&preview=true
Expected: The static front page content is displayed.
Actual: The blog post index is displayed. The preview URL is redirected
with preview=true stripped.
**What happens internally**
1. `parse_query()` line ~1057: The `array_diff` check fails because
`preview_nonce` is not in the allowlist. `is_home` stays `true`, `is_page`
stays `false`, `is_singular` stays `false`.
2. `get_posts()` line ~2046: The backstop fires because `is_home` is
`true` and `$query_vars['preview']` is `'true'`. It sets `is_page = true`,
`is_home = false`, and `page_id` to the front page ID. **But it does not
set `is_singular = true`.**
3. `get_posts()` line ~2618: `$post_type_where` is correctly set to
`post_type = 'page'` based on `is_page = true`.
4. `get_posts()` line ~2705: The `! $this->is_singular` branch is
entered. This branch builds its own combined post_type + post_status
clause. Since `$post_type` is empty (line ~2003), line ~2713 defaults to
`array('post')`, overriding the correct `post_type_where` from step 3.
5. The resulting SQL is `WHERE ID = <page_id> AND post_type = 'post'`,
which returns zero rows because the front page is a `page`.
6. With zero results, `redirect_canonical` strips `preview=true` from
the URL and redirects. On the second request, neither `parse_query()` nor
the backstop can identify the request as the static front page.
** Note **
I've fixed the plugin which exposed this issue, but the is_singular
invariant violation in the backstop is a core issue.
--
Ticket URL: <https://core.trac.wordpress.org/ticket/65072>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list