Completed
Push — add/xml-sitemap ( b67113 )
by
unknown
13:36
created

modules/xml-sitemap/sitemap.php (9 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * Generate sitemap files in base XML as well as popular namespace extensions
4
 *
5
 * @author Automattic
6
 * @version 2.0
7
 * @link http://sitemaps.org/protocol.php Base sitemaps protocol
8
 * @link http://www.google.com/support/webmasters/bin/answer.py?answer=74288 Google news sitemaps
9
 */
10
11
12
/**
13
 * Convert a MySQL datetime string to an ISO 8601 string
14
 *
15
 * @link http://www.w3.org/TR/NOTE-datetime W3C date and time formats document
16
 *
17
 * @param string $mysql_date UTC datetime in MySQL syntax of YYYY-MM-DD HH:MM:SS
18
 *
19
 * @return string ISO 8601 UTC datetime string formatted as YYYY-MM-DDThh:mm:ssTZD where timezone offset is always +00:00
20
 */
21
function jetpack_w3cdate_from_mysql( $mysql_date ) {
22
	return str_replace( ' ', 'T', $mysql_date ) . '+00:00';
23
}
24
25
/**
26
 * Get the maximum comment_date_gmt value for approved comments for the given post_id
27
 *
28
 * @param int $post_id post identifier
29
 *
30
 * @return string datetime MySQL value or null if no comment found
31
 */
32
function jetpack_get_approved_comments_max_datetime( $post_id ) {
33
	global $wpdb;
34
35
	return $wpdb->get_var( $wpdb->prepare( "SELECT MAX(comment_date_gmt) FROM $wpdb->comments WHERE comment_post_ID = %d AND comment_approved = '1' AND comment_type=''", $post_id ) );
36
}
37
38
/**
39
 * Return the content type used to serve a Sitemap XML file
40
 * Uses text/xml by default, possibly overridden by jetpack_sitemap_content_type filter
41
 *
42
 * @return string Internet media type for the sitemap XML
43
 */
44
function jetpack_sitemap_content_type() {
45
	return apply_filters( 'jetpack_sitemap_content_type', 'text/xml' );
46
}
47
48
function jetpack_print_sitemap_item( $data ) {
49
	jetpack_print_xml_tag( array ( 'url' => $data ) );
50
}
51
52
function jetpack_print_xml_tag( $array ) {
53
	foreach ( $array as $key => $value ) {
54
		if ( is_array( $value ) ) {
55
			echo "<$key>";
56
			jetpack_print_xml_tag( $value );
57
			echo "</$key>";
58
		} else {
59
			echo "<$key>" . esc_html( $value ) . "</$key>";
60
		}
61
	}
62
}
63
64
/**
65
 * Convert an array to a SimpleXML child of the passed tree.
66
 *
67
 * @param array $data array containing element value pairs, including other arrays, for XML contruction
68
 * @param SimpleXMLElement $tree A SimpleXMLElement class object used to attach new children
69
 *
70
 * @return SimpleXMLElement full tree with new children mapped from array
71
 */
72
function jetpack_sitemap_array_to_simplexml( $data, &$tree ) {
73
	$doc_namespaces = $tree->getDocNamespaces();
74
75
	foreach ( $data as $key => $value ) {
76
		// Allow namespaced keys by use of colon in $key, namespaces must be part of the document
77
		$namespace = null;
78
		if ( false !== strpos( $key, ':' ) ) {
79
			list( $namespace_prefix, $key ) = explode( ':', $key );
80
			if ( isset( $doc_namespaces[ $namespace_prefix ] ) ) {
81
				$namespace = $doc_namespaces[ $namespace_prefix ];
82
			}
83
		}
84
85
		if ( is_array( $value ) ) {
86
			$child = $tree->addChild( $key, null, $namespace );
87
			jetpack_sitemap_array_to_simplexml( $value, $child );
88
		} else {
89
			$tree->addChild( $key, esc_html( $value ), $namespace );
90
		}
91
	}
92
93
	return $tree;
94
}
95
96
/**
97
 * Define an array of attribute value pairs for use inside the root element of an XML document.
98
 * Intended for mapping namespace and namespace URI values.
99
 * Passes array through sitemap_ns for other functions to add their own namespaces
100
 *
101
 * @return array array of attribute value pairs passed through the sitemap_ns filter
102
 */
103
function jetpack_sitemap_namespaces() {
104
	return apply_filters( 'sitemap_ns', array (
105
		'xmlns:xsi'          => 'http://www.w3.org/2001/XMLSchema-instance',
106
		'xsi:schemaLocation' => 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd',
107
		'xmlns'              => 'http://www.sitemaps.org/schemas/sitemap/0.9',
108
		// Mobile namespace from http://support.google.com/webmasters/bin/answer.py?hl=en&answer=34648
0 ignored issues
show
Unused Code Comprehensibility introduced by
38% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
109
		'xmlns:mobile'       => 'http://www.google.com/schemas/sitemap-mobile/1.0',
110
		'xmlns:image'        => 'http://www.google.com/schemas/sitemap-image/1.1',
111
	) );
112
}
113
114
function jetpack_sitemap_initstr( $charset ) {
115
	$initstr = '<?xml version="1.0" encoding="' . $charset . '"?>' . "\n" . '<!-- generator="jetpack" -->' . "\n";
116
	$initstr .= '<urlset';
117
	foreach ( jetpack_sitemap_namespaces() as $attribute => $value ) {
118
		$initstr .= ' ' . esc_html( $attribute ) . '="' . esc_attr( $value ) . '"';
119
	}
120
	$initstr .= ' />';
121
122
	return $initstr;
123
}
124
125
/**
126
 * Print an XML sitemap conforming to the Sitemaps.org protocol
127
 * Outputs an XML list of up to the latest 1000 posts.
128
 *
129
 * @link http://sitemaps.org/protocol.php Sitemaps.org protocol
130
 */
131
function jetpack_print_sitemap() {
132
	if ( defined( 'JETPACK_SKIP_DEFAULT_SITEMAP' ) && JETPACK_SKIP_DEFAULT_SITEMAP ) {
133
		return;
134
	}
135
	global $wpdb;
136
137
	$xml = get_transient( 'jetpack_sitemap' );
138
139
	if ( $xml ) {
140
		header( 'Content-Type: ' . jetpack_sitemap_content_type(), true );
141
		echo $xml;
142
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_print_sitemap() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
143
	}
144
145
	$post_types = array ( 'post', 'page' );
146
147
	$post_types_in = array ();
148
	$post_types    = apply_filters( 'jetpack_sitemap_post_types', $post_types );
149
	foreach ( (array) $post_types as $post_type ) {
150
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
151
	}
152
	$post_types_in = join( ",", $post_types_in );
153
154
	// use direct query instead because get_posts was acting too heavy for our needs
155
	//$posts = get_posts( array( 'numberposts'=>1000, 'post_type'=>$post_types, 'post_status'=>'published' ) );
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
156
	$posts = $wpdb->get_results( "SELECT ID, post_type, post_modified_gmt, comment_count FROM $wpdb->posts WHERE post_status='publish' AND post_type IN ({$post_types_in}) ORDER BY post_modified_gmt DESC LIMIT 1000" );
157
	if ( empty( $posts ) ) {
158
		header( 'HTTP/1.0 404 Not Found', true, 404 );
159
	}
160
	header( 'Content-Type: ' . jetpack_sitemap_content_type() );
161
	$initstr = jetpack_sitemap_initstr( get_bloginfo( 'charset' ) );
162
	$tree    = simplexml_load_string( $initstr );
163
	// If we did not get a valid string, force UTF-8 and try again.
164
	if ( false === $tree ) {
165
		$initstr = jetpack_sitemap_initstr( 'UTF-8' );
166
		$tree    = simplexml_load_string( $initstr );
167
	}
168
169
	// Acquire necessary attachment data for all of the posts in a performant manner
170
	$attachment_parents = wp_list_pluck( $posts, 'ID' );
171
	$post_attachments   = array ();
172
	while ( $sub_posts = array_splice( $attachment_parents, 0, 100 ) ) {
173
		$post_parents = implode( ',', array_map( 'intval', $sub_posts ) );
174
175
		// Get the attachment IDs for all posts. We need to see how many
176
		// attachments each post parent has and limit it to 5.
177
		$query                = "SELECT ID, post_parent FROM {$wpdb->posts} WHERE post_parent IN ({$post_parents}) AND post_type='attachment' AND post_mime_type='image/jpeg' LIMIT 0,1000;";
178
		$all_attachments      = $wpdb->get_results( $query );
179
		$selected_attachments = array ();
180
		$attachment_count     = array ();
181
182
		foreach ( $all_attachments as $attachment ) {
183
			if ( ! isset( $attachment_count[ $attachment->post_parent ] ) ) {
184
				$attachment_count[ $attachment->post_parent ] = 0;
185
			}
186
187
			// Skip this particular attachment if we already have 5 for the post
188
			if ( $attachment_count[ $attachment->post_parent ] >= 5 ) {
189
				continue;
190
			}
191
192
			$selected_attachments[] = $attachment->ID;
193
			$attachment_count[ $attachment->post_parent ] ++;
194
		}
195
196
		// bail if there weren't any attachments to avoid an extra query
197
		if ( empty( $selected_attachments ) ) {
198
			continue;
199
		}
200
201
		// Get more of the attachment object for the attachments we actually care about
202
		$attachment_ids   = implode( ',', array_map( 'intval', $selected_attachments ) );
203
		$query            = "SELECT p.ID, p.post_parent, p.post_title, p.post_excerpt, p.guid FROM {$wpdb->posts} as p WHERE p.ID IN ({$attachment_ids}) AND p.post_type='attachment' AND p.post_mime_type='image/jpeg' LIMIT 500;";
204
		$attachments      = $wpdb->get_results( $query );
205
		$post_attachments = array_merge( $post_attachments, $attachments );
206
	}
207
208
	unset( $initstr );
209
	$latest_mod = '';
210
	foreach ( $posts as $post ) {
211
212
		// Add in filter to allow skipping specific posts
213
		if ( apply_filters( 'sitemap_skip_post', false, $post ) ) {
214
			continue;
215
		}
216
217
		$post_latest_mod = null;
218
		$url             = array ( 'loc' => esc_url( get_permalink( $post->ID ) ) );
219
220
		// If this post is configured to be the site home, skip since it's added separately later
221
		if ( untrailingslashit( get_permalink( $post->ID ) ) == untrailingslashit( get_option( 'home' ) ) ) {
222
			continue;
223
		}
224
225
		// Mobile node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=34648
226
		$url['mobile:mobile'] = '';
227
228
		// Image node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=178636
229
		// These attachments were produced with batch SQL earlier in the script
230
		if ( ! post_password_required( $post->ID ) && $attachments = wp_filter_object_list( $post_attachments, array ( 'post_parent' => $post->ID ) ) ) {
231
232
			$url['image:image'] = array ();
233
234
			foreach ( $attachments as $attachment ) {
235
				$attachment_url = false;
0 ignored issues
show
$attachment_url is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
236
				if ( $attachment->guid ) {
237
238
					// Copied from core's wp_get_attachment_url(). We already
239
					// have the guid value, so we don't want to get it again.
240
					// Note: we're using the WP.com version of the function.
241
242
					$attachment_url = apply_filters( 'get_the_guid', $attachment->guid );
243
244
					// If we don't have an attachment URL, don't include this image
245
					$attachment_url = apply_filters( 'wp_get_attachment_url', $attachment_url, $attachment->ID );
246
247
					if ( ! $attachment_url ) {
248
						unset( $url['image:image'] );
249
						continue;
250
					}
251
252
					$url['image:image']['loc'] = esc_url( $attachment_url );
253
				}
254
255
				// Only include title if not empty
256 View Code Duplication
				if ( $attachment_title = apply_filters( 'the_title_rss', $attachment->post_title ) ) {
257
					$url['image:image']['title'] = html_entity_decode( esc_html( $attachment_title ), ENT_XML1 );
258
				}
259
260
				// Only include caption if not empty
261 View Code Duplication
				if ( $attachment_caption = apply_filters( 'the_excerpt_rss', $attachment->post_excerpt ) ) {
262
					$url['image:image']['caption'] = html_entity_decode( esc_html( $attachment_caption ), ENT_XML1 );
263
				}
264
			}
265
		}
266
267
		if ( $post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ) {
268
			$post_latest_mod = $post->post_modified_gmt;
269
		}
270
		if ( $post->comment_count > 0 ) {
271
			// last modified based on last comment
272
			$latest_comment_datetime = jetpack_get_approved_comments_max_datetime( $post->ID );
273
			if ( ! empty( $latest_comment_datetime ) ) {
274
				if ( is_null( $post_latest_mod ) || $latest_comment_datetime > $post_latest_mod ) {
275
					$post_latest_mod = $latest_comment_datetime;
276
				}
277
			}
278
			unset( $latest_comment_datetime );
279
		}
280
		if ( ! empty( $post_latest_mod ) ) {
281
			$latest_mod     = max( $latest_mod, $post_latest_mod );
282
			$url['lastmod'] = jetpack_w3cdate_from_mysql( $post_latest_mod );
283
		}
284
		unset( $post_latest_mod );
285
		if ( $post->post_type == 'page' ) {
286
			$url['changefreq'] = 'weekly';
287
			$url['priority']   = '0.6'; // set page priority above default priority of 0.5
288
		} else {
289
			$url['changefreq'] = 'monthly';
290
		}
291
		jetpack_sitemap_array_to_simplexml( array ( 'url' => apply_filters( 'sitemap_url', $url, $post->ID ) ), $tree );
292
		unset( $url );
293
	}
294
	$blog_home = array (
295
		'loc'        => esc_url( get_option( 'home' ) ),
296
		'changefreq' => 'daily',
297
		'priority'   => '1.0'
298
	);
299
	if ( ! empty( $latest_mod ) ) {
300
		$blog_home['lastmod'] = jetpack_w3cdate_from_mysql( $latest_mod );
301
		header( 'Last-Modified:' . mysql2date( 'D, d M Y H:i:s', $latest_mod, 0 ) . ' GMT' );
302
	}
303
	jetpack_sitemap_array_to_simplexml( array ( 'url' => apply_filters( 'sitemap_url_home', $blog_home ) ), $tree );
304
	unset( $blog_home );
305
306
	$tree = apply_filters( 'jetpack_print_sitemap', $tree, $latest_mod );
307
308
	$xml = $tree->asXML();
309
	unset( $tree );
310
	if ( ! empty( $xml ) ) {
311
		set_transient( 'jetpack_sitemap', $xml, DAY_IN_SECONDS );
312
		echo $xml;
313
	}
314
315
	die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_print_sitemap() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
316
}
317
318
function jetpack_print_news_sitemap( $format ) {
0 ignored issues
show
The parameter $format is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
319
320
	$xml = get_transient( 'jetpack_news_sitemap' );
321
322
	if ( $xml ) {
323
		header( 'Content-Type: application/xml' );
324
		echo $xml;
325
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_print_news_sitemap() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
326
	}
327
328
	global $wpdb;
329
	$post_types = apply_filters( 'jetpack_sitemap_news_sitemap_post_types', array ( 'post' ) );
330
	if ( empty( $post_types ) ) {
331
		return;
332
	}
333
334
	$post_types_in = array ();
335
	foreach ( $post_types as $post_type ) {
336
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
337
	}
338
	$post_types_in_string = implode( ', ', $post_types_in );
339
340
	$limit        = apply_filters( 'jetpack_sitemap_news_sitemap_count', 1000 );
341
	$cur_datetime = current_time( 'mysql', true );
342
343
	$query = $wpdb->prepare( "
344
		SELECT p.ID, p.post_title, p.post_type, p.post_date, p.post_name, p.post_date_gmt, GROUP_CONCAT(t.name SEPARATOR ', ') AS keywords
345
		FROM
346
			$wpdb->posts AS p LEFT JOIN $wpdb->term_relationships AS r ON p.ID = r.object_id
347
			LEFT JOIN $wpdb->term_taxonomy AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'post_tag'
348
			LEFT JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
349
		WHERE
350
			post_status='publish' AND post_type IN ( {$post_types_in_string} ) AND post_date_gmt > (%s - INTERVAL 2 DAY)
351
		GROUP BY p.ID
352
		ORDER BY p.post_date_gmt DESC LIMIT %d", $cur_datetime, $limit );
353
354
	header( 'Content-Type: application/xml' );
355
	ob_start();
356
	echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
357
	?>
358
	<!-- generator="jetpack" -->
359
	<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
360
	        xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
361
	        xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
362
	        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
363
	        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
364
		>
365
		<?php
366
		$posts = $wpdb->get_results( $query );
367
		foreach ( $posts as $post ):
368
369
			// Add in filter to allow skipping specific posts
370
			if ( apply_filters( 'jetpack_sitemap_news_skip_post', false, $post ) ) {
371
				continue;
372
			}
373
374
			$GLOBALS['post']                       = $post;
375
			$url                                   = array ();
376
			$url['loc']                            = get_permalink( $post->ID );
377
			$news                                  = array ();
378
			$news['news:publication']['news:name'] = get_bloginfo_rss( 'name' );
379
			if ( function_exists( 'get_blog_lang_code' ) ) {
380
				$news['news:publication']['news:language'] = get_blog_lang_code();
381
			}
382
			$news['news:publication_date'] = jetpack_w3cdate_from_mysql( $post->post_date_gmt );
383
			$news['news:title']            = get_the_title_rss();
384
			if ( $post->keywords ) {
385
				$news['news:keywords'] = html_entity_decode( ent2ncr( $post->keywords ), ENT_HTML5 );
386
			}
387
			$url['news:news'] = $news;
388
389
			// Add image to sitemap
390
			if ( current_theme_supports( 'post-thumbnails' ) && has_post_thumbnail( $post->ID ) ) {
391
				$post_thumbnail_id  = get_post_thumbnail_id( $post->ID );
392
				$post_thumbnail_src = wp_get_attachment_image_src( $post_thumbnail_id );
393
				if ( $post_thumbnail_src ) {
394
					$url['image:image'] = array ( 'image:loc' => esc_url( $post_thumbnail_src[0] ) );
395
				}
396
			}
397
398
			$url = apply_filters( 'jetpack_sitemap_news_sitemap_item', $url, $post );
399
400
			if ( empty( $url ) ) {
401
				continue;
402
			}
403
404
			jetpack_print_sitemap_item( $url );
405
		endforeach;
406
		?>
407
	</urlset>
408
	<?php
409
	$xml = ob_get_contents();
410
	ob_end_clean();
411
	if ( ! empty( $xml ) ) {
412
		set_transient( 'jetpack_news_sitemap', $xml, DAY_IN_SECONDS );
413
		echo $xml;
414
	}
415
416
	die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_print_news_sitemap() contains an exit expression.

An exit expression should only be used in rare cases. For example, if you write a short command line script.

In most cases however, using an exit expression makes the code untestable and often causes incompatibilities with other libraries. Thus, unless you are absolutely sure it is required here, we recommend to refactor your code to avoid its usage.

Loading history...
417
}
418
419
/**
420
 * Absolute URL of the current blog's sitemap
421
 *
422
 * @return string sitemap URL
423
 */
424
function jetpack_sitemap_uri() {
425
	global $current_blog;
426
427
	$domain = $current_blog->primary_redirect ? $current_blog->primary_redirect : $current_blog->domain;
428
429
	return apply_filters( 'sitemap_location', 'http://' . $domain . '/sitemap.xml' );
430
}
431
432
/**
433
 * Absolute URL of the current blog's news sitemap
434
 */
435
function jetpack_news_sitemap_uri() {
436
	return apply_filters( 'news_sitemap_location', home_url( '/news-sitemap.xml', 'http' ) );
437
}
438
439
/**
440
 * Output the master sitemap URLs for the current blog context
441
 */
442
function jetpack_sitemap_discovery() {
443 View Code Duplication
	if ( ! defined( 'JETPACK_SKIP_DEFAULT_SITEMAP' ) || true !== JETPACK_SKIP_DEFAULT_SITEMAP ) {
444
		echo 'Sitemap: ' . esc_url( jetpack_sitemap_uri() ) . PHP_EOL;
445
	}
446
447 View Code Duplication
	if ( ! defined( 'JETPACK_SKIP_DEFAULT_NEWS_SITEMAP' ) || true !== JETPACK_SKIP_DEFAULT_NEWS_SITEMAP ) {
448
		echo 'Sitemap: ' . esc_url( jetpack_news_sitemap_uri() ) . PHP_EOL . PHP_EOL;
449
	}
450
}
451
452
/**
453
 * Clear the sitemap cache when a sitemap action has changed
454
 *
455
 * @param int $post_id unique post identifier. not used.
456
 */
457
function jetpack_sitemap_handle_update( $post_id ) {
0 ignored issues
show
The parameter $post_id is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
458
	delete_transient( 'jetpack_sitemap' );
459
	delete_transient( 'jetpack_news_sitemap' );
460
}
461
462
if ( ! function_exists( 'is_publicly_available' ) || is_publicly_available() ) {
463
	add_action( 'do_robotstxt', 'jetpack_sitemap_discovery', 5, 0 );
464
465
	add_action( 'publish_post', 'jetpack_sitemap_handle_update', 12, 1 );
466
	add_action( 'publish_page', 'jetpack_sitemap_handle_update', 12, 1 );
467
	add_action( 'trash_post', 'jetpack_sitemap_handle_update', 12, 1 );
468
	add_action( 'deleted_post', 'jetpack_sitemap_handle_update', 12, 1 );
469
470
	if ( $_SERVER['REQUEST_URI'] == '/sitemap.xml' ) {
471
		add_action( 'init', 'jetpack_print_sitemap', 999 ); // run later so things like custom post types have been registered
472
	} elseif ( $_SERVER['REQUEST_URI'] == '/news-sitemap.xml' ) {
473
		add_action( 'init', 'jetpack_print_news_sitemap', 999 ); // run later so things like custom post types have been registered
474
475
	}
476
}
477
478