For a single custom post type, I'm using previous_post_link and next_post_link with simple arrows. (Although text arrows are shown here, in the actual I'm using graphics with the text hidden via CSS.) Code:

<nav class="arrowNav">
    <div class="nav-previous">
       <?php previous_post_link('%link', '«'); ?>

    <div class="nav-next">
       <?php next_post_link('%link', '»'); ?>

This works fine except for the edge cases. I'd like the posts to wrap around: that is, for the first post, I'd like previous_post_link to link to the last post, and for the last post next_post_link would link to the first post. It appears the default for both those cases is null. How do I test for first and last post status and produce links for each?


Add following custom functions in functions.php file and instead of calling previous_post_link and next_post_link functions call custom_next_post_link and custom_previous_post_link custom functions respectively.

function custom_adjacent_post_link($format, $link, $in_same_cat = false, $excluded_categories = '', $previous = true)
    if ($previous && is_attachment())
        $post = get_post(get_post()->post_parent);
        $post = get_adjacent_post($in_same_cat, $excluded_categories, $previous);

    if (!$post) {
        $post =  '';
        $args = 'posts_per_page=1&orderby=date&ignore_sticky_posts=1';

        if ($previous)
            $args .= '&order=DESC';
            $args .= '&order=ASC';

        $the_query = new WP_Query($args);
        while ($the_query->have_posts()) :
            $post = get_post(get_the_ID());

    $title = $post->post_title;

    if (empty($post->post_title))
        $title = $previous ? __('Previous Post') : __('Next Post');

    $title = apply_filters('the_title', $title, $post->ID);
    $date = mysql2date(get_option('date_format'), $post->post_date);
    $rel = $previous ? 'prev' : 'next';

    $string = '<a href="' . get_permalink($post) . '" rel="' . $rel . '">';
    $inlink = str_replace('%title', $title, $link);
    $inlink = str_replace('%date', $date, $inlink);
    $inlink = $string . $inlink . '</a>';

    $output = str_replace('%link', $inlink, $format);
    $adjacent = $previous ? 'previous' : 'next';
    echo apply_filters("{$adjacent}_post_link", $output, $format, $link, $post);
function custom_previous_post_link($format = '&laquo; %link', $link = '%title', $in_same_cat = false, $excluded_categories = '')
    custom_adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, true);
function custom_next_post_link($format = '%link &raquo;', $link = '%title', $in_same_cat = false, $excluded_categories = '')
    custom_adjacent_post_link($format, $link, $in_same_cat, $excluded_categories, false);
  • Thanks Vinod! This works fine and I think will work for me in other contexts. Wish the standard versions had wraparound capability. – boomturn Mar 6 '13 at 19:24

The accepted answer works, but probly should have used get_posts() instead of a whole wpquery and loop:

    if ( ! $post ) { 
    $args = array('posts_per_page'=> 1,
            'orderby'=> 'date',
            'ignore_sticky_posts' => 1
    $adjposts = get_posts($args);
    $post = $adjposts[0];   

It's generally frowned upon to use wpquery if you dont need to. With full credit, otherwise, to Vinod Dalvi.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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