Experimental project

This is a sandbox project, which contains experimental code for developer use only.

Overview

This Drupal module provides a simple ajax pager and sorter for custom listing pages. It falls back to (and relies on) the normal Drupal paging behavior and markup. The pager is a click-triggered "Click for more" style of pager. The sorter is a click-triggered sort toggle, which assumes that the listing page sort is controlled by a query string called "sort". (Eg, http://example.com/my-listing?sort=date)

Features

  • Converts normal Drupal pager into an AJAX "Click for more" pager.
  • Adds toggle-based AJAX sorting if the listing page supports it
  • Remembers paging/sorting when users click away and then use back-button

Usage

To add the pager and/or sorter to a page, in the render array for the output use a '#theme' element of 'ajaxpagersorter_pager' and/or 'ajaxpagersorter_sorter'. Depending on whether you are doing a pager or a sorter, you would include additional parameters, as you can see in the examples below. This mostly involves identifying certain classes or selectors to tell ajaxpagersorter how to find the content on the page.

Here is an example of pager usage in a page callback:

function my_page_callback() {
  
  // Get a list of published article teasers, paged at 10 articles per page.
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', 'article')
    ->propertyCondition('status', NODE_PUBLISHED)
    ->propertyOrderBy('created', 'DESC')
    ->pager(10, 0);
    
  // Execute the query and load the article teasers.
  $result = $query->execute();
  if (empty($result['node'])) {
    return;
  }
  $nids = array_keys($result['node']);
  $nodes = entity_load('node', $nids);
  $teasers = entity_view('node', $nodes, 'teaser');
  
  // Return a render array.
  return array(
    // Wrap everything in this div.
    '#prefix' => '<div class="wrapper-around-everything">',
    '#suffix' => '</div>',
    'teasers' => array(
      // Wrap the teasers in another div.
      '#prefix' => '<div class="wrapper-around-teasers-only">',
      '#suffix' => '</div>',
      'teasers' => $teasers,
    ),
    // Finally display the pager as a '#theme' element.
    'pager' => array(
      '#theme' => 'ajaxpagersorter_pager',
      // If you want to have custom styles for the button during load, you
      // would use this class to do that.
      '#loading_class' => 'class-to-add-to-buttons-during-load',
      // This refers to the outer wrapper we did above.
      '#wrapper_outer_selector' => '.wrapper-around-everything',
      // This refers to the inner wrapper we did above.
      '#wrapper_inner_selector' => '.wrapper-around-teasers-only',
      // Custom text for the paging button.
      '#pager_button_text' => t('Click here for more!'),
      // An array of classes to add to the paging button. (for style purposes)
      '#pager_button_classes' => array('my-general-button', 'my-red-button'),
    ),
  );
}

Here is an example of using the sorter in a page callback:

function my_page_callback() {
  
  // Get a list of 10 published article teasers, sorted by either date or title.
  $query = new EntityFieldQuery();
  $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', 'article')
    ->propertyCondition('status', NODE_PUBLISHED)
    ->range(0, 10);
    
  // We will use either date or title to sort, depending on a URL parameter.
  // (Defaulting to date sorting)
  $sort_mode = (empty($_GET['sort'])) ? 'date' ? $_GET['sort'];
  if ('date' == $sort_mode) {
    $query->propertyOrderBy('created', 'DESC');
  }
  elseif ('title' == $sort_mode) {
    $query->propertyOrderBy('title', 'ASC');
  }
  
  // Execute the query and load the article teasers.
  $result = $query->execute();
  if (empty($result['node'])) {
    return;
  }
  $nids = array_keys($result['node']);
  $nodes = entity_load('node', $nids);
  $teasers = entity_view('node', $nodes, 'teaser');
  
  // Return a render array.
  return array(
    // Wrap everything in this div.
    '#prefix' => '<div class="wrapper-around-everything">',
    '#suffix' => '</div>',
    'teasers' => array(
      // Wrap the teasers in another div.
      '#prefix' => '<div class="wrapper-around-teasers-only">',
      '#suffix' => '</div>',
      'teasers' => $teasers,
    ),
    // Finally display the sorter as a '#theme' element.
    'pager' => array(
      '#theme' => 'ajaxpagersorter_sorter',
      // If you want to have custom styles for the buttons during load, you
      // would use this class to do that.
      '#loading_class' => 'class-to-add-to-buttons-during-load',
      // This refers to the outer wrapper we did above.
      '#wrapper_outer_selector' => '.wrapper-around-everything',
      // This refers to the inner wrapper we did above.
      '#wrapper_inner_selector' => '.wrapper-around-teasers-only',
      // The sorts, an array button labels keyed to query string keys
      'sort_buttons' => array(
        'date' => t('Date'),
        'title' => t('Title'),
      ),
      // An array of the classs to add to each sort button.
      'sort_button_classes' => array('my-general-button', 'my-green-button'),
      // The class to add when a sort button is active.
      'sort_button_active_class' => 'my-active-sort-class',
      // An optional default sort. (Defaults to the first sort button.)
      // This should match the logic used by the custom listing.
      'default_sort' => 'date',
    ),
  );
}

Pagers and sorters are designed to be able to be used together, so feel free to include both on the same page, for a sortable and pageable listing.

Project information

  • Created by brockfanning on , updated