I have custom post type for comics, called “comic” and have written a basic comic navigation. First —previous — (current) title — next — and last comic.

In functions.php, this code calls for the first and last post:

* Get the first and latest post link for custom post type

function first_comic_link( $query ) {

// Query the database for the oldest post
$first_comic = new WP_Query( array(
'post_type' => 'comic',  
'post_per_page' =>1,
'order'   => 'ASC',

if ($first_comic->have_posts()) { 

    echo $first_url; 

  // Prevent the loop in this function from interfering with other loops.
for latest post link
function latest_comic_link( $query ) {

// Query the database for the most recent post
$last_comic = new WP_Query( array(
'post_type' => 'comic', 
if ($last_comic->have_posts()) {

    echo $latest_url;

// Prevent the loop in this function from interfering with other loops.


The above code could also live in template_tags.php. It might be more logical to group “first”, “last” with “next” and “previous” functions.

In single_comic.php, the code for the specific navigation:

<?php if (( 'comic' ) ) : //navigation links for comics ?>

        <nav class="navigation-comic">
    <nav class="nav-first"><a href="<?php first_comic_link() ?>" title="First Episode">|&lt; First</a></nav>
    <nav class="nav-previous"><?php previous_post_link( '%link', '← Previous', TRUE ); ?></nav>
    <nav class="nav-title"><?php the_title( '<h3 class="comic-title"><a href="' . esc_url( get_permalink() ) . '" rel="bookmark">', '</a></h3>' ); ?></nav>
    <nav class="nav-next"><?php next_post_link( '%link', 'Next →', TRUE ); ?></nav>
    <nav class="nav-last"><a href="<?php latest_comic_link() ?>" title="Latest Episode">Latest &gt;|</a></nav>
            <?php wp_reset_query(); ?>

The result will get the first and last comic post all right. Testing on localhost, WP_DEBUG set on “true”, with no error.

Now I’d like to improve this to work with different stories looping through a specific category for each. Just how it works with previous & next functions. Clicking previous or next gives you the adjacent post, staying in the same category. So each comic story in a given a category would show from first to last post without interfering with other categories.

I am looking for an elegant solution to do this, after trying several methods and looking through the codex to no avail. Would appreciate any pointers in the right direction as well as any improvement on my current code, thank you.

1 Answer 1


It is sometimes irritating that some build-in functions don't have appropriate filters to modify their output. get_boundary_post() is one of those build-in functions. Unfortunately it does not get posts according to post type, only taxonomy. You can still however make use of this function to get the first and last post. It does support the $in_same_term parameter, the same as the next_post_link() and previous_post_link() functions.

Just a note here, the codex page for get_boundary_post() is incorrect, there are 4 parameters, like below (Check the source, currently lines 1694 - 1750 in wp-includes/link-template.php)

get_boundary_post( $in_same_term = false, $excluded_terms = '', $start = true, $taxonomy = 'category' )

If you need more control over this function, simply copy the complete function to functions.php, rename it and make the desired modifications

Use get_boundary_post() as follows to get the first and last post in the same category from a taxonomy called mytax

//First post
$first = get_boundary_post( true, '', true, 'mytax' );
echo apply_filters( 'the_title', $first[0]->post_title );
//Last post
$last = get_boundary_post(true, '', false, 'mytax');
echo apply_filters( 'the_title', $last[0]->post_title );

Just one note, if you set the $in_same_term parameter to true in either post links, you need to set the taxonomy as well if the taxonomy is not the default category taxonomy, for example

previous_post_link( '%link', 'Previous post in same term', TRUE, ' ', 'mytax' );


I think most probably why you get the same post returned is the fact that get_boundary_post uses get_posts which uses WP_Query which default to the post type post. As I said, there is no filter here.

The best will be to copy the function, rename it and modify as needed.

Try something like this

function get_my_custom_boundary_post( $in_same_term = false, $excluded_terms = '', $start = true, $taxonomy = 'category' ) {
    $post = get_post();
    if ( ! $post || ! is_single() || is_attachment() || ! taxonomy_exists( $taxonomy ) )
        return null;

    $query_args = array(
        'post_type' => 'MYPOSTTYPE',
        'posts_per_page' => 1,
        'order' => $start ? 'ASC' : 'DESC',
        'update_post_term_cache' => false,
        'update_post_meta_cache' => false

    $term_array = array();

    if ( ! is_array( $excluded_terms ) ) {
        if ( ! empty( $excluded_terms ) )
            $excluded_terms = explode( ',', $excluded_terms );
            $excluded_terms = array();

    if ( $in_same_term || ! empty( $excluded_terms ) ) {
        if ( $in_same_term )
            $term_array = wp_get_object_terms( $post->ID, $taxonomy, array( 'fields' => 'ids' ) );

        if ( ! empty( $excluded_terms ) ) {
            $excluded_terms = array_map( 'intval', $excluded_terms );
            $excluded_terms = array_diff( $excluded_terms, $term_array );

            $inverse_terms = array();
            foreach ( $excluded_terms as $excluded_term )
                $inverse_terms[] = $excluded_term * -1;
            $excluded_terms = $inverse_terms;

        $query_args[ 'tax_query' ] = array( array(
            'taxonomy' => $taxonomy,
            'terms' => array_merge( $term_array, $excluded_terms )
        ) );

    return get_posts( $query_args );

Then just change MYPOSTTYPE to your actual post type, and also change the previously given code to

//First post
$first = get_my_custom_boundary_post( true, '', true, 'mytax' );
echo apply_filters( 'the_title', $first[0]->post_title );
//Last post
$last = get_my_custom_boundary_post(true, '', false, 'mytax');
echo apply_filters( 'the_title', $last[0]->post_title );
  • (ah, too late, can't edit) Thank you very much Pieter. I had tried $in_same_term before, but $start was indeed missing. However, I am still puzzled: I adapted the function with get_boundary_post(), “first” and “last” will now stay in the current category, but display the current post. No matter the combination, either $start or $in_same_term seems to be ignored (still, no error). Going back to furter testing…
    – Hoa
    Commented Feb 23, 2015 at 13:19
  • I will test this later today and let you know :-) Commented Feb 23, 2015 at 13:22
  • You're most kind.
    – Hoa
    Commented Feb 23, 2015 at 13:23
  • Sorry, there was a bug in my code, I have updated the code and should now work :-) Commented Feb 23, 2015 at 14:11
  • Thank you. I can't get this to work. It does look like something is preventing the function to fetch the first & last post. All combinations from this invariably return the same post, ignoring $start. Can't figure out why.
    – Hoa
    Commented Feb 24, 2015 at 19:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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