WordPress.org

Make WordPress Core

Opened 5 months ago

#51794 new defect (bug)

An author_name query with nonexistent user returns posts with no author

Reported by: trepmal 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"

Attachments (2)

51794.diff (1.3 KB) - added by trepmal 5 months ago.
hacky patch
51794.2.diff (1.4 KB) - added by trepmal 5 months ago.
actually test for 0 posts returned

Download all attachments as: .zip

Change History (2)

@trepmal
5 months ago

hacky patch

@trepmal
5 months ago

actually test for 0 posts returned

Note: See TracTickets for help on using tickets.