[ Index ]

PHP Cross Reference of Drupal 6 (gatewave)

title

Body

[close]

/sites/all/modules/xmlsitemap/ -> xmlsitemap.module (source)

   1  <?php
   2  // $Id: xmlsitemap.module,v 1.20.2.45.2.165 2010/04/30 03:36:43 davereid Exp $
   3  
   4  /**
   5   * @defgroup xmlsitemap XML sitemap: create sitemaps.org sitemaps.
   6   */
   7  
   8  /**
   9   * @file
  10   * Main file for the xmlsitemap module.
  11   */
  12  
  13  /**
  14   * Drupal 7 backport to define REQUEST_TIME.
  15   */
  16  if (!defined('REQUEST_TIME')) {
  17    define('REQUEST_TIME', isset($_SERVER['REQUEST_TIME']) ? $_SERVER['REQUEST_TIME'] : time());
  18  }
  19  
  20  /**
  21   * The maximum number of links in one sitemap chunk file.
  22   */
  23  define('XMLSITEMAP_MAX_SITEMAP_LINKS', 50000);
  24  
  25  /**
  26   * The maximum filesize of a sitemap chunk file.
  27   */
  28  define('XMLSITEMAP_MAX_SITEMAP_FILESIZE', 10485760);
  29  
  30  define('XMLSITEMAP_FREQUENCY_YEARLY', 31449600); // 60 * 60 * 24 * 7 * 52
  31  define('XMLSITEMAP_FREQUENCY_MONTHLY', 2419200); // 60 * 60 * 24 * 7 * 4
  32  define('XMLSITEMAP_FREQUENCY_WEEKLY', 604800); // 60 * 60 * 24 * 7
  33  define('XMLSITEMAP_FREQUENCY_DAILY', 86400); // 60 * 60 * 24
  34  define('XMLSITEMAP_FREQUENCY_HOURLY', 3600); // 60 * 60
  35  define('XMLSITEMAP_FREQUENCY_ALWAYS', 60);
  36  
  37  /**
  38   * Short lastmod timestamp format.
  39   */
  40  define('XMLSITEMAP_LASTMOD_SHORT', 'Y-m-d');
  41  
  42  /**
  43   * Medium lastmod timestamp format.
  44   */
  45  define('XMLSITEMAP_LASTMOD_MEDIUM', 'Y-m-d\TH:i\Z');
  46  
  47  /**
  48   * Long lastmod timestamp format.
  49   */
  50  define('XMLSITEMAP_LASTMOD_LONG', 'c');
  51  
  52  /**
  53   * The default inclusion status for link types in the sitemaps.
  54   */
  55  define('XMLSITEMAP_STATUS_DEFAULT', 0);
  56  
  57  /**
  58   * The default priority for link types in the sitemaps.
  59   */
  60  define('XMLSITEMAP_PRIORITY_DEFAULT', 0.5);
  61  
  62  /**
  63   * Implements hook_help().
  64   */
  65  function xmlsitemap_help($path, $arg) {
  66    $output = '';
  67  
  68    switch ($path) {
  69      case 'admin/help/xmlsitemap':
  70      case 'admin/settings/xmlsitemap/settings/%/%/%':
  71      case 'admin/settings/xmlsitemap/edit/%':
  72      case 'admin/settings/xmlsitemap/delete/%':
  73        return;
  74      case 'admin/help#xmlsitemap':
  75        break;
  76      case 'admin/settings/xmlsitemap':
  77        if (!module_exists('elements')) {
  78          $output .= '<p>' . t('In order to perform bulk operations on the sitemaps listed below, it is highly recommended to download and install the <a href="@elements">Elements module</a>.', array('@elements' => 'http://drupal.org/project/elements')) . '</p>';
  79        }
  80        break;
  81      case 'admin/settings/xmlsitemap/rebuild':
  82        $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>';
  83    }
  84  
  85    if (arg(0) == 'admin' && strpos($path, 'xmlsitemap') !== FALSE && user_access('administer xmlsitemap')) {
  86      module_load_include('inc', 'xmlsitemap');
  87      if ($arg[1] == 'settings') {
  88        // Alert the user to any potential problems detected by hook_requirements.
  89        xmlsitemap_check_status();
  90      }
  91      $output .= _xmlsitemap_get_blurb();
  92    }
  93  
  94    return $output;
  95  }
  96  
  97  /**
  98   * Implements hook_perm().
  99   */
 100  function xmlsitemap_perm() {
 101    $permissions['administer xmlsitemap'] = array(
 102      'title' => t('Administer XML sitemap settings.'),
 103    );
 104    return array_keys($permissions);
 105  }
 106  
 107  /**
 108   * Load an XML sitemap array from the database.
 109   *
 110   * @param $smid
 111   *   An XML sitemap ID.
 112   */
 113  function xmlsitemap_sitemap_load($smid) {
 114    $sitemap = xmlsitemap_sitemap_load_multiple(array($smid));
 115    return $sitemap ? reset($sitemap) : FALSE;
 116  }
 117  
 118  /**
 119   * Load multiple XML sitemaps from the database.
 120   *
 121   * @param $smids
 122   *   An array of XML sitemap IDs.
 123   */
 124  function xmlsitemap_sitemap_load_multiple(array $smids) {
 125    $sitemaps = array();
 126    if ($smids) {
 127      $query = db_query("SELECT * FROM {xmlsitemap_sitemap} WHERE smid IN (" . db_placeholders($smids) . ")", $smids);
 128      while ($sitemap = db_fetch_array($query)) {
 129        $smid = $sitemap['smid'];
 130        $sitemaps[$smid] = $sitemap;
 131        $sitemaps[$smid]['context'] = unserialize($sitemap['context']);
 132        $sitemaps[$smid]['uri'] = xmlsitemap_sitemap_uri($sitemaps[$smid]);
 133      }
 134    }
 135    return $sitemaps;
 136  }
 137  
 138  /**
 139   * Load an XML sitemap array from the database based on its context.
 140   *
 141   * @param $context
 142   *   An optional XML sitemap context array to use to find the correct XML
 143   *   siteamp. If not provided, the current site's context will be used.
 144   *
 145   * @see xmlsitemap_get_current_context()
 146   */
 147  function xmlsitemap_sitemap_load_by_context(array $context = NULL) {
 148    if (!isset($context)) {
 149      $context = xmlsitemap_get_current_context();
 150    }
 151    $hash = md5(serialize($context));
 152    $smid = db_result(db_query_range("SELECT smid FROM {xmlsitemap_sitemap} WHERE context_hash = '%s'", $hash, 0, 1));
 153    return xmlsitemap_sitemap_load($smid);
 154  }
 155  
 156  /**
 157   * Save changes to an XML sitemap or add a new XML sitemap.
 158   *
 159   * @param $sitemap
 160   *   The XML sitemap array to be saved. If $sitemap['smid'] is omitted, a new
 161   *   XML sitemap will be added.
 162   *
 163   * @todo Save the sitemap's URL as a column?
 164   */
 165  function xmlsitemap_sitemap_save(array $sitemap) {
 166    // Make sure context is sorted before saving the hash.
 167    asort($sitemap['context']);
 168    $sitemap['context_hash'] = md5(serialize($sitemap['context']));
 169  
 170    if (!empty($sitemap['smid'])) {
 171      drupal_write_record('xmlsitemap_sitemap', $sitemap, array('smid'));
 172    }
 173    else {
 174      drupal_write_record('xmlsitemap_sitemap', $sitemap);
 175    }
 176  }
 177  
 178  /**
 179   * Delete an XML sitemap.
 180   *
 181   * @param $smid
 182   *   An XML sitemap ID.
 183   */
 184  function xmlsitemap_sitemap_delete($smid) {
 185    xmlsitemap_sitemap_delete_multiple(array($smid));
 186  }
 187  
 188  /**
 189   * Delete multiple XML sitemaps.
 190   *
 191   * @param $smids
 192   *   An array of XML sitemap IDs.
 193   */
 194  function xmlsitemap_sitemap_delete_multiple(array $smids) {
 195    if (!empty($smids)) {
 196      $sitemaps = xmlsitemap_sitemap_load_multiple($smids);
 197      db_query("DELETE FROM {xmlsitemap_sitemap} WHERE smid IN (" . db_placeholders($smid) . ")", $smids);
 198  
 199      foreach ($sitemaps as $sitemap) {
 200        xmlsitemap_clear_directory($sitemap, TRUE);
 201        module_invoke_all('xmlsitemap_sitemap_delete', $sitemap);
 202      }
 203    }
 204  }
 205  
 206  /**
 207   * Return the expected file path for a specific sitemap chunk.
 208   *
 209   * @param $sitemap
 210   *   An XML sitemap array.
 211   * @param $chunk
 212   *   An optional specific chunk in the sitemap. Defaults to the index page.
 213   */
 214  function xmlsitemap_sitemap_get_file(array $sitemap, $chunk = 'index') {
 215    return xmlsitemap_get_directory($sitemap) . "/{$chunk}.xml";
 216  }
 217  
 218  /**
 219   * Returns the uri elements of an XML sitemap.
 220   *
 221   * @param $sitemap
 222   *   An unserialized data array for an XML sitemap.
 223   * @return
 224   *   An array containing the 'path' and 'options' keys used to build the uri of
 225   *   the XML sitemap, and matching the signature of url().
 226   */
 227  function xmlsitemap_sitemap_uri(array $sitemap) {
 228    xmlsitemap_load_all_includes();
 229  
 230    $uri['path'] = 'sitemap.xml';
 231    $uri['options'] = module_invoke_all('xmlsitemap_context_url_options', $sitemap['context']);
 232    drupal_alter('xmlsitemap_context_url_options', $uri['options'], $sitemap['context']);
 233    $uri['options'] += array(
 234      'absolute' => TRUE,
 235      'base_url' => variable_get('xmlsitemap_base_url', $GLOBALS['base_url']),
 236    );
 237    return $uri;
 238  }
 239  
 240  /**
 241   * Implements hook_menu().
 242   */
 243  function xmlsitemap_menu() {
 244    $items['admin/settings/xmlsitemap'] = array(
 245      'title' => 'XML sitemap',
 246      'description' => 'Configure the XML sitemaps.',
 247      'page callback' => 'drupal_get_form',
 248      'page arguments' => array('xmlsitemap_sitemap_list_form'),
 249      'access arguments' => array('administer xmlsitemap'),
 250      'file' => 'xmlsitemap.admin.inc',
 251    );
 252    $items['admin/settings/xmlsitemap/list'] = array(
 253      'title' => 'List',
 254      'type' => MENU_DEFAULT_LOCAL_TASK,
 255      'weight' => -10,
 256    );
 257    $items['admin/settings/xmlsitemap/add'] = array(
 258      'title' => 'Add new XML sitemap',
 259      'page callback' => 'drupal_get_form',
 260      'page arguments' => array('xmlsitemap_sitemap_edit_form'),
 261      'access arguments' => array('administer xmlsitemap'),
 262      'type' => MENU_CALLBACK,
 263      'file' => 'xmlsitemap.admin.inc',
 264    );
 265    $items['admin/settings/xmlsitemap/edit/%xmlsitemap_sitemap'] = array(
 266      'page callback' => 'drupal_get_form',
 267      'page arguments' => array('xmlsitemap_sitemap_edit_form', 4),
 268      'access arguments' => array('administer xmlsitemap'),
 269      'type' => MENU_CALLBACK,
 270      'file' => 'xmlsitemap.admin.inc',
 271    );
 272    $items['admin/settings/xmlsitemap/delete/%xmlsitemap_sitemap'] = array(
 273      'page callback' => 'drupal_get_form',
 274      'page arguments' => array('xmlsitemap_sitemap_delete_form', 4),
 275      'access arguments' => array('administer xmlsitemap'),
 276      'type' => MENU_CALLBACK,
 277      'file' => 'xmlsitemap.admin.inc',
 278    );
 279    $items['admin/settings/xmlsitemap/settings'] = array(
 280      'title' => 'Settings',
 281      'page callback' => 'drupal_get_form',
 282      'page arguments' => array('xmlsitemap_settings_form'),
 283      'access arguments' => array('administer xmlsitemap'),
 284      'type' => MENU_LOCAL_TASK,
 285      'file' => 'xmlsitemap.admin.inc',
 286      'weight' => 10,
 287    );
 288    $items['admin/settings/xmlsitemap/rebuild'] = array(
 289      'title' => 'Rebuild links',
 290      'description' => 'Rebuild the site map.',
 291      'page callback' => 'drupal_get_form',
 292      'page arguments' => array('xmlsitemap_rebuild_form'),
 293      'access arguments' => array('administer xmlsitemap'),
 294      'type' => MENU_LOCAL_TASK,
 295      'file' => 'xmlsitemap.admin.inc',
 296      'weight' => 20,
 297    );
 298  
 299    $items['sitemap.xml'] = array(
 300      'page callback' => 'xmlsitemap_output_chunk',
 301      'access arguments' => array('access content'),
 302      'type' => MENU_CALLBACK,
 303      'file' => 'xmlsitemap.pages.inc',
 304    );
 305    $items['sitemap.xsl'] = array(
 306      'page callback' => 'xmlsitemap_output_xsl',
 307      'access callback' => TRUE,
 308      'type' => MENU_CALLBACK,
 309      'file' => 'xmlsitemap.pages.inc',
 310    );
 311  
 312    // CTools/Dialog API callback for editing bundle settings.
 313    if (module_exists('ctools') && module_exists('dialog')) {
 314      $items['admin/settings/xmlsitemap/settings/%/%/%ctools_js'] = array(
 315        'page callback' => 'xmlsitemap_bundle_settings_dialog',
 316        'page arguments' => array(4, 5, 6),
 317        'access arguments' => array('administer xmlsitemap'),
 318        'type' => MENU_CALLBACK,
 319        'file' => 'xmlsitemap.admin.inc',
 320      );
 321    }
 322  
 323    return $items;
 324  }
 325  
 326  /**
 327   * Implements hook_cron().
 328   */
 329  function xmlsitemap_cron() {
 330    // If there were no new or changed links, skip.
 331    if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
 332      return;
 333    }
 334  
 335    // If the minimum sitemap lifetime hasn't been passed, skip.
 336    $lifetime = REQUEST_TIME - variable_get('xmlsitemap_generated_last', 0);
 337    if ($lifetime < variable_get('xmlsitemap_minimum_lifetime', 0)) {
 338      return;
 339    }
 340  
 341    // Regenerate the sitemap XML files.
 342    module_load_include('generate.inc', 'xmlsitemap');
 343    xmlsitemap_run_progressive_batch('xmlsitemap_regenerate_batch');
 344  }
 345  
 346  /**
 347   * Implements hook_form_FORM_ID_alter().
 348   *
 349   * Add a submit handler to manually clear any XML sitemap cache entries.
 350   */
 351  function xmlsitemap_form_system_modules_alter(&$form, $form_state) {
 352    $form['#submit'][] = 'xmlsitemap_system_modules_submit';
 353  }
 354  
 355  /**
 356   * Submit callback; manually clears XML sitemap caches when modules are changed.
 357   */
 358  function xmlsitemap_system_modules_submit($form, $form_state) {
 359    cache_clear_all('xmlsitemap:', 'cache', TRUE);
 360  }
 361  
 362  /**
 363   * Implements hook_robotstxt().
 364   */
 365  function xmlsitemap_robotstxt() {
 366    if ($sitemap = xmlsitemap_sitemap_load_by_context()) {
 367      $robotstxt[] = 'Sitemap: ' . url($sitemap['uri']['path'], $sitemap['uri']['options']);
 368      return $robotstxt;
 369    }
 370  }
 371  
 372  /**
 373   * Determine the frequency of updates to a link.
 374   *
 375   * @param $interval
 376   *   An interval value in seconds.
 377   * @return
 378   *   A string representing the update frequency according to the sitemaps.org
 379   *   protocol.
 380   */
 381  function xmlsitemap_get_changefreq($interval) {
 382    if ($interval <= 0 || !is_numeric($interval)) {
 383      return FALSE;
 384    }
 385  
 386    foreach (xmlsitemap_get_changefreq_options() as $value => $frequency) {
 387      if ($interval <= $value) {
 388        return $frequency;
 389      }
 390    }
 391  
 392    return 'never';
 393  }
 394  
 395  /**
 396   * Get the current number of sitemap chunks.
 397   */
 398  function xmlsitemap_get_chunk_count($reset = FALSE) {
 399    static $chunks;
 400    if (!isset($chunks) || $reset) {
 401      $count = max(xmlsitemap_get_link_count($reset), 1);
 402      $chunks = ceil($count / xmlsitemap_get_chunk_size($reset));
 403    }
 404    return $chunks;
 405  }
 406  
 407  /**
 408   * Get the current number of sitemap links.
 409   */
 410  function xmlsitemap_get_link_count($reset = FALSE) {
 411    static $count;
 412    if (!isset($count) || $reset) {
 413      $count = db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE access = 1 AND status = 1"));
 414    }
 415    return $count;
 416  }
 417  
 418  /**
 419   * Get the sitemap chunk size.
 420   *
 421   * This function is useful with the chunk size is set to automatic as it will
 422   * calculate the appropriate value. Use this function instead of @code
 423   * xmlsitemap_var('chunk_size') @endcode when the actual value is needed.
 424   *
 425   * @param $reset
 426   *   A boolean to reset the saved, static result. Defaults to FALSE.
 427   * @return
 428   *   An integer with the number of links in each sitemap page.
 429   */
 430  function xmlsitemap_get_chunk_size($reset = FALSE) {
 431    static $size;
 432    if (!isset($size) || $reset) {
 433      $size = xmlsitemap_var('chunk_size');
 434      if ($size === 'auto') {
 435        $count = max(xmlsitemap_get_link_count($reset), 1); // Prevent divide by zero.
 436        $size = min(ceil($count / 10000) * 5000, XMLSITEMAP_MAX_SITEMAP_LINKS);
 437      }
 438    }
 439    return $size;
 440  }
 441  
 442  /**
 443   * Recalculate the changefreq of a sitemap link.
 444   *
 445   * @param $link
 446   *   A sitemap link array.
 447   */
 448  function xmlsitemap_recalculate_changefreq(&$link) {
 449    $link['changefreq'] = round((($link['changefreq'] * $link['changecount']) + (REQUEST_TIME - $link['lastmod'])) / ($link['changecount'] + 1));
 450    $link['changecount']++;
 451    $link['lastmod'] = REQUEST_TIME;
 452  }
 453  
 454  /**
 455   * Calculates the average interval between UNIX timestamps.
 456   *
 457   * @param $timestamps
 458   *   An array of UNIX timestamp integers.
 459   * @return
 460   *   An integer of the average interval.
 461   */
 462  function xmlsitemap_calculate_changefreq($timestamps) {
 463    sort($timestamps);
 464    $count = count($timestamps) - 1;
 465    $diff = 0;
 466  
 467    for ($i = 0; $i < $count; $i++) {
 468      $diff += $timestamps[$i + 1] - $timestamps[$i];
 469    }
 470  
 471    return $count > 0 ? round($diff / $count) : 0;
 472  }
 473  
 474  /**
 475   * Check if there is a visible sitemap link given a certain set of conditions.
 476   *
 477   * @param $conditions
 478   *   An array of values to match keyed by field.
 479   * @param $flag
 480   *   An optional boolean that if TRUE, will set the regenerate needed flag if
 481   *   there is a match. Defaults to FALSE.
 482   * @return
 483   *   TRUE if there is a visible link, or FALSE otherwise.
 484   */
 485  function _xmlsitemap_check_changed_links(array $conditions = array(), array $updates = array(), $flag = FALSE) {
 486    // If we are changing status or access, check for negative current values.
 487    $conditions['status'] = (!empty($updates['status']) && empty($condition['status'])) ? 0 : 1;
 488    $conditions['access'] = (!empty($updates['access']) && empty($condition['access'])) ? 0 : 1;
 489  
 490    module_load_include('inc', 'xmlsitemap');
 491    $args = _xmlsitemap_build_conditions($conditions);
 492    $sql = "SELECT 1 FROM {xmlsitemap} WHERE ". implode(' AND ', $conditions);
 493    $changed = db_result(db_query_range($sql, $args, 0, 1));
 494  
 495    if ($changed && $flag) {
 496      variable_set('xmlsitemap_regenerate_needed', TRUE);
 497    }
 498  
 499    return $changed;
 500  }
 501  
 502  /**
 503   * Check if there is sitemap link is changed from the existing data.
 504   *
 505   * @param $link
 506   *   An array of the sitemap link.
 507   * @param $original_link
 508   *   An optional array of the existing data. This should only contain the
 509   *   fields necessary for comparison. If not provided the existing data will be
 510   *   loaded from the database.
 511   * @param $flag
 512   *   An optional boolean that if TRUE, will set the regenerate needed flag if
 513   *   there is a match. Defaults to FALSE.
 514   * @return
 515   *   TRUE if the link is changed, or FALSE otherwise.
 516   */
 517  function _xmlsitemap_check_changed_link(array $link, $original_link = NULL, $flag = FALSE) {
 518    $changed = FALSE;
 519  
 520    if ($original_link === NULL) {
 521      // Load only the fields necessary for data to be changed in the sitemap.
 522      $original_link = db_fetch_array(db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = '%s' AND id = %d", $link['type'], $link['id'], 0, 1));
 523    }
 524  
 525    if (!$original_link) {
 526      if ($link['access'] && $link['status']) {
 527        // Adding a new visible link.
 528        $changed = TRUE;
 529      }
 530    }
 531    else {
 532      if (!($original_link['access'] && $original_link['status']) && $link['access'] && $link['status']) {
 533        // Changing a non-visible link to a visible link.
 534        $changed = TRUE;
 535      }
 536      elseif ($original_link['access'] && $original_link['status'] && array_diff_assoc($original_link, $link)) {
 537        // Changing a visible link
 538        $changed = TRUE;
 539      }
 540    }
 541  
 542    if ($changed && $flag) {
 543      variable_set('xmlsitemap_regenerate_needed', TRUE);
 544    }
 545  
 546    return $changed;
 547  }
 548  
 549  /**
 550   * Load a specific sitemap link from the database.
 551   *
 552   * @param $entity_type
 553   *   A string with the entity type.
 554   * @param $entity_id
 555   *   An integer with the entity ID.
 556   * @return
 557   *   A sitemap link (array) or FALSE if the conditions were not found.
 558   */
 559  function xmlsitemap_link_load($entity_type, $entity_id) {
 560    $link = xmlsitemap_link_load_multiple(array('type' => $entity_type, 'id' => $entity_id));
 561    return $link ? reset($link) : FALSE;
 562  }
 563  
 564  /**
 565   * Load sitemap links from the database.
 566   *
 567   * @param $conditions
 568   *   An array of conditions on the {xmlsitemap} table in the form
 569   *   'field' => $value.
 570   * @return
 571   *   An array of sitemap link arrays.
 572   */
 573  function xmlsitemap_link_load_multiple(array $conditions = array()) {
 574    $links = array();
 575  
 576    module_load_include('inc', 'xmlsitemap');
 577    $args = _xmlsitemap_build_conditions($conditions);
 578    $query = db_query("SELECT * FROM {xmlsitemap} WHERE " . implode(' AND ', $conditions), $args);
 579  
 580    while ($link = db_fetch_array($query)) {
 581      $links[] = $link;
 582    }
 583  
 584    return $links;
 585  }
 586  
 587  /**
 588   * Saves or updates a sitemap link.
 589   *
 590   * @param $link
 591   *   An array with a sitemap link.
 592   */
 593  function xmlsitemap_link_save(array $link) {
 594    $link += array(
 595      'access' => 1,
 596      'status' => 1,
 597      'status_override' => 0,
 598      'lastmod' => 0,
 599      'priority' => XMLSITEMAP_PRIORITY_DEFAULT,
 600      'priority_override' => 0,
 601      'changefreq' => 0,
 602      'changecount' => 0,
 603      'language' => '',
 604    );
 605  
 606    // Allow other modules to alter the link before saving.
 607    xmlsitemap_load_all_includes();
 608    drupal_alter('xmlsitemap_link', $link);
 609  
 610    // Temporary validation checks.
 611    // @todo Remove in final?
 612    if ($link['priority'] < 0 || $link['priority'] > 1) {
 613      trigger_error(t('Invalid sitemap link priority %priority.<br />@link', array('%priority' => $link['priority'], '@link' => var_export($link, TRUE))), E_USER_ERROR);
 614    }
 615    if ($link['changecount'] < 0) {
 616      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);
 617      $link['changecount'] = 0;
 618    }
 619  
 620    $existing = db_fetch_array(db_query_range("SELECT loc, access, status, lastmod, priority, changefreq, changecount, language FROM {xmlsitemap} WHERE type = '%s' AND id = %d", $link['type'], $link['id'], 0, 1));
 621  
 622    // Check if this is a changed link and set the regenerate flag if necessary.
 623    if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
 624      _xmlsitemap_check_changed_link($link, $existing, TRUE);
 625    }
 626  
 627    module_load_include('inc', 'xmlsitemap');
 628    if ($existing) {
 629      xmlsitemap_write_record('xmlsitemap', $link, array('type', 'id'));
 630    }
 631    else {
 632      xmlsitemap_write_record('xmlsitemap', $link);
 633    }
 634  
 635    // Allow other modules to respond after saving the link.
 636    //module_invoke_all('xmlsitemap_save_link', $link);
 637  
 638    return $link;
 639  }
 640  
 641  /**
 642   * Perform a mass update of sitemap data.
 643   *
 644   * If visible links are updated, this will automatically set the regenerate
 645   * needed flag to TRUE.
 646   *
 647   * @param $updates
 648   *   An array of values to update fields to, keyed by field name.
 649   * @param $conditions
 650   *   An array of values to match keyed by field.
 651   * @return
 652   *   The number of links that were updated.
 653   */
 654  function xmlsitemap_link_update_multiple($updates = array(), $conditions = array()) {
 655    // If we are going to modify a visible sitemap link, we will need to set
 656    // the regenerate needed flag.
 657    if (!variable_get('xmlsitemap_regenerate_needed', FALSE)) {
 658      _xmlsitemap_check_changed_links($conditions, $updates, TRUE);
 659    }
 660  
 661    // Process updates.
 662    $args = array();
 663    module_load_include('inc', 'xmlsitemap');
 664    _xmlsitemap_build_conditions($updates, $args, '=', TRUE);
 665    _xmlsitemap_build_conditions($conditions, $args);
 666    $sql = "UPDATE {xmlsitemap} SET " . implode(', ', $updates) . " WHERE " . implode(' AND ', $conditions);
 667    db_query($sql, $args);
 668  
 669    return db_affected_rows();
 670  }
 671  
 672  /**
 673   * Delete a specific sitemap link from the database.
 674   *
 675   * If a visible sitemap link was deleted, this will automatically set the
 676   * regenerate needed flag.
 677   *
 678   * @param $entity_type
 679   *   A string with the entity type.
 680   * @param $entity_id
 681   *   An integer with the entity ID.
 682   * @return
 683   *   The number of links that were deleted.
 684   */
 685  function xmlsitemap_link_delete($entity_type, $entity_id) {
 686    $conditions = array('type' => $entity_type, 'id' => $entity_id);
 687    return xmlsitemap_link_delete_multiple($conditions);
 688  }
 689  
 690  /**
 691   * Delete multiple sitemap links from the database.
 692   *
 693   * If visible sitemap links were deleted, this will automatically set the
 694   * regenerate needed flag.
 695   *
 696   * @param $conditions
 697   *   An array of conditions on the {xmlsitemap} table in the form
 698   *   'field' => $value.
 699   * @return
 700   *   The number of links that were deleted.
 701   */
 702  function xmlsitemap_link_delete_multiple(array $conditions) {
 703    if (!variable_get('xmlsitemap_regenerate_needed', TRUE)) {
 704      _xmlsitemap_check_changed_links($conditions, array(), TRUE);
 705    }
 706  
 707    module_load_include('inc', 'xmlsitemap');
 708    $args = _xmlsitemap_build_conditions($conditions);
 709    db_query("DELETE FROM {xmlsitemap} WHERE " . implode(' AND ', $conditions), $args);
 710  
 711    return db_affected_rows();
 712  }
 713  
 714  /**
 715   * Submit handler; Set the regenerate needed flag if variables have changed.
 716   *
 717   * This function needs to be called before system_settings_form_submit() or any
 718   * calls to variable_set().
 719   */
 720  function xmlsitemap_form_submit_flag_regenerate($form, $form_state) {
 721    foreach ($form_state['values'] as $variable => $value) {
 722      $stored_value = variable_get($variable, 'not_a_variable');
 723      if (is_array($value) && !empty($form_state['values']['array_filter'])) {
 724        $value = array_keys(array_filter($value));
 725      }
 726      if ($stored_value != 'not_a_variable' && $stored_value != $value) {
 727        variable_set('xmlsitemap_regenerate_needed', TRUE);
 728        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);
 729        return;
 730      }
 731    }
 732  }
 733  
 734  /**
 735   * Internal default variables for xmlsitemap_var().
 736   */
 737  function xmlsitemap_variables() {
 738    return array(
 739      'xmlsitemap_rebuild_needed' => FALSE,
 740      'xmlsitemap_regenerate_needed' => FALSE,
 741      'xmlsitemap_minimum_lifetime' => 0,
 742      'xmlsitemap_generated_last' => 0,
 743      'xmlsitemap_xsl' => 1,
 744      'xmlsitemap_prefetch_aliases' => 1,
 745      'xmlsitemap_chunk_size' => 'auto',
 746      'xmlsitemap_batch_limit' => 100,
 747      'xmlsitemap_path' => 'xmlsitemap',
 748      'xmlsitemap_base_url' => $GLOBALS['base_url'],
 749      'xmlsitemap_developer_mode' => 0,
 750      'xmlsitemap_frontpage_priority' => 1.0,
 751      'xmlsitemap_frontpage_changefreq' => XMLSITEMAP_FREQUENCY_DAILY,
 752      'xmlsitemap_max_chunks' => 0,
 753      'xmlsitemap_max_filesize' => 0,
 754      'xmlsitemap_lastmod_format' => XMLSITEMAP_LASTMOD_MEDIUM,
 755      // Removed variables are set to NULL so they can still be deleted.
 756      'xmlsitemap_gz' => FALSE,
 757      'xmlsitemap_regenerate_last' => NULL,
 758      'xmlsitemap_custom_links' => NULL,
 759      'xmlsitemap_priority_default' => NULL,
 760      'xmlsitemap_languages' => NULL,
 761    );
 762  }
 763  
 764  /**
 765   * Internal implementation of variable_get().
 766   */
 767  function xmlsitemap_var($name, $default = NULL) {
 768    $defaults = &xmlsitemap_static(__FUNCTION__);
 769    if (!isset($defaults)) {
 770      $defaults = xmlsitemap_variables();
 771    }
 772  
 773    $name = 'xmlsitemap_' . $name;
 774  
 775    // @todo Remove when stable.
 776    if (!isset($defaults[$name])) {
 777      trigger_error(strtr('Default variable for %variable not found.', array('%variable' => theme('placeholder', $name))));
 778    }
 779  
 780    return variable_get($name, isset($default) || !isset($defaults[$name]) ? $default : $defaults[$name]);
 781  }
 782  
 783  /**
 784   * Set the current user stored in $GLOBALS['user'].
 785   */
 786  function xmlsitemap_switch_user($new_user = NULL) {
 787    global $user;
 788    $user_original = &xmlsitemap_static(__FUNCTION__);
 789  
 790    if (!isset($new_user)) {
 791      if (isset($user_original)) {
 792        // Restore the original user.
 793        $user = $user_original;
 794        $user_original = NULL;
 795        session_save_session(TRUE);
 796      }
 797      else {
 798        return FALSE;
 799      }
 800    }
 801    elseif (is_numeric($new_user) && $user->uid != $new_user) {
 802      // Get the full user object.
 803      if (!$new_user) {
 804        $new_user = drupal_anonymous_user();
 805      }
 806      elseif (!$new_user = user_load($new_user)) {
 807        return FALSE;
 808      }
 809  
 810      // Backup the original user object.
 811      if (!isset($user_original)) {
 812        $user_original = $user;
 813        session_save_session(FALSE);
 814      }
 815  
 816      $user = $new_user;
 817    }
 818    elseif (is_object($new_user) && $user->uid != $new_user->uid) {
 819      // Backup the original user object.
 820      if (!isset($user_original)) {
 821        $user_original = $user;
 822        session_save_session(FALSE);
 823      }
 824  
 825      $user = $new_user;
 826    }
 827    else {
 828      return FALSE;
 829    }
 830  
 831    return $user;
 832  }
 833  
 834  /**
 835   * Restore the user that was originally loaded.
 836   *
 837   * @return
 838   *  Current user.
 839   */
 840  function xmlsitemap_restore_user() {
 841    return xmlsitemap_switch_user();
 842  }
 843  
 844  function xmlsitemap_process_form_link_options($form, &$form_state) {
 845    $link = &$form_state['values']['xmlsitemap'];
 846    $fields = array('status' => XMLSITEMAP_STATUS_DEFAULT, 'priority' => XMLSITEMAP_PRIORITY_DEFAULT);
 847  
 848    foreach ($fields as $field => $default) {
 849      if ($link[$field] === 'default') {
 850        $link[$field] = isset($link[$field . '_default']) ? $link[$field . '_default'] : $default;
 851        $link[$field . '_override'] = 0;
 852      }
 853      else {
 854        $link[$field . '_override'] = 1;
 855      }
 856    }
 857  }
 858  
 859  /**
 860   * @todo Document this function.
 861   * @todo Make these translatable
 862   */
 863  function xmlsitemap_get_changefreq_options() {
 864    return array(
 865      XMLSITEMAP_FREQUENCY_ALWAYS => 'always',
 866      XMLSITEMAP_FREQUENCY_HOURLY => 'hourly',
 867      XMLSITEMAP_FREQUENCY_DAILY => 'daily',
 868      XMLSITEMAP_FREQUENCY_WEEKLY => 'weekly',
 869      XMLSITEMAP_FREQUENCY_MONTHLY => 'monthly',
 870      XMLSITEMAP_FREQUENCY_YEARLY => 'yearly',
 871    );
 872  }
 873  
 874  /**
 875   * Returns information about supported sitemap link types.
 876   *
 877   * @param $type
 878   *   (optional) The link type to return information for. If omitted,
 879   *   information for all link types is returned.
 880   * @param $reset
 881   *   (optional) Boolean whether to reset the static cache and do nothing. Only
 882   *   used for tests.
 883   *
 884   * @see hook_xmlsitemap_link_info()
 885   * @see hook_xmlsitemap_link_info_alter()
 886   */
 887  function xmlsitemap_get_link_info($type = NULL, $reset = FALSE) {
 888    global $language;
 889    $link_info = &xmlsitemap_static(__FUNCTION__);
 890  
 891    if ($reset) {
 892      $link_info = NULL;
 893    }
 894    elseif ($cached = cache_get('xmlsitemap:link_info:' . $language->language)) {
 895      $link_info = $cached->data;
 896    }
 897  
 898    if (!isset($link_info)) {
 899      xmlsitemap_load_all_includes();
 900      $link_info = module_invoke_all('xmlsitemap_link_info');
 901      foreach ($link_info as $key => &$info) {
 902        $info += array(
 903          'type' => $key,
 904          'base table' => FALSE,
 905          'bundles' => array(),
 906          'xmlsitemap' => array(),
 907        );
 908        if (!isset($info['xmlsitemap']['rebuild callback']) && !empty($info['base table']) && !empty($info['entity keys']['id']) && !empty($info['xmlsitemap']['process callback'])) {
 909          $info['xmlsitemap']['rebuild callback'] = 'xmlsitemap_rebuild_batch_fetch';
 910        }
 911        foreach ($info['bundles'] as $bundle => &$bundle_info) {
 912          $bundle_info += array(
 913            'xmlsitemap' => array(),
 914          );
 915          $bundle_info['xmlsitemap'] += xmlsitemap_link_bundle_load($key, $bundle);
 916        }
 917      }
 918      drupal_alter('xmlsitemap_link_info', $link_info);
 919      ksort($link_info);
 920      // Cache by language since this info contains translated strings.
 921      cache_set('xmlsitemap:link_info:' . $language->language, $link_info);
 922    }
 923  
 924    if (isset($type)) {
 925      return isset($link_info[$type]) ? $link_info[$type] : NULL;
 926    }
 927  
 928    return $link_info;
 929  }
 930  
 931  function xmlsitemap_get_directory(array $sitemap = NULL) {
 932    $directory = &xmlsitemap_static(__FUNCTION__);
 933  
 934    if (!isset($directory)) {
 935      $directory = file_create_path(variable_get('xmlsitemap_path', 'xmlsitemap'));
 936    }
 937  
 938    return $directory . (!empty($sitemap) ? '/' . $sitemap['context_hash'] : '');
 939  }
 940  
 941  /**
 942   * Check that the sitemap files directory exists and is writable.
 943   */
 944  function xmlsitemap_check_directory(array $sitemap = NULL) {
 945    $directory = xmlsitemap_get_directory($sitemap);
 946    return file_check_directory($directory, FILE_CREATE_DIRECTORY | FILE_MODIFY_PERMISSIONS);
 947  }
 948  
 949  function xmlsitemap_clear_directory(array $sitemap = NULL, $delete = FALSE) {
 950    $directory = xmlsitemap_get_directory($sitemap);
 951    return _xmlsitemap_delete_recursive($directory, $delete);
 952  }
 953  
 954  /**
 955   * Recursively delete all files and folders in the specified filepath.
 956   *
 957   * This is a backport of Drupal 7's file_unmanaged_delete_recursive().
 958   *
 959   * Note that this only deletes visible files with write permission.
 960   *
 961   * @param $path
 962   *   A filepath relative to file_directory_path.
 963   * @param $delete_root
 964   *   A boolean if TRUE will delete the $path directory afterwards.
 965   */
 966  function _xmlsitemap_delete_recursive($path, $delete_root = FALSE) {
 967    if (is_file($path) || is_link($path)) {
 968      unlink($path);
 969    }
 970    elseif (is_dir($path)) {
 971      $dir = dir($path);
 972      while (($entry = $dir->read()) !== FALSE) {
 973        if ($entry == '.' || $entry == '..') {
 974          continue;
 975        }
 976        $entry_path = $path . '/' . $entry;
 977        _xmlsitemap_delete_recursive($entry_path, TRUE);
 978      }
 979      $dir->close();
 980      return $delete_root ? rmdir($path) : TRUE;
 981    }
 982  }
 983  
 984  /**
 985   * Load a language object by its language code.
 986   *
 987   * @param $language
 988   *   A language code. If not provided the default language will be returned.
 989   * @return
 990   *   A language object.
 991   */
 992  function xmlsitemap_language_load($language = '') {
 993    $languages = &xmlsitemap_static(__FUNCTION__);
 994  
 995    if (!isset($languages)) {
 996      $languages = language_list();
 997      $languages[''] = NULL;
 998    }
 999  
1000    return isset($languages[$language]) ? $languages[$language] : NULL;
1001  }
1002  
1003  function xmlsitemap_get_link_type_enabled_bundles($entity_type) {
1004    $bundles = array();
1005    $info = xmlsitemap_get_link_info($entity_type);
1006    foreach ($info['bundles'] as $bundle => $bundle_info) {
1007      $settings = xmlsitemap_link_bundle_load($entity_type, $bundle);
1008      if (!empty($settings['status'])) {
1009      //if (!empty($bundle_info['xmlsitemap']['status'])) {
1010        $bundles[] = $bundle;
1011      }
1012    }
1013    return $bundles;
1014  }
1015  
1016  function xmlsitemap_get_link_type_indexed_status($entity_type, $bundle = '') {
1017    $info = xmlsitemap_get_link_info($entity_type);
1018    $status['indexed'] = db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE type = '%s' AND subtype = '%s'", $entity_type, $bundle));
1019    $status['visible'] = db_result(db_query("SELECT COUNT(id) FROM {xmlsitemap} WHERE type = '%s' AND subtype = '%s' AND status = 1 AND access = 1", $entity_type, $bundle));
1020    $base_table = db_escape_table($info['base table']);
1021    $id_key = db_escape_string($info['entity keys']['id']);
1022    if (!empty($info['entity keys']['bundle'])) {
1023      $bundle_key = db_escape_string($info['entity keys']['bundle']);
1024      $bundle_placeholder = db_type_placeholder(_xmlsitemap_get_field_type($info['base table'], $info['entity keys']['bundle']));
1025      $status['total'] = db_result(db_query("SELECT COUNT($id_key) FROM {{$base_table}} WHERE $id_key > 0 AND $bundle_key = $bundle_placeholder", $bundle));
1026    }
1027    else {
1028      $status['total'] = db_result(db_query("SELECT COUNT($id_key) FROM {{$base_table}} WHERE $id_key > 0"));
1029    }
1030    return $status;
1031  }
1032  
1033  function xmlsitemap_link_bundle_settings_save($entity, $bundle, array $settings, $update_links = TRUE) {
1034    if ($update_links) {
1035      $old_settings = xmlsitemap_link_bundle_load($entity, $bundle);
1036      if ($settings['status'] != $old_settings['status']) {
1037        xmlsitemap_link_update_multiple(array('status' => $settings['status']), array('type' => $entity, 'subtype' => $bundle, 'status_override' => 0));
1038      }
1039      if ($settings['priority'] != $old_settings['priority']) {
1040        xmlsitemap_link_update_multiple(array('priority' => $settings['priority']), array('type' => $entity, 'subtype' => $bundle, 'priority_override' => 0));
1041      }
1042    }
1043  
1044    variable_set("xmlsitemap_settings_{$entity}_{$bundle}", $settings);
1045    cache_clear_all('xmlsitemap:link_info:', 'cache', TRUE);
1046    //xmlsitemap_get_link_info(NULL, TRUE);
1047  }
1048  
1049  function xmlsitemap_link_bundle_rename($entity, $bundle_old, $bundle_new) {
1050    if ($bundle_old != $bundle_new) {
1051      $settings = xmlsitemap_link_bundle_load($entity, $bundle_old);
1052      variable_del("xmlsitemap_settings_{$entity}_{$bundle_old}");
1053      xmlsitemap_link_bundle_settings_save($entity, $bundle_new, $settings, FALSE);
1054      xmlsitemap_link_update_multiple(array('subtype' => $bundle_new), array('type' => $entity, 'subtype' => $bundle_old));
1055    }
1056  }
1057  
1058  function xmlsitemap_link_bundle_load($entity, $bundle) {
1059    $settings = variable_get("xmlsitemap_settings_{$entity}_{$bundle}", array());
1060    $settings += array('status' => XMLSITEMAP_STATUS_DEFAULT, 'priority' => XMLSITEMAP_PRIORITY_DEFAULT);
1061    return $settings;
1062  }
1063  
1064  function xmlsitemap_link_bundle_delete($entity, $bundle, $delete_links = TRUE) {
1065    variable_del("xmlsitemap_settings_{$entity}_{$bundle}");
1066    if ($delete_links) {
1067      xmlsitemap_link_delete_multiple(array('type' => $entity, 'subtype' => $bundle));
1068    }
1069    cache_clear_all('xmlsitemap:link_info:', 'cache', TRUE);
1070    //xmlsitemap_get_link_info(NULL, TRUE);
1071  }
1072  
1073  function xmlsitemap_can_admin_bundle($entity, $bundle) {
1074    $info = xmlsitemap_get_link_info($entity);
1075  
1076    if (isset($info['bundles'][$bundle]['admin'])) {
1077      $admin = $info['bundles'][$bundle]['admin'];
1078      $admin += array('access arguments' => array());
1079  
1080      if (!isset($admin['access callback']) && count($admin['access arguments']) == 1) {
1081        $admin['access callback'] = 'user_access';
1082      }
1083  
1084      if (!empty($admin['access callback'])) {
1085        return call_user_func_array($admin['access callback'], $admin['access arguments']);
1086      }
1087    }
1088  
1089    return FALSE;
1090  }
1091  
1092  function xmlsitemap_get_bundle_path($entity, $bundle) {
1093    $info = xmlsitemap_get_link_info($entity);
1094  
1095    if (!empty($info['bundles'][$bundle]['admin']['real path'])) {
1096      return $info['bundles'][$bundle]['admin']['real path'];
1097    }
1098    elseif (!empty($info['bundles'][$bundle]['admin']['path'])) {
1099      return $info['bundles'][$bundle]['admin']['path'];
1100    }
1101    else {
1102      return FALSE;
1103    }
1104  }
1105  
1106  function xmlsitemap_get_context_info($context = NULL, $reset = FALSE) {
1107    global $language;
1108    $info = &xmlsitemap_static(__FUNCTION__);
1109    xmlsitemap_load_all_includes();
1110  
1111    if ($reset) {
1112      $info = NULL;
1113    }
1114    elseif ($cached = cache_get('xmlsitemap:context_info:' . $language->language)) {
1115      $info = $cached->data;
1116    }
1117  
1118    if (!isset($info)) {
1119      $info = module_invoke_all('xmlsitemap_context_info');
1120      drupal_alter('xmlsitemap_context_info', $info);
1121      ksort($info);
1122      // Cache by language since this info contains translated strings.
1123      cache_set('xmlsitemap:context_info:' . $language->language, $info);
1124    }
1125  
1126    if (isset($context)) {
1127      return isset($info[$context]) ? $info[$context] : NULL;
1128    }
1129  
1130    return $info;
1131  }
1132  
1133  /**
1134   * Get the sitemap context of the current request.
1135   */
1136  function xmlsitemap_get_current_context() {
1137    $context = &xmlsitemap_static(__FUNCTION__);
1138    xmlsitemap_load_all_includes();
1139  
1140    if (!isset($context)) {
1141      $context = module_invoke_all('xmlsitemap_context');
1142      drupal_alter('xmlsitemap_context', $context);
1143      asort($context);
1144    }
1145  
1146    return $context;
1147  }
1148  
1149  /**
1150   * Run a progressive batch operation.
1151   */
1152  function xmlsitemap_run_progressive_batch() {
1153    $batch = batch_get();
1154    if (!empty($batch)) {
1155      // If there is already something in the batch, don't run.
1156      return FALSE;
1157    }
1158  
1159    $args = func_get_args();
1160    $batch_callback = array_shift($args);
1161  
1162    if (!lock_acquire($batch_callback)) {
1163      return FALSE;
1164    }
1165  
1166    // Build the batch array.
1167    $batch = call_user_func_array($batch_callback, $args);
1168    batch_set($batch);
1169  
1170    // We need to manually set the progressive variable again.
1171    // @todo Remove when http://drupal.org/node/638712 is fixed.
1172    $batch =& batch_get();
1173    $batch['progressive'] = FALSE;
1174  
1175    // Run the batch process.
1176    batch_process();
1177  
1178    lock_release($batch_callback);
1179    return TRUE;
1180  }
1181  
1182  function _xmlsitemap_sitemap_context_summary(array $sitemap, $context_key, array $context_info) {
1183    $context_value = isset($sitemap['context'][$context_key]) ? $sitemap['context'][$context_key] : NULL;
1184  
1185    if (!isset($context_value)) {
1186      return t('Default');
1187    }
1188    elseif (!empty($context_info['summary callback'])) {
1189      return $context_info['summary callback']($context_value);
1190    }
1191    else {
1192      return $context_value;
1193    }
1194  }
1195  
1196  /**
1197   * Workaround for missing breadcrumbs on callback and action paths.
1198   */
1199  function _xmlsitemap_set_breadcrumb($path = 'admin/settings/xmlsitemap') {
1200    $breadcrumb = array();
1201    $path = explode('/', $path);
1202    do {
1203      $menu_path = implode('/', $path);
1204      $menu_item = menu_get_item($menu_path);
1205      array_unshift($breadcrumb, l($menu_item['title'], $menu_path));
1206    } while (array_pop($path) && !empty($path));
1207    array_unshift($breadcrumb, l(t('Home'), NULL));
1208    drupal_set_breadcrumb($breadcrumb);
1209  }
1210  
1211  // Functions specific to the Drupal 6 branch of this module.
1212  
1213  function xmlsitemap_static_reset($name = NULL) {
1214    xmlsitemap_static($name, NULL, TRUE);
1215  }
1216  
1217  function &xmlsitemap_static($name, $default_value = NULL, $reset = FALSE) {
1218    static $data = array(), $default = array();
1219    if (!isset($name)) {
1220      // All variables are reset. This needs to be done one at a time so that
1221      // references returned by earlier invocations of drupal_static() also get
1222      // reset.
1223      foreach ($default as $name => $value) {
1224        $data[$name] = $value;
1225      }
1226      // As the function returns a reference, the return should always be a
1227      // variable.
1228      return $data;
1229    }
1230    if ($reset) {
1231      // The reset means the default is loaded.
1232      if (array_key_exists($name, $default)) {
1233        $data[$name] = $default[$name];
1234      }
1235      else {
1236        // Reset was called before a default is set and yet a variable must be
1237        // returned.
1238        return $data;
1239      }
1240    }
1241    elseif (!array_key_exists($name, $data)) {
1242      // Store the default value internally and also copy it to the reference to
1243      // be returned.
1244      $default[$name] = $data[$name] = $default_value;
1245    }
1246    return $data[$name];
1247  }
1248  
1249  function xmlsitemap_sitemap_get_all_smids() {
1250    $smids = array();
1251    $query = db_query("SELECT smid FROM {xmlsitemap_sitemap}");
1252    while ($smid = db_result($query)) {
1253      $smids[] = $smid;
1254    }
1255    return $smids;
1256  }
1257  
1258  /**
1259   * Given an table and field, return the field type.
1260   *
1261   * @param $table
1262   *   The table name.
1263   * @param $field
1264   *   The field name.
1265   * @return
1266   *   The schema type of {table}.field.
1267   */
1268  function _xmlsitemap_get_field_type($table, $field) {
1269    $schema = &xmlsitemap_static(__FUNCTION__);
1270    if (!isset($schema[$table])) {
1271      $schema[$table] = drupal_get_schema($table);
1272    }
1273    return $schema[$table]['fields'][$field]['type'];
1274  }
1275  
1276  /**
1277   * Load all modulename.xmlsitemap.inc files.
1278   *
1279   * Instead of blindly running on all modules like module_load_all_includes(),
1280   * this function will cache which modules actually have those files, which
1281   * benefits performance.
1282   */
1283  function xmlsitemap_load_all_includes() {
1284    $modules = &xmlsitemap_static(__FUNCTION__);
1285  
1286    if (!isset($modules)) {
1287      if ($cache = cache_get('xmlsitemap:registry:xmlsitemap.inc')) {
1288        $modules = $cache->data;
1289      }
1290      else {
1291        $modules = module_list();
1292      }
1293  
1294      foreach ($modules as $index => $module) {
1295        if (module_load_include('xmlsitemap.inc', $module) === FALSE) {
1296          // If the module.xmlsitemap.inc file does not exist, remove it from
1297          // the registry.
1298          unset($modules[$index]);
1299        }
1300      }
1301  
1302      if (!$cache) {
1303        cache_set('xmlsitemap:registry:xmlsitemap.inc', $modules);
1304      }
1305    }
1306  }
1307  
1308  /**
1309   * Backport of element_get_visible_children() from Drupal 7.
1310   */
1311  function xmlsitemap_element_get_visible_children(array $elements) {
1312    foreach (element_children($elements) as $key) {
1313      // Skip un-accessible children.
1314      if (isset($elements[$key]['#access']) && !$elements[$key]['#access']) {
1315        continue;
1316      }
1317  
1318      // Skip value and hidden elements, since they are not rendered.
1319      if (isset($elements[$key]['#type']) && in_array($elements[$key]['#type'], array('value', 'hidden'))) {
1320        continue;
1321      }
1322  
1323      return TRUE;
1324    }
1325  
1326    return FALSE;
1327  }


Generated: Thu Mar 24 11:18:33 2011 Cross-referenced by PHPXref 0.7