How to create Drupal pagination that use rel=“next” and rel=“prev”

Submitted by ivica on Mon, 14.05.2012
Tags: 

If you want to optimize your Drupal site pages to have HTML link elements rel=”next” and rel=”prev” to indicate the relationship between component URLs in a paginated series here is what you need to do (note that this example is written for Drupal 6, but Drupal 7 solution should be similar).

Drupal pager rendering is controlled by couple of theme functions theme_pager, theme_pager_first, theme_pager_last, theme_pager_previous, theme_pager_next, theme_pager_link. Of all this theme function best is to override theme_pager_link which you will add into your template.php theme file. You just to change end of theme_pager_link function and add next lines of code:

<?php
  $query
= count($query) ? implode('&', $query) : NULL;

 
// Pagination with rel=“next” and rel=“prev”. Does not support well multiple
  // pagers on the same page - it will create relnext and relprev links
  // in header for that case only for the first pager that is rendered.
 
static $rel_prev = FALSE, $rel_next = FALSE;
  if (!
$rel_prev && $text == t('‹ previous')) {
   
$rel_prev = TRUE;
   
drupal_set_html_head('<link rel="prev" href="' . url($url, array('query' => $query)) . '" />');
  }
  if (!
$rel_next && $text == t('next ›')) {
   
$rel_next = TRUE;
   
drupal_set_html_head('<link rel="next" href="' . url($url, array('query' => $query)) . '" />');
  }
 
  return
l($text, $url, array('attributes' => $attributes, 'query' => $query));
?>

So your whole function should look like this:

<?php
function theme_pager_link($text, $page_new, $element, $parameters = array(), $attributes = array()) {
 
$page = isset($_GET['page']) ? $_GET['page'] : '';
  if (
$new_page = implode(',', pager_load_array($page_new[$element], $element, explode(',', $page)))) {
   
$parameters['page'] = $new_page;
  }

 
$query = array();
  if (
count($parameters)) {
   
$query[] = drupal_query_string_encode($parameters, array());
  }
 
$querystring = pager_get_querystring();
  if (
$querystring != '') {
   
$query[] = $querystring;
  }

 
// Set each pager link title
 
if (!isset($attributes['title'])) {
    static
$titles = NULL;
    if (!isset(
$titles)) {
     
$titles = array(
       
t('« first') => t('Go to first page'),
       
t('‹ previous') => t('Go to previous page'),
       
t('next ›') => t('Go to next page'),
       
t('last »') => t('Go to last page'),
      );
    }
    if (isset(
$titles[$text])) {
     
$attributes['title'] = $titles[$text];
    }
    else if (
is_numeric($text)) {
     
$attributes['title'] = t('Go to page @number', array('@number' => $text));
    }
  }

 
$query = count($query) ? implode('&', $query) : NULL;
 
 
// Pagination with rel=“next” and rel=“prev”. Does not support well multiple
  // pagers on the same page - it will create relnext and relprev links
  // in header for that case only for the first pager that is rendered.
 
static $rel_prev = FALSE, $rel_next = FALSE;
  if (!
$rel_prev && $text == t('‹ previous')) {
   
$rel_prev = TRUE;
   
drupal_set_html_head('<link rel="prev" href="' . url($url, array('query' => $query)) . '" />');
  }
  if (!
$rel_next && $text == t('next ›')) {
   
$rel_next = TRUE;
   
drupal_set_html_head('<link rel="next" href="' . url($url, array('query' => $query)) . '" />');
  }
 
  return
l($text, $url, array('attributes' => $attributes, 'query' => $query));
}
?>

Note that this solution will work well when you have only one pager on your page, but it will not work well in situation if you have multiple pagers on your page this code will create rel prev/next head links only for first rendered pager.

12 comments

by soulston on Tue, 12.06.2012

Thanks for this, for Drupal 7 I used drupal_add_html_head_link:

drupal_add_html_head_link(array('rel' => 'next', 'href' => url($_GET['q'], array('query' => $query))));

I also removed the following line as it was causing an error:

$query = count($query) ? implode('&', $query) : NULL;

by Jim on Tue, 04.12.2012

I've not been able to get this to work on Drupal 7. Maybe I'm putting the code into the wrong file? Can someone provide very explicit instructions (in the form of: in this file, insert this code)?

Thanks!

by herder on Mon, 25.03.2013

D7 solution:
add two section code in theme_pager function(include/pager.inc), we could hook in template.php
1.rel="prev"
if ($li_previous) {
$items[] = array(
'class' => array('prev'),//pager-previous=>prev
'data' => $li_previous,
);

//Pages: rel="next" & rel="prev" on paginated pages
preg_match("/<a.+?href=['\"](.+)['\"]>/i", $li_previous, $prev_match);
$prev_link = invmodule_url_rewrite($prev_match[1]);
drupal_add_html_head_link(array('rel' => 'prev', 'href' => $prev_link));
}

2.rel="next"
if ($li_next) {
$items[] = array(
'class' => array('next'),//pager-next=>next
'data' => $li_next,
);

//Pages: rel="next" & rel="prev" on paginated pages
preg_match("/<a.+?href=['\"](.+)['\"]>/i", $li_next, $next_match);
$next_link = invmodule_url_rewrite($next_match[1]);
drupal_add_html_head_link(array('rel' => 'next', 'href' => $next_link));
}

invmodule_url_rewrite() gives not defined error. You can replace this line to get it working:

$next_link = invmodule_url_rewrite($next_match[1]);

with this line:

$next_link = $GLOBALS['base_url'] . $next_match[1];

by ForTheWin on Tue, 20.08.2013

Drupal 7 has a module called Clean Pager: https://drupal.org/project/cleanpager, that can automatically accomplish this!

Hi,
Thank you for this post. I replaced the function theme_pager_link in the /includes/pager.inc file with the one provided by NetEntropy and the rel="prev" and rel="next" appears correctly in the source code now:

<link rel="prev" href="/blog-post/" />
<link rel="next" href="/blog-post/?page=2" />

But unfortunately, the pager links at the bottom no longer work. The numbers appear at the bottom, but I can't click on them to get to the next page. Has anyone else run into this? Any guidance would be great.

Thanks!

by Lindsay on Wed, 24.12.2014

Hi ForTheWin, were you able to find a fix for the buttons not working?

Hello would you mind sharing which blog platform you're working with?
I'm looking to start my own blog in the near future but I'm having a tough time selecting
between BlogEngine/Wordpress/B2evolution and
Drupal. The reason I ask is because your design and style seems different
then most blogs and I'm looking for something completely unique.
P.S Apologies for being off-topic but I had to ask!

by admin on Fri, 08.04.2016

Yeah this is Drupal 7 using Taski theme https://www.drupal.org/project/tarski.

function yourtheme_pager_link($text, $page_new, $element, $parameters = array(), $attributes = array()) {

// Pagination with rel=“next” and rel=“prev”. Does not support well multiple
// pagers on the same page - it will create relnext and relprev links
// in header for that case only for the first pager that is rendered.
static $rel_prev = FALSE, $rel_next = FALSE;
if (!$rel_prev && $text == t('‹ previous')) {
$rel_prev = TRUE;
drupal_set_html_head('<link rel="prev" href="' . url($url, array('query' => $query)) . '" />');
}
if (!$rel_next && $text == t('next ›')) {
$rel_next = TRUE;
drupal_set_html_head('<link rel="next" href="' . url($url, array('query' => $query)) . '" />');
}

return theme_pager_link($text, $page_new, $element, $parameters = array(), $attributes = array());

}

This way as long as signature to theme_pager_link does not change you are ok in the event of the function itself changing

by Bill on Wed, 10.12.2014

It wouldn't work properly for me as $url wasn't defined. This helped:

$url = $_GET['q'];