[wp-trac] [WordPress Trac] #30911: Overhaul post_status logic in WP_Query
WordPress Trac
noreply at wordpress.org
Mon Jan 5 15:24:12 UTC 2015
#30911: Overhaul post_status logic in WP_Query
--------------------------+------------------------------------------
Reporter: boonebgorges | Owner:
Type: defect (bug) | Status: new
Priority: normal | Milestone: Future Release
Component: Query | Version:
Severity: normal | Keywords: needs-unit-tests needs-patch
Focuses: |
--------------------------+------------------------------------------
`WP_Query` filters based on post_status in two different places:
1. When building the main SQL query (`SELECT ID FROM $wpdb->posts`...).
https://core.trac.wordpress.org/browser/tags/4.1/src/wp-
includes/query.php#L2946 This block is responsible for parsing the
'post_status' query var, and rectifying these passed post_statuses with
the 'perm' param, the logged-in user's permissions, and whether
`is_admin()`. (The ability to query by 'post_status' dates from [5575].)
2. On `single` queries (`is_page()`, `is_single()`), additional filtering
happens *after* the query.
https://core.trac.wordpress.org/browser/tags/4.1/src/wp-
includes/query.php#L3511 The intended purpose of this block is to ensure
that Preview works (since posts being previewed generally are not
published). The current incarnation of the preview logic (ie, living in
`WP_Query`) was introduced in [2523].
These two 'post_status' blocks have two different purposes and two
different histories, but they interact in a number of problematic ways.
Just a few of the problems:
a. Querying posts with 'fields=ids' means that the post ids are returned
before the second filter block gets a chance to run. As a result, certain
`WP_Query` objects (eg 'p=123&post_status=trash') can return different
post IDs depending on whether you request 'fields=ids'.
b. Values passed to the post_status parameter of `WP_Query` are sometimes
overridden forcibly, based on logged-in user status. In an ideal world,
`WP_Query` would not make any essential reference to the logged-in user.
Realistically, we can't change some of this behavior for reasons having to
do with backward compatibility. But there are places where the current
user logic could be reworked so that it provides defaults, which can then
be overridden by the params passed to `WP_Query`. Some relevant tickets:
#28568, #29167
c. Filtering out non-previewable posts after the main query has taken
place means doing more SQL queries than necessary in cases where
post_status=draft and `is_single()`.
d. Filtering out non-previewable posts after the main query has taken
place can result in certain sorts of data leakage. See eg #30910.
e. Having two separate blocks that filter results based on post_status
makes unnecessarily complicated to fix post_status bugs. See eg #30530,
#22001, #23309.
My initial thought is that the second block should be removed. Preview
logic should either be merged with the first block of post_status parsing
logic that runs when building the main post query, or it should be moved
into a separate query_var, which would then be passed when making a
Preview request. In general, the challenge here is to ensure that the
default post_status whitelist is properly sensitive to the permissions of
the logged-in user - which sometimes means building clauses like
`(post_status = 'publish' OR ( post_status = 'private' AND post_author =
123 ))`.
I've started to write some unit tests that describe the (weird and
complicated) existing behavior. See #29167 [31047].
--
Ticket URL: <https://core.trac.wordpress.org/ticket/30911>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform
More information about the wp-trac
mailing list