| [ Index ] |
PHP Cross Reference of Drupal 6 (gatewave) |
[Summary view] [Print] [Text view]
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 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
| Generated: Thu Mar 24 11:18:33 2011 | Cross-referenced by PHPXref 0.7 |