Conditional page/post navigation links in WordPress

Update: This post has been replaced with an updated version.

While creating a new theme for this site, I added some CSS styling around the page/post navigation links.

For example, in my index.php page, I have the following HTML/WordPress code:

<div class='navigation'>
  <span class='older'><?php next_posts_link('&laquo; Older Entries') ?></span>
  <span class='newer'><?php previous_posts_link('Newer Entries &raquo;') ?></span>
</div>

And the following CSS code:

.navigation {font-size:.7em; background:#353535; height:16px; margin:0 -16px 8px -16px; padding:8px 6px 0px;}
.navigation span {margin-top:-4px;}
.navigation .older {float:left;}
.navigation .newer {float:right;}

Everything looked great, until I brought up a page that did not have a previous or next link. The styled navigation div was still there, but there was nothing in it. So, I set out to conditionally display the navigation div if either a previous or next link existed.

WordPress gives you two different sets of functions to display page/post navigation links:

To display the previous and next page links (where the "next" page is the older entries or page n+1 and the "previous" page is the newer entries or page n-1): next_posts_link and previous_posts_link.
Note: It looks like the suggested function to call for these links is posts_nav_link, but it just calls next_posts_link and previous_posts_link internally, so I'll just stick to calling them directly.

To display the previous and next post links (where the "next" post is a newer post entry and "previous" is an older post entry): next_post_link and previous_post_link.

So, I needed a way to capture the value of the next and previous links and then only display the navigation div if either contained a value. However, the WordPress functions mentioned above echo the link HTML when called, making it impossible to add conditions around them.

A helpful person on the WordPress forums pointed out that a plugin would be overkill for solving this problem, so I created a functions.php file to my theme with two new functions and 4 overridden functions:

Note: I've posted a alternative solution.

<?php

/**
 * New function that will display the navigation only if a previous or next page exists
 * Hint: For pages, next == older and previous == newer
 */
function posts_navigation($next_label='&laquo; Older Entries', $previous_label='Newer Entries &raquo;', $max_page=0) {
	$older = theme_next_posts_link($next_label);
	$newer = theme_previous_posts_link($previous_label);

	if(strlen($older) > 0 || strlen($newer) > 0) {
		echo "<div class='navigation'>";
		echo "<span class='older'>".$older."</span>";
		echo "<span class='newer'>".$newer."</span>";
		echo "</div>";
	}
}

/**
 * New function that will display the navigation only if a previous or next entry exists
 * Hint: For entries, next == newer and previous == older
 */
function post_navigation($format='%link', $next_link='%title  &raquo;', $previous_link='&laquo; %title', $in_same_cat = false, $excluded_categories = '') {
	$older = theme_previous_post_link($format, $previous_link);
	$newer = theme_next_post_link($format, $next_link);

	if(strlen($older) > 0 || strlen($newer) > 0) {
		echo "<div class='navigation'>";
		echo "<span class='older'>".$older."</span>";
		echo "<span class='newer'>".$newer."</span>";
		echo "</div>";
	}
}

/**
 * Overrides the WordPress next_posts() function in link-template.php
 * Modification: Changed echo to return
 */
function theme_next_posts($max_page = 0) {
	return clean_url(get_next_posts_page_link($max_page));
}

/**
 * Overrides the WordPress next_posts_link() function in link-template.php
 * Modification: 
 *	 - Removed echo's 
 *	 - Added a $next_posts_link variable
 *	 - Calls overridden next_posts() function, theme_next_posts()
 *	 - Returns the $next_posts_link value
 */
function theme_next_posts_link($label='Next Page &raquo;', $max_page=0) {
	global $paged, $wpdb, $wp_query;
	$next_posts_link = '';
	if ( !$max_page ) {
		$max_page = $wp_query->max_num_pages;
	}
	if ( !$paged )
		$paged = 1;
	$nextpage = intval($paged) + 1;
	if ( (! is_single()) && (empty($paged) || $nextpage <= $max_page) ) {
		$next_posts_link .= '<a href="';
		$next_posts_link .= theme_next_posts($max_page);
		$next_posts_link .= '">'. preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
	}
	return $next_posts_link;
}

/**
 * Overrides the WordPress previous_posts() function in link-template.php
 * Modification: Changed echo to return
 */
function theme_previous_posts() {
	return clean_url(get_previous_posts_page_link());
}

/**
 * Overrides the WordPress previous_posts_link() function in link-template.php
 * Modification:
 *	 - Removed echo's 
 *	 - Added a $previous_posts_link variable
 *	 - Calls overridden previous_posts() function, theme_previous_posts()
 *	 - Returns the $previous_posts_link value
 */
function theme_previous_posts_link($label='&laquo; Previous Page') {
	global $paged;
	$previous_posts_link = '';
	if ( (!is_single())	&& ($paged > 1) ) {
		$previous_posts_link .= '<a href="';
		$previous_posts_link .= theme_previous_posts();
		$previous_posts_link .= '">'. preg_replace('/&([^#])(?![a-z]{1,8};)/', '&#038;$1', $label) .'</a>';
	}
	return $previous_posts_link;
}

/**
 * Overrides the WordPress previous_post_link() function in link-template.php
 * Modification: Changed echo to return
 */
function theme_previous_post_link($format='&laquo; %link', $link='%title', $in_same_cat = false, $excluded_categories = '') {

	if ( is_attachment() )
		$post = & get_post($GLOBALS['post']->post_parent);
	else
		$post = get_previous_post($in_same_cat, $excluded_categories);

	if ( !$post )
		return;

	$title = $post->post_title;

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

	$title = apply_filters('the_title', $title, $post);
	$string = '<a href="'.get_permalink($post->ID).'">';
	$link = str_replace('%title', $title, $link);
	$link = $pre . $string . $link . '</a>';

	$format = str_replace('%link', $link, $format);

	return $format;
}

/**
 * Overrides the WordPress next_post_link() function in link-template.php
 * Modification: Changed echo to return
 */
function theme_next_post_link($format='%link &raquo;', $link='%title', $in_same_cat = false, $excluded_categories = '') {
	$post = get_next_post($in_same_cat, $excluded_categories);

	if ( !$post )
		return;

	$title = $post->post_title;

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

	$title = apply_filters('the_title', $title, $post);
	$string = '<a href="'.get_permalink($post->ID).'">';
	$link = str_replace('%title', $title, $link);
	$link = $string . $link . '</a>';
	$format = str_replace('%link', $link, $format);

	return $format;
}

?>

And now, I have conditional page/post navigation links for my theme!

Topics:

4 Comments

  1. January 17, 2008 @ 11:11 am #

    Hi. I think there are two bugs here... I believe

    $nextpage <= $max_page

    should actually be

    $nextpage < $max_page

    And why is there a 1 at the end on the following line:

    $nextpage = intval($paged) 1;

  2. January 17, 2008 @ 1:42 pm #

    @Naif - this code was deprecated in favor of a different approach. However, you did find something that must have been garbled when posting:

    $nextpage = intval($paged) 1;

    should be:

    $nextpage = intval($paged) + 1;

    which makes $nextpage < = $max_page correct. I've updated the page and will put a note about this approach being replaced.

  3. May 2, 2009 @ 7:27 pm #

    Hi

    I would like to use this function, or a variant of it but i cant get it working, basically i am using previous_post_link() as follows:


    $img = "<img src=\"/image/galleries/" . $catnicename . "/" . $image ."\" alt=\"" . get_the_title() . "\" />";

    if (previous_post_link('%link', $img, TRUE) == Null) {
    echo $img;
    } else {
    previous_post_link('%link', $img, TRUE);
    }

    which works great inless there is a previous_post_link in which case it prints the link with the $img variable inbetween the >a href tags (which is what i want, and then the $img again.

    I am thinking the solution is in your code here somewhere but i cant find it, could you help me out?

    David

  4. May 4, 2009 @ 8:55 am #

    @David - Have you checked out the updated version of this concept?

Leave a Comment

Sorry, comments are closed. You can contact me directly, if you like.

Eric Martin
1home
2blog
3projects
4photography
5about
6contact
ssearch
ccomment
p/←previous
n/→next
ttop