Skip to content

Instantly share code, notes, and snippets.

@jameswilson
Last active August 19, 2020 15:42
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jameswilson/678e7f9fcc50cc92fbeb to your computer and use it in GitHub Desktop.
Save jameswilson/678e7f9fcc50cc92fbeb to your computer and use it in GitHub Desktop.
Drupal 7 Accessible Pager (Backport from Drupal 8)
<?php
// Place this file your theme's "templates" folder.
/**
* @file
* Theme override to display a pager.
*
* This is a backport of pager.html.twig from Drupal 8 to Drupal 7, which add
* accessibility support for WCAG 2.0 section 2.4.9.
*
* Available variables:
* - items: List of pager items.
* The list is keyed by the following elements:
* - first: Item for the first page; not present on the first page of results.
* - previous: Item for the previous page; not present on the first page
* of results.
* - next: Item for the next page; not present on the last page of results.
* - last: Item for the last page; not present on the last page of results.
* - pages: List of pages, keyed by page number.
* Sub-sub elements:
* items.first, items.previous, items.next, items.last, and each item inside
* items.pages contain the following elements:
* - href: URL with appropriate query parameters for the item.
* - attributes: A keyed list of HTML attributes for the item.
* - text: The visible text used for the item link, such as "‹ previous"
* or "next ›".
* - current: The page number of the current page.
* - ellipses: If there are more pages than the quantity allows, then an
* ellipsis before or after the listed pages may be present.
* - previous: Present if the currently visible list of pages does not start
* at the first page.
* - next: Present if the visible list of pages ends before the last page.
*
* @see template_preprocess_pager()
*/
?>
<?php if (count($items)) : ?>
<nav class="item-list item-list--pager" role="navigation" aria-labelledby="pagination-heading">
<h4 id="pagination-heading" class="element-invisible"><?= t('Pagination') ?></h4>
<ul class="pager">
<?php // Print first item if we are not on the first page. ?>
<?php if ($items['first']) : ?>
<li class="pager-first">
<a href="<?= $items['first']['href'] ?>" title="<?= t('Go to first page') ?>"<?= $items['first']['attributes'] ?>>
<span class="element-invisible"><?= t('First page') ?></span>
<span aria-hidden="true"><?= t('« first') ?></span>
</a>
</li>
<?php endif; ?>
<?php // Print previous item if we are not on the first page. ?>
<?php if ($items['previous']) : ?>
<li class="pager-previous">
<a href="<?= $items['previous']['href'] ?>" title="<?= t('Go to previous page') ?>" rel="prev"<?= $items['previous']['attributes'] ?>>
<span class="element-invisible"><?= t('Previous page') ?></span>
<span aria-hidden="true"><?= t('‹ previous') ?></span>
</a>
</li>
<?php endif; ?>
<?php // Add an ellipsis if there are further previous pages. ?>
<?php if ($ellipses['previous']) : ?>
<li class="pager-ellipsis" role="presentation">&hellip;</li>
<?php endif; ?>
<?php // Now generate the actual pager piece. ?>
<?php foreach($items['pages'] as $key => $item) : ?>
<li class="pager-item<?= $current == $key ? ' pager-current' : '' ?>">
<?php if ($current == $key) : ?>
<?php $title = t('Current page'); ?>
<?php else : ?>
<?php $title = t('Go to page @key', array('@key' => $key)); ?>
<?php endif; ?>
<a href="<?= $item['href'] ?>" title="<?= $title ?>" class="<?= $current == $key ? ' active' : '' ?>">
<span class="element-invisible">
<?= $current == $key ? t('Current page') : t('Page'); ?>
</span><?= $key ?>
</a>
</li>
<?php endforeach; ?>
<?php // Add an ellipsis if there are further next pages. ?>
<?php if ($ellipses['next']) : ?>
<li class="pager-ellipsis" role="presentation">&hellip;</li>
<?php endif; ?>
<?php // Print next item if we are not on the last page. ?>
<?php if ($items['next']) : ?>
<li class="pager-next">
<a href="<?= $items['next']['href'] ?>" title="<?= t('Go to next page') ?>" rel="next"<?= $items['next']['attributes'] ?>>
<span class="element-invisible"><?= t('Next page') ?></span>
<span aria-hidden="true"><?= t('next ›') ?></span>
</a>
</li>
<?php endif; ?>
<?php // Print last item if we are not on the last page. ?>
<?php if ($items['last']) : ?>
<li class="pager-last">
<a href="<?= $items['last']['href'] ?>" title="<?= t('Go to last page') ?>"<?= $items['last']['attributes'] ?>>
<span class="element-invisible"><?= t('Last page') ?></span>
<span aria-hidden="true"><?= t('last »') ?></span>
</a>
</li>
<?php endif; ?>
</ul>
</nav>
<?php endif; ?>
<?php
// Paste the code below in your theme's template.php file.
/**
* Implements hook_preprocess_pager().
*
* This is a backport of template_preprocess_pager from Drupal 8.
*/
function template_preprocess_pager(&$variables) {
$element = $variables['element'];
$parameters = $variables['parameters'];
$quantity = $variables['quantity'];
$route_name = $_GET['q'];
global $pager_page_array, $pager_total;
// Nothing to do if there is only one page.
if ($pager_total[$element] <= 1) {
return;
}
$tags = $variables['tags'];
// Calculate various markers within this pager piece:
// Middle is used to "center" pages around the current page.
$pager_middle = ceil($quantity / 2);
// current is the page we are currently paged to
$pager_current = $pager_page_array[$element] + 1;
// first is the first page listed by this pager piece (re quantity)
$pager_first = $pager_current - $pager_middle + 1;
// last is the last page listed by this pager piece (re quantity)
$pager_last = $pager_current + $quantity - $pager_middle;
// max is the maximum page number
$pager_max = $pager_total[$element];
// End of marker calculations.
// Prepare for generation loop.
$i = $pager_first;
if ($pager_last > $pager_max) {
// Adjust "center" if at end of query.
$i = $i + ($pager_max - $pager_last);
$pager_last = $pager_max;
}
if ($i <= 0) {
// Adjust "center" if at start of query.
$pager_last = $pager_last + (1 - $i);
$i = 1;
}
// End of generation loop preparation.
// Create the "first" and "previous" links if we are not on the first page.
if ($pager_page_array[$element] > 0) {
$items['first'] = array();
$options = array(
'query' => pager_query_add_page($parameters, $element, 0),
);
$items['first']['href'] = url($route_name, $options);
if (isset($tags[0])) {
$items['first']['text'] = $tags[0];
}
$items['previous'] = array();
$options = array(
'query' => pager_query_add_page($parameters, $element, $pager_page_array[$element] - 1),
);
$items['previous']['href'] = url($route_name, $options);
if (isset($tags[1])) {
$items['previous']['text'] = $tags[1];
}
}
if ($i != $pager_max) {
// Add an ellipsis if there are further previous pages.
if ($i > 1) {
$variables['ellipses']['previous'] = TRUE;
}
// Now generate the actual pager piece.
for (; $i <= $pager_last && $i <= $pager_max; $i++) {
$options = array(
'query' => pager_query_add_page($parameters, $element, $i - 1),
);
$items['pages'][$i]['href'] = url($route_name, $options);
if ($i == $pager_current) {
$variables['current'] = $i;
}
}
// Add an ellipsis if there are further next pages.
if ($i < $pager_max + 1) {
$variables['ellipses']['next'] = TRUE;
}
}
// Create the "next" and "last" links if we are not on the last page.
if ($pager_page_array[$element] < ($pager_max - 1)) {
$items['next'] = array();
$options = array(
'query' => pager_query_add_page($parameters, $element, $pager_page_array[$element] + 1),
);
$items['next']['href'] = url($route_name, $options);
if (isset($tags[3])) {
$items['next']['text'] = $tags[3];
}
$items['last'] = array();
$options = array(
'query' => pager_query_add_page($parameters, $element, $pager_max - 1),
);
$items['last']['href'] = url($route_name, $options);
if (isset($tags[4])) {
$items['last']['text'] = $tags[4];
}
}
$variables['items'] = $items;
}
/**
* Backport of pager_query_add_page() from Drupal 8.
*/
function pager_query_add_page(array $query, $element, $index) {
global $pager_page_array;
// Determine the first result to display on the linked page.
$page_new = pager_load_array($index, $element, $pager_page_array);
$page = isset($_GET['page']) ? $_GET['page'] : '';
if ($new_page = implode(',', pager_load_array($page_new[$element], $element, explode(',', $page)))) {
$query['page'] = $new_page;
}
// Merge the query parameters passed to this function with the parameters
// from the current request. In case of collision, the parameters passed
// into this function take precedence.
if ($current_request_query = pager_get_query_parameters()) {
$query = array_merge($current_request_query, $query);
}
return $query;
}
@jameswilson
Copy link
Author

I believe I've not correctly written the functionality to allow proper ability to override the "tags" text. (first, last, next, previous)

 <span aria-hidden="true"><?= t('last »') ?></span>

^ doesn't properly take the $items['last']['text'] into account..

   if (isset($tags[4])) {
      $items['last']['text'] = $tags[4];
    }

@jameswilson
Copy link
Author

I've created an issue on Drupal.org to get this officially backported: https://www.drupal.org/node/2550929

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment