WordPress.org

Make WordPress Core

Opened 8 years ago

Closed 7 years ago

#2408 closed defect (bug) (fixed)

Next/Previous page links get messed up if a plugin makes certain changes to the WP_Query->request

Reported by: isaacschlueter Owned by:
Milestone: 2.1 Priority: normal
Severity: normal Version: 2.0.1
Component: General Keywords: WP_Query, plugin, next page link, bug, fix
Focuses: Cc:

Description

If a plugin makes changes to the WP_Query->request in certain ways, you'll end up having a "Previous Posts" link returned from next_posts_link() when in fact there are no posts.

The UltimateTagWarrior plugin allows you to request the intersection of certain tags. So, you can get all posts tagged with both "foo" and "quux". The resulting $wp_query->request looks something like like:

SELECT DISTINCT * FROM wp_posts  
INNER JOIN wp_post2tag p2t on wp_posts.ID = p2t.post_id 
INNER JOIN wp_tags t on p2t.tag_id = t.tag_id  
WHERE 1=1 
AND post_date_gmt <= '2006-02-08 01:08:59' 
AND (post_status = "publish" OR post_author = 1 AND post_status != 'draft' AND post_status != 'static') AND post_status != "attachment" AND t.tag IN ('foo','quux')
GROUP BY wp_posts.ID
HAVING COUNT(ID) = 2
ORDER BY post_date DESC LIMIT 0, 5

The "GROUP BY" and the "HAVING" statements restrict it only to posts that have BOTH tags.

However, when this is crunched in next_posts_link(), it creates a statement like this:

SELECT COUNT(DISTINCT ID) 
FROM wp_posts  
INNER JOIN wp_post2tag p2t on wp_posts.ID = p2t.post_id 
INNER JOIN wp_tags t on p2t.tag_id = t.tag_id  
WHERE 1=1 
AND post_date_gmt <= '2006-02-08 01:08:59' AND (post_status = "publish" OR post_author = 1 
AND post_status != 'draft' AND post_status != 'static') 
AND post_status != "attachment" AND t.tag IN ('foo','quux')

The result of this query is some huge number, because it counts everything having EITHER tag, and counts several of them twice! So, it always thinks that there's a next page, and your error_log gets filled with 404s for /tag/foo+quux/page/4 or whatever.

SOLUTION

In wp-includes/template-functions-links.php, change next_posts_link() to this, so that it still works for "normal" requests, and also for these funky ones like these:

function next_posts_link($label='Next Page &raquo;', $max_page=0) {
	global $paged, $result, $request, $posts_per_page, $wpdb, $max_num_pages;
	if ( !$max_page ) {
			if ( isset($max_num_pages) ) {
				$max_page = $max_num_pages;
			} else {
				preg_match('#FROM\s(.*)\s(LIMIT|ORDER)#siU', $request, $matches);
				$fromwhere = $matches[1];
				$numposts = $wpdb->query("SELECT COUNT(DISTINCT ID) FROM $fromwhere");
				$max_page = $max_num_pages = ceil($numposts / $posts_per_page);
			}
	}
	if ( !$paged )
		$paged = 1;
	$nextpage = intval($paged) + 1;
	if ( (! is_single()) && (empty($paged) || $nextpage <= $max_page) ) {
		echo '<a href="';
		next_posts($max_page);
		echo '">'. preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
	}
}

Also, this will cut a processing step out of the function, as well, since it calls query directly instead of calling get_var which in turn calls query.

Running this fix on my live site right now, http://isaacschlueter.com/
Seems to be working great.

Change History (1)

comment:1 ryan7 years ago

  • Milestone set to 2.1
  • Resolution set to fixed
  • Status changed from new to closed

We've redone how max_num_pages is computed and removed paging by days, so this should be fixed.

Note: See TracTickets for help on using tickets.