You are here

cleanpager.module in Clean Pagination 7

Same filename and directory in other branches
  1. 8 cleanpager.module
  2. 5 cleanpager.module
  3. 6 cleanpager.module

File

cleanpager.module
View source
<?php

define('CLEANPAGER_ADDITIONAL_PATH_VARIABLE', 'page');

/**
 * Implementation of hook_menu()
 */
function cleanpager_menu() {
  $items = array();
  $items['admin/config/system/cleanpage'] = array(
    'title' => 'Clean Pagination Settings',
    'description' => 'Global configuration of Clean Pagination functionality.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'cleanpager_admin_settings',
    ),
    'access arguments' => array(
      'cleanpager administer',
    ),
    'type' => MENU_NORMAL_ITEM,
  );
  return $items;
}

/**
 * Defines admin settings form
 */
function cleanpager_admin_settings($form, &$form_state) {
  $form = array();
  $form['cleanpager_pages'] = array(
    '#title' => t('Pages'),
    '#description' => t('Set which pages to apply clean pagination to. Put each page on a new line and use the source page path (do not use the url alias), without a leading slash. For example, enter "node/1" for node 1. For the front page, enter "@value".', array(
      '@value' => '<front>',
    )),
    '#type' => 'textarea',
    '#rows' => '7',
    '#default_value' => variable_get('cleanpager_pages', ''),
  );
  $form['cleanpager_use_seo_links'] = array(
    '#title' => t('Use SEO Links'),
    '#description' => t('Using SEO links will add the page URL to the pagination links, and then will remove them via jquery once the page is loaded.'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('cleanpager_use_seo_links', ''),
  );
  $form['cleanpager_redirect_301'] = array(
    '#title' => t('Use 301 Redirects'),
    '#description' => t('If a user lands on a page that has ?page=X in the query string but should have clean pagination, issue a 301 redirect.'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('cleanpager_redirect_301', FALSE),
  );

  /*$form['cleanpager_add_can_link']= array(
      '#title' => t('Add canonical link to head'),
      '#description' => t('DO NOT USE. After further research, adding this link on paged pages is actually a bad idea. It is recommended to just use next and prev links. Add canonical information to header. This will add <a href="http://support.google.com/webmasters/bin/answer.py?hl=en&answer=139394">rel="canonical"</a> link to the head of every page that uses cleanpager.'),
      '#type' => 'checkbox',
      '#default_value' => variable_get('cleanpager_add_can_link', FALSE),
    );*/
  $form['cleanpager_add_rel_link'] = array(
    '#title' => t('Add next/prev links to head'),
    '#description' => t('Add pagination information to header. This will add <a href="http://support.google.com/webmasters/bin/answer.py?hl=en&answer=1663744">rel="prev" and rel="next"</a> links to the head of every page with a pager on it, regardless of whether or not it is using cleanpager.'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('cleanpager_add_rel_link', FALSE),
  );
  $form['cleanpager_use_additional_path'] = array(
    '#title' => t('Use !page_variable/page_number', array(
      '!page_variable' => CLEANPAGER_ADDITIONAL_PATH_VARIABLE,
    )),
    '#description' => t('Instead of simply adding /page_number at the end of paged urls, use /!page_variable/page_number.', array(
      '!page_variable' => CLEANPAGER_ADDITIONAL_PATH_VARIABLE,
    )),
    '#type' => 'checkbox',
    '#default_value' => variable_get('cleanpager_use_additional_path', TRUE),
  );
  $form['cleanpager_add_trailing'] = array(
    '#title' => t('Add trailing slash'),
    '#description' => t('Add a trailing slash (/) to all urls generated by Clean Pagination. I.E. "pager_url/page/1/"'),
    '#type' => 'checkbox',
    '#default_value' => variable_get('cleanpager_add_trailing', FALSE),
  );
  return system_settings_form($form);
}

/**
 * Implements hook_permission().
 */
function cleanpager_permission() {
  return array(
    "cleanpager administer" => array(
      'title' => t("cleanpager administer"),
    ),
  );
}

/**
 * Implements hook_boot().
 */
function cleanpager_boot() {
  global $language_url, $language;
  if (!isset($GLOBALS['language'])) {
    $default = language_default();
    foreach (language_types() as $type) {
      $GLOBALS[$type] = $default;
    }
  }
  require_once 'includes/path.inc';
  require_once 'includes/common.inc';
  cleanpager_check_match();
}

/**
 * Implements hook_init().
 */
function cleanpager_init() {
  global $_cleanpager_rewritten;

  // The current url looks like /test?page=1 but it should have clean pager
  $path = cleanpager_path();
  if (!$_cleanpager_rewritten && variable_get('cleanpager_redirect_301', FALSE) && isset($_GET['page']) && cleanpager_match_path($path)) {
    $path = _cleanpager_generate_current_page_url();

    // Pass along additional query string values.
    $query_values = $_GET;
    unset($query_values['page']);
    if (isset($query_values['q'])) {
      unset($query_values['q']);
    }

    // Execut the redirect.
    drupal_goto($path, array(
      'query' => $query_values,
    ), 301);
  }
  elseif (cleanpager_check_match()) {
    if (variable_get('cleanpager_add_can_link', FALSE)) {
      $path = _cleanpager_generate_current_page_url();
      drupal_add_html_head_link(array(
        'rel' => 'canonical',
        'href' => url($path, array(
          'absolute' => TRUE,
        )),
      ));
    }
    if (variable_get('cleanpager_use_seo_links', '') == 1) {
      drupal_add_js(drupal_get_path('module', 'cleanpager') . '/cleanpager.js');
    }
  }
}

/**
 * Generate the current page url with page.
 */
function _cleanpager_generate_current_page_url() {
  $path = cleanpager_path();
  if ($path && drupal_is_front_page()) {
    $path = '';
  }
  if (isset($_GET['page'])) {
    if (variable_get('cleanpager_use_additional_path', TRUE)) {
      $path .= ($path ? '/' : '') . CLEANPAGER_ADDITIONAL_PATH_VARIABLE;
    }
    $path .= ($path ? '/' : '') . $_GET['page'];
  }

  // Add the trailing slash.
  if ($path && variable_get('cleanpager_add_trailing', FALSE)) {
    $path .= '/';
  }
  return $path;
}

/**
 * Wrapper for drupal_match_path() to correctly handle the front page.
 */
function cleanpager_match_path($q) {

  // Change the matches to have a new line in them (blank line) so that
  // the front page where there is no query string is correctly matched.
  $matches = str_replace('<front>', "<front>\n", variable_get('cleanpager_pages', ''));
  return drupal_match_path($q, $matches);
}

/**
 * Checks if the page should use clean pagination
 */
function cleanpager_check_match() {
  $q_use = NULL;
  $q = cleanpager_path();
  if (cleanpager_match_path($q)) {
    $q_use = $q;
  }

  // The main path didn't work, try the path alias.
  if ($q_use === NULL) {
    $q = drupal_get_path_alias($q);
    if (cleanpager_match_path($q)) {
      $q_use = $q;
    }
    else {
      $q = drupal_get_normal_path($q);
      if (cleanpager_match_path($q)) {
        $q_use = $q;
      }
    }
  }

  // The path was matched.
  if ($q_use !== NULL) {
    _cleanpager_rewrite_path();
    return $q;
  }
  return FALSE;
}

/**
 * Remove number at end of path
 */
function cleanpager_path() {

  // Make sure the path came from the browser to use it.
  $q = _cleanpager_get_q();
  $q_array = explode('/', $q);
  if (_cleanpager_is_pager_element(end($q_array))) {
    array_pop($q_array);

    // Check for page/page_number
    if (variable_get('cleanpager_use_additional_path', TRUE)) {
      if (end($q_array) == CLEANPAGER_ADDITIONAL_PATH_VARIABLE) {
        array_pop($q_array);
        $q = implode('/', $q_array);
      }
    }
    else {
      $q = implode('/', $q_array);
    }
  }
  return $q;
}

/**
 * Helper function to get the query string. Handles views ajax.
 */
function _cleanpager_get_q() {
  $q = isset($_GET['q']) ? $_GET['q'] : '';
  if (arg(0) == 'views' && arg(1) == 'ajax' && !empty($_POST['view_path'])) {
    $q = rtrim($_POST['view_path'], '/');
  }
  return $q;
}

/**
 * Override theme for a pager link
 */
function cleanpager_theme_pager_link($variables) {
  $text = $variables['text'];
  $page_new = $variables['page_new'];
  $element = $variables['element'];
  $parameters = $variables['parameters'];
  $attributes = $variables['attributes'];
  $page = isset($_GET['page']) ? $_GET['page'] : '';
  if ($new_page = implode(',', pager_load_array($page_new[$element], $element, explode(',', $page)))) {
    $parameters['page'] = $new_page;
  }
  $cleanpage = cleanpager_check_match();
  if ($cleanpage) {
    unset($parameters['page']);
  }
  $query = array();
  if (count($parameters)) {
    $query = drupal_get_query_parameters($parameters, array());
  }
  if ($query_pager = pager_get_query_parameters()) {
    $query = array_merge($query, $query_pager);
  }

  // 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];
    }
    elseif (is_numeric($text)) {
      $attributes['title'] = t('Go to page @number', array(
        '@number' => $text,
      ));
    }
  }
  $q = _cleanpager_get_q();
  if ($cleanpage) {
    $q = cleanpager_path();
    if (drupal_is_front_page()) {
      $cleanpage = '';
    }
    else {

      // Use the aliased path.
      $cleanpage = drupal_get_path_alias($cleanpage);
    }
    if (variable_get('cleanpager_use_additional_path', TRUE)) {
      $cleanpage .= ($cleanpage ? '/' : '') . CLEANPAGER_ADDITIONAL_PATH_VARIABLE;
    }
  }
  else {
    unset($cleanpage);
  }

  // If we're on the front page, don't add in the path. For example,
  // use page/1 instead of node/page/1.
  if (drupal_is_front_page()) {
    $q = '';
  }
  else {

    // Use the aliased path if there is one.
    $q = drupal_get_path_alias($q);
  }

  // Store the original text in case it's modified and it's used down
  // below to add rel and previous.
  $original_text = $text;
  if (isset($new_page) && isset($cleanpage) && $page_new[$element] > 0) {
    if (variable_get('cleanpager_use_seo_links', '') == 1) {
      $text = 'Visit ' . $q . ' Page ' . $text;
    }
    $link = array(
      'title' => $text,
      'href' => $cleanpage . ($cleanpage ? '/' : '') . $new_page . (variable_get('cleanpager_add_trailing', FALSE) ? '/' : ''),
      'attributes' => $attributes,
      'query' => count($query) ? $query : NULL,
    );
  }
  else {
    $link = array(
      'title' => $text,
      'href' => $q . ($q && variable_get('cleanpager_add_trailing', FALSE) ? '/' : ''),
      'attributes' => $attributes,
      'query' => count($query) ? $query : NULL,
    );
  }
  if (variable_get('cleanpager_add_rel_link', FALSE)) {

    // 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 && $original_text == t('‹ previous')) {
      $rel_prev = TRUE;
      drupal_add_html_head_link(array(
        'rel' => 'prev',
        'href' => url($link['href'], array(
          'query' => $link['query'],
          'absolute' => TRUE,
        )),
      ));
    }
    if (!$rel_next && $original_text == t('next ›')) {
      $rel_next = TRUE;
      drupal_add_html_head_link(array(
        'rel' => 'next',
        'href' => url($link['href'], array(
          'query' => $link['query'],
          'absolute' => TRUE,
        )),
      ));
    }
  }

  // Check if an array or the html should be returned.
  if (!isset($variables['return_link_array'])) {
    global $theme_key;
    $themes = list_themes();
    $variables['return_link_array'] = _cleanpager_is_array_theme($themes, $theme_key);
  }
  if ($variables['return_link_array']) {
    return $link;
  }
  return l($link['title'], $link['href'], array(
    'attributes' => $link['attributes'],
    'query' => $link['query'],
  ));
}

/**
 * Determine if the theme needs an array instead of a link.
 */
function _cleanpager_is_array_theme($themes, $theme_key) {

  // check if the given theme needs an array rather than an html string
  if (in_array($theme_key, variable_get('cleanpager_array_themes', array(
    'tao',
  )))) {
    return TRUE;
  }
  $theme_object = $themes[$theme_key];

  // Check the base theme.
  if (isset($theme_object->info) && !empty($theme_object->info['base theme'])) {
    return _cleanpager_is_array_theme($themes, $theme_object->info['base theme']);
  }
  return FALSE;
}

/**
 * Implementation of hook_theme_registry_alter().
 */
function cleanpager_theme_registry_alter(&$theme_registry) {

  // Kill the next/previous forum topic navigation links.
  if ($theme_registry['pager_link']['function'] == 'theme_pager_link') {
    $theme_registry['pager_link']['function'] = 'cleanpager_theme_pager_link';
  }
}

/**
 * Remove number at end of path
 */
function _cleanpager_rewrite_path(&$pager = FALSE, &$page = NULL) {
  static $q, $pr, $p;
  global $_cleanpager_rewritten;
  if (!isset($q)) {
    $_cleanpager_rewritten = FALSE;
    $q = _cleanpager_get_q();
    $p = 0;
    $pr = FALSE;
    $q_array = explode('/', $q);
    if (_cleanpager_is_pager_element(end($q_array))) {
      $p = array_pop($q_array);

      // Check for page/page_number
      if (variable_get('cleanpager_use_additional_path', TRUE)) {
        if (end($q_array) == CLEANPAGER_ADDITIONAL_PATH_VARIABLE) {
          array_pop($q_array);
          $pr = TRUE;
        }
      }
      else {
        $pr = TRUE;
      }
      if ($pr) {

        // Store that the $_REQUEST and $_GET were rewritten.
        $_cleanpager_rewritten = TRUE;
        $q = implode('/', $q_array);
        if (arg(0) == 'views' && arg(1) == 'ajax' && !empty($_POST['view_path'])) {
          $_POST['view_path'] = $q;
          $_POST['view_args'] = '';
          $_POST['pager_element'] = $p;
        }
        else {
          $_REQUEST['q'] = $_GET['q'] = $q;
        }
        $_REQUEST['page'] = $_GET['page'] = $p;
      }
    }
  }
  $page = $p;
  $pager = $pr;
  return $q;
}

/**
 * Determine if the given string a 'page' value.
 */
function _cleanpager_is_pager_element($value) {
  if (is_numeric($value)) {
    return TRUE;
  }

  // Handle multiple pagers (i.e. 0,0,1,0);
  $parts = explode(',', $value);
  foreach ($parts as $p) {
    if (!is_numeric($p)) {
      return FALSE;
    }
  }
  return TRUE;
}

Functions

Namesort descending Description
cleanpager_admin_settings Defines admin settings form
cleanpager_boot Implements hook_boot().
cleanpager_check_match Checks if the page should use clean pagination
cleanpager_init Implements hook_init().
cleanpager_match_path Wrapper for drupal_match_path() to correctly handle the front page.
cleanpager_menu Implementation of hook_menu()
cleanpager_path Remove number at end of path
cleanpager_permission Implements hook_permission().
cleanpager_theme_pager_link Override theme for a pager link
cleanpager_theme_registry_alter Implementation of hook_theme_registry_alter().
_cleanpager_generate_current_page_url Generate the current page url with page.
_cleanpager_get_q Helper function to get the query string. Handles views ajax.
_cleanpager_is_array_theme Determine if the theme needs an array instead of a link.
_cleanpager_is_pager_element Determine if the given string a 'page' value.
_cleanpager_rewrite_path Remove number at end of path

Constants