Drupal Custom Pager navigation

Submitted by Janak on Thu, 10/22/2009 - 12:13

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

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

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

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

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

Step 5

Customise the output with your own CSS

Your thoughts and comments are most welcome.