You are here

xmlsitemap.module in XML sitemap 6

Creates a sitemap compatible with the sitemaps.org schema.

File

xmlsitemap.module
View source
<?php

/**
 * @file
 * Creates a sitemap compatible with the sitemaps.org schema.
 */

/**
 * @addtogroup xmlsitemap
 * @{
 */

/*****************************************************************************
 * Public constants.
 ****************************************************************************/

/**
 * The date format used in the sitemap.
 */
if (!defined('DATE_W3C')) {
  define('DATE_W3C', 'Y-m-d\\TH:i:s+00:00');
}

/**
 * The timestamp of server request to avoid repeatedly generating value.
 */
if (!defined('REQUEST_TIME')) {
  if (isset($_SERVER['REQUEST_TIME'])) {
    define('REQUEST_TIME', $_SERVER['REQUEST_TIME']);
  }
  else {
    define('REQUEST_TIME', time());
  }
}

/**
 * The flag set when a sitemap link is not enabled.
 */
define('XMLSITEMAP_LINK_DISABLED', 1);

/**
 * The maximum number of links in one sitemap chunk file.
 */
define('XMLSITEMAP_MAX_SITEMAP_LINKS', 50000);

/**
 * The maximum filesize of a sitemap chunk file.
 */
define('XMLSITEMAP_MAX_SITEMAP_FILESIZE', 10485760);

/**
 * The maximum number of links in one sitemap index file.
 */
define('XMLSITEMAP_MAX_SITEMAP_INDEX_LINKS', 1000);

/**
 * The default number of links in one sitemap chunk file.
 */
define('XMLSITEMAP_DEFAULT_SITEMAP_LINKS', 1000);

/*****************************************************************************
 * Drupal hooks.
 ****************************************************************************/

/**
 * Implementation of hook_form_alter().
 */
function xmlsitemap_form_alter(&$form, &$form_state, $form_id) {
  switch ($form_id) {
    case 'locale_languages_configure_form':
    case 'path_admin_form':
    case 'pathauto_admin_settings':
    case 'system_clean_url_settings':
      $form['#submit'][] = 'xmlsitemap_settings_submit';
      break;
  }
}

/**
 * Implementation of hook_help().
 */
function xmlsitemap_help($path, $arg) {
  switch ($path) {
    case 'admin/settings/xmlsitemap':
    case 'admin/settings/xmlsitemap/engines':
      $output = t('The sitemap is located at <a href="@sitemap">@sitemap</a>.', array(
        '@sitemap' => url('sitemap.xml', array(
          'absolute' => TRUE,
        )),
      ));
      break;
    case 'admin/help#xmlsitemap':
      $output = '<p>' . t('XML sitemap automatically creates a sitemap that conforms to the <a href="@sitemaps.org">sitemaps.org specification</a>. This helps search engines keep their search results up to date.', array(
        '@sitemaps.org' => 'http://www.sitemaps.org',
      )) . '</p>';
      $output .= '<h3>' . t('Supporting modules') . '</h3>';
      $output .= '<p>' . t('By itself, the XML sitemap module adds only the front page of your site to the sitemap. Other types of links are handled by supporting modules.') . '</p>';
      $optional = '';
      foreach (module_implements('xmlsitemap_description', TRUE) as $module) {
        $function = $module . '_xmlsitemap_description';
        $optional .= $function();
      }
      if (!empty($optional)) {
        $output .= "<dl>{$optional}</dl>";
      }
      $output .= '<p>' . t('Links may be assigned a priority between 0.0 and 1.0. The default priority is 0.5. A priority of <em>Not in sitemap</em> excludes a link from the sitemap.') . '</p>';
      $output .= '<p>' . t('For more information, see the online handbook entry for <a href="@xmlsitemap">XML sitemap module</a>.', array(
        '@xmlsitemap' => 'http://drupal.org/handbook/modules/gsitemap',
      )) . '</p>';
      break;
    default:
      $output = '';
      break;
  }
  return $output;
}

/**
 * Implementation of hook_menu().
 */
function xmlsitemap_menu() {
  $items = array();
  $access_config = array(
    'administer site configuration',
  );
  $access_content = array(
    'access content',
  );
  $items['admin/settings/xmlsitemap'] = array(
    'title' => 'XML sitemap',
    'description' => 'Configure the XML sitemap.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'xmlsitemap_settings',
    ),
    'access arguments' => $access_config,
    'file' => 'xmlsitemap.admin.inc',
  );
  $items['admin/settings/xmlsitemap/sitemap'] = array(
    'title' => 'Sitemap',
    'description' => 'Configure the XML sitemap.',
    'weight' => -1,
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'file' => 'xmlsitemap.admin.inc',
  );
  $items['admin/settings/xmlsitemap/tools'] = array(
    'title' => 'Tools',
    'description' => 'Sitemap tools.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'xmlsitemap_tools',
    ),
    'access arguments' => $access_config,
    'type' => MENU_LOCAL_TASK,
    'file' => 'xmlsitemap.admin.inc',
  );
  $items['sitemap.xml'] = array(
    'title' => 'Sitemap index',
    'page callback' => 'xmlsitemap_output',
    'access arguments' => $access_content,
    'type' => MENU_CALLBACK,
    'file' => 'xmlsitemap.pages.inc',
  );
  $chunk_size = variable_get('xmlsitemap_chunk_size', XMLSITEMAP_DEFAULT_SITEMAP_LINKS);
  $link_count = xmlsitemap_link_count();
  if ($link_count > $chunk_size) {
    for ($chunk = 0; $chunk < $link_count / $chunk_size; ++$chunk) {
      $items["sitemap{$chunk}.xml"] = array(
        'title' => 'Sitemap !number',
        'title arguments' => array(
          '!number' => $chunk,
        ),
        'page callback' => 'xmlsitemap_output',
        'page arguments' => array(
          (string) $chunk,
        ),
        'access arguments' => $access_content,
        'type' => MENU_CALLBACK,
        'file' => 'xmlsitemap.pages.inc',
      );
    }
  }
  $items['sitemap.xsl'] = array(
    'page callback' => 'xmlsitemap_output_xsl',
    'access arguments' => $access_content,
    'type' => MENU_CALLBACK,
    'file' => 'xmlsitemap.pages.inc',
  );
  return $items;
}

/**
 * Implementation of hook_perm().
 */
function xmlsitemap_perm() {
  return array(
    'override node settings',
    'override profile settings',
  );
}

/**
 * Implementation of hook_robotstxt().
 */
function xmlsitemap_robotstxt() {
  return array(
    "Sitemap: " . url('sitemap.xml', array(
      'absolute' => TRUE,
    )),
  );
}

/**
 * Implementation of hook_xmlsitemap_operations().
 */
function xmlsitemap_xmlsitemap_operations() {
  return array(
    'delete_cache_files' => array(
      'label' => t('Delete the sitemap cache files'),
      'callback' => 'xmlsitemap_delete_cache_files',
    ),
    'flag_sitemap' => array(
      'label' => t('Flag the sitemap as requiring update'),
      'callback' => 'xmlsitemap_flag_sitemap',
    ),
  );
}

/*****************************************************************************
 * Public functions.
 ****************************************************************************/

/**
 * Batch callback called when the batch operations are completed.
 */
function xmlsitemap_batch_operations_finished($success, $results, $operations) {
  if ($success) {
    drupal_set_message(t('The update has been performed.'));
  }
  else {
    drupal_set_message(t('An error occurred and processing did not complete.'), 'error');
    $message = format_plural($count = count($results), '1 item successfully processed.', '@count items successfully processed.');
    if ($count) {
      $message .= theme('item_list', $results, t('Last items successfully processed:'));
    }
    drupal_set_message($message);
  }
}

/**
 * Return the language string used to identify the cache file for the sitemap
 * content.
 */
function xmlsitemap_language_id() {
  global $language;
  return isset($language->language) ? $language->language : language_default('language');
}

/**
 * Return the array for the cron limit options.
 */
function xmlsitemap_cron_options() {
  return array(
    '2000' => t('2000 rows'),
    '1500' => t('1500 rows'),
    '1000' => t('1000 rows'),
    '500' => t('500 rows'),
    '250' => t('250 rows'),
    '100' => t('100 rows'),
    '50' => t('50 rows'),
    '25' => t('25 rows'),
    '20' => t('20 rows'),
    '15' => t('15 rows'),
    '10' => t('10 rows'),
    '5' => t('5 rows'),
    '-1' => t('Do not process via cron'),
  );
}

/**
 * Delete the cache file used for the sitemap content, and mark the sitemap as
 * changed.
 */
function xmlsitemap_delete_cache_files() {
  $parent_directory = variable_get('xmlsitemap_cache_directory', file_directory_path() . '/xmlsitemap');
  if (!is_dir($parent_directory)) {
    return;
  }
  file_scan_directory($parent_directory, 'xsm-.*\\.xml', array(
    '.',
    '..',
    'CVS',
  ), 'file_delete', FALSE);
  xmlsitemap_flag_sitemap();
  return;
}

/**
 * Mark the sitemap as changed, and the cache as needing update.
 */
function xmlsitemap_flag_sitemap() {
  if (!variable_get('xmlsitemap_sitemap_is_changed', FALSE)) {
    variable_set('xmlsitemap_sitemap_is_changed', TRUE);
  }
  if (!variable_get('xmlsitemap_sitemap_needs_update', FALSE)) {
    variable_set('xmlsitemap_sitemap_needs_update', TRUE);
  }
}

/**
 * Return the number of links present in xmlsitemap table.
 */
function xmlsitemap_link_count() {
  static $link_count;
  if (!isset($link_count)) {
    $link_count = db_result(db_query("SELECT COUNT(xsm.loc)" . xmlsitemap_sitemap_query()));
  }
  return $link_count;
}

/**
 * Return the number of chunk files.
 */
function xmlsitemap_chunk_count() {
  $link_count = xmlsitemap_link_count();
  $chunk_size = variable_get('xmlsitemap_chunk_size', XMLSITEMAP_DEFAULT_SITEMAP_LINKS);
  return ceil($link_count / $chunk_size);
}

/**
 * Return an array of sitemap priority options.
 *
 * @param $option
 *  If not given, the array will include priority values from 0.0 to 1.0.
 * - exclude: Add option to exclude item from sitemap.
 * - default: Add option to use default priority. Only for cases where a
 *   default priority exists.
 * - both: Add both the default and exclude options.
 *
 * @return
 *  An array of priority options.
 */
function xmlsitemap_priority_options($option = '') {
  $options = array(
    '1' => t('1.0'),
    '0.9' => t('0.9'),
    '0.8' => t('0.8'),
    '0.7' => t('0.7'),
    '0.6' => t('0.6'),
    '0.5' => t('0.5'),
    '0.4' => t('0.4'),
    '0.3' => t('0.3'),
    '0.2' => t('0.2'),
    '0.1' => t('0.1'),
    '0' => t('0.0'),
  );
  if ($option == 'exclude' || $option == 'both') {
    $options['-1'] = t('Not in sitemap');
  }
  if ($option == 'default' || $option == 'both') {
    $options['-2'] = t('Default');
  }
  return $options;
}

/**
 * Determine the frequency of updates to a link.
 *
 * @param $interval
 *  The number of seconds since the last change, or the number of seconds
 *  between the last change, and the previous change.
 *
 * @return
 *  A string representing the update frequency according to the sitemaps.org
 *  protocol.
 */
function xmlsitemap_sitemap_frequency($interval) {
  $frequencies = array(
    'always' => 3600,
    'hourly' => 86400,
    'daily' => 604800,
    'weekly' => 2419200,
    'monthly' => 29030400,
    'yearly' => 100000000,
  );
  if ($interval < 0 || !is_numeric($interval)) {
    return 'never';
  }
  foreach ($frequencies as $frequency => $value) {
    if ($interval < $value) {
      break;
    }
  }
  return $frequency;
}

/**
 * Complete the query used to select rows from the xmlsitemap table.
 */
function xmlsitemap_sitemap_query() {
  global $language;
  $default = language_default();
  $language_query = "AND xsm.language IN ('" . $language->language . "', '')";
  switch (variable_get('language_negotiation', LANGUAGE_NEGOTIATION_NONE)) {
    case LANGUAGE_NEGOTIATION_NONE:
      $language_query = '';
      break;
    case LANGUAGE_NEGOTIATION_PATH_DEFAULT:
    case LANGUAGE_NEGOTIATION_PATH:
      if (variable_get('xmlsitemap_all_links_to_default_language', 0) && $language->language == $default->language) {
        $language_query = '';
      }
      break;
  }
  return "\n    FROM {xmlsitemap} xsm\n    INNER JOIN {system} s ON s.name = xsm.module\n    WHERE s.type = 'module'\n      AND s.status = 1\n      AND xsm.changefreq <> 0\n      AND xsm.changed <> 0\n      {$language_query}\n      AND (xsm.priority >= 0 AND xsm.priority <= 1)\n    ";
}

/**
 * Return an array used to add additional form fields in the user form.
 */
function xmlsitemap_user_form_fieldset() {
  static $done = FALSE;
  $form = array();
  if (!$done) {
    $form['xmlsitemap'] = array(
      '#type' => 'fieldset',
      '#title' => t('XML sitemap'),
      '#collapsible' => TRUE,
      '#access' => user_access('override profile settings') || user_access('administer users'),
      '#weight' => 7,
    );
    $done = TRUE;
  }
  return $form;
}

/**
 * @} End of "addtogroup xmlsitemap".
 */

Functions

Namesort descending Description
xmlsitemap_batch_operations_finished Batch callback called when the batch operations are completed.
xmlsitemap_chunk_count Return the number of chunk files.
xmlsitemap_cron_options Return the array for the cron limit options.
xmlsitemap_delete_cache_files Delete the cache file used for the sitemap content, and mark the sitemap as changed.
xmlsitemap_flag_sitemap Mark the sitemap as changed, and the cache as needing update.
xmlsitemap_form_alter Implementation of hook_form_alter().
xmlsitemap_help Implementation of hook_help().
xmlsitemap_language_id Return the language string used to identify the cache file for the sitemap content.
xmlsitemap_link_count Return the number of links present in xmlsitemap table.
xmlsitemap_menu Implementation of hook_menu().
xmlsitemap_perm Implementation of hook_perm().
xmlsitemap_priority_options Return an array of sitemap priority options.
xmlsitemap_robotstxt Implementation of hook_robotstxt().
xmlsitemap_sitemap_frequency Determine the frequency of updates to a link.
xmlsitemap_sitemap_query Complete the query used to select rows from the xmlsitemap table.
xmlsitemap_user_form_fieldset Return an array used to add additional form fields in the user form.
xmlsitemap_xmlsitemap_operations Implementation of hook_xmlsitemap_operations().

Constants

Namesort descending Description
XMLSITEMAP_DEFAULT_SITEMAP_LINKS The default number of links in one sitemap chunk file.
XMLSITEMAP_LINK_DISABLED The flag set when a sitemap link is not enabled.
XMLSITEMAP_MAX_SITEMAP_FILESIZE The maximum filesize of a sitemap chunk file.
XMLSITEMAP_MAX_SITEMAP_INDEX_LINKS The maximum number of links in one sitemap index file.
XMLSITEMAP_MAX_SITEMAP_LINKS The maximum number of links in one sitemap chunk file.