Basic Next/Previous Navigation For Nodes
22:18When viewing a node, I wanted the ability to page through to the next and previous article.
- Code is abstracted out into 2 different functions.
- You can specify the text to be used for the generated links.
- Uses l() instead of hardcoding directly generating the links using $nid. l() uses aliases if available and therefore generated links are consistent with the rest of the site.
- Uses a few class attributes to generated links so they can be styled.
These 2 functions (plus maybe a lot of other similar functions) can be abstracted out into a module.
- Create a file called template.php in your theme's folder if it does not already exist, assuming that theme is PHPTemplate-based.
- Copy the 2 functions
next_node()
andprevious_node()
into template.php. Copy the functions along with their complete definitions i.e. the whole body not only the function names. Make sure the functions are withing<?php
and?>
tags. - Copy the code snippet to the place in node.tpl.php where you want
the links to appear. These links should appear only when a node is view
in its entirety so put them in a
if($page!=0)
.
For themes using other engines you will have to read the appropriate documentation to know where to put the code.
<?php
/**
* Enables theme developers to include a link to the node of the same type
* that comes immediately after the the node being currently viewed.
*
* A node has to be published and promoted to the front page to
* qualify as the 'next node'. Unpublished and nodes not promoted
* to front page are not considered. Access control is respected.
*
* Theme developers would normally use this in the template for a node.
*
* @param $node
* node whose next node is to be found.
* @param $next_node_text
* The text for the link that will be created. If no text is given
* then the title of the next node is used.
* @param $prepend_text
* Text to be prepended to the created link. It is not a part of the link.
* @param $append_text
* Text to be appended to the created link. It is not a part of the link.
*
*/
function next_node($node, $next_node_text=NULL, $prepend_text=NULL, $append_text=NULL)
{
$query = db_rewrite_sql("SELECT nid, title FROM {node} WHERE created > '%s' AND status=1 and promote=1 AND type='%s' ORDER BY created ASC LIMIT 1", "node", "nid");
$result = db_query($query, $node->created, $node->type);
$next_node = db_fetch_object($result);
if(!$next_node_text) // If next_node_text is not specified then use the next node's title as the text for the link.
{
$next_node_text = $next_node->title;
}
if($next_node->nid!=NULL)
{
return $prepend_text.l($next_node_text, 'node/'.$next_node->nid, array('title'=>'Go to the next post "'.$next_node_text.'"', 'class'=>'goto-previous-node')).$append_text;
}
else // There is no next node for this node...
{
return NULL;
}
}
/**
* Enables theme developers to include a link to the node of same type
* that comes immediately before the the node being currently viewed.
*
* A node has to be published and promoted to the front page to
* qualify as the 'previous node'. Unpublished and nodes not promoted
* to front page are not considered. Access control is respected.
*
* Theme developers would normally use this in the template for a node.
*
* @param $node
* node whose next node is to be found.
* @param $previous_node_text
* The text for the link that will be created. If no text is given
* then the title of the previous node is used.
* @param $prepend_text
* Text to be prepended to the created link. It is not a part of the link.
* @param $append_text
* Text to be appended to the created link. It is not a part of the link.
*
*/
function previous_node($node, $previous_node_text=NULL, $prepend_text=NULL, $append_text=NULL)
{
$query = db_rewrite_sql("SELECT nid, title FROM {node} WHERE created < '%s' AND status=1 and promote=1 AND type='%s' ORDER BY created DESC LIMIT 1", "node", "nid");
$result = db_query($query, $node->created, $node->type);
$previous_node = db_fetch_object($result);
if(!$previous_node_text) // If previous_node_text is not specified then use the previous node's title as the text for the link.
{
$previous_node_text = $previous_node->title;
}
if($previous_node->nid!=NULL)
{
return $prepend_text.l($previous_node_text, 'node/'.$previous_node->nid, array('title'=>'Go to the previous post "'.$previous_node_text.'"', 'class'=>'goto-previous-node')).$append_text;
}
else // This node does not have a previous node...
{
return NULL;
}
}
?>
Alternately you use this return statement:
return $prepend_text.l($next_node_text,
'node/'.$next_node_nid, array('title'=>'Go to the next post
"'.$next_node_text.'"', 'class'=>'goto-next-node')).$append_text;
I used the above code in my node.tpl.php just below the node body like this:
<?php
if($page!=0)
{
$previous_node_link = previous_node($node, NULL, '<< ', NULL);
$next_node_link = next_node($node, NULL, NULL, ' >>');
print '<div>';
if($previous_node_link && $next_node_link)
{
print $previous_node_link.' | '.$next_node_link;
}
else if($previous_node_link)
{
print $previous_node_link;
}
else if($next_node_link)
{
print $next_node_link;
}
print '</div>';
}
?>
update:
The above functions, though functional are huge resource hogs. Doing a node_load on every node until you find the correct taxonomy term has a huge performace impact. This can be overcome by with some simple sql joins. Here is an updated function. I've also combined the 2 functions into one.
<?php
function node_sibling($dir = 'next', $node, $next_node_text=NULL, $prepend_text=NULL, $append_text=NULL, $tid = FALSE){
if($tid){
$query = 'SELECT n.nid, n.title FROM {node} n INNER JOIN {term_node} tn ON n.nid=tn.nid WHERE '
. 'n.nid ' . ($dir == 'previous' ? '<' : '>') . ' %d AND n.type = "%s" AND n.status=1 '
. 'AND tn.tid = %d ORDER BY n.nid ' . ($dir == 'previous' ? 'DESC' : 'ASC');
$result = db_query($query, $node->nid, $node->type, $tid);
}else{
$query = 'SELECT n.nid, n.title FROM {node} n WHERE '
. 'n.nid ' . ($dir == 'previous' ? '<' : '>') . ' %d AND n.type = "%s" AND n.status=1 '
. 'ORDER BY n.nid ' . ($dir == 'previous' ? 'DESC' : 'ASC');
$result = db_query($query, $node->nid, $node->type);
}
if($row = db_fetch_object($result)){
$text = $next_node_text ? $next_node_text : $row->title;
return $prepend_text . l($text, 'node/'.$row->nid, array('rel' => $dir)) . $append_text;
}else{
return NULL;
}
}
?>