xmlsitemap.module in XML sitemap 5
Same filename and directory in other branches
Creates a site map compatible with the sitemaps.org schema.
File
xmlsitemap.moduleView source
<?php
/**
* @file Creates a site map compatible with the sitemaps.org schema.
*/
/**
* @addtogroup xmlsitemap
* @{
*/
/**
* Implementation of hook_help().
*/
function xmlsitemap_help($section) {
switch ($section) {
case 'admin/settings/xmlsitemap':
case 'admin/settings/xmlsitemap/settings':
return t('Configure the site map. Your site map is at !url.', array(
'!url' => '<a href="' . xmlsitemap_url('sitemap.xml', drupal_lookup_path('alias', 'sitemap.xml') ? drupal_lookup_path('alias', 'sitemap.xml') : NULL, NULL, NULL, TRUE) . '">' . xmlsitemap_url('sitemap.xml', drupal_lookup_path('alias', 'sitemap.xml') ? drupal_lookup_path('alias', 'sitemap.xml') : NULL, NULL, NULL, TRUE) . '</a>',
));
case 'admin/settings/xmlsitemap/engines':
return t('Configure behavior for search engines.');
case 'admin/settings/xmlsitemap/additional':
return t('Set up additional links for your site map.');
}
}
/**
* Implementation of hook_menu().
*/
function xmlsitemap_menu($may_cache) {
$items = array();
if ($may_cache) {
$items[] = array(
'path' => 'admin/settings/xmlsitemap',
'title' => t('XML Sitemap'),
'description' => t('Configure site map.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'xmlsitemap_settings_sitemap',
),
'access' => user_access('administer site configuration'),
);
$items[] = array(
'path' => 'admin/settings/xmlsitemap/settings',
'title' => t('Site map'),
'description' => t('Configure site map.'),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -1,
);
$items[] = array(
'path' => 'admin/settings/xmlsitemap/engines',
'title' => t('Search engines'),
'description' => t('Configure search engines.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'xmlsitemap_settings_engines',
),
'type' => MENU_LOCAL_TASK,
'access' => user_access('administer site configuration'),
);
$items[] = array(
'path' => 'admin/settings/xmlsitemap/additional',
'title' => t('Additional'),
'description' => t('Configure additional links.'),
'callback' => 'drupal_get_form',
'callback arguments' => array(
'xmlsitemap_settings_additional',
),
'type' => MENU_LOCAL_TASK,
'access' => user_access('administer site configuration'),
'weight' => 1,
);
$items[] = array(
'path' => 'sitemap.xml',
'title' => t('Site map index'),
'callback' => '_xmlsitemap_output',
'type' => MENU_CALLBACK,
'access' => user_access('access content'),
);
}
else {
$chunk_count = variable_get('xmlsitemap_chunk_count', 0);
for ($chunk = 0; $chunk < $chunk_count; ++$chunk) {
$items[] = array(
'path' => "sitemap{$chunk}.xml",
'title' => t('Site map !number', array(
'!number' => $chunk,
)),
'callback' => '_xmlsitemap_output',
'callback arguments' => array(
$chunk,
),
'type' => MENU_CALLBACK,
'access' => user_access('access content'),
);
}
}
return $items;
}
/**
* Menu callback; return site map settings form.
*/
function xmlsitemap_settings_sitemap() {
$form['xmlsitemap_chunk_size'] = array(
'#type' => 'textfield',
'#title' => t('Chunk size'),
'#default_value' => variable_get('xmlsitemap_chunk_size', 50000),
'#size' => 10,
'#maxlength' => 5,
'#description' => t('This is the number of links to include in one site map. Values can range between 1 and 50,000. If the total number of links exceeds the chunk size, multiple site maps will be generated.'),
'#weight' => -1,
);
$form['xmlsitemap_front_page_priority'] = array(
'#type' => 'select',
'#title' => t('Front page priority'),
'#default_value' => variable_get('xmlsitemap_front_page_priority', 1),
'#options' => xmlsitemap_priority_options(),
'#description' => t('This is the absolute priority for the front page.'),
'#weight' => -1,
);
return system_settings_form($form);
}
/**
* Validate site map settings form.
*/
function xmlsitemap_settings_sitemap_validate($form_id, $form_values) {
if ($form_values['xmlsitemap_chunk_size'] > 50000) {
form_set_error('xmlsitemap_chunk_size', t('Cannot send more than 50,000 links at one time.'));
}
}
/**
* Submit site map settings form.
*/
function xmlsitemap_settings_sitemap_submit($form_id, $form_values) {
system_settings_form_submit($form_id, $form_values);
xmlsitemap_update_sitemap();
}
/**
* Menu callback; return search engine settings form.
*/
function xmlsitemap_settings_engines() {
$form['submission'] = array(
'#type' => 'fieldset',
'#title' => t('Submission settings'),
);
$form['submission']['xmlsitemap_submit'] = array(
'#type' => 'checkbox',
'#title' => t('Submit site map when updated.'),
'#default_value' => variable_get('xmlsitemap_submit', FALSE),
'#description' => t('If enabled, search engines will be notified of changes to the site map each time it is updated.'),
);
$form['submission']['xmlsitemap_cron_submit'] = array(
'#type' => 'checkbox',
'#title' => t('Submit site map on cron run.'),
'#default_value' => variable_get('xmlsitemap_cron_submit', FALSE),
'#description' => t('If enabled, search engines will be notified of changes to the site map each time cron is run.'),
);
$form['submission']['xmlsitemap_log_access'] = array(
'#type' => 'checkbox',
'#title' => t('Log access.'),
'#default_value' => variable_get('xmlsitemap_log_access', FALSE),
'#description' => t('If enabled, a watchdog entry will be made each time the site map is accessed, containing information about the requestor.'),
);
$form = array_merge($form, module_invoke_all('xmlsitemap_engines', 'form'));
menu_rebuild();
return system_settings_form($form);
}
/**
* Submit search engine settings form.
*/
function xmlsitemap_settings_engines_submit($form_id, $form_values) {
if ($form_values['xmlsitemap_root']) {
$form_values['xmlsitemap_submit'] = FALSE;
$form_values['xmlsitemap_log_access'] = FALSE;
}
system_settings_form_submit($form_id, $form_values);
}
/**
* Menu callback; return additional links form.
*/
function xmlsitemap_settings_additional() {
$form['xmlsitemap_additional_links_priority'] = array(
'#type' => 'select',
'#title' => t('Link priority'),
'#default_value' => variable_get('xmlsitemap_additional_links_priority', 0.5),
'#options' => xmlsitemap_priority_options(),
'#description' => t('This is the default priority for additional links.'),
);
$form['delete']['#tree'] = TRUE;
$form['path']['#tree'] = TRUE;
$form['link']['#tree'] = TRUE;
$form['link']['new'] = array(
'#type' => 'textfield',
'#size' => 40,
'#description' => t('Enter a Drupal path to add to the site map.'),
'#attributes' => array(
'tabindex' => 1,
),
);
$form['old_priority']['#tree'] = TRUE;
$form['priority']['#tree'] = TRUE;
$form['priority']['new'] = array(
'#type' => 'select',
'#default_value' => 'NULL',
'#options' => xmlsitemap_priority_options('default'),
'#attributes' => array(
'tabindex' => 2,
),
);
$result = pager_query("SELECT path, priority FROM {xmlsitemap_additional} ORDER BY last_changed DESC", 50);
while ($link = db_fetch_object($result)) {
$id = $link->path == 'new' ? '_new' : str_replace(array(
'_',
'%',
), array(
'__',
'_',
), urlencode($link->path));
$form['delete'][$id] = array(
'#type' => 'checkbox',
'#default_value' => FALSE,
);
$form['path'][$id] = array(
'#type' => 'value',
'#value' => $link->path,
);
$form['link'][$id] = array(
'#value' => l($link->path, $link->path),
);
$priority = isset($link->priority) ? $link->priority : 'NULL';
$form['old_priority'][$id] = array(
'#type' => 'value',
'#value' => $priority,
);
$form['priority'][$id] = array(
'#type' => 'select',
'#default_value' => $priority,
'#options' => xmlsitemap_priority_options('default'),
);
}
$form['pager'] = array(
'#value' => theme('pager', NULL, 50),
);
return system_settings_form($form);
}
/**
* Theme additional links form.
* @ingroup themeable
*/
function theme_xmlsitemap_settings_additional($form) {
$output = '';
$output .= drupal_render($form['xmlsitemap_additional_links_priority']);
$header = array(
t('Delete'),
t('Path'),
t('Priority'),
);
foreach (element_children($form['link']) as $id) {
$row = array();
$row[] = isset($form['delete'][$id]) ? drupal_render($form['delete'][$id]) : array_merge(array(
'header' => TRUE,
'valign' => 'bottom',
), theme('table_select_header_cell'));
$row[] = drupal_render($form['link'][$id]);
$row[] = drupal_render($form['priority'][$id]);
$rows[$id] = array(
'data' => $row,
'valign' => 'top',
);
}
if (!empty($rows)) {
$output .= theme('table', $header, $rows);
}
$output .= drupal_render($form);
drupal_add_js('document.getElementById("edit-link-new").focus()', 'inline', 'footer');
return $output;
}
/**
* Submit additional links form.
*/
function xmlsitemap_settings_additional_submit($form_id, $form_values) {
$update = FALSE;
if ($form_values['op'] == t('Save configuration')) {
if ($form_values['xmlsitemap_additional_links_priority'] != variable_get('xmlsitemap_additional_links_priority', 0.1)) {
$update = TRUE;
}
if (!empty($form_values['delete'])) {
foreach ($form_values['delete'] as $id => $delete) {
if ($delete || $form_values['path'][$id] == trim($form_values['link']['new'])) {
db_query("DELETE FROM {xmlsitemap_additional} WHERE path = '%s'", $form_values['path'][$id]);
unset($form_values['priority'][$id]);
$update = TRUE;
}
}
unset($form_values['delete']);
}
$path = trim($form_values['link']['new']);
$pid = db_result(db_query("SELECT pid FROM {url_alias} WHERE src = '%s'", $path));
if (!empty($path)) {
db_query("\n INSERT INTO {xmlsitemap_additional} (path, pid, last_changed, priority) VALUES ('%s', %s, %d, %s)\n ", $path, empty($pid) ? 'NULL' : $pid, time(), $form_values['priority']['new']);
unset($form_values['link'], $form_values['priority']['new']);
$update = TRUE;
}
if (!empty($form_values['priority'])) {
foreach ($form_values['priority'] as $id => $priority) {
if ($priority != $form_values['old_priority'][$id]) {
$pid = db_result(db_query("SELECT pid FROM {url_alias} WHERE src = '%s'", $form_values['path'][$id]));
db_query("\n UPDATE {xmlsitemap_additional}\n SET pid = %s, previously_changed = last_changed, last_changed = %d, priority = %s\n WHERE path = '%s'\n ", empty($pid) ? 'NULL' : $pid, time(), $priority, $form_values['path'][$id]);
$update = TRUE;
}
}
unset($form_values['path'], $form_values['priority'], $form_values['old_priority']);
}
}
elseif (variable_get('xmlsitemap_additional_links_priority', 0.1) != 0.1) {
if (in_array('NULL', $form_values['old_priority'])) {
$update = TRUE;
}
unset($form_values['delete'], $form_values['path'], $form_values['link'], $form_values['old_priority'], $form_values['priority']);
}
system_settings_form_submit($form_id, $form_values);
if ($update) {
xmlsitemap_update_sitemap();
}
}
/**
* Get an array of site map priority options.
* @param $option:
* If not given, the array will include priority values from 0.0 to 1.0.
* - exclude: Add option to exclude item from site map.
* - default: Add option to use default priority. Only for cases where a
* default priority exists.
* - both: Add both the default and exclude options.
* @return An array of priority options.
*/
function xmlsitemap_priority_options($option = NULL) {
if ($option == 'default' || $option == 'both') {
$options['NULL'] = t('Default');
}
$options['1'] = '1.0';
$values = array(
'0.9',
'0.8',
'0.7',
'0.6',
'0.5',
'0.4',
'0.3',
'0.2',
'0.1',
);
foreach ($values as $value) {
$options[$value] = $value;
}
$options['0'] = '0.0';
if ($option == 'exclude' || $option == 'both') {
$options['-1'] = t('Not in site map');
}
return $options;
}
/**
* Implementation of hook_robotstxt().
*/
function xmlsitemap_robotstxt() {
return array(
"Sitemap: " . xmlsitemap_url('sitemap.xml', drupal_lookup_path('alias', 'sitemap.xml') ? drupal_lookup_path('alias', 'sitemap.xml') : NULL, NULL, NULL, TRUE),
);
}
/**
* Menu callback; display the site map.
* @param $chunk:
* An integer specifying which chunk of the site map is being requested. If
* not set and there is more than one chunk, display the site map index.
* @return None
*/
function _xmlsitemap_output($chunk = NULL) {
drupal_set_header('Content-type: text/xml; charset=utf-8');
global $user;
$dest = file_directory_path() . '/xmlsitemap';
file_check_directory($dest, FILE_CREATE_DIRECTORY);
if (isset($chunk)) {
$dest .= "/sitemap{$chunk}.xml.gz";
$type = t('Site map @chunk', array(
'@chunk' => $chunk,
));
}
else {
$dest .= '/sitemap.xml.gz';
$link_count = _xmlsitemap_link_count();
$chunk_size = variable_get('xmlsitemap_chunk_size', 50000);
$type = $link_count > $chunk_size ? t('Site map index') : t('Site map');
}
$status = TRUE;
if (!file_exists($dest) || variable_get('xmlsitemap_update', FALSE)) {
$page = isset($chunk) ? $chunk : 'index';
$status = _xmlsitemap_update_cache($page);
}
if ($status) {
if (strpos($_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip') === FALSE || zlib_get_coding_type() !== FALSE || extension_loaded('eAccelerator') || variable_get('cache', CACHE_DISABLED) != CACHE_DISABLED && empty($user->uid)) {
readgzfile($dest);
}
else {
drupal_set_header('Content-Encoding: gzip');
print file_get_contents($dest);
}
if (variable_get('xmlsitemap_log_access', FALSE)) {
$message = array_shift(module_invoke_all('xmlsitemap_engines', 'access', $type));
$message = isset($message) ? $message : t('!sitemap downloaded by @user-agent at @address.', array(
'!sitemap' => $type,
'@user-agent' => $_SERVER['HTTP_USER_AGENT'],
'@address' => $_SERVER['REMOTE_ADDR'],
));
watchdog('xmlsitemap', $message);
}
}
else {
drupal_not_found();
}
}
/**
* Count the total number of links in the site.
* @return An integer containing the total number of links
*/
function _xmlsitemap_link_count() {
static $count;
$count = isset($count) ? $count : count(_xmlsitemap_links());
return $count;
}
/**
* Update the cached site map files.
* @return TRUE if the update was successful, FALSE otherwise.
*/
function _xmlsitemap_update_cache($page = NULL) {
global $user;
$current_user = $user;
$user = user_load(array(
'uid' => 0,
));
$path = file_directory_path() . '/xmlsitemap';
file_check_directory($path, FILE_CREATE_DIRECTORY);
$node_count = db_result(db_query("SELECT COUNT(*) FROM {node}"));
$dest = $path . '/sitemap.xml.gz';
$link_count = _xmlsitemap_link_count();
$chunk_size = variable_get('xmlsitemap_chunk_size', 50000);
$status = TRUE;
if ($link_count > $chunk_size) {
$data = gzencode(_xmlsitemap_output_index($link_count));
if (file_save_data($data, $dest, FILE_EXISTS_REPLACE) === 0 && ($page == 'index' || !isset($page))) {
$status = FALSE;
}
for ($chunk = 0; $chunk < $link_count / $chunk_size; ++$chunk) {
$dest = $path . "/sitemap{$chunk}.xml.gz";
$data = gzencode(_xmlsitemap_output_chunk($chunk));
if (file_save_data($data, $dest, FILE_EXISTS_REPLACE) === 0 && ($page == $chunk || !isset($page))) {
$status = FALSE;
}
}
}
else {
$chunk = 0;
$data = gzencode(_xmlsitemap_output_chunk($chunk));
if (file_save_data($data, $dest, FILE_EXISTS_REPLACE) === 0 && ($page == 'index' || !isset($page))) {
$status = FALSE;
}
}
variable_set('xmlsitemap_chunk_count', $chunk);
variable_set('xmlsitemap_update', FALSE);
if (!$status) {
drupal_set_message(t('Unable to load site map. Make sure that there is an xmlsitemap directory in your files directory and that it is writable by Drupal.'), 'error');
}
$user = $current_user;
return $status;
}
/**
* Generate the site map index.
* @param $link_count:
* An integer containing the total number of links in the site
* @return A string containing the site map index
*/
function _xmlsitemap_output_index($link_count) {
$output = '';
$xsl_path = file_directory_path() . '/xmlsitemap/gss.xsl';
$xsl_path = file_exists($xsl_path) ? _xmlsitemap_file_create_url($xsl_path) : base_path() . drupal_get_path('module', 'xmlsitemap') . '/gss/gss.xsl';
$output .= '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$output .= '<?xml-stylesheet type="text/xsl" href="' . $xsl_path . '" ?>' . "\n";
$output .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"' . "\n";
$output .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . "\n";
$output .= ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9' . "\n";
$output .= ' http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd">' . "\n";
$chunk_size = variable_get('xmlsitemap_chunk_size', 50000);
for ($chunk = 0; $chunk < $link_count / $chunk_size; ++$chunk) {
$output .= '<sitemap><loc>' . xmlsitemap_url("sitemap{$chunk}.xml", NULL, NULL, NULL, TRUE) . '</loc>';
$previous = $chunk * $chunk_size;
$links = array_slice(_xmlsitemap_links(), $previous, $chunk_size);
$output .= '<lastmod>' . gmdate('Y-m-d\\TH:i:s+00:00', array_reduce($links, '_xmlsitemap_chunk_last_change')) . '</lastmod>';
$output .= "</sitemap>\n";
}
$output .= '</sitemapindex>';
return $output;
}
/**
* Compare link modification time to modification time of previous link.
* @param $time:
* Modification time of previous link
* @param $value:
* Link array
* @return Most recent time
*/
function _xmlsitemap_chunk_last_change($time, $value) {
if ($time < $value['#lastmod']) {
$time = $value['#lastmod'];
}
return $time;
}
/**
* Generate a chunk of the site map.
* @param $chunk:
* An integer specifying which chunk of the site map to display
* @return A string containing a chunk of the site map
*/
function _xmlsitemap_output_chunk($chunk) {
$output = '';
if (!ini_get('safe_mode')) {
set_time_limit(240);
}
$xsl_path = file_directory_path() . '/xmlsitemap/gss.xsl';
$xsl_path = file_exists($xsl_path) ? _xmlsitemap_file_create_url($xsl_path) : base_path() . drupal_get_path('module', 'xmlsitemap') . '/gss/gss.xsl';
$output .= '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
$output .= '<?xml-stylesheet type="text/xsl" href="' . $xsl_path . '" ?>' . "\n";
$output .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"' . "\n";
$output .= ' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"' . "\n";
$output .= ' xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9' . "\n";
$output .= ' http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">' . "\n";
$chunk_size = variable_get('xmlsitemap_chunk_size', 50000);
$previous = $chunk * $chunk_size;
$output .= implode("\n", _xmlsitemap_format(array_slice(_xmlsitemap_links(), $previous, $chunk_size)));
$output .= "\n</urlset>";
return $output;
}
/**
* Modified version of file_create_url(). Allows us to remove language
* prefixes.
* @param $path: the path to the file
* @return A URL to the file
*/
function _xmlsitemap_file_create_url($path) {
// Strip file_directory_path from $path. We only include relative paths in urls.
if (strpos($path, file_directory_path() . '/') === 0) {
$path = trim(substr($path, strlen(file_directory_path())), '\\/');
}
switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
case FILE_DOWNLOADS_PUBLIC:
return $GLOBALS['base_url'] . '/' . file_directory_path() . '/' . str_replace('\\', '/', $path);
case FILE_DOWNLOADS_PRIVATE:
return xmlsitemap_url('system/files/' . $path, NULL, NULL, NULL, TRUE);
}
}
/**
* Implementation of hook_file_download().
*/
function xmlsitemap_file_download($file) {
if ($file == 'xmlsitemap/gss.xsl') {
return array(
'Content-Type:',
);
}
}
/**
* Get all site map links.
* @return An array of links from hook_xmlsitemap_links().
*/
function _xmlsitemap_links() {
static $links;
if (!isset($links)) {
if (module_exists('i18n')) {
i18n_selection_mode('off');
}
$entries = module_invoke_all('xmlsitemap_links');
if (module_exists('i18n')) {
i18n_selection_mode('reset');
}
if (!empty($entries)) {
foreach ($entries as $key => $link) {
$lastmod[$key] = $link['#lastmod'];
}
array_multisort($lastmod, $entries);
}
$links = $entries;
}
return $links;
}
/**
* Process an array of links.
* @param $entries: An array of links to process
* @return A string of formatted links
*/
function _xmlsitemap_format($entries) {
$links = array();
foreach ($entries as $entry) {
if (isset($entry['#loc'])) {
$link = ' <url>' . "\n";
$link .= ' <loc>' . check_url($entry['#loc']) . '</loc>' . "\n";
if (isset($entry['#lastmod'])) {
$link .= ' <lastmod>' . gmdate('Y-m-d\\TH:i:s+00:00', $entry['#lastmod']) . '</lastmod>' . "\n";
}
if (isset($entry['#changefreq'])) {
$link .= ' <changefreq>' . _xmlsitemap_frequency($entry['#changefreq']) . '</changefreq>' . "\n";
}
if (isset($entry['#priority']) && $entry['#priority'] <= 1 && $entry['#priority'] >= 0) {
$link .= ' <priority>' . number_format($entry['#priority'], 1) . '</priority>' . "\n";
}
$link .= ' </url>';
$links[] = $link;
}
}
return $links;
}
/**
* Determine the frequency of updates to a link.
* @param $interval: The number of seconds since last change
* @return A string representing the update frequency according to the
* sitemaps.org protocol
*/
function _xmlsitemap_frequency($interval) {
$frequencies = array(
'always' => 3600,
'hourly' => 86400,
'daily' => 604800,
'weekly' => 2419200,
'monthly' => 29030400,
'yearly' => 100000000,
'never' => 0,
);
$frequency = 'never';
if (!is_numeric($interval)) {
if (isset($frequencies[$interval])) {
$frequency = $interval;
}
}
else {
foreach ($frequencies as $frequency => $value) {
if ($interval < $value) {
break;
}
}
}
return $frequency;
}
/**
* Implementation of hook_xmlsitemap_links().
*/
function xmlsitemap_xmlsitemap_links($type = NULL, $excludes = array()) {
$links = array();
if (!isset($type)) {
global $base_url;
$links[] = array(
'#loc' => "{$base_url}/",
'#changefreq' => 'always',
'#priority' => variable_get('xmlsitemap_front_page_priority', 1),
);
$links = array_merge($links, _xmlsitemap_additional_links());
$links = array_merge($links, module_invoke_all('gsitemap'));
$links = array_merge($links, _xmlsitemap_xml_links());
if (!empty($links)) {
foreach ($links as $key => $link) {
$loc[$key] = $link['#loc'];
}
array_multisort($loc, $links);
}
}
return $links;
}
/**
* Get additional links.
* @return An array of links. Each link is an array containing the XML
* values for a site map URL.
*/
function _xmlsitemap_additional_links() {
$links = array();
$result = db_query("\n SELECT xa.*, ua.dst AS alias FROM {xmlsitemap_additional} xa\n LEFT JOIN {url_alias} ua ON xa.pid = ua.pid\n ");
while ($link = db_fetch_object($result)) {
$age = time() - $link->last_changed;
if (!empty($link->previously_changed)) {
$interval = $link->last_changed - $link->previously_changed;
}
else {
$interval = 0;
}
$links[] = array(
'#loc' => xmlsitemap_url($link->path, $link->alias, NULL, NULL, TRUE),
'#lastmod' => $link->last_changed,
'#changefreq' => max($age, $interval),
'#priority' => isset($link->priority) ? $link->priority : variable_get('xmlsitemap_additional_links_priority', 0.1),
);
}
return $links;
}
/**
* Extract links from site maps returned by hook_xmlsitemap_links().
* @return An array of links.
*/
function _xmlsitemap_xml_links() {
$links = array();
$xml = module_invoke_all('xmlsitemap_links', 'xml');
$xml = array_merge($xml, module_invoke_all('gsitemap', 'xml'));
foreach ($xml as $entries) {
$start = strpos($entries, '<url>');
if ($start !== FALSE) {
$length = strpos($entries, '</urlset>') - $start;
$entries = substr($entries, $start, $length);
$entries = explode('<url>', $entries);
foreach ($entries as $value) {
if (($start = strpos($value, '<loc>')) !== FALSE) {
$length = $start + strlen('<loc>');
$link['#loc'] = substr($value, $length, strpos($value, '</loc>') - $length);
if (($start = strpos($value, '<lastmod>')) !== FALSE) {
$length = $start + strlen('<lastmod>');
$t = array_shift(explode('+', substr($value, $length, strpos($value, '</lastmod>') - $length)));
$t = explode('T', $t);
$t = array_merge(explode('-', $t[0]), explode(':', $t[1]));
$link['#lastmod'] = gmmktime($t[3], $t[4], $t[5], $t[1], $t[2], $t[0]);
}
if (($start = strpos($value, '<changefreq>')) !== FALSE) {
$length = $start + strlen('<changefreq>');
$link['#changefreq'] = substr($value, $length, strpos($value, '</changefreq>') - $length);
}
if (($start = strpos($value, '<priority>')) !== FALSE) {
$length = $start + strlen('<priority>');
$link['#priority'] = substr($value, $length, strpos($value, '</priority>') - $length);
}
$links[] = $link;
}
}
}
}
return $links;
}
/**
* Modified version of url(). We don't want to do a separate database query
* for each url, so we pass the alias as an extra parameter.
* @param $alias: The URL alias. Default is NULL.
* @return The fully formatted URL
*/
function xmlsitemap_url($path = NULL, $alias = NULL, $query = NULL, $fragment = NULL, $absolute = FALSE) {
if (isset($fragment)) {
$fragment = "#{$fragment}";
}
$colonpos = strpos($path, ':');
if ($colonpos !== FALSE && !preg_match('![/?#]!', substr($path, 0, $colonpos)) && filter_xss_bad_protocol($path, FALSE) == check_plain($path)) {
if (strpos($path, '#') !== FALSE) {
list($path, $old_fragment) = explode('#', $path, 2);
if (isset($old_fragment) && !isset($fragment)) {
$fragment = "#{$old_fragment}";
}
}
if (isset($query)) {
$path .= (strpos($path, '?') !== FALSE ? '&' : '?') . $query;
}
return $path . $fragment;
}
global $base_url;
static $script;
static $clean_url;
$script = isset($script) ? $script : strpos($_SERVER['SERVER_SOFTWARE'], 'Apache') === FALSE ? 'index.php' : '';
$clean_url = isset($clean_url) ? $clean_url : variable_get('clean_url', FALSE);
$base = $absolute ? $base_url . '/' : base_path();
if (!empty($path) && $path != '<front>') {
$path = _xmlsitemap_get_path_alias($path, $alias);
$path = drupal_urlencode($path);
if (!$clean_url) {
if (isset($query)) {
return $base . $script . '?q=' . $path . '&' . $query . $fragment;
}
else {
return $base . $script . '?q=' . $path . $fragment;
}
}
else {
if (isset($query)) {
return $base . $path . '?' . $query . $fragment;
}
else {
return $base . $path . $fragment;
}
}
}
else {
if (isset($query)) {
return $base . $script . '?' . $query . $fragment;
}
else {
return $base . $fragment;
}
}
}
/**
* Modified version of drupal_get_path_alias() for xmlsitemap_url().
* @param $path: An internal Drupal path
* @param $alias: The URL alias. Default is NULL.
* @return A processed path
*/
function _xmlsitemap_get_path_alias($path, $alias = NULL) {
$result = $path;
if (!empty($alias)) {
$result = $alias;
}
if (function_exists('custom_url_rewrite')) {
$result = custom_url_rewrite('alias', $result, $path);
}
if (module_exists('i18n')) {
i18n_get_lang_prefix($result, TRUE);
}
return $result;
}
/**
* Implementation of hook_cron().
*/
function xmlsitemap_cron() {
if (variable_get('xmlsitemap_cron_submit', FALSE) && variable_get('xmlsitemap_changed', FALSE)) {
_xmlsitemap_ping();
}
}
/**
* Mark the site map as changed and the cache as needing update.
* @return None
*/
function xmlsitemap_update_sitemap() {
variable_set('xmlsitemap_changed', TRUE);
variable_set('xmlsitemap_update', TRUE);
if (variable_get('xmlsitemap_submit', FALSE)) {
_xmlsitemap_submit_on_exit();
}
}
/**
* Schedule a call to _xmlsitemap_ping() to be run on exit. Use this
* function instead of _xmlsitemap_ping() to avoid a delay in outputting
* the page to the user.
* @return TRUE if the function has been called previously, FALSE otherwise.
*/
function _xmlsitemap_submit_on_exit() {
static $called = FALSE;
$return = $called;
$called = TRUE;
return $return;
}
/**
* Implementation of hook_exit().
*/
function xmlsitemap_exit() {
if (_xmlsitemap_submit_on_exit()) {
_xmlsitemap_ping();
}
}
/**
* Submit the site map to search engines.
* @return None
*/
function _xmlsitemap_ping() {
$status = _xmlsitemap_update_cache();
if ($status) {
module_invoke_all('xmlsitemap_engines', 'ping');
variable_set('xmlsitemap_changed', FALSE);
}
}
/**
* @} End of "addtogroup xmlsitemap".
*/
Functions
Name | Description |
---|---|
theme_xmlsitemap_settings_additional | Theme additional links form. |
xmlsitemap_cron | Implementation of hook_cron(). |
xmlsitemap_exit | Implementation of hook_exit(). |
xmlsitemap_file_download | Implementation of hook_file_download(). |
xmlsitemap_help | Implementation of hook_help(). |
xmlsitemap_menu | Implementation of hook_menu(). |
xmlsitemap_priority_options | Get an array of site map priority options. |
xmlsitemap_robotstxt | Implementation of hook_robotstxt(). |
xmlsitemap_settings_additional | Menu callback; return additional links form. |
xmlsitemap_settings_additional_submit | Submit additional links form. |
xmlsitemap_settings_engines | Menu callback; return search engine settings form. |
xmlsitemap_settings_engines_submit | Submit search engine settings form. |
xmlsitemap_settings_sitemap | Menu callback; return site map settings form. |
xmlsitemap_settings_sitemap_submit | Submit site map settings form. |
xmlsitemap_settings_sitemap_validate | Validate site map settings form. |
xmlsitemap_update_sitemap | Mark the site map as changed and the cache as needing update. |
xmlsitemap_url | Modified version of url(). We don't want to do a separate database query for each url, so we pass the alias as an extra parameter. |
xmlsitemap_xmlsitemap_links | Implementation of hook_xmlsitemap_links(). |
_xmlsitemap_additional_links | Get additional links. |
_xmlsitemap_chunk_last_change | Compare link modification time to modification time of previous link. |
_xmlsitemap_file_create_url | Modified version of file_create_url(). Allows us to remove language prefixes. |
_xmlsitemap_format | Process an array of links. |
_xmlsitemap_frequency | Determine the frequency of updates to a link. |
_xmlsitemap_get_path_alias | Modified version of drupal_get_path_alias() for xmlsitemap_url(). |
_xmlsitemap_links | Get all site map links. |
_xmlsitemap_link_count | Count the total number of links in the site. |
_xmlsitemap_output | Menu callback; display the site map. |
_xmlsitemap_output_chunk | Generate a chunk of the site map. |
_xmlsitemap_output_index | Generate the site map index. |
_xmlsitemap_ping | Submit the site map to search engines. |
_xmlsitemap_submit_on_exit | Schedule a call to _xmlsitemap_ping() to be run on exit. Use this function instead of _xmlsitemap_ping() to avoid a delay in outputting the page to the user. |
_xmlsitemap_update_cache | Update the cached site map files. |
_xmlsitemap_xml_links | Extract links from site maps returned by hook_xmlsitemap_links(). |