Conditional page/post navigation links in WordPress

November 18th, 2007
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!

Tags: , ,

5 Responses to “Conditional page/post navigation links in WordPress”


  1. 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. Author Comment

    Eric Martin

    @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. [...] possuía essa navegação embutida. Assim que reparei nesse problema, pensei imediatamente não em criá-los no rodapé, mas sim, em fazer uso do excelente plugin WP-PageNavi, que, no caso do modelo de índice do blog, [...]


  4. 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

  5. Author Comment

    Eric Martin

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

Sorry, comments are closed for this post.
If you have any further questions or comments, feel free to contact me directly.