Drupal Custom Pager navigation

For my portfolio site I wanted each image node (CCK + imagefield) to have a thumbnail strip of 10 or so images from the same category. Very simple stuff I thought. A quick search and I came across fantastic module called Custom Pagers by Eaton. This highly flexible module provides you a Next and Previous custom pager that you can display in your node pages. This was perfect for blog nodes but I wanted more control over the pager and I only wanted nodes to be pulled out from the same taxonomy term as the node being displayed.. fairly simple idea:

- hook_nodeapi - so we can intercept the current node
- Identify the term we want to target (you will need to adapt this for your own taxonomy)
- Pass the NID and TID to our custom pager function
- Select nodes from the db and process them
- return results to hook_nodeapi and add to node object
- print your custom pager in the node template

Example

Here is what the code looks like:

Step 1

Setup the hook_nodeapi

<?php
function mymodule_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL){
  switch(
$op){
    case
'view':
     
//only apply to "mynode" node type
     
if($node->type == "mynode" and $a3 == null and $a4 != null){
       
//loop through taxonomy if you need to
       
foreach ($node->taxonomy as $term_obj){
         
//if its the right term vocab..
          // do your custom code here
         
if($term_obj->vid == 1){            
           
//thumbnail custom pager
           
$node->node_thumbnail_nav = mymodule_node_thumbnail_nav($node->nid, $term_obj->tid);
          }
        }      
      }
      break;
  }
}
?>

Step 2

Function to return the custom pager nodes

<?php
function mymodule_node_thumbnail_nav($nid, $tid){
 
// current one will be added to the total later,
  // make sure number is always 1 less than the TOTAL displayed
 
$total_thumbnails_to_display = 10;
 
$left = ceil(($total_thumbnails_to_display) / 2);
 
$right = floor(($total_thumbnails_to_display) / 2);
 
 
$next_nids_array = mymodule_node_thumbnail_nav_db($nid, $tid, 'more', $total_thumbnails_to_display);
 
$previous_nids_array = mymodule_node_thumbnail_nav_db($nid, $tid, 'less', $total_thumbnails_to_display);
 
 
// if we dont have enough next (newer) items, pad with previous    
 
if(count($next_nids_array) < $right){
   
$previous_nids_array = array_splice($previous_nids_array, 0, $total_thumbnails_to_display - count($next_nids_array)); 
  }
 
// if we dont have enough previous (older) items, pad with next
 
elseif(count($previous_nids_array) < $left){
   
$next_nids_array = array_splice($next_nids_array, 0, $total_thumbnails_to_display - count($previous_nids_array)); 
  }
 
// all good, splice in the center to get both left (older) and right (newer) nodes
 
else{
   
$previous_nids_array = array_splice($previous_nids_array, 0, $left);
   
$next_nids_array = array_splice($next_nids_array, 0, $right);
  }
 
 
//merge left and right and add current node
 
$all_nids_array = array_merge($next_nids_array, array($nid), $previous_nids_array);
 
 
// sort the list
 
sort($all_nids_array);
 
 
//check if there is something to work with
 
if(count($all_nids_array) != 0){
   
//we have our list, lets work though it
   
foreach($all_nids_array as $available_nid){
     
$node_obj = node_load($available_nid);
       
     
$current_nid_class = "";
     
//for the current nid we need a custom class to identify it
     
if($available_nid == $nid){
       
$current_nid_class=' current_nid';
      }
 
     
$image = $node_obj->field_image_attach[0]['filepath'];
     
$linked_image = l(theme('imagecache', 'photo_mini', $image, $node_obj->title, $node_obj->title), 'node/' . $node_obj->nid, array('html'=>true));
 
     
$thumbs .= "<div class=\"thumbnail_item{$current_nid_class}\">{$linked_image}</div>";
    }
    return
"<div class=\"thumbnail_container\">{$thumbs}</div>";    
  }

}
?>

Step 3

MySql DB query stuff

<?php
function mymodule_node_thumbnail_nav_db($nid, $tid, $op='more', $limit=10){
  if(
$op == 'more'){ $op = '>'; $order = "ASC";}
  else{
$op = '<'; $order = "DESC";}
 
 
$sql = "
  SELECT
  node.nid
  FROM
  node
  Inner Join term_node ON node.nid = term_node.nid
  WHERE
  node.type = 'mynode' AND
  node.status = 1 AND
  node.moderate = 0 AND
  node.nid %s %d AND
  term_node.tid = %d
  ORDER BY node.nid %s
  LIMIT %d 
  "
;
 
 
$nids_array = array();
 
$result = db_query($sql, $op, $nid, $tid, $order, $limit);
  while(
$row = db_fetch_object($result)){
   
$nids_array[] = $row->nid;
  }
 
  return
$nids_array;
}
?>

Step 4

Edit your node template and add

<?php
if($node->node_thumbnail_nav){ $print $node->node_thumbnail_nav;}
?>

Step 5

Customise the output with your own CSS

For a working demo, check any of the nodes from portfolio section of my site.

Your thoughts and comments are most welcome.


Bookmark and Share

2 comments

Anonymous's picture

That's a pretty cool way to paginate. Excellent tutorial.

Anonymous's picture

Good stuff, I'll be using this in a website I'm working on.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account, used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options