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

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

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

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

Anonymous's picture

Is it possible to use ajax for drupal custom pagination? If you have any idea please share with code.. That will be great..!! Thanx for this sharing.. :)

Anonymous's picture

thx, for an excellent site!

Unless I misunderstood,
An alternative is a configuration using a view with imagethumbs. Create a view listing the desired nodes. Set display to be the slideviewer and set the pager to thumbs.

Anonymous's picture

Is there any way how to do this with images and node reference field to gallery? (not terms)

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be 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 can enable syntax highlighting of source code with the following tags: <code>, <blockcode>, <apache>, <bash>, <c>, <cpp>, <css>, <drupal5>, <drupal6>, <java>, <javascript>, <php>, <python>, <ruby>, <vim>, <xml>. The supported tag styles are: <foo>, [foo]. PHP source code can also be enclosed in <?php ... ?> or <% ... %>.

More information about formatting options