WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm trying to create links to the next and previous posts within a specific tag (on the post page itself), but I can't seem to find a plugin or source that does this.

I want to be able to something like this, appearing below the post.


Anybody know of a way to accomplish this? Otherwise I'll have to write something myself, which is fine, but I figured I wouldn't reinvent the wheel unless I have to.

share|improve this question
are you talking about outside of the /tag/tagname page? – BandonRandon Apr 7 '11 at 6:05
I'm talking about on the single.php page. Will edit to make that more clear. – The How-To Geek Apr 7 '11 at 6:09

get_adjacent_post(), which is used by all functions that return a (link to) the next or previous post, only has a $in_same_cat argument, which looks at the categories the post is in, not the tags.

You could hook into the get_[next|previous]_post_join to modify the join query for your call, but then it's probably easier to copy the function, remove the category-specific code and replace it with tag-specific code. Or make it even more generic and submit it as a patch to WordPress :-)

share|improve this answer
Yeah, I found that function, was hoping somebody else had already written it =) – The How-To Geek Apr 7 '11 at 6:45

Does this work for that problem? http://digwp.com/2010/04/post-navigation-outside-loop/

The code in that post works for "Archive-View Pages" & "Single-View Pages" :P

share|improve this answer
That doesn't give me specific tag links. – The How-To Geek Apr 7 '11 at 6:44

Here's a version of the copy/paste edit that @Jan Fabry alluded to above (definitely not the most elegant solution, but it should work):

 * Retrieve adjacent post.
 * Can either be next or previous post.
 * @param bool $in_same_tag Optional. Whether post should be in same category.
 * @param string $excluded_tags Optional. Excluded tags IDs.
 * @param bool $previous Optional. Whether to retrieve previous post.
 * @return mixed Post object if successful. Null if global $post is not set. Empty string if no corresponding post exists.
function get_adjacent_post_by_tag($in_same_tag = false, $excluded_tags = '', $previous = true) {
    global $post, $wpdb;

    if ( empty( $post ) )
        return null;

    $current_post_date = $post->post_date;

    $join = '';
    $posts_in_ex_tags_sql = '';
    if ( $in_same_tag || !empty($excluded_tags) ) {
        $join = " INNER JOIN $wpdb->term_relationships AS tr ON p.ID = tr.object_id INNER JOIN $wpdb->term_taxonomy tt ON tr.term_taxonomy_id = tt.term_taxonomy_id";

        if ( $in_same_tag ) {
            $tag_array = wp_get_object_terms($post->ID, 'post_tag', array('fields' => 'ids'));
            $join .= " AND tt.taxonomy = 'post_tag' AND tt.term_id IN (" . implode(',', $tag_array) . ")";

        $posts_in_ex_tags_sql = "AND tt.taxonomy = 'post_tag'";
        if ( !empty($excluded_tags) ) {
            $excluded_tags = array_map('intval', explode(' and ', $excluded_tags));
            if ( !empty($tag_array) ) {
                $excluded_tags = array_diff($excluded_tags, $tag_array);
                $posts_in_ex_tags_sql = '';

            if ( !empty($excluded_tags) ) {
                $posts_in_ex_tags_sql = " AND tt.taxonomy = 'post_tag' AND tt.term_id NOT IN (" . implode($excluded_tags, ',') . ')';

    $adjacent = $previous ? 'previous' : 'next';
    $op = $previous ? '<' : '>';
    $order = $previous ? 'DESC' : 'ASC';

    $join  = apply_filters( "get_{$adjacent}_post_join", $join, $in_same_tag, $excluded_tags );
    $where = apply_filters( "get_{$adjacent}_post_where", $wpdb->prepare("WHERE p.post_date $op %s AND p.post_type = %s AND p.post_status = 'publish' $posts_in_ex_tags_sql", $current_post_date, $post->post_type), $in_same_tag, $excluded_tags );
    $sort  = apply_filters( "get_{$adjacent}_post_sort", "ORDER BY p.post_date $order LIMIT 1" );

    $query = "SELECT p.* FROM $wpdb->posts AS p $join $where $sort";
    $query_key = 'adjacent_post_' . md5($query);
    $result = wp_cache_get($query_key, 'counts');
    if ( false !== $result )
        return $result;

    $result = $wpdb->get_row("SELECT p.* FROM $wpdb->posts AS p $join $where $sort");
    if ( null === $result )
        $result = '';

    wp_cache_set($query_key, $result, 'counts');
    return $result;
share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.