Opened 19 years ago
Closed 19 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: |
|
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 »', $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};)/', '&$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.
We've redone how max_num_pages is computed and removed paging by days, so this should be fixed.