/[drupal]/contributions/modules/gsitemap/xmlsitemap.module
ViewVC logotype

Contents of /contributions/modules/gsitemap/xmlsitemap.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.20 - (show annotations) (download) (as text)
Thu Jun 28 03:03:09 2007 UTC (2 years, 4 months ago) by darrenoh
Branch: MAIN
CVS Tags: HEAD
Changes since 1.19: +2 -2 lines
File MIME type: text/x-php
#155014 Unable to delete additional links. Patch by Adam Cooper (cooperaj).
1 <?php
2 // $Id: xmlsitemap.module,v 1.19 2007/06/15 16:00:33 darrenoh Exp $
3
4 /**
5 * @file
6 * Creates a site map compatible with the sitemaps.org schema.
7 */
8
9 /**
10 * Implementation of hook_help().
11 */
12 function xmlsitemap_help($section) {
13 switch ($section) {
14 case 'admin/settings/xmlsitemap':
15 case 'admin/settings/xmlsitemap/settings':
16 return t('The following options allow you to alter the behavior of the XML Sitemap module. Your site map can be found at !url.', array('!url' => l(url('sitemap.xml', array('absolute' => TRUE)), 'sitemap.xml')));
17 }
18 }
19
20 /**
21 * Implementation of hook_perm().
22 */
23 function xmlsitemap_perm() {
24 return array('override node priority');
25 }
26
27 /**
28 * Implementation of hook_menu().
29 */
30 function xmlsitemap_menu() {
31 $items = array();
32 $items['admin/settings/xmlsitemap'] = array(
33 'title' => 'XML Sitemap',
34 'description' => 'Adjust the settings used to generate your XML site map.',
35 'page callback' => 'drupal_get_form',
36 'page arguments' => array('xmlsitemap_admin_settings'),
37 'access arguments' => array('administer site configuration'),
38 );
39 $items['admin/settings/xmlsitemap/settings'] = array(
40 'title' => 'Settings',
41 'type' => MENU_DEFAULT_LOCAL_TASK,
42 );
43 $items['admin/settings/xmlsitemap/additional'] = array(
44 'title' => 'Additional links',
45 'description' => 'Specify additional pages to add to your site map.',
46 'page callback' => 'drupal_get_form',
47 'page arguments' => array('xmlsitemap_admin_settings_additional'),
48 'weight' => 1,
49 'type' => MENU_LOCAL_TASK,
50 );
51 $items['sitemap.xml'] = array(
52 'title' => 'Site map index',
53 'page callback' => 'xmlsitemap_output',
54 'access arguments' => array('access content'),
55 'type' => MENU_CALLBACK,
56 );
57 if ($verify = variable_get('xmlsitemap_verify', '')) {
58 $items[$verify] = array(
59 'title' => 'Google verification page',
60 'page callback' => 'xmlsitemap_verify',
61 'access arguments' => array('access content'),
62 'type' => MENU_CALLBACK,
63 );
64 }
65 for ($chunk = 0; $chunk < variable_get('xmlsitemap_chunk_count', 0); ++$chunk) {
66 $items["sitemap$chunk.xml"] = array(
67 'title' => 'Site map !number',
68 'title arguments' => array('!number' => $chunk),
69 'page callback' => 'xmlsitemap_output',
70 'page arguments' => array("$chunk"),
71 'access arguments' => array('access content'),
72 'type' => MENU_CALLBACK,
73 );
74 }
75 return $items;
76 }
77
78 /**
79 * Menu callback; display verification page for Google.
80 */
81 function xmlsitemap_verify() {
82 echo 'Hello, Google!';
83 }
84
85 /**
86 * Implementation of hook_form_alter().
87 */
88 function xmlsitemap_form_alter(&$form, $form_id) {
89 if (user_access('override node priority') && isset($form['type']) && $form_id == $form['type']['#value'] .'_node_form') {
90 $node = $form['#node'];
91 $form['xmlsitemap_settings'] = array(
92 '#type' => 'fieldset',
93 '#title' => t('XML Sitemap settings'),
94 '#collapsible' => TRUE,
95 '#collapsed' => TRUE,
96 '#weight' => 30,
97 );
98 $form['xmlsitemap_settings']['priority_override'] = array(
99 '#type' => 'textfield',
100 '#title' => t('Priority override'),
101 '#default_value' => $node->priority_override,
102 '#size' => 10,
103 '#maxlength' => 5,
104 '#description' => t('Optionally override the site map priority for this post. The lowest priority is 0.0; the highest priority is 1.0. A priority of -1 will prevent this post from appearing in the site map.'),
105 );
106 }
107 }
108
109 /**
110 * Implmentation of hook_nodeapi().
111 */
112 function xmlsitemap_nodeapi(&$node, $op, $teaser = NULL, $page = NULL) {
113 switch ($op) {
114 case 'insert':
115 if (!(strlen($node->priority_override) > 0 && is_numeric($node->priority_override) && user_access('override node priority'))) {
116 $node->priority_override = 'NULL';
117 }
118 $pid = db_result(db_query("SELECT pid FROM {url_alias} WHERE src = '%s'", 'node/'. $node->nid));
119 if ($pid === FALSE) {
120 db_query("INSERT INTO {xmlsitemap} (nid, last_changed, priority_override) VALUES(%d, %d, %s)", $node->nid, $node->changed, $node->priority_override);
121 }
122 else {
123 db_query("INSERT INTO {xmlsitemap} (nid, pid, last_changed, priority_override) VALUES (%d, %d, %d, %s)", $node->nid, $pid, $node->changed, $node->priority_override);
124 }
125 if (variable_get('xmlsitemap_submit', 0) && $node->status) {
126 _xmlsitemap_submit_on_exit();
127 }
128 else {
129 variable_set('xmlsitemap_changed', TRUE);
130 variable_set('xmlsitemap_update', TRUE);
131 }
132 break;
133 case 'prepare':
134 if ($node->nid && user_access('override node priority')) {
135 $result = db_query("SELECT priority_override FROM {xmlsitemap} WHERE nid = %d", $node->nid);
136 if ($nd = db_result($result)) {
137 $node->priority_override = $nd;
138 }
139 }
140 break;
141 case 'update':
142 if (!(strlen($node->priority_override) > 0 && is_numeric($node->priority_override))) {
143 $node->priority_override = 'NULL';
144 }
145 $pid = db_result(db_query("SELECT pid FROM {url_alias} WHERE src = '%s'", 'node/'. $node->nid));
146 $result = db_query('SELECT * FROM {xmlsitemap} x LEFT JOIN {node} n USING (nid) WHERE x.nid = %d', $node->nid);
147 if (!($oldnode = db_fetch_object($result))) {
148 if ($pid === FALSE) {
149 db_query('INSERT INTO {xmlsitemap} (nid, last_changed, priority_override) VALUES(%d, %d, %s)', $node->nid, $node->changed, $node->priority_override);
150 }
151 else {
152 db_query('INSERT INTO {xmlsitemap} (nid, pid, last_changed, priority_override) VALUES (%d, %d, %d, %s)', $node->nid, $pid, $node->changed, $node->priority_override);
153 }
154 }
155 else {
156 if (user_access('override node priority')) {
157 if ($pid === FALSE) {
158 db_query('UPDATE {xmlsitemap} SET last_changed = %d, previously_changed = %d, priority_override = %s WHERE nid = %d', $node->changed, $oldnode->last_changed, $node->priority_override, $node->nid);
159 }
160 else {
161 db_query('UPDATE {xmlsitemap} SET pid = %d, last_changed = %d, previously_changed = %s, priority_override = %s WHERE nid = %d', $pid, $node->changed, $oldnode->last_changed, $node->priority_override, $node->nid);
162 }
163 }
164 else {
165 if ($pid === FALSE) {
166 db_query('UPDATE {xmlsitemap} SET last_changed = %d, previously_changed = %d WHERE nid = %d', $node->changed, $oldnode->last_changed, $node->nid);
167 }
168 else {
169 db_query("UPDATE {xmlsitemap} SET pid = %d, last_changed = %d, previously_changed = %s WHERE nid = %d", $pid, $node->changed, $oldnode->last_changed, $node->nid);
170 }
171 }
172 }
173 if (variable_get('xmlsitemap_submit', 0) && ($node->status || $oldnode->status)) {
174 _xmlsitemap_submit_on_exit();
175 }
176 else {
177 variable_set('xmlsitemap_changed', TRUE);
178 variable_set('xmlsitemap_update', TRUE);
179 }
180 break;
181 case 'delete':
182 db_query('DELETE FROM {xmlsitemap} WHERE nid = %d', $node->nid);
183 if (variable_get('xmlsitemap_submit', 0) && $node->status) {
184 _xmlsitemap_submit_on_exit();
185 }
186 else {
187 variable_set('xmlsitemap_changed', TRUE);
188 variable_set('xmlsitemap_update', TRUE);
189 }
190 break;
191 case 'validate':
192 if (strlen($node->priority_override) > 0) {
193 if (!is_numeric($node->priority_override) || (($node->priority_override > 1) || ($node->priority_override < 0 && $node->priority_override != -1))) {
194 form_set_error('priority_override', t('Priority must be a number between 0.0 and 1.0, inclusive, or -1 to prevent this node from appearing in the site map.'));
195 }
196 }
197 break;
198 }
199 }
200
201 /**
202 * Implementation of hook_comment().
203 */
204 function xmlsitemap_comment($op, $comment) {
205 $comment = (object) $comment;
206 if ($op == 'insert' || $op == 'update' || $op == 'moderate' || $op == 'delete') {
207 $result = db_query('SELECT * FROM {xmlsitemap} WHERE nid = %d', $comment->nid);
208 if (!($node = db_fetch_object($result))) {
209 $node = db_fetch_object(db_query('SELECT nid, changed FROM {node} WHERE nid = %d', $comment->nid));
210 db_query('INSERT INTO {xmlsitemap} (nid, last_changed, last_comment) VALUES (%d, %d, %d)', $node->nid, $node->changed, $comment->timestamp);
211 }
212 else {
213 if (isset($node->last_comment)) {
214 db_query('UPDATE {xmlsitemap} SET last_comment = %d, previous_comment = %d WHERE nid = %d', $comment->timestamp, $node->last_comment, $node->nid);
215 }
216 else {
217 db_query('UPDATE {xmlsitemap} SET last_comment = %d WHERE nid = %d', $comment->timestamp, $node->nid);
218 }
219 }
220 if (variable_get('xmlsitemap_submit', 0)) {
221 _xmlsitemap_submit_on_exit();
222 }
223 else {
224 variable_set('xmlsitemap_changed', TRUE);
225 variable_set('xmlsitemap_update', TRUE);
226 }
227 }
228 }
229
230 /**
231 * Menu callback; return module settings form.
232 */
233 function xmlsitemap_admin_settings() {
234 $form['priority_settings'] = array(
235 '#type' => 'fieldset',
236 '#title' => t('Priority settings'),
237 '#collapsible' => TRUE,
238 );
239 $form['priority_settings']['xmlsitemap_frontpage'] = array(
240 '#type' => 'textfield',
241 '#title' => t('Front page priority'),
242 '#default_value' => variable_get('xmlsitemap_frontpage', '1.0'),
243 '#size' => 10,
244 '#maxlength' => 5,
245 '#description' => t('This is the absolute priority for the front page. Values can range between 0.0 and 1.0.'),
246 );
247 $form['priority_settings']['xmlsitemap_promotewt'] = array(
248 '#type' => 'textfield',
249 '#title' => t('Promotion adjustment'),
250 '#default_value' => variable_get('xmlsitemap_promotewt', '0.3'),
251 '#size' => 10,
252 '#maxlength' => 5,
253 '#description' => t('This number will be added to the priority of each node that is promoted to the front page.'),
254 );
255 $form['priority_settings']['xmlsitemap_commentwt'] = array(
256 '#type' => 'textfield',
257 '#title' => t('Comment ratio weight'),
258 '#default_value' => variable_get('xmlsitemap_commentwt', '0.5'),
259 '#size' => 10,
260 '#maxlength' => 5,
261 '#description' => t('This number will be multiplied with the ratio of the number of comments on the node over the number of comments on the node with the most comments, i.e., this number will be added to the priority of the node with the most comments.'),
262 );
263 $form['priority_settings'][] = array(
264 '#value' => '<p>'. t('You can enter -1 in any of the following fields to prevent nodes of that type from appearing in the site map.') .'</p>',
265 );
266 foreach (node_get_types('names') as $type => $name) {
267 $form['priority_settings']['xmlsitemap_'. $type .'wt'] = array(
268 '#type' => 'textfield',
269 '#title' => t('%name adjustment', array('%name' => ucfirst($name))),
270 '#default_value' => variable_get('xmlsitemap_'. $type .'wt', '0.1'),
271 '#size' => 10,
272 '#maxlength' => 5,
273 '#description' => t('This number will be added to the priority of nodes of type %name.', array('%name' => $name)),
274 );
275 }
276
277 $form['search_engines'] = array(
278 '#type' => 'fieldset',
279 '#title' => t('Search engines'),
280 '#collapsible' => TRUE,
281 '#collapsed' => TRUE,
282 );
283 $form['search_engines']['google'] = array(
284 '#type' => 'fieldset',
285 '#title' => t('Google'),
286 );
287 $form['search_engines']['google']['xmlsitemap_google_submit'] = array(
288 '#type' => 'checkbox',
289 '#title' => t('Submit site map to Google.'),
290 '#default_value' => variable_get('xmlsitemap_google_submit', TRUE),
291 );
292 $form['search_engines']['google']['xmlsitemap_google_url'] = array(
293 '#type' => 'textfield',
294 '#title' => t('Submission URL'),
295 '#default_value' => variable_get('xmlsitemap_google_url', 'http://www.google.com/webmasters/tools/ping?sitemap='. url('sitemap.xml', array('absolute' => TRUE))),
296 '#description' => t('The URL to submit the site map to.'),
297 );
298 $form['search_engines']['google']['xmlsitemap_verify'] = array(
299 '#type' => 'textfield',
300 '#title' => t('Verification link'),
301 '#default_value' => variable_get('xmlsitemap_verify', ''),
302 '#description' => t('In order to show statistics, Google will ask you to verify that you control this site by creating a page with a certain name. Enter that name here and the XML Sitemap module will hook that filename. Note that this will only work if you have clean URLs enabled.'),
303 );
304 $form['search_engines']['yahoo'] = array(
305 '#type' => 'fieldset',
306 '#title' => t('Yahoo'),
307 );
308 $form['search_engines']['yahoo']['xmlsitemap_yahoo_submit'] = array(
309 '#type' => 'checkbox',
310 '#title' => t('Submit site map to Yahoo.'),
311 '#default_value' => variable_get('xmlsitemap_yahoo_submit', FALSE),
312 );
313 $form['search_engines']['yahoo']['xmlsitemap_yahoo_url'] = array(
314 '#type' => 'textfield',
315 '#title' => t('Submission URL'),
316 '#default_value' => variable_get('xmlsitemap_yahoo_url', 'http://search.yahooapis.com/SiteExplorerService/V1/ping?sitemap='. url('sitemap.xml', array('absolute' => TRUE))),
317 '#description' => t('The URL to submit the site map to.'),
318 );
319 $form['search_engines']['ask.com'] = array(
320 '#type' => 'fieldset',
321 '#title' => t('Ask.com'),
322 );
323 $form['search_engines']['ask.com']['xmlsitemap_ask_com_submit'] = array(
324 '#type' => 'checkbox',
325 '#title' => t('Submit site map to Ask.com.'),
326 '#default_value' => variable_get('xmlsitemap_ask_com_submit', FALSE),
327 );
328 $form['search_engines']['ask.com']['xmlsitemap_ask_com_url'] = array(
329 '#type' => 'textfield',
330 '#title' => t('Submission URL'),
331 '#default_value' => variable_get('xmlsitemap_ask_com_url', 'http://submissions.ask.com/ping?sitemap='. url('sitemap.xml', array('absolute' => TRUE))),
332 '#description' => t('The URL to submit the site map to.'),
333 );
334 $form['search_engines']['xmlsitemap_submit'] = array(
335 '#type' => 'checkbox',
336 '#title' => t('Submit site map when updated.'),
337 '#default_value' => variable_get('xmlsitemap_submit', 0),
338 '#description' => t('If enabled, search engines will be notified of changes to the site map each time it is updated.'),
339 );
340 $form['search_engines']['xmlsitemap_cron_submit'] = array(
341 '#type' => 'checkbox',
342 '#title' => t('Submit site map on cron run.'),
343 '#default_value' => variable_get('xmlsitemap_cron_submit', 0),
344 '#description' => t('If enabled, search engines will be notified of changes to the site map each time cron is run.'),
345 );
346 $form['search_engines']['xmlsitemap_logacc'] = array(
347 '#type' => 'checkbox',
348 '#title' => t('Log accesses.'),
349 '#default_value' => variable_get('xmlsitemap_logacc', 0),
350 '#description' => t('If enabled, a watchdog entry will be made each time the site map is accessed, containing information about the requestor.'),
351 );
352
353 $form['other_settings'] = array(
354 '#type' => 'fieldset',
355 '#title' => t('Other settings'),
356 '#collapsible' => TRUE,
357 '#collapsed' => TRUE,
358 );
359 $form['other_settings']['xmlsitemap_chunk_size'] = array(
360 '#type' => 'textfield',
361 '#title' => t('Chunk size'),
362 '#default_value' => variable_get('xmlsitemap_chunk_size', 50000),
363 '#size' => 10,
364 '#maxlength' => 5,
365 '#description' => t('This is the number of links to send at one time. Values can range between 1 and 50,000.'),
366 );
367 $form['other_settings']['xmlsitemap_countcom'] = array(
368 '#type' => 'checkbox',
369 '#title' => t('Count comments in change date and frequency'),
370 '#default_value' => variable_get('xmlsitemap_countcom', 1),
371 '#description' => t('If enabled, the frequency of comments on a node will affect its change frequency and last modification date.'),
372 );
373 $form['other_settings']['xmlsitemap_showterms'] = array(
374 '#type' => 'checkbox',
375 '#title' => t('Include links to taxonomy term pages'),
376 '#default_value' => variable_get('xmlsitemap_showterms', 0),
377 '#description' => t('If enabled, links to taxonomy term pages will be included in the site map.'),
378 );
379 $form['other_settings']['xmlsitemap_showusers'] = array(
380 '#type' => 'checkbox',
381 '#title' => t('Include links to user profile pages'),
382 '#default_value' => variable_get('xmlsitemap_showusers', 0),
383 '#description' => t('If enabled, links to user profile pages will be included in the site map (requires anonymous users to have "access user profiles" permission).'),
384 );
385
386 menu_rebuild(); // Needed for Google verification link
387
388 return system_settings_form($form);
389 }
390
391 function xmlsitemap_admin_settings_validate($form_id, $form_values) {
392 if ($form_values['xmlsitemap_chunk_size'] > 50000) {
393 form_set_error('xmlsitemap_chunk_size', t('Cannot send more than 50,000 links at one time.'));
394 }
395 else {
396 variable_set('xmlsitemap_changed', TRUE);
397 variable_set('xmlsitemap_update', TRUE);
398 }
399 }
400
401 /**
402 * Menu callback; return additional links form.
403 */
404 function xmlsitemap_admin_settings_additional() {
405 $pages = array();
406 $result = db_query('SELECT path FROM {xmlsitemap_additional}');
407 while ($page = db_fetch_object($result)) {
408 $pages[] = $page->path;
409 }
410 $pages = implode("\n", $pages);
411 $form['old_pages'] = array(
412 '#type' => 'hidden',
413 '#value' => $pages,
414 );
415 $form['pages'] = array(
416 '#type' => 'textarea',
417 '#title' => t('Pages'),
418 '#default_value' => $pages,
419 '#description' => t('Enter one page per line as Drupal paths. For example, if the URL is <em>http://example.com/node/1</em>, enter <em>node/1</em>.'),
420 '#cols' => 30,
421 '#rows' => 15,
422 );
423 $form['priority'] = array(
424 '#type' => 'textfield',
425 '#title' => t('Additional links priority'),
426 '#default_value' => variable_get('xmlsitemap_priority', '0.5'),
427 '#size' => 10,
428 '#maxlength' => 5,
429 '#description' => t('This is the absolute priority for additional links. Values can range between 0.0 and 1.0. The default priority is 0.5.'),
430 );
431 return system_settings_form($form);
432 }
433
434 function xmlsitemap_admin_settings_additional_validate($form_id, $form_values) {
435 if ($form_values['priority'] > 1 || $form_values['priority'] < 0) {
436 form_set_error('priority', t('Priority must be between 0.0 and 1.0.'));
437 }
438 }
439
440 function xmlsitemap_admin_settings_additional_submit($form_id, $form_values) {
441 if ($form_values['priority'] == '') {
442 $form_values['priority'] = '0.5';
443 }
444 else {
445 $form_values['priority'] = number_format($form_values['priority'], 1);
446 }
447 $old_pages = explode("\n", $form_values['old_pages']);
448 $pages = explode("\n", $form_values['pages']);
449 foreach ($pages as $key => $page) {
450 $pages[$key] = trim($page);
451 }
452 $delete_pages = array_diff($old_pages, $pages);
453 foreach ($delete_pages as $page) {
454 if (!empty($page)) {
455 db_query("DELETE FROM {xmlsitemap_additional} WHERE path = '%s'", $page);
456 variable_set('xmlsitemap_changed', TRUE);
457 variable_set('xmlsitemap_update', TRUE);
458 }
459 }
460 $add_pages = array_diff($pages, $old_pages);
461 foreach ($add_pages as $page) {
462 $page = trim($page);
463 $pid = db_result(db_query("SELECT pid FROM {url_alias} WHERE src = '%s'", $page));
464 if (!empty($page)) {
465 if ($pid === FALSE) {
466 db_query("
467 INSERT INTO {xmlsitemap_additional} (path, last_changed, previously_changed)
468 VALUES ('%s', %d, %d)
469 ", $page, time(), NULL);
470 }
471 else {
472 db_query("
473 INSERT INTO {xmlsitemap_additional} (path, pid, last_changed, previously_changed)
474 VALUES ('%s', %d, %d, %d)
475 ", $page, $pid, time(), NULL);
476 }
477 variable_set('xmlsitemap_changed', TRUE);
478 variable_set('xmlsitemap_update', TRUE);
479 }
480 }
481 db_query('UPDATE {xmlsitemap_additional} SET priority = %s', $form_values['priority']);
482 variable_set('xmlsitemap_priority', $form_values['priority']);
483 }
484
485 /**
486 * Implementation of hook_xmlsitemap().
487 */
488 function xmlsitemap_xmlsitemap($type = NULL, $excludes = array()) {
489 $additional = array();
490 switch ($type) {
491 case 'node':
492 case 'term':
493 case 'user':
494 break;
495 default:
496 $result = db_query('SELECT x.*, u.dst AS alias FROM {xmlsitemap_additional} x LEFT JOIN {url_alias} u ON x.pid = u.pid');
497 while ($link = db_fetch_object($result)) {
498 $age = time() - $link->last_changed;
499 if (!empty($link->previously_changed)) {
500 $interval = $link->last_changed - $link->previously_changed;
501 }
502 else {
503 $interval = 0;
504 }
505 $entry = array(
506 '#loc' => xmlsitemap_url($link->path, $link->alias, array('absolute' => TRUE)),
507 '#lastmod' => $link->last_changed,
508 '#changefreq' => max($age, $interval),
509 '#priority' => $link->priority,
510 );
511 $additional[] = $entry;
512 }
513 }
514 return $additional;
515 }
516
517 /**
518 * Implementation of hook_cron().
519 */
520 function xmlsitemap_cron() {
521 if (variable_get('xmlsitemap_cron_submit', 0) && variable_get('xmlsitemap_changed', FALSE)) {
522 _xmlsitemap_submit();
523 }
524 }
525
526 /**
527 * Menu callback; display the site map.
528 * @param $chunk: An integer specifying which chunk of the site map is being
529 * requested. If not set, display the site map index.
530 * @return Nothing
531 */
532 function xmlsitemap_output($chunk = NULL) {
533 drupal_set_header('Content-type: text/xml; charset=utf-8');
534 global $base_path;
535 $path = file_directory_temp();
536 $directories = 'drupal_xmlsitemap/'. getenv('HTTP_HOST') . $base_path;
537 $directories = explode('/', trim($directories, '/'));
538 foreach ($directories as $directory) {
539 $path = "$path/". str_replace('~', '_', $directory);
540 }
541 if (isset($chunk)) {
542 $dest = "$path/$chunk.xml.gz";
543 $type = t('Site map @chunk', array('@chunk' => $chunk));
544 }
545 else {
546 $dest = "$path/index.xml.gz";
547 $type = t('Site map index');
548 }
549 $status = TRUE;
550 if (!file_exists($dest) || variable_get('xmlsitemap_update', FALSE)) {
551 $status = _xmlsitemap_update_cache();
552 }
553 if ($status) {
554 if (strpos(getenv('HTTP_ACCEPT_ENCODING'), 'gzip') === FALSE) {
555 readgzfile($dest);
556 }
557 else {
558 drupal_set_header('Content-Encoding: gzip');
559 readfile($dest);
560 }
561 if (variable_get('xmlsitemap_logacc', 0)) {
562 if (strpos(getenv('HTTP_USER_AGENT'), 'Googlebot') === FALSE) {
563 watchdog('xmlsitemap', t('!sitemap downloaded by @user-agent at @address.', array('!sitemap' => $type, '@user-agent' => getenv('HTTP_USER_AGENT'), '@address' => getenv('REMOTE_ADDR'))));
564 }
565 else {
566 watchdog('xmlsitemap', t('!sitemap downloaded by Google.', array('!sitemap' => $type)));
567 }
568 }
569 }
570 else {
571 drupal_set_message(t('Unable to load site map. Make sure your temporary directory exists and is writable by Drupal.'), 'error');
572 }
573 }
574
575 /**
576 * Generate the site map index.
577 * @param $link_count: An integer containing the total number of links in
578 * the site
579 * @return A string containing the site map index
580 */
581 function xmlsitemap_output_index($link_count) {
582 $output = '';
583 global $base_url;
584 $countcom = variable_get('xmlsitemap_countcom', 1);
585
586 $output .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
587 $output .= '<?xml-stylesheet type="text/xsl" href="'. $base_url .'/'. drupal_get_path('module', 'xmlsitemap') .'/gss.xsl" ?>'."\n";
588 $output .= '<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/siteindex.xsd">'."\n";
589
590 $excludes = array();
591 foreach (node_get_types() as $type => $name) {
592 if (variable_get('xmlsitemap_'. $type .'wt', 0) < 0) {
593 $excludes[] = db_escape_string($type);
594 }
595 }
596
597 $chunk_size = variable_get('xmlsitemap_chunk_size', 50000);
598 for ($chunk = 0; $chunk < $link_count / $chunk_size; ++$chunk) {
599 $output .= '<sitemap><loc>'. url("sitemap$chunk.xml", array('absolute' => TRUE)) .'</loc>';
600
601 $range->low = $chunk * $chunk_size;
602 $range->high = ($chunk + 1) * $chunk_size;
603 $last_changed_node = db_result(db_query("SELECT MAX(changed) as changed from {node} WHERE nid >= %d AND nid < %d", $range->low, $range->high));
604
605 if ($countcom) {
606 $last_changed_comment = db_result(db_query("SELECT MAX(timestamp) as timestamp from {comments} WHERE nid >= %d AND nid < %d", $range->low, $range->high));
607 }
608 else {
609 $last_changed_comment = 0;
610 }
611
612 $output .= '<lastmod>'. gmdate('Y-m-d\TH:i:s+00:00', max($last_changed_node, $last_changed_comment)) .'</lastmod>';
613 $output .= "</sitemap>\n";
614 }
615 $output .= '</sitemapindex>';
616 return $output;
617 }
618
619 /**
620 * Generate a chunk of the site map.
621 * @param $chunk: An integer specifying which chunk of the site map to
622 * display
623 * @return A string containing a chunk of the site map
624 */
625 function xmlsitemap_output_chunk($chunk) {
626 $output = '';
627 global $base_url;
628 if (!ini_get('safe_mode')) {
629 set_time_limit(240);
630 }
631 $range->low = $chunk * variable_get('xmlsitemap_chunk_size', 50000);
632 $range->high = $range->low + variable_get('xmlsitemap_chunk_size', 50000);
633
634 $output .= '<?xml version="1.0" encoding="UTF-8"?>'."\n";
635 $output .= '<?xml-stylesheet type="text/xsl" href="'. $base_url .'/'. drupal_get_path('module', 'xmlsitemap') .'/gss.xsl" ?>'."\n";
636 $output .= '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">'."\n";
637
638 if ($range->low < $range->high) {
639 $previous_links = 1;
640 if ($previous_links >= $range->low) {
641 $output .= "<url><loc>$base_url/</loc><changefreq>always</changefreq><priority>". number_format(variable_get('xmlsitemap_frontpage', '1.0'), 1) ."</priority></url>\n";
642 $range->low = $previous_links;
643 }
644 }
645 if ($range->low < $range->high) {
646 $excludes = array();
647 foreach (node_get_types() as $type => $name) {
648 if (variable_get('xmlsitemap_'. $type .'wt', 0) < 0) {
649 $excludes[$type] = db_escape_string($type);
650 }
651 }
652 $additional = module_invoke_all('xmlsitemap', 'node', $excludes);
653 if (!empty($additional)) {
654 $output .= _xmlsitemap_sublinks($additional, 'node', 'nid', $range, $previous_links, $excludes);
655 }
656 else {
657 $count = db_result(db_query(db_rewrite_sql("
658 SELECT COUNT(*)
659 FROM {node} n
660 LEFT JOIN {xmlsitemap} x
661 ON n.nid = x.nid
662 WHERE n.status > 0
663 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
664 AND n.type NOT IN ('". implode("', '", $excludes) ."')
665 ")));
666 $count = $count + $previous_links > $range->high ? $range->high - $previous_links : $count;
667 $previous_links = $previous_links + $count;
668 if ($previous_links >= $range->low && !empty($count)) {
669 $nid = db_result(db_query_range(db_rewrite_sql("
670 SELECT n.nid
671 FROM {node} n
672 LEFT JOIN {xmlsitemap} x
673 ON n.nid = x.nid
674 WHERE n.status > 0
675 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
676 AND n.type NOT IN ('". implode("', '", $excludes) ."')
677 ORDER BY n.nid
678 "), $count - 1, 1));
679 $limit = $previous_links - $range->low;
680 $output .= _xmlsitemap_links('nid', $nid, $limit, $excludes);
681 $range->low = $previous_links;
682 }
683 }
684 }
685 if ($range->low < $range->high && variable_get('xmlsitemap_showterms', FALSE)) {
686 $additional = module_invoke_all('xmlsitemap', 'term');
687 if (!empty($additional)) {
688 $output .= _xmlsitemap_sublinks($additional, 'term_data', 'tid', $range, $previous_links);
689 }
690 else {
691 $count = db_result(db_query(db_rewrite_sql('SELECT COUNT(*) FROM {term_data}', 'term_data', 'tid')));
692 $count = $count > $range->high - $previous_links ? $range->high - $previous_links : $count;
693 $previous_links = $previous_links + $count;
694 if ($previous_links >= $range->low && !empty($count)) {
695 $tid = db_result(db_query_range(db_rewrite_sql('SELECT tid FROM {term_data} ORDER BY tid', 'term_data', 'tid'), $count - 1, 1));
696 $limit = $previous_links - $range->low;
697 $output .= _xmlsitemap_links('tid', $tid, $limit);
698 $range->low = $previous_links;
699 }
700 }
701 }
702 if ($range->low < $range->high && variable_get('xmlsitemap_showusers', FALSE) && user_access('access user profiles')) {
703 $additional = module_invoke_all('xmlsitemap', 'user');
704 if (!empty($additional)) {
705 $output .= _xmlsitemap_sublinks($additional, 'users', 'uid', $range, $previous_links);
706 }
707 else {
708 $count = db_result(db_query('SELECT COUNT(*) FROM {users}'));
709 $count = $count > $range->high - $previous_links ? $range->high - $previous_links : $count;
710 $previous_links = $previous_links + $count;
711 if ($previous_links >= $range->low && !empty($count)) {
712 $uid = db_result(db_query_range('SELECT uid FROM {users} ORDER BY uid', $count - 1, 1));
713 $limit = $previous_links - $range->low;
714 $output .= _xmlsitemap_links('uid', $uid, $limit);
715 $range->low = $previous_links;
716 }
717 }
718 }
719 if ($range->low < $range->high) {
720 $additional = _xmlsitemap_xml();
721 if (!empty($additional)) {
722 $link = $range->low - $previous_links;
723 $count = count($additional);
724 $count = $count > $range->high - $previous_links ? $range->high - $previous_links : $count;
725 $previous_links = $previous_links + $count;
726 if ($previous_links >= $range->low) {
727 $limit = $previous_links - $range->low;
728 foreach (array_slice($additional, $link, $limit) as $entry) {
729 $output .= $entry;
730 }
731 $range->low = $previous_links;
732 }
733 }
734 }
735 if ($range->low < $range->high) {
736 $additional = module_invoke_all('xmlsitemap');
737 if (!empty($additional)) {
738 $link = $range->low - $previous_links;
739 $count = count($additional);
740 $count = $count > $range->high - $previous_links ? $range->high - $previous_links : $count;
741 $previous_links = $previous_links + $count;
742 if ($previous_links >= $range->low) {
743 $limit = $previous_links - $range->low;
744 $output .= _xmlsitemap_additional(array_slice($additional, $link, $limit));
745 $range->low = $previous_links;
746 }
747 }
748 }
749 $output .= '</urlset>';
750 return $output;
751 }
752
753 /**
754 * Return formatted links and sub-links.
755 * @param $additional: An array of links
756 * @param $table: A string specifying the table to retrieve links from
757 * @param $type: A string specifying the type of links to retrieve
758 * @param $range: An object containing low (first link in range) and high
759 * (first link in next range) counts.
760 * @param $previous_links: An integer containing the number of links already
761 * printed
762 * @return A string of formatted links
763 */
764 function _xmlsitemap_sublinks($additional, $table, $type, &$range, &$previous_links, $excludes = array()) {
765 $output = '';
766 foreach ($additional as $key => $entry) {
767 $link_count[$key] = $entry[$type];
768 }
769 $link_count = array_count_values($link_count);
770 $previous_id = 0;
771 $link = 0;
772 foreach ($link_count as $id => $links) {
773 if ($range->low < $range->high) {
774 if ($type == 'nid') {
775 $count = db_result(db_query(db_rewrite_sql("
776 SELECT COUNT(*)
777 FROM {node} n
778 LEFT JOIN {xmlsitemap} x
779 ON n.nid = x.nid
780 WHERE n.status > 0
781 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
782 AND n.type NOT IN ('". implode("', '", $excludes) ."')
783 AND n.nid >= %d
784 AND n.nid <= %d
785 "), $previous_id, $id));
786 }
787 elseif ($type == 'uid') {
788 $count = db_result(db_query('SELECT COUNT(*) FROM {users} WHERE uid >= %d AND uid <= %d'), $previous_id, $id);
789 }
790 else {
791 $count = db_result(db_query(db_rewrite_sql('SELECT COUNT(*) FROM {%s} WHERE %s >= %d AND %s <= %d', $table, $type), $table, $type, $previous_id, $type, $id));
792 }
793 $previous_id = $id + 1;
794 $count = $count + $previous_links > $range->high ? $range->high - $previous_links : $count;
795 $previous_links = $previous_links + $count;
796 if ($previous_links >= $range->low) {
797 $limit = $previous_links - $range->low;
798 $output .= _xmlsitemap_links($type, $id, $limit, $excludes);
799 $range->low = $previous_links;
800 }
801 }
802 else {
803 break;
804 }
805 if ($range->low < $range->high) {
806 $links = $links + $previous_links > $range->high ? $range->high - $previous_links : $links;
807 $previous_links = $previous_links + $links;
808 if ($previous_links >= $range->low) {
809 $limit = $previous_links - $range->low;
810 $output .= _xmlsitemap_additional(array_slice($additional, $link, $limit));
811 $range->low = $previous_links;
812 }
813 $link = $link + $links;
814 }
815 else {
816 break;
817 }
818 }
819 if ($range->low < $range->high) {
820 if ($type == 'nid') {
821 $count = db_result(db_query(db_rewrite_sql("
822 SELECT COUNT(*)
823 FROM {node} n
824 LEFT JOIN {xmlsitemap} x
825 ON n.nid = x.nid
826 WHERE n.status > 0
827 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
828 AND n.type NOT IN ('". implode("', '", $excludes) ."')
829 AND n.nid >= %d
830 "), $previous_id));
831 $count = $count + $previous_links > $range->high ? $range->high - $previous_links : $count;
832 $id = db_result(db_query_range(db_rewrite_sql("
833 SELECT n.nid
834 FROM {node} n
835 LEFT JOIN {xmlsitemap} x
836 ON n.nid = x.nid
837 WHERE n.status > 0
838 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
839 AND n.type NOT IN ('". implode("', '", $excludes) ."')
840 AND n.nid >= %d
841 ORDER BY n.nid
842 "), $previous_id, $count - 1, 1));
843 }
844 elseif ($type == 'uid') {
845 $count = db_result(db_query('SELECT COUNT(*) FROM {users} WHERE uid >= %d'), $previous_id);
846 $count = $count + $previous_links > $range->high ? $range->high - $previous_links : $count;
847 $id = db_result(db_query_range('SELECT uid FROM {users} WHERE uid >= %d ORDER BY uid', $count - 1, 1), $previous_id);
848 }
849 else {
850 $count = db_result(db_query(db_rewrite_sql('SELECT COUNT(*) FROM {%s} WHERE %s >= %d', $table, $type), $table, $type, $previous_id));
851 $count = $count + $previous_links > $range->high ? $range->high - $previous_links : $count;
852 $id = db_result(db_query_range(db_rewrite_sql('SELECT %s FROM {%s} WHERE %s >= %d ORDER BY %s', $table, $type), $type, $table, $type, $previous_id, $type, $count - 1, 1));
853 }
854 $previous_links = $previous_links + $count;
855 if ($previous_links >= $range->low) {
856 $limit = $previous_links < $range->high ? $previous_links - $range->low : $range->high - $range->low;
857 $output .= _xmlsitemap_links($type, $id, $limit, $excludes);
858 $range->low = $previous_links;
859 }
860 }
861 return $output;
862 }
863
864 /**
865 * Return formatted links.
866 * @param $type A string specifying the type of links to return
867 * @param $id The id of the last link to return
868 * @param $limit An integer containing the number of links to return
869 * @return A string of formatted links
870 */
871 function _xmlsitemap_links($type, $id, $limit, $excludes = array()) {
872 $output = '';
873 switch ($type) {
874 case 'tid':
875 $offset = db_result(db_query(db_rewrite_sql('SELECT COUNT(*) - %d FROM {term_data} WHERE tid <= %d', 'term_data', 'tid'), $limit, $id));
876 $result = db_query_range(db_rewrite_sql('SELECT * FROM {term_data} WHERE tid <= %d ORDER BY tid', 'term_data', 'tid'), $id, $offset, $limit);
877 while ($term = db_fetch_object($result)) {
878 $output .= '<url><loc>'. url(taxonomy_term_path($term), array('absolute' => TRUE)) ."</loc><changefreq>always</changefreq></url>\n";
879 }
880 break;
881 case 'uid':
882 $offset = db_result(db_query('SELECT COUNT(*) - %d FROM {users} WHERE uid <= %d', $limit, $id));
883 $result = db_query_range('SELECT uid FROM {users} WHERE uid <= %d ORDER BY uid', $id, $offset, $limit);
884 while ($user = db_fetch_object($result)) {
885 $output .= '<url><loc>'. url('user/'. $user->uid, array('absolute' => TRUE)) ."</loc><changefreq>always</changefreq></url>\n";
886 }
887 break;
888 case 'nid':
889 $countcom = variable_get('xmlsitemap_countcom', 1);
890 $offset = db_result(db_query(db_rewrite_sql("
891 SELECT COUNT(*) - %d
892 FROM {node} n
893 LEFT JOIN {xmlsitemap} x
894 ON n.nid = x.nid
895 WHERE n.status > 0
896 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
897 AND n.type NOT IN ('". implode("', '", $excludes) ."')
898 AND n.nid <= %d
899 "), $limit, $id));
900 if (module_exists('comment')) {
901 $result = db_query_range(db_rewrite_sql("
902 SELECT n.nid, n.type, n.promote, s.comment_count, n.changed, x.previously_changed, s.last_comment_timestamp, x.previous_comment, x.priority_override, u.dst AS alias
903 FROM {node} n
904 LEFT JOIN {node_comment_statistics} s
905 ON n.nid = s.nid
906 LEFT JOIN {xmlsitemap} x
907 ON n.nid = x.nid
908 LEFT JOIN {url_alias} u
909 ON x.pid = u.pid
910 WHERE n.status > 0
911 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
912 AND n.type NOT IN ('". implode("', '", $excludes) ."')
913 AND n.nid <= %d
914 ORDER BY n.nid
915 "), $id, $offset, $limit);
916 $maxcomments = db_result(db_query('SELECT MAX(comment_count) FROM {node_comment_statistics}'));
917 }
918 else {
919 $result = db_query_range(db_rewrite_sql("
920 SELECT n.nid, n.type, n.promote, n.changed, x.previously_changed, x.priority_override, u.dst AS alias
921 FROM {node} n
922 LEFT JOIN {xmlsitemap} x
923 ON n.nid = x.nid
924 LEFT JOIN {url_alias} u
925 ON x.pid = u.pid
926 WHERE n.status > 0
927 AND (x.priority_override >= 0 OR x.priority_override IS NULL)
928 AND n.type NOT IN ('". implode("', '", $excludes) ."')
929 AND n.nid <= %d
930 ORDER BY n.nid
931 "), $id, $offset, $limit);
932 $maxcomments = 0;
933 }
934 while ($node = db_fetch_object($result)) {
935 $pri = xmlsitemap_node_priority($node, $maxcomments);
936 if ($pri < 0) {
937 continue;
938 }
939 $output .= '<url><loc>'. xmlsitemap_url('node/'. $node->nid, $node->alias, array('absolute' => TRUE)) .'</loc>';
940 $output .= '<lastmod>'. gmdate('Y-m-d\TH:i:s+00:00', max($node->changed, $node->last_comment_timestamp * $countcom)) .'</lastmod>';
941 $output .= '<priority>'. number_format($pri, 1) .'</priority>';
942 $age = time() - max($node->changed, $node->last_comment_timestamp * $countcom);
943 if ($countcom) {
944 if (!empty($node->previously_changed) && isset($node->previous_comment)) {
945 $interval = min($node->changed, $node->last_comment_timestamp) - max($node->previously_changed, $node->previous_comment);
946 }
947 elseif (!empty($node->previously_changed)) {
948 $interval = min($node->changed, $node->last_comment_timestamp) - $node->previously_changed;
949 }
950 elseif (isset($node->previous_comment)) {
951 $interval = min($node->changed, $node->last_comment_timestamp) - $node->previous_comment;
952 }
953 else {
954 $interval = 0;
955 }
956 }
957 else {
958 if (!empty($node->previously_changed)) {
959 $interval = $node->changed - $node->previously_changed;
960 }
961 else {
962 $interval = 0;
963 }
964 }
965 $output .= '<changefreq>'. _xmlsitemap_frequency(max($age, $interval)) ."</changefreq></url>\n";
966 }
967 break;
968 }
969 return $output;
970 }
971
972 /**
973 * Process an array of links.
974 * @param $link_array: An array of links to process
975 * @return A string of formatted links
976 */
977 function _xmlsitemap_additional($link_array) {
978 $output = '';
979 foreach ($link_array as $entry) {
980 if (isset($entry['#loc'])) {
981 $output .= '<url><loc>'. check_url($entry['#loc']) .'</loc>';
982 if (isset($entry['#lastmod'])) {
983 $output .= '<lastmod>'. gmdate('Y-m-d\TH:i:s+00:00', $entry['#lastmod']) .'</lastmod>';
984 }
985 if (isset($entry['#changefreq'])) {
986 $output .= '<changefreq>'. _xmlsitemap_frequency($entry['#changefreq']) .'</changefreq>';
987 }
988 if (isset($entry['#priority']) && $entry['#priority'] <= 1 && $entry['#priority'] >= 0) {
989 $output .= '<priority>'. number_format($entry['#priority'], 1) .'</priority>';
990 }
991 $output .= "</url>\n";
992 }
993 }
994 return $output;
995 }
996
997 /**
998 * Calculate the priority of a node.
999 * @param $node: A node object
1000 * @param $maxcomments: The maximum number of comments for any node, used to
1001 * rank node by number of comments
1002 * @return A number between 0.0 and 1.0, or -1
1003 */
1004 function xmlsitemap_node_priority($node, $maxcomments) {
1005 if (!<