home | career | drupal | java | mac | mysql | perl | php | scala | uml | unix

Drupal example source code file (xmlsitemap.module)

This example Drupal source code file (xmlsitemap.module) is included in the DevDaily.com "Drupal Source Code Warehouse" project. The intent of this project is to help you "Learn Drupal by Example".

PHP - Drupal tags/keywords

array, bundle, directory, false, file, foreach, function, if, isset, php, return, sitemap, true, variable

The xmlsitemap.module Drupal example source code

<?php
// $Id: xmlsitemap.module,v 1.104 2011/02/09 21:45:59 davereid Exp $

/**
 * @defgroup xmlsitemap XML sitemap
 */

/**
 * @file
 * Main file for the xmlsitemap module.
 */

/**
 * 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);

define('XMLSITEMAP_FREQUENCY_YEARLY', 31449600); // 60 * 60 * 24 * 7 * 52
define('XMLSITEMAP_FREQUENCY_MONTHLY', 2419200); // 60 * 60 * 24 * 7 * 4
define('XMLSITEMAP_FREQUENCY_WEEKLY', 604800); // 60 * 60 * 24 * 7
define('XMLSITEMAP_FREQUENCY_DAILY', 86400); // 60 * 60 * 24
define('XMLSITEMAP_FREQUENCY_HOURLY', 3600); // 60 * 60
define('XMLSITEMAP_FREQUENCY_ALWAYS', 60);

/**
 * Short lastmod timestamp format.
 */
define('XMLSITEMAP_LASTMOD_SHORT', 'Y-m-d');

/**
 * Medium lastmod timestamp format.
 */
define('XMLSITEMAP_LASTMOD_MEDIUM', 'Y-m-d\TH:i\Z');

/**
 * Long lastmod timestamp format.
 */
define('XMLSITEMAP_LASTMOD_LONG', 'c');

/**
 * The default inclusion status for link types in the sitemaps.
 */
define('XMLSITEMAP_STATUS_DEFAULT', 0);

/**
 * The default priority for link types in the sitemaps.
 */
define('XMLSITEMAP_PRIORITY_DEFAULT', 0.5);

/**
 * Implements hook_hook_info().
 */
function xmlsitemap_hook_info() {
  $hooks = array(
    'xmlsitemap_link_info',
    'xmlsitemap_link_info_alter',
    'xmlsitemap_link_alter',
    'xmlsitemap_index_links',
    'xmlsitemap_context_info',
    'xmlsitemap_context_info_alter',
    'xmlsitemap_context_url_options',
    'xmlsitemap_context',
    'xmlsitemap_sitemap_insert',
    'xmlsitemap_sitemap_update',
    'xmlsitemap_sitemap_operations',
    'xmlsitemap_sitemap_delete',
    'xmlsitemap_sitemap_link_url_options_alter',
    'query_xmlsitemap_generate_alter',
    'query_xmlsitemap_link_bundle_access_alter',
    'form_xmlsitemap_sitemap_edit_form_alter',
  );

  $hooks = array_combine($hooks, $hooks);
  foreach ($hooks as $hook => $info) {
    $hooks[$hook] = array('group' => 'xmlsitemap');
  }

  return $hooks;
}

/**
 * Implements hook_help().
 */
function xmlsitemap_help($path, $arg) {
  $output = '';

  switch ($path) {
    case 'admin/help/xmlsitemap':
    case 'admin/config/search/xmlsitemap/settings/%/%/%':
    case 'admin/config/search/xmlsitemap/edit/%':
    case 'admin/config/search/xmlsitemap/delete/%':
      return;
    case 'admin/help#xmlsitemap':
      break;
    case 'admin/config/search/xmlsitemap':
      break;
    case 'admin/config/search/xmlsitemap/rebuild':
      $output .= '<p>' . t("This action rebuilds your site's XML sitemap and regenerates the cached files, and may be a lengthy process. If you just installed XML sitemap, this can be helpful to import all your site's content into the sitemap. Otherwise, this should only be used in emergencies.") . '</p>';
  }

  if (arg(0) == 'admin' && strpos($path, 'xmlsitemap') !== FALSE && user_access('administer xmlsitemap')) {
    module_load_include('inc', 'xmlsitemap');
    if ($arg[1] == 'config') {
      // Alert the user to any potential problems detected by hook_requirements.
      xmlsitemap_check_status();
    }
    $output .= _xmlsitemap_get_blurb();
  }

  return $output;
}

/**
 * Implements hook_perm().
 */
function xmlsitemap_permission() {
  $permissions['administer xmlsitemap'] = array(
    'title' => t('Administer XML sitemap settings.'),
  );
  return $permissions;
}

/**
 * Implements hook_menu().
 */
function xmlsitemap_menu() {
  $items['admin/config/search/xmlsitemap'] = array(
    'title' => 'XML sitemap',
    'description' => "Configure your site's XML sitemaps to help search engines find and index pages on your site.",
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_sitemap_list_form'),
    'access arguments' => array('administer xmlsitemap'),
    'file' => 'xmlsitemap.admin.inc',
  );
  $items['admin/config/search/xmlsitemap/list'] = array(
    'title' => 'List',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/config/search/xmlsitemap/add'] = array(
    'title' => 'Add new XML sitemap',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_sitemap_edit_form'),
    'access arguments' => array('administer xmlsitemap'),
    'type' => MENU_LOCAL_ACTION,
    'file' => 'xmlsitemap.admin.inc',
    'modal' => TRUE,
    'options' => array('modal' => TRUE),
  );
  $items['admin/config/search/xmlsitemap/edit/%xmlsitemap_sitemap'] = array(
    'title' => 'Edit XML sitemap',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_sitemap_edit_form', 5),
    'access arguments' => array('administer xmlsitemap'),
    'file' => 'xmlsitemap.admin.inc',
    'modal' => TRUE,
  );
  $items['admin/config/search/xmlsitemap/delete/%xmlsitemap_sitemap'] = array(
    'title' => 'Delete XML sitemap',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_sitemap_delete_form', 5),
    'access arguments' => array('administer xmlsitemap'),
    'file' => 'xmlsitemap.admin.inc',
    'modal' => TRUE,
  );

  $items['admin/config/search/xmlsitemap/settings'] = array(
    'title' => 'Settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_settings_form'),
    'access arguments' => array('administer xmlsitemap'),
    'type' => MENU_LOCAL_TASK,
    'file' => 'xmlsitemap.admin.inc',
    'weight' => 10,
  );
  $items['admin/config/search/xmlsitemap/settings/%xmlsitemap_link_bundle/%'] = array(
    'load arguments' => array(6),
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_link_bundle_settings_form', 5),
    'access callback' => 'xmlsitemap_link_bundle_access',
    'access arguments' => array(5),
    'file' => 'xmlsitemap.admin.inc',
    'modal' => TRUE,
  );

  $items['admin/config/search/xmlsitemap/rebuild'] = array(
    'title' => 'Rebuild links',
    'description' => 'Rebuild the site map.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xmlsitemap_rebuild_form'),
    'access callback' => '_xmlsitemap_rebuild_form_access',
    'type' => MENU_LOCAL_TASK,
    'file' => 'xmlsitemap.admin.inc',
    'weight' => 20,
  );

  $items['sitemap.xml'] = array(
    'page callback' => 'xmlsitemap_output_chunk',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'file' => 'xmlsitemap.pages.inc',
  );
  $items['sitemap.xsl'] = array(
    'page callback' => 'xmlsitemap_output_xsl',
    'access callback' => TRUE,
    'type' => MENU_CALLBACK,
    'file' => 'xmlsitemap.pages.inc',
  );

  return $items;
}

/**
 * Menu access callback; determines if the user can use the rebuild links page.
 */
function _xmlsitemap_rebuild_form_access() {
  module_load_include('generate.inc', 'xmlsitemap');
  $rebuild_types = xmlsitemap_get_rebuildable_link_types();
  return !empty($rebuild_types) && user_access('administer xmlsitemap');
}

/**
 * Implements hook_cron().
 *
 * @todo Use new Queue system. Need to add {sitemap}.queued.
 * @todo Regenerate one at a time?
 */
function xmlsitemap_cron() {
  // If there were no new or changed links, skip.
  if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
    return;
  }

  // If the minimum sitemap lifetime hasn't been passed, skip.
  $lifetime = REQUEST_TIME - variable_get('xmlsitemap_generated_last', 0);
  if ($lifetime < variable_get('xmlsitemap_minimum_lifetime', 0)) {
    return;
  }

  // Regenerate the sitemap XML files.
  module_load_include('generate.inc', 'xmlsitemap');
  xmlsitemap_run_unprogressive_batch('xmlsitemap_regenerate_batch');
}

/**
 * Implements hook_modules_enabled().
 */
function xmlsitemap_modules_enabled(array $modules) {
  cache_clear_all('xmlsitemap:', 'cache', TRUE);
}

/**
 * Implements hook_modules_disabled().
 */
function xmlsitemap_modules_disabled(array $modules) {
  cache_clear_all('xmlsitemap:', 'cache', TRUE);
}

/**
 * Implements hook_robotstxt().
 */
function xmlsitemap_robotstxt() {
  if ($sitemap = xmlsitemap_sitemap_load_by_context()) {
    $robotstxt[] = 'Sitemap: ' . url($sitemap->uri['path'], $sitemap->uri['options']);
    return $robotstxt;
  }
}

/**
 * Internal default variables for xmlsitemap_var().
 */
function xmlsitemap_variables() {
  return array(
    'xmlsitemap_rebuild_needed' => FALSE,
    'xmlsitemap_regenerate_needed' => FALSE,
    'xmlsitemap_minimum_lifetime' => 0,
    'xmlsitemap_generated_last' => 0,
    'xmlsitemap_xsl' => 1,
    'xmlsitemap_prefetch_aliases' => 1,
    'xmlsitemap_chunk_size' => 'auto',
    'xmlsitemap_batch_limit' => 100,
    'xmlsitemap_path' => 'xmlsitemap',
    'xmlsitemap_base_url' => $GLOBALS['base_url'],
    'xmlsitemap_developer_mode' => 0,
    'xmlsitemap_frontpage_priority' => 1.0,
    'xmlsitemap_frontpage_changefreq' => XMLSITEMAP_FREQUENCY_DAILY,
    'xmlsitemap_lastmod_format' => XMLSITEMAP_LASTMOD_MEDIUM,
    'xmlsitemap_gz' => FALSE,
    // Removed variables are set to NULL so they can still be deleted.
    'xmlsitemap_regenerate_last' => NULL,
    'xmlsitemap_custom_links' => NULL,
    'xmlsitemap_priority_default' => NULL,
    'xmlsitemap_languages' => NULL,
    'xmlsitemap_max_chunks' => NULL,
    'xmlsitemap_max_filesize' => NULL,
  );
}

/**
 * Internal implementation of variable_get().
 */
function xmlsitemap_var($name, $default = NULL) {
  $defaults = &drupal_static(__FUNCTION__);
  if (!isset($defaults)) {
    $defaults = xmlsitemap_variables();
  }

  $name = 'xmlsitemap_' . $name;

  // @todo Remove when stable.
  if (!isset($defaults[$name])) {
    trigger_error(strtr('Default variable for %variable not found.', array('%variable' => drupal_placeholder($name))));
  }

  return variable_get($name, isset($default) || !isset($defaults[$name]) ? $default : $defaults[$name]);
}

/**
 * @defgroup xmlsitemap_api XML sitemap API.
 * @{
 * This is the XML sitemap API to be used by modules wishing to work with
 * XML sitemap and/or link data.
 */

/**
 * Load an XML sitemap array from the database.
 *
 * @param $smid
 *   An XML sitemap ID.
 *
 * @return
 *   The XML sitemap object.
 */
function xmlsitemap_sitemap_load($smid) {
  $sitemap = xmlsitemap_sitemap_load_multiple(array($smid));
  return $sitemap ? reset($sitemap) : FALSE;
}

/**
 * Load multiple XML sitemaps from the database.
 *
 * @param $smids
 *   An array of XML sitemap IDs, or FALSE to load all XML sitemaps.
 * @param $conditions
 *   An array of conditions in the form 'field' => $value.
 *
 * @return
 *   An array of XML sitemap objects.
 */
function xmlsitemap_sitemap_load_multiple($smids = array(), array $conditions = array()) {
  if ($smids !== FALSE) {
    $conditions['smid'] = $smids;
  }

  $query = db_select('xmlsitemap_sitemap');
  $query->fields('xmlsitemap_sitemap');
  foreach ($conditions as $field => $value) {
    $query->condition($field, $value);
  }

  $sitemaps = $query->execute()->fetchAllAssoc('smid');
  foreach ($sitemaps as $smid => $sitemap) {
    $sitemaps[$smid]->context = unserialize($sitemap->context);
    $sitemaps[$smid]->uri = xmlsitemap_sitemap_uri($sitemaps[$smid]);
  }

  return $sitemaps;
}

/**
 * Load an XML sitemap array from the database based on its context.
 *
 * @param $context
 *   An optional XML sitemap context array to use to find the correct XML
 *   sitemap. If not provided, the current site's context will be used.
 *
 * @see xmlsitemap_get_current_context()
 */
function xmlsitemap_sitemap_load_by_context(array $context = NULL) {
  if (!isset($context)) {
    $context = xmlsitemap_get_current_context();
  }
  $hash = xmlsitemap_sitemap_get_context_hash($context);
  $smid = db_query_range("SELECT smid FROM {xmlsitemap_sitemap} WHERE smid = :hash", 0, 1, array(':hash' => $hash))->fetchField();
  return xmlsitemap_sitemap_load($smid);
}

/**
 * Save changes to an XML sitemap or add a new XML sitemap.
 *
 * @param $sitemap
 *   The XML sitemap array to be saved. If $sitemap->smid is omitted, a new
 *   XML sitemap will be added.
 *
 * @todo Save the sitemap's URL as a column?
 */
function xmlsitemap_sitemap_save(stdClass $sitemap) {
  if (!isset($sitemap->context)) {
    $sitemap->context = array();
  }

  // Make sure context is sorted before saving the hash.
  $sitemap->is_new = empty($sitemap->smid);
  $sitemap->old_smid = $sitemap->is_new ? NULL : $sitemap->smid;
  $sitemap->smid = xmlsitemap_sitemap_get_context_hash($sitemap->context);

  // If the context was changed, we need to perform additional actions.
  if (!$sitemap->is_new && $sitemap->smid != $sitemap->old_smid) {
    // Rename the files directory so the sitemap does not break.
    $old_sitemap = (object) array('smid' => $sitemap->old_smid);
    $old_dir = xmlsitemap_get_directory($old_sitemap);
    $new_dir = xmlsitemap_get_directory($sitemap);
    xmlsitemap_directory_move($old_dir, $new_dir);

    // Change the smid field so drupal_write_record() does not fail.
    db_update('xmlsitemap_sitemap')
      ->fields(array('smid' => $sitemap->smid))
      ->condition('smid', $sitemap->old_smid)
      ->execute();

    // Mark the sitemaps as needing regeneration.
    variable_set('xmlsitemap_regenerate_needed', TRUE);
  }

  if ($sitemap->is_new) {
    drupal_write_record('xmlsitemap_sitemap', $sitemap);
    module_invoke_all('xmlsitemap_sitemap_insert', $sitemap);
  }
  else {
    drupal_write_record('xmlsitemap_sitemap', $sitemap, array('smid'));
    module_invoke_all('xmlsitemap_sitemap_update', $sitemap);
  }

  return $sitemap;
}

/**
 * Delete an XML sitemap.
 *
 * @param $smid
 *   An XML sitemap ID.
 */
function xmlsitemap_sitemap_delete($smid) {
  xmlsitemap_sitemap_delete_multiple(array($smid));
}

/**
 * Delete multiple XML sitemaps.
 *
 * @param $smids
 *   An array of XML sitemap IDs.
 */
function xmlsitemap_sitemap_delete_multiple(array $smids) {
  if (!empty($smids)) {
    $sitemaps = xmlsitemap_sitemap_load_multiple($smids);
    db_delete('xmlsitemap_sitemap')
        ->condition('smid', $smids)
        ->execute();

    foreach ($sitemaps as $sitemap) {
      xmlsitemap_clear_directory($sitemap, TRUE);
      module_invoke_all('xmlsitemap_sitemap_delete', $sitemap);
    }
  }
}

/**
 * Return the expected file path for a specific sitemap chunk.
 *
 * @param $sitemap
 *   An XML sitemap array.
 * @param $chunk
 *   An optional specific chunk in the sitemap. Defaults to the index page.
 */
function xmlsitemap_sitemap_get_file(stdClass $sitemap, $chunk = 'index') {
  return xmlsitemap_get_directory($sitemap) . "/{$chunk}.xml";
}

/**
 * Find the maximum file size of all a sitemap's XML files.
 *
 * @param $sitemap
 *   The XML sitemap array.
 */
function xmlsitemap_sitemap_get_max_filesize(stdClass $sitemap) {
  $dir = xmlsitemap_get_directory($sitemap);
  $sitemap->max_filesize = 0;
  foreach (file_scan_directory($dir, '/\.xml$/') as $file) {
    $sitemap->max_filesize = max($sitemap->max_filesize, filesize($file->uri));
  }
  return $sitemap->max_filesize;
}

function xmlsitemap_sitemap_get_context_hash(array &$context) {
  asort($context);
  return drupal_hash_base64(serialize($context));
}

/**
 * Returns the uri elements of an XML sitemap.
 *
 * @param $sitemap
 *   An unserialized data array for an XML sitemap.
 * @return
 *   An array containing the 'path' and 'options' keys used to build the uri of
 *   the XML sitemap, and matching the signature of url().
 */
function xmlsitemap_sitemap_uri(stdClass $sitemap) {
  $uri['path'] = 'sitemap.xml';
  $uri['options'] = module_invoke_all('xmlsitemap_context_url_options', $sitemap->context);
  drupal_alter('xmlsitemap_context_url_options', $uri['options'], $sitemap->context);
  $uri['options'] += array(
    'absolute' => TRUE,
    'base_url' => variable_get('xmlsitemap_base_url', $GLOBALS['base_url']),
  );
  return $uri;
}

/**
 * Load a specific sitemap link from the database.
 *
 * @param $entity_type
 *   A string with the entity type.
 * @param $entity_id
 *   An integer with the entity ID.
 * @return
 *   A sitemap link (array) or FALSE if the conditions were not found.
 */
function xmlsitemap_link_load($entity_type, $entity_id) {
  $link = xmlsitemap_link_load_multiple(array('type' => $entity_type, 'id' => $entity_id));
  return $link ? reset($link) : FALSE;
}

/**
 * Load sitemap links from the database.
 *
 * @param $conditions
 *   An array of conditions on the {xmlsitemap} table in the form
 *   'field' => $value.
 * @return
 *   An array of sitemap link arrays.
 */
function xmlsitemap_link_load_multiple(array $conditions = array()) {
  $query = db_select('xmlsitemap');
  $query->fields('xmlsitemap');

  foreach ($conditions as $field => $value) {
    $query->condition($field, $value);
  }

  $links = $query->execute()->fetchAll(PDO::FETCH_ASSOC);

  return $links;
}

/**
 * Saves or updates a sitemap link.
 *
 * @param $link
 *   An array with a sitemap link.
 */
function xmlsitemap_link_save(array $link) {
  $link += array(
    'access' => 1,
    'status' => 1,
    'status_override' => 0,
    'lastmod' => 0,
    'priority' => XMLSITEMAP_PRIORITY_DEFAULT,
    'priority_override' => 0,
    'changefreq' => 0,
    'changecount' => 0,
    'language' => LANGUAGE_NONE,
  );

  // Allow other modules to alter the link before saving.
  drupal_alter('xmlsitemap_link', $link);

  // Temporary validation checks.
  // @todo Remove in final?
  if ($link['priority'] < 0 || $link['priority'] > 1) {
    trigger_error(t('Invalid sitemap link priority %priority.<br />@link', array('%priority' => $link['priority'], '@link' => var_export($link, TRUE))), E_USER_ERROR);
  }
  if ($link['changecount'] < 0) {
    trigger_error(t('Negative changecount value. Please report this to <a href="@516928">@516928</a>.<br />@link', array('@516928' => 'http://drupal.org/node/516928', '@link' => var_export($link, TRUE))), E_USER_ERROR);
    $link['changecount'] = 0;
  }

  $existing = db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = :type AND id = :id", 0, 1, array(':type' => $link['type'], ':id' => $link['id']))->fetchAssoc();

  // Check if this is a changed link and set the regenerate flag if necessary.
  if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
    _xmlsitemap_check_changed_link($link, $existing, TRUE);
  }

  if ($existing) {
    drupal_write_record('xmlsitemap', $link, array('type', 'id'));
  }
  else {
    drupal_write_record('xmlsitemap', $link);
  }

  // Allow other modules to respond after saving the link.
  //module_invoke_all('xmlsitemap_save_link', $link);

  return $link;
}

/**
 * Perform a mass update of sitemap data.
 *
 * If visible links are updated, this will automatically set the regenerate
 * needed flag to TRUE.
 *
 * @param $updates
 *   An array of values to update fields to, keyed by field name.
 * @param $conditions
 *   An array of values to match keyed by field.
 * @return
 *   The number of links that were updated.
 */
function xmlsitemap_link_update_multiple($updates = array(), $conditions = array(), $check_flag = TRUE) {
  // If we are going to modify a visible sitemap link, we will need to set
  // the regenerate needed flag.
  if ($check_flag && !variable_get('xmlsitemap_regenerate_needed', FALSE)) {
    _xmlsitemap_check_changed_links($conditions, $updates, TRUE);
  }

  // Process updates.
  $query = db_update('xmlsitemap');
  $query->fields($updates);
  foreach ($conditions as $field => $value) {
    $query->condition($field, $value);
  }

  return $query->execute();
}

/**
 * Delete a specific sitemap link from the database.
 *
 * If a visible sitemap link was deleted, this will automatically set the
 * regenerate needed flag.
 *
 * @param $entity_type
 *   A string with the entity type.
 * @param $entity_id
 *   An integer with the entity ID.
 * @return
 *   The number of links that were deleted.
 */
function xmlsitemap_link_delete($entity_type, $entity_id) {
  $conditions = array('type' => $entity_type, 'id' => $entity_id);
  return xmlsitemap_link_delete_multiple($conditions);
}

/**
 * Delete multiple sitemap links from the database.
 *
 * If visible sitemap links were deleted, this will automatically set the
 * regenerate needed flag.
 *
 * @param $conditions
 *   An array of conditions on the {xmlsitemap} table in the form
 *   'field' => $value.
 * @return
 *   The number of links that were deleted.
 */
function xmlsitemap_link_delete_multiple(array $conditions) {
  // Because this function is called from sub-module uninstall hooks, we have
  // to manually check if the table exists since it could have been removed
  // in xmlsitemap_uninstall().
  // @todo Remove this check when http://drupal.org/node/151452 is fixed.
  if (!db_table_exists('xmlsitemap')) {
    return FALSE;
  }

  if (!variable_get('xmlsitemap_regenerate_needed', TRUE)) {
    _xmlsitemap_check_changed_links($conditions, array(), TRUE);
  }

  $query = db_delete('xmlsitemap');
  foreach ($conditions as $field => $value) {
    $query->condition($field, $value);
  }

  return $query->execute();
}

/**
 * Check if there is a visible sitemap link given a certain set of conditions.
 *
 * @param $conditions
 *   An array of values to match keyed by field.
 * @param $flag
 *   An optional boolean that if TRUE, will set the regenerate needed flag if
 *   there is a match. Defaults to FALSE.
 * @return
 *   TRUE if there is a visible link, or FALSE otherwise.
 */
function _xmlsitemap_check_changed_links(array $conditions = array(), array $updates = array(), $flag = FALSE) {
  // If we are changing status or access, check for negative current values.
  $conditions['status'] = (!empty($updates['status']) && empty($condition['status'])) ? 0 : 1;
  $conditions['access'] = (!empty($updates['access']) && empty($condition['access'])) ? 0 : 1;

  $query = db_select('xmlsitemap');
  $query->addExpression('1');
  foreach ($conditions as $field => $value) {
    $query->condition($field, $value);
  }
  $query->range(0, 1);
  $changed = $query->execute()->fetchField();

  if ($changed && $flag) {
    variable_set('xmlsitemap_regenerate_needed', TRUE);
  }

  return $changed;
}

/**
 * Check if there is sitemap link is changed from the existing data.
 *
 * @param $link
 *   An array of the sitemap link.
 * @param $original_link
 *   An optional array of the existing data. This should only contain the
 *   fields necessary for comparison. If not provided the existing data will be
 *   loaded from the database.
 * @param $flag
 *   An optional boolean that if TRUE, will set the regenerate needed flag if
 *   there is a match. Defaults to FALSE.
 * @return
 *   TRUE if the link is changed, or FALSE otherwise.
 */
function _xmlsitemap_check_changed_link(array $link, $original_link = NULL, $flag = FALSE) {
  $changed = FALSE;

  if ($original_link === NULL) {
    // Load only the fields necessary for data to be changed in the sitemap.
    $original_link = db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = :type AND id = :id", 0, 1, array(':type' => $link['type'], ':id' => $link['id']))->fetchAssoc();
  }

  if (!$original_link) {
    if ($link['access'] && $link['status']) {
      // Adding a new visible link.
      $changed = TRUE;
    }
  }
  else {
    if (!($original_link['access'] && $original_link['status']) && $link['access'] && $link['status']) {
      // Changing a non-visible link to a visible link.
      $changed = TRUE;
    }
    elseif ($original_link['access'] && $original_link['status'] && array_diff_assoc($original_link, $link)) {
      // Changing a visible link
      $changed = TRUE;
    }
  }

  if ($changed && $flag) {
    variable_set('xmlsitemap_regenerate_needed', TRUE);
  }

  return $changed;
}

/**
 * @} End of "defgroup xmlsitemap_api"
 */

function xmlsitemap_get_directory(stdClass $sitemap = NULL) {
  $directory = &drupal_static(__FUNCTION__);

  if (!isset($directory)) {
    $directory = variable_get('xmlsitemap_path', 'xmlsitemap');
  }

  if (!empty($sitemap->smid)) {
    return file_build_uri($directory . '/' . $sitemap->smid);
  }
  else {
    return file_build_uri($directory);
  }
}

/**
 * Check that the sitemap files directory exists and is writable.
 */
function xmlsitemap_check_directory(stdClass $sitemap = NULL) {
  $directory = xmlsitemap_get_directory($sitemap);
  $result = file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
  if (!$result) {
    watchdog('file system', 'The directory %directory does not exist or is not writable.', array('%directory' => $directory), WATCHDOG_ERROR);
  }
  return $result;
}

function xmlsitemap_check_all_directories() {
  $directories = array();

  $sitemaps = xmlsitemap_sitemap_load_multiple(FALSE);
  foreach ($sitemaps as $smid => $sitemap) {
    $directory = xmlsitemap_get_directory($sitemap);
    $directories[$directory] = $directory;
  }

  foreach ($directories as $directory) {
    $result = file_prepare_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
    if ($result) {
      $directories[$directory] = TRUE;
    }
    else {
      $directories[$directory] = FALSE;
    }
  }

  return $directories;
}

function xmlsitemap_clear_directory(stdClass $sitemap = NULL, $delete = FALSE) {
  $directory = xmlsitemap_get_directory($sitemap);
  return _xmlsitemap_delete_recursive($directory, $delete);
}

/**
 * Move a directory to a new location.
 *
 * @param $old_dir
 *   A string specifying the filepath or URI of the original directory.
 * @param $new_dir
 *   A string specifying the filepath or URI of the new directory.
 * @param $replace
 *   Replace behavior when the destination file already exists.
 *
 * @return
 *   TRUE if the directory was moved successfully. FALSE otherwise.
 */
function xmlsitemap_directory_move($old_dir, $new_dir, $replace = FILE_EXISTS_REPLACE) {
  $success = file_prepare_directory($new_dir, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);

  $old_path = drupal_realpath($old_dir);
  $new_path = drupal_realpath($new_dir);
  if (!is_dir($old_path) || !is_dir($new_path) || !$success) {
    return FALSE;
  }

  $files = file_scan_directory($old_dir, '/.*/');
  foreach ($files as $file) {
    $file->uri_new = $new_dir . '/' . basename($file->filename);
    $success &= (bool) file_unmanaged_move($file->uri, $file->uri_new, $replace);
  }

  // The remove the directory.
  $success &= drupal_rmdir($old_dir);
  return $success;
}

/**
 * Recursively delete all files and folders in the specified filepath.
 *
 * This is a backport of Drupal 7's file_unmanaged_delete_recursive().
 *
 * Note that this only deletes visible files with write permission.
 *
 * @param $path
 *   A filepath relative to the Drupal root directory.
 * @param $delete_root
 *   A boolean if TRUE will delete the $path directory afterwards.
 */
function _xmlsitemap_delete_recursive($path, $delete_root = FALSE) {
  // Resolve streamwrapper URI to local path.
  $path = drupal_realpath($path);
  if (is_dir($path)) {
    $dir = dir($path);
    while (($entry = $dir->read()) !== FALSE) {
      if ($entry == '.' || $entry == '..') {
        continue;
      }
      $entry_path = $path . '/' . $entry;
      file_unmanaged_delete_recursive($entry_path, TRUE);
    }
    $dir->close();
    return $delete_root ? drupal_rmdir($path) : TRUE;
  }
  return file_unmanaged_delete($path);
}

/**
 * Returns information about supported sitemap link types.
 *
 * @param $type
 *   (optional) The link type to return information for. If omitted,
 *   information for all link types is returned.
 * @param $reset
 *   (optional) Boolean whether to reset the static cache and do nothing. Only
 *   used for tests.
 *
 * @see hook_xmlsitemap_link_info()
 * @see hook_xmlsitemap_link_info_alter()
 */
function xmlsitemap_get_link_info($type = NULL, $reset = FALSE) {
  global $language;
  $link_info = &drupal_static(__FUNCTION__);

  if ($reset) {
    $link_info = NULL;
    entity_info_cache_clear();
  }
  elseif ($cached = cache_get('xmlsitemap:link_info:' . $language->language)) {
    $link_info = $cached->data;
  }

  if (!isset($link_info)) {
    $link_info = entity_get_info();
    foreach ($link_info as $key => $info) {
      if (empty($info['uri callback']) || !isset($info['xmlsitemap'])) {
        // Remove any non URL-able or XML sitemap un-supported entites.
        unset($link_info[$key]);
      }
      foreach ($info['bundles'] as $bundle_key => $bundle) {
        if (!isset($bundle['xmlsitemap'])) {
          // Remove any un-supported entity bundles.
          //unset($link_info[$key]['bundles'][$bundle_key]);
        }
      }
    }
    $link_info = array_merge($link_info, module_invoke_all('xmlsitemap_link_info'));
    foreach ($link_info as $key => &$info) {
      $info += array(
        'type' => $key,
        'base table' => FALSE,
        'bundles' => array(),
        'xmlsitemap' => array(),
      );
      if (!isset($info['xmlsitemap']['rebuild callback']) && !empty($info['base table']) && !empty($info['entity keys']['id']) && !empty($info['xmlsitemap']['process callback'])) {
        $info['xmlsitemap']['rebuild callback'] = 'xmlsitemap_rebuild_batch_fetch';
      }
      foreach ($info['bundles'] as $bundle => &$bundle_info) {
        $bundle_info += array(
          'xmlsitemap' => array(),
        );
        $bundle_info['xmlsitemap'] += xmlsitemap_link_bundle_load($key, $bundle, FALSE);
      }
    }
    drupal_alter('xmlsitemap_link_info', $link_info);
    ksort($link_info);
    // Cache by language since this info contains translated strings.
    cache_set('xmlsitemap:link_info:' . $language->language, $link_info);
  }

  if (isset($type)) {
    return isset($link_info[$type]) ? $link_info[$type] : NULL;
  }

  return $link_info;
}

function xmlsitemap_get_link_type_enabled_bundles($entity_type) {
  $bundles = array();
  $info = xmlsitemap_get_link_info($entity_type);
  foreach ($info['bundles'] as $bundle => $bundle_info) {
    $settings = xmlsitemap_link_bundle_load($entity_type, $bundle);
    if (!empty($settings['status'])) {
    //if (!empty($bundle_info['xmlsitemap']['status'])) {
      $bundles[] = $bundle;
    }
  }
  return $bundles;
}

function xmlsitemap_get_link_type_indexed_status($entity_type, $bundle = '') {
  $info = xmlsitemap_get_link_info($entity_type);

  $status['indexed'] = db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE type = :entity AND subtype = :bundle", array(':entity' => $entity_type, ':bundle' => $bundle))->fetchField();
  $status['visible'] = db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE type = :entity AND subtype = :bundle AND status = 1 AND access = 1", array(':entity' => $entity_type, ':bundle' => $bundle))->fetchField();

  $total = new EntityFieldQuery();
  $total->entityCondition('entity_type', $entity_type);
  $total->entityCondition('bundle', $bundle);
  $total->entityCondition('entity_id', 0, '>');
  //$total->addTag('xmlsitemap_link_bundle_access');
  $total->addTag('xmlsitemap_link_indexed_status');
  $total->addMetaData('entity', $entity_type);
  $total->addMetaData('bundle', $bundle);
  $total->addMetaData('entity_info', $info);
  $total->count();
  $status['total'] = $total->execute();

  return $status;
}

/**
 * Implements hook_entity_query_alter().
 *
 * @todo Remove when http://drupal.org/node/1054168 is fixed.
 */
function xmlsitemap_entity_query_alter($query) {
  $conditions = &$query->entityConditions;

  // Alter user entity queries only.
  if (isset($conditions['entity_type']) && $conditions['entity_type']['value'] == 'user' && isset($conditions['bundle'])) {
    unset($conditions['bundle']);
  }
}

function xmlsitemap_link_bundle_settings_save($entity, $bundle, array $settings, $update_links = TRUE) {
  if ($update_links) {
    $old_settings = xmlsitemap_link_bundle_load($entity, $bundle);
    if ($settings['status'] != $old_settings['status']) {
      xmlsitemap_link_update_multiple(array('status' => $settings['status']), array('type' => $entity, 'subtype' => $bundle, 'status_override' => 0));
    }
    if ($settings['priority'] != $old_settings['priority']) {
      xmlsitemap_link_update_multiple(array('priority' => $settings['priority']), array('type' => $entity, 'subtype' => $bundle, 'priority_override' => 0));
    }
  }

  variable_set("xmlsitemap_settings_{$entity}_{$bundle}", $settings);
  cache_clear_all('xmlsitemap:link_info:', 'cache', TRUE);
  //xmlsitemap_get_link_info(NULL, TRUE);
}

function xmlsitemap_link_bundle_rename($entity, $bundle_old, $bundle_new) {
  if ($bundle_old != $bundle_new) {
    $settings = xmlsitemap_link_bundle_load($entity, $bundle_old);
    variable_del("xmlsitemap_settings_{$entity}_{$bundle_old}");
    xmlsitemap_link_bundle_settings_save($entity, $bundle_new, $settings, FALSE);
    xmlsitemap_link_update_multiple(array('subtype' => $bundle_new), array('type' => $entity, 'subtype' => $bundle_old));
  }
}

/**
 * Rename a link type.
 */
function xmlsitemap_link_type_rename($entity_old, $entity_new, $bundles = NULL) {
  $variables = db_query("SELECT name FROM {variable} WHERE name LIKE :pattern", array(':pattern' => db_like('xmlsitemap_settings_' . $entity_old . '_') . '%'))->fetchCol();
  foreach ($variables as $variable) {
    $value = variable_get($variable);
    variable_del($variable);
    if (isset($value)) {
      $variable_new = str_replace($entity_old, $entity_new, $variable);
      variable_set($variable_new, $value);
    }
  }

  xmlsitemap_link_update_multiple(array('type' => $entity_new), array('type' => $entity_old), FALSE);
  xmlsitemap_get_link_info(NULL, TRUE);
}

function xmlsitemap_link_bundle_load($entity, $bundle, $load_bundle_info = TRUE) {
  $info = array(
    'entity' => $entity,
    'bundle' => $bundle,
  );
  if ($load_bundle_info) {
    $entity_info = xmlsitemap_get_link_info($entity);
    if (isset($entity_info['bundles'][$bundle])) {
      $info['info'] = $entity_info['bundles'][$bundle];
    }
  }
  $info += variable_get("xmlsitemap_settings_{$entity}_{$bundle}", array());
  $info += array(
    'status' => XMLSITEMAP_STATUS_DEFAULT,
    'priority' => XMLSITEMAP_PRIORITY_DEFAULT,
  );
  return $info;
}

function xmlsitemap_link_bundle_delete($entity, $bundle, $delete_links = TRUE) {
  variable_del("xmlsitemap_settings_{$entity}_{$bundle}");
  if ($delete_links) {
    xmlsitemap_link_delete_multiple(array('type' => $entity, 'subtype' => $bundle));
  }
  cache_clear_all('xmlsitemap:link_info:', 'cache', TRUE);
  //xmlsitemap_get_link_info(NULL, TRUE);
}

function xmlsitemap_link_bundle_access($entity, $bundle = NULL) {
  if (is_array($entity) && !isset($bundle)) {
    $bundle = $entity;
  }
  else {
    $bundle = xmlsitemap_link_bundle_load($entity, $bundle);
  }

  if (isset($bundle['info']['admin'])) {
    $admin = $bundle['info']['admin'];
    $admin += array('access arguments' => array());

    if (!isset($admin['access callback']) && count($admin['access arguments']) == 1) {
      $admin['access callback'] = 'user_access';
    }

    if (!empty($admin['access callback'])) {
      return call_user_func_array($admin['access callback'], $admin['access arguments']);
    }
  }

  return FALSE;
}

function xmlsitemap_get_bundle_path($entity, $bundle) {
  $info = xmlsitemap_get_link_info($entity);

  if (!empty($info['bundles'][$bundle]['admin']['real path'])) {
    return $info['bundles'][$bundle]['admin']['real path'];
  }
  elseif (!empty($info['bundles'][$bundle]['admin']['path'])) {
    return $info['bundles'][$bundle]['admin']['path'];
  }
  else {
    return FALSE;
  }
}

/**
 * Implements hook_field_attach_rename_bundle().
 */
function xmlsitemap_field_attach_rename_bundle($entity_type, $bundle_old, $bundle_new) {
  xmlsitemap_link_bundle_rename($entity_type, $bundle_old, $bundle_new);
}

/**
 * Implements hook_field_attach_delete_bundle().
 */
function xmlsitemap_field_attach_delete_bundle($entity_type, $bundle, $instances) {
  xmlsitemap_link_bundle_delete($entity_type, $bundle, TRUE);
}

/**
 * Determine the frequency of updates to a link.
 *
 * @param $interval
 *   An interval value in seconds.
 * @return
 *   A string representing the update frequency according to the sitemaps.org
 *   protocol.
 */
function xmlsitemap_get_changefreq($interval) {
  if ($interval <= 0 || !is_numeric($interval)) {
    return FALSE;
  }

  foreach (xmlsitemap_get_changefreq_options() as $value => $frequency) {
    if ($interval <= $value) {
      return $frequency;
    }
  }

  return 'never';
}

/**
 * Get the current number of sitemap chunks.
 */
function xmlsitemap_get_chunk_count($reset = FALSE) {
  static $chunks;
  if (!isset($chunks) || $reset) {
    $count = max(xmlsitemap_get_link_count($reset), 1);
    $chunks = ceil($count / xmlsitemap_get_chunk_size($reset));
  }
  return $chunks;
}

/**
 * Get the current number of sitemap links.
 */
function xmlsitemap_get_link_count($reset = FALSE) {
  static $count;
  if (!isset($count) || $reset) {
    $count = db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE access = 1 AND status = 1")->fetchField();
  }
  return $count;
}

/**
 * Get the sitemap chunk size.
 *
 * This function is useful with the chunk size is set to automatic as it will
 * calculate the appropriate value. Use this function instead of @code
 * xmlsitemap_var('chunk_size') @endcode when the actual value is needed.
 *
 * @param $reset
 *   A boolean to reset the saved, static result. Defaults to FALSE.
 * @return
 *   An integer with the number of links in each sitemap page.
 */
function xmlsitemap_get_chunk_size($reset = FALSE) {
  static $size;
  if (!isset($size) || $reset) {
    $size = xmlsitemap_var('chunk_size');
    if ($size === 'auto') {
      $count = max(xmlsitemap_get_link_count($reset), 1); // Prevent divide by zero.
      $size = min(ceil($count / 10000) * 5000, XMLSITEMAP_MAX_SITEMAP_LINKS);
    }
  }
  return $size;
}

/**
 * Recalculate the changefreq of a sitemap link.
 *
 * @param $link
 *   A sitemap link array.
 */
function xmlsitemap_recalculate_changefreq(&$link) {
  $link['changefreq'] = round((($link['changefreq'] * $link['changecount']) + (REQUEST_TIME - $link['lastmod'])) / ($link['changecount'] + 1));
  $link['changecount']++;
  $link['lastmod'] = REQUEST_TIME;
}

/**
 * Calculates the average interval between UNIX timestamps.
 *
 * @param $timestamps
 *   An array of UNIX timestamp integers.
 * @return
 *   An integer of the average interval.
 */
function xmlsitemap_calculate_changefreq($timestamps) {
  sort($timestamps);
  $count = count($timestamps) - 1;
  $diff = 0;

  for ($i = 0; $i < $count; $i++) {
    $diff += $timestamps[$i + 1] - $timestamps[$i];
  }

  return $count > 0 ? round($diff / $count) : 0;
}

/**
 * Submit handler; Set the regenerate needed flag if variables have changed.
 *
 * This function needs to be called before system_settings_form_submit() or any
 * calls to variable_set().
 */
function xmlsitemap_form_submit_flag_regenerate($form, $form_state) {
  foreach ($form_state['values'] as $variable => $value) {
    $stored_value = variable_get($variable, 'not_a_variable');
    if (is_array($value) && !empty($form_state['values']['array_filter'])) {
      $value = array_keys(array_filter($value));
    }
    if ($stored_value != 'not_a_variable' && $stored_value != $value) {
      variable_set('xmlsitemap_regenerate_needed', TRUE);
      drupal_set_message(t('XML sitemap settings have been modified and the files should be regenerated. You can <a href="@run-cron">run cron manually</a> to regenerate the cached files.', array('@run-cron' => url('admin/reports/status/run-cron', array('query' => drupal_get_destination())))), 'warning', FALSE);
      return;
    }
  }
}

/**
 * Set the current user stored in $GLOBALS['user'].
 *
 * @todo Remove when http://drupal.org/node/287292 is fixed.
 */
function xmlsitemap_switch_user($new_user = NULL) {
  global $user;
  $user_original = &drupal_static(__FUNCTION__);

  if (!isset($new_user)) {
    if (isset($user_original)) {
      // Restore the original user.
      $user = $user_original;
      $user_original = NULL;
      drupal_save_session(TRUE);
    }
    else {
      return FALSE;
    }
  }
  elseif (is_numeric($new_user) && $user->uid != $new_user) {
    // Get the full user object.
    if (!$new_user) {
      $new_user = drupal_anonymous_user();
    }
    elseif (!$new_user = user_load($new_user)) {
      return FALSE;
    }

    // Backup the original user object.
    if (!isset($user_original)) {
      $user_original = $user;
      drupal_save_session(FALSE);
    }

    $user = $new_user;
  }
  elseif (is_object($new_user) && $user->uid != $new_user->uid) {
    // Backup the original user object.
    if (!isset($user_original)) {
      $user_original = $user;
      drupal_save_session(FALSE);
    }

    $user = $new_user;
  }
  else {
    return FALSE;
  }

  return $user;
}

/**
 * Restore the user that was originally loaded.
 *
 * @return
 *  Current user.
 */
function xmlsitemap_restore_user() {
  return xmlsitemap_switch_user();
}

function xmlsitemap_process_form_link_options($form, &$form_state) {
  $link = &$form_state['values']['xmlsitemap'];
  $fields = array('status' => XMLSITEMAP_STATUS_DEFAULT, 'priority' => XMLSITEMAP_PRIORITY_DEFAULT);

  foreach ($fields as $field => $default) {
    if ($link[$field] === 'default') {
      $link[$field] = isset($link[$field . '_default']) ? $link[$field . '_default'] : $default;
      $link[$field . '_override'] = 0;
    }
    else {
      $link[$field . '_override'] = 1;
    }
  }
}

function xmlsitemap_link_bundle_settings_form_submit($form, &$form_state) {
  $entity = $form['xmlsitemap']['#entity'];
  $bundle = $form['xmlsitemap']['#bundle'];

  // Handle new bundles by fetching the proper bundle key value from the form
  // state values.
  if (empty($bundle)) {
    $entity_info = $form['xmlsitemap']['#entity_info'];
    if (isset($entity_info['bundle keys']['bundle'])) {
      $bundle_key = $entity_info['bundle keys']['bundle'];
      if (isset($form_state['values'][$bundle_key])) {
        $bundle = $form_state['values'][$bundle_key];
        $form['xmlsitemap']['#bundle'] = $bundle;
      }
    }
  }

  xmlsitemap_link_bundle_settings_save($entity, $bundle, $form_state['values']['xmlsitemap']);

  $entity_info = $form['xmlsitemap']['#entity_info'];
  if (!empty($form['xmlsitemap']['#show_message'])) {
    drupal_set_message(t('XML sitemap settings for the @bundle-label %bundle have been saved.', array('@bundle-label' => drupal_strtolower($entity_info['bundle label']), '%bundle' => $entity_info['bundles'][$bundle]['label'])));
  }

  // Unset the form values since we have already saved the bundle settings and
  // we don't want these values to get saved as variables in-case this form
  // also uses system_settings_form().
  unset($form_state['values']['xmlsitemap']);
}

/**
 * @todo Document this function.
 * @todo Make these translatable
 */
function xmlsitemap_get_changefreq_options() {
  return array(
    XMLSITEMAP_FREQUENCY_ALWAYS => 'always',
    XMLSITEMAP_FREQUENCY_HOURLY => 'hourly',
    XMLSITEMAP_FREQUENCY_DAILY => 'daily',
    XMLSITEMAP_FREQUENCY_WEEKLY => 'weekly',
    XMLSITEMAP_FREQUENCY_MONTHLY => 'monthly',
    XMLSITEMAP_FREQUENCY_YEARLY => 'yearly',
  );
}

/**
 * Load a language object by its language code.
 *
 * @todo Remove when http://drupal.org/node/660736 is fixed in Drupal core.
 *
 * @param $language
 *   A language code. If not provided the default language will be returned.
 * @return
 *   A language object.
 */
function xmlsitemap_language_load($language = LANGUAGE_NONE) {
  $languages = &drupal_static(__FUNCTION__);

  if (!isset($languages)) {
    $languages = language_list();
    $languages[LANGUAGE_NONE] = NULL;
  }

  return isset($languages[$language]) ? $languages[$language] : NULL;
}

/**
 * @defgroup xmlsitemap_context_api XML sitemap API for sitemap contexts.
 * @{
 */

function xmlsitemap_get_context_info($context = NULL, $reset = FALSE) {
  global $language;
  $info = &drupal_static(__FUNCTION__);

  if ($reset) {
    $info = NULL;
  }
  elseif ($cached = cache_get('xmlsitemap:context_info:' . $language->language)) {
    $info = $cached->data;
  }

  if (!isset($info)) {
    $info = module_invoke_all('xmlsitemap_context_info');
    drupal_alter('xmlsitemap_context_info', $info);
    ksort($info);
    // Cache by language since this info contains translated strings.
    cache_set('xmlsitemap:context_info:' . $language->language, $info);
  }

  if (isset($context)) {
    return isset($info[$context]) ? $info[$context] : NULL;
  }

  return $info;
}

/**
 * Get the sitemap context of the current request.
 */
function xmlsitemap_get_current_context() {
  $context = &drupal_static(__FUNCTION__);

  if (!isset($context)) {
    $context = module_invoke_all('xmlsitemap_context');
    drupal_alter('xmlsitemap_context', $context);
    asort($context);
  }

  return $context;
}

function _xmlsitemap_sitemap_context_summary(stdClass $sitemap, $context_key, array $context_info) {
  $context_value = isset($sitemap->context[$context_key]) ? $sitemap->context[$context_key] : NULL;

  if (!isset($context_value)) {
    return t('Default');
  }
  elseif (!empty($context_info['summary callback'])) {
    return $context_info['summary callback']($context_value);
  }
  else {
    return $context_value;
  }
}

/**
 * @} End of "defgroup xmlsitemap_context_api"
 */

/**
 * Run a not-progressive batch operation.
 */
function xmlsitemap_run_unprogressive_batch() {
  $batch = batch_get();
  if (!empty($batch)) {
    // If there is already something in the batch, don't run.
    return FALSE;
  }

  $args = func_get_args();
  $batch_callback = array_shift($args);

  if (!lock_acquire($batch_callback)) {
    return FALSE;
  }

  // Attempt to increase the execution time.
  drupal_set_time_limit(240);

  // Build the batch array.
  $batch = call_user_func_array($batch_callback, $args);
  batch_set($batch);

  // We need to manually set the progressive variable again.
  // @todo Remove when http://drupal.org/node/638712 is fixed.
  $batch =& batch_get();
  $batch['progressive'] = FALSE;

  // Run the batch process.
  batch_process();

  lock_release($batch_callback);
  return TRUE;
}

/**
 * Workaround for missing breadcrumbs on callback and action paths.
 *
 * @todo Remove when http://drupal.org/node/576290 is fixed.
 */
function _xmlsitemap_set_breadcrumb($path = 'admin/config/search/xmlsitemap') {
  $breadcrumb = array();
  $path = explode('/', $path);
  do {
    $menu_path = implode('/', $path);
    $menu_item = menu_get_item($menu_path);
    array_unshift($breadcrumb, l($menu_item['title'], $menu_path));
  } while (array_pop($path) && !empty($path));
  array_unshift($breadcrumb, l(t('Home'), NULL));
  drupal_set_breadcrumb($breadcrumb);
}

function xmlsitemap_get_operation_link($url, $options = array()) {
  static $destination;

  if (!isset($destination)) {
    $destination = drupal_get_destination();
  }

  $link = array('href' => $url) + $options;

  // Fetch the item's menu router link info and title.
  if (!isset($link['title'])) {
    $item = menu_get_item($url);
    $link['title'] = $item['title'];
  }

  $link += array('query' => $destination);
  return $link;
}

Other Drupal examples (source code examples)

Here is a short list of links related to this Drupal xmlsitemap.module source code file:

new blog posts

"Drupal" is a registered trademark of Dries Buytaert.

my drupal tutorials and examples  

Copyright 1998-2016 Alvin Alexander, alvinalexander.com
All Rights Reserved.

Beginning in 2016, a portion of the proceeds from pages under the '/drupal-code-examples/' URI will be donated to charity.