$link) { $nid[$key] = $link['nid']; $loc[$key] = $link['#loc']; } array_multisort($nid, $loc, $links); } } return $links; } /** * Get array of excluded types. * @return An array of node types to exclude. */ function _xmlsitemap_node_excludes() { static $excludes; if (!isset($excludes)) { $excludes = array(); foreach (node_get_types() as $type => $name) { if (variable_get("xmlsitemap_node_type_priority_$type", 0.5) < 0) { $excludes[] = $type; } } } return $excludes; } /** * Get node links. * @param $excludes: An array of node types to exclude. * @return An array of links. Each link is an array containing the XML * values for a site map URL. */ function _xmlsitemap_node_links($excludes = array()) { $links = array(); if (module_exists('comment')) { $sql = " SELECT n.nid, n.type, n.promote, s.comment_count, n.changed, xn.previously_changed, s.last_comment_timestamp, xn.previous_comment, xn.priority_override, ua.dst AS alias FROM {node} n LEFT JOIN {node_comment_statistics} s ON s.nid = n.nid"; } else { $sql = " SELECT n.nid, n.type, n.promote, n.changed, xn.previously_changed, xn.priority_override, ua.dst AS alias FROM {node} n"; } $sql .= " LEFT JOIN {xmlsitemap_node} xn ON xn.nid = n.nid LEFT JOIN {url_alias} ua ON ua.pid = xn.pid WHERE n.status > 0 AND (n.type NOT IN ('". implode("', '", $excludes) ."') AND xn.priority_override IS NULL OR xn.priority_override >= 0) AND n.nid <> %d"; $result = db_query(db_rewrite_sql($sql), _xmlsitemap_node_frontpage()); while ($node = db_fetch_object($result)) { $links[] = array( 'nid' => $node->nid, '#loc' => xmlsitemap_url('node/'. $node->nid, $node->alias, NULL, NULL, TRUE), '#lastmod' => variable_get('xmlsitemap_node_count_comments', TRUE) ? max($node->changed, $node->last_comment_timestamp) : $node->changed, '#changefreq' => xmlsitemap_node_frequency($node), '#priority' => xmlsitemap_node_priority($node), ); } return $links; } function xmlsitemap_node_frequency($node) { $age = time() - $node->changed; if (variable_get('xmlsitemap_node_count_comments', TRUE)) { $age = time() - max($node->changed, $node->last_comment_timestamp); if (!empty($node->previously_changed) && isset($node->previous_comment)) { $interval = min($node->changed, $node->last_comment_timestamp) - max($node->previously_changed, $node->previous_comment); } elseif (!empty($node->previously_changed)) { $interval = min($node->changed, $node->last_comment_timestamp) - $node->previously_changed; } elseif (isset($node->previous_comment)) { $interval = min($node->changed, $node->last_comment_timestamp) - $node->previous_comment; } else { $interval = 0; } } else { $interval = empty($node->previously_changed) ? 0 : $node->changed - $node->previously_changed; } return max($age, $interval); } /** * Get the nid of the front page node. * @return Integer of front page node ID, or 0 if front page is not a node. */ function _xmlsitemap_node_frontpage() { static $nid; if (!isset($nid)) { $nid = 0; $frontpage = explode('/', drupal_get_normal_path(variable_get('site_frontpage', 'node'))); if (count($frontpage) == 2 && $frontpage[0] == 'node' && is_numeric($frontpage[1])) { $nid = $frontpage[1]; } } return $nid; } /** * Calculate the priority of a node. * @param $node: A node object * @return A number between 0 and 1, or -1 */ function xmlsitemap_node_priority($node) { static $promote_priority; static $comment_priority; static $maxcomments; $promote_priority = isset($promote_priority) ? $promote_priority : variable_get('xmlsitemap_node_promote_priority', 0.3); $comment_priority = isset($comment_priority) ? $comment_priority : variable_get('xmlsitemap_node_comment_priority', 0.5); if (!isset($maxcomments)) { $maxcomments = 0; if (module_exists('comment')) { $maxcomments = db_result(db_query("SELECT MAX(comment_count) FROM {node_comment_statistics}")); } } $priority = $node->priority_override; if (!isset($node->priority_override)) { $priority = 0; $priority += variable_get("xmlsitemap_node_type_priority_$node->type", 0.5); if ($node->promote) { $priority += $promote_priority; } if (!empty($maxcomments)) { $priority += $node->comment_count / $maxcomments * $comment_priority; } $priority = round($priority, 1); $priority = min($priority, 0.9); } return $priority; } /** * Implementation of hook_perm(). */ function xmlsitemap_node_perm() { return array('override node priority'); } /** * Implementation of hook_form_alter(). */ function xmlsitemap_node_form_alter($form_id, &$form) { switch ($form_id) { case $form['type']['#value'] .'_node_form': if (isset($form['type'])) { $node = $form['#node']; if (user_access('override node priority')) { $form['xmlsitemap_node'] = array( '#type' => 'fieldset', '#title' => t('Site map settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#weight' => 30, ); $options = xmlsitemap_priority_options('both'); $default = variable_get("xmlsitemap_node_type_priority_$node->type", '0.5'); $form['xmlsitemap_node']['priority_override'] = array( '#type' => 'select', '#title' => t('Site map priority'), '#default_value' => $node->priority_override, '#options' => $options, '#description' => t('The default priority is %priority.', array('%priority' => $options[$default])), ); } else { $form['priority_override'] = array('#type' => 'value', '#value' => $node->priority_override); } $form['xmlsitemap_node_status'] = array('#type' => 'value', '#value' => $node->status); } break; case 'node_type_form': if (isset($form['identity']['type'])) { $form['xmlsitemap_node'] = array( '#type' => 'fieldset', '#title' => t('Site map'), '#collapsible' => TRUE, '#collapsed' => TRUE, ); $form['xmlsitemap_node']['xmlsitemap_node_type_priority'] = array( '#type' => 'select', '#title' => t('Priority adjustment'), '#default_value' => variable_get("xmlsitemap_node_type_priority_{$form['#node_type']->type}", 0.5), '#options' => xmlsitemap_priority_options('exclude'), '#description' => t('This number will be added to the priority of this content type.'), ); $form['xmlsitemap_old_priority'] = array('#type' => 'value', '#value' => variable_get("xmlsitemap_node_type_priority_{$form['#node_type']->type}", 0.5)); $form['#submit']['_xmlsitemap_node_submit'] = array(); $form['submit']['#weight'] = 1; $form['reset']['#weight'] = 1; } break; case 'xmlsitemap_settings_sitemap': $form['xmlsitemap_node'] = array( '#type' => 'fieldset', '#title' => t('Content priority'), '#description' => t('The default priority for specific content types can be set on the !link pages.', array( '!link' => l(t('content type settings'), 'admin/content/types'), )), ); $form['xmlsitemap_node']['xmlsitemap_node_promote_priority'] = array( '#type' => 'select', '#title' => t('Promotion adjustment'), '#default_value' => variable_get('xmlsitemap_node_promote_priority', 0.3), '#options' => xmlsitemap_priority_options(), '#description' => t('This number will be added to the priority of each post that is promoted to the front page.'), ); $form['xmlsitemap_node']['xmlsitemap_node_comment_priority'] = array( '#type' => 'select', '#title' => t('Comment ratio weight'), '#default_value' => variable_get('xmlsitemap_node_comment_priority', 0.5), '#options' => xmlsitemap_priority_options(), '#description' => t('This number will be multiplied by the ratio of the number of comments on a post to the highest number of comments on any post—that is, this number will be added to the priority of the post with the most comments.'), ); $form['xmlsitemap_node']['xmlsitemap_node_count_comments'] = array( '#type' => 'checkbox', '#title' => t('Count comments in change date and frequency'), '#default_value' => variable_get('xmlsitemap_node_count_comments', TRUE), '#description' => t('If enabled, the frequency of comments on a post will affect its change frequency and last modification date.'), ); $form['buttons']['#weight'] = 1; break; } } /** * Implmentation of hook_nodeapi(). */ function xmlsitemap_node_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) { switch ($op) { case 'prepare': $priority = db_result(db_query("SELECT priority_override FROM {xmlsitemap_node} WHERE nid = %d", $node->nid)); $node->priority_override = isset($priority) && $priority !== FALSE ? $priority : 'NULL'; break; case 'insert': $node->priority_override = isset($node->priority_override) ? $node->priority_override : 'NULL'; $query = " INSERT INTO {xmlsitemap_node} (nid, pid, last_changed, priority_override) SELECT %d, ua.pid, %d, %s FROM {node} n"; switch ($GLOBALS['db_type']) { case 'mysql': case 'mysqli': $query .= " LEFT JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(%d AS CHAR))"; break; case 'pgsql': $query .= " LEFT JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(%d AS VARCHAR))"; break; } $query .= " LIMIT 1"; db_query($query, $node->nid, $node->changed, $node->priority_override, $node->nid); if ($node->status) { xmlsitemap_update_sitemap(); } break; case 'update': if (!isset($node->priority_override)) { $priority = db_result(db_query("SELECT priority_override FROM {xmlsitemap_node} WHERE nid = %d", $node->nid)); $node->priority_override = isset($priority) && $priority !== FALSE ? $priority : 'NULL'; } switch ($GLOBALS['db_type']) { case 'mysql': case 'mysqli': db_query(" UPDATE {xmlsitemap_node} xn LEFT JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(xn.nid AS CHAR)) SET xn.pid = ua.pid, xn.previously_changed = xn.last_changed, xn.last_changed = %d, xn.priority_override = %s WHERE xn.nid = %d ", $node->changed, $node->priority_override, $node->nid); break; case 'pgsql': db_query(" UPDATE {xmlsitemap_node} SET pid = {url_alias}.pid, previously_changed = last_changed, last_changed = %d, priority_override = %s FROM {url_alias} WHERE nid = %d AND ({url_alias}.src = CONCAT('node/', CAST(nid AS VARCHAR)) OR {url_alias}.src IS NULL) ", $node->changed, $node->priority_override, $node->nid); break; } if ($node->status || $node->xmlsitemap_node_status) { xmlsitemap_update_sitemap(); } break; case 'delete': db_query("DELETE FROM {xmlsitemap_node} WHERE nid = %d", $node->nid); if ($node->status) { xmlsitemap_update_sitemap(); } break; } } /** * Implementation of hook_comment(). */ function xmlsitemap_node_comment($comment, $op) { $comment = (object) $comment; switch ($op) { case 'insert': case 'update': case 'moderate': case 'delete': db_query("UPDATE {xmlsitemap_node} SET previous_comment = last_comment, last_comment = %d WHERE nid = %d", $comment->timestamp, $comment->nid); if (variable_get('xmlsitemap_node_count_comments', TRUE)) { xmlsitemap_update_sitemap(); } break; } } /** * Add submit actions to forms. * @return None */ function _xmlsitemap_node_submit($form_id, $form_values) { switch ($form_id) { case 'node_type_form': $op = isset($form_values['op']) ? $form_values['op'] : ''; $type = isset($form_values['old_type']) ? $form_values['old_type'] : trim($form_values['type']); $priority = $form_values['xmlsitemap_node_type_priority']; $old_priority = $form_values['xmlsitemap_old_priority']; if ($op == t('Save content type') && $priority != $old_priority || $op == t('Reset to defaults') && $old_priority != 0.1) { xmlsitemap_update_sitemap(); } break; } } /** * Implementation of hook_node_type(). */ function xmlsitemap_node_node_type($op, $info) { if ($op == 'delete' && variable_get("xmlsitemap_node_type_priority_$info->old_type", 0.5) != 0.5) { xmlsitemap_update_sitemap(); } } /** * Implementation of hook_cron(). */ function xmlsitemap_node_cron() { if (db_result(db_query_range("SELECT COUNT(*) FROM {node} n LEFT JOIN {xmlsitemap_node} xn ON xn.nid = n.nid WHERE xn.nid IS NULL", 0, 1))) { $query = " INSERT INTO {xmlsitemap_node} (nid, last_changed, last_comment, previous_comment) SELECT n.nid, n.changed, s.last_comment_timestamp, MAX(c.timestamp) FROM {node} n LEFT JOIN {node_comment_statistics} s ON s.nid = n.nid LEFT OUTER JOIN {comments} c ON c.nid = n.nid AND c.timestamp < s.last_comment_timestamp LEFT JOIN {xmlsitemap_node} xn ON xn.nid = n.nid WHERE xn.nid IS NULL GROUP BY n.nid, n.changed, s.last_comment_timestamp "; db_query($query); switch ($GLOBALS['db_type']) { case 'mysql': case 'mysqli': db_query(" UPDATE {xmlsitemap_node} xn INNER JOIN {url_alias} ua ON ua.src = CONCAT('node/', CAST(xn.nid AS CHAR)) SET xn.pid = ua.pid WHERE xn.pid IS NULL "); break; case 'pgsql': db_query(" UPDATE {xmlsitemap_node} SET pid = {url_alias}.pid FROM {url_alias} WHERE {url_alias}.src = CONCAT('node/', CAST(nid AS VARCHAR)) AND {xmlsitemap_node}.pid IS NULL "); break; } xmlsitemap_update_sitemap(); } } /** * Implementation of hook_views_style_plugins(). */ function xmlsitemap_node_views_style_plugins() { return array( 'xmlsitemap_sitemap' => array( 'name' => t('XML Sitemap: Sitemap'), 'theme' => 'xmlsitemap_node_view_sitemap', ), 'xmlsitemap_news' => array( 'name' => t('XML Sitemap: News'), 'theme' => 'xmlsitemap_node_view_news', ), ); } /** * Implementation of hook_views_query_alter(). */ function xmlsitemap_node_views_query_alter(&$query, &$view, $summary, $level) { switch ($view->page_type) { case 'xmlsitemap_news': $query->add_field('created', 'node'); case 'xmlsitemap_sitemap': $xn_join = array( 'left' => array( 'table' => 'node', 'field' => 'nid', ), 'right' => array( 'field' => 'nid', ), ); $ua_join = array( 'left' => array( 'table' => 'xmlsitemap_node', 'field' => 'pid', ), 'right' => array( 'field' => 'pid', ), ); $query->add_table('xmlsitemap_node', FALSE, 1, $xn_join); $query->add_table('url_alias', FALSE, 1, $ua_join); if (module_exists('comment')) { $query->add_table('node_comment_statistics'); $query->add_field('comment_count', 'node_comment_statistics'); $query->add_field('last_comment_timestamp', 'node_comment_statistics'); $query->add_field('previous_comment', 'xmlsitemap_node'); } $query->add_field('type', 'node'); $query->add_field('promote', 'node'); $query->add_field('changed', 'node'); $query->add_field('previously_changed', 'xmlsitemap_node'); $query->add_field('priority_override', 'xmlsitemap_node'); $query->add_field('dst', 'url_alias', 'alias'); break; } } /** * Display the nodes of a view as an XML site map. */ function theme_xmlsitemap_node_view_sitemap($view, $nodes, $type) { drupal_set_header('Content-Type: text/xml; charset=utf-8'); $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 .= ''."\n"; $output .= ''."\n"; $output .= 'changed, $node->last_comment_timestamp) : $node->changed; $output .= ' '."\n"; $output .= ' '. xmlsitemap_url('node/'. $node->nid, $node->alias, NULL, NULL, TRUE) .''."\n"; $output .= ' '. gmdate('Y-m-d\TH:i:s+00:00', $lastmod) .''."\n"; $output .= ' '. _xmlsitemap_frequency(xmlsitemap_node_frequency($node)) .''."\n"; $output .= ' '. number_format(xmlsitemap_node_priority($node), 1) .''."\n"; $output .= ' '."\n"; } $output .= ''; print $output; module_invoke_all('exit'); exit; } /** * Display the nodes of a view as a Google News site map. */ function theme_xmlsitemap_node_view_news($view, $nodes, $type) { drupal_set_header('Content-Type: text/xml; charset=utf-8'); $output .= ''."\n"; $output .= 'changed, $node->last_comment_timestamp) : $node->changed; $output .= ' '."\n"; $output .= ' '. xmlsitemap_url('node/'. $node->nid, $node->alias, NULL, NULL, TRUE) .''."\n"; $output .= ' '. gmdate('Y-m-d\TH:i:s+00:00', $lastmod) .''."\n"; $output .= ' '. _xmlsitemap_frequency(xmlsitemap_node_frequency($node)) .''."\n"; $output .= ' '. number_format(xmlsitemap_node_priority($node), 1) .''."\n"; $output .= ' '."\n"; $output .= ' '. gmdate('Y-m-d\TH:i:s+00:00', $node->created) .''."\n"; $output .= ' '."\n"; $output .= ' '."\n"; } $output .= ''; print $output; module_invoke_all('exit'); exit; } /** * @} End of "addtogroup xmlsitemap". */