Opened 3 years ago
#51794 new defect (bug)
An author_name query with nonexistent user returns posts with no author
Reported by: |
|
Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Query | Keywords: | has-patch |
Focuses: | Cc: |
Description
This was initially noticed on a production site where an author URL with a bogus author slug (e.g. http://local.wordpress.test/author/thisuserdoesnotexist/) was returning posts.
If an author_name
query is made with gibberish (or any nonexistent author slug), the query will return results for post_author = 0
.
wp> $q = new WP_Query( [ 'author_name' => 'thisuserdoesnotexist' ] ); [...] wp> $q->is_404; bool(false) wp> $q->found_posts; int(3562) wp> $q->request; string(213) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (wp_posts.post_author = 0) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') ORDER BY wp_posts.post_date DESC LIMIT 0, 10"
Are there a lot of sites out there with posts assigned to a 0 author? No idea, but my test site has a lot from generating posts via WP_CLI.
The issue stems from wp-includes/class-wp-query.php#L2254-L2258...
$q['author'] = get_user_by( 'slug', $q['author_name'] ); if ( $q['author'] ) { $q['author'] = $q['author']->ID; } $whichauthor .= " AND ({$wpdb->posts}.post_author = " . absint( $q['author'] ) . ')';
...where a potentially false result from get_user_by()
is cast to an int and used in a query.
With the included patch, this is the result of the same query:
wp> $q->is_404 bool(true) wp> $q->found_posts int(0) wp> $q->request string(250) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND wp_posts.post_author NOT IN (0) AND (wp_posts.post_author = 0) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') ORDER BY wp_posts.post_date DESC LIMIT 0, 10"
The patch is a hack though, relying on another absint()
to make our query search for posts that both are and are not by 0
:) There's probably a better way.
But, removing the hacky $qv['author'] = $qv['author_name'];
line leaves this, which although returns a 404 to the browser, still runs the query:
wp> $q->is_404 bool(true) wp> $q->found_posts int(3562) wp> $q->request string(213) "SELECT SQL_CALC_FOUND_ROWS wp_posts.ID FROM wp_posts WHERE 1=1 AND (wp_posts.post_author = 0) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') ORDER BY wp_posts.post_date DESC LIMIT 0, 10"
hacky patch