Completed
Push — branch-4.0 ( fc0d6f...bf547c )
by
unknown
08:22
created

sitemaps.php ➔ jetpack_print_sitemap()   F

Complexity

Conditions 27
Paths 6337

Size

Total Lines 200
Code Lines 95

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 27
eloc 95
nc 6337
nop 0
dl 0
loc 200
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Generate sitemap files in base XML as well as popular namespace extensions.
4
 *
5
 * @author Automattic
6
 * @link http://sitemaps.org/protocol.php Base sitemaps protocol.
7
 * @link http://www.google.com/support/webmasters/bin/answer.py?answer=74288 Google news sitemaps.
8
 */
9
10
11
/**
12
 * Convert a MySQL datetime string to an ISO 8601 string.
13
 *
14
 * @module sitemaps
15
 *
16
 * @link http://www.w3.org/TR/NOTE-datetime W3C date and time formats document.
17
 *
18
 * @param string $mysql_date UTC datetime in MySQL syntax of YYYY-MM-DD HH:MM:SS.
19
 *
20
 * @return string ISO 8601 UTC datetime string formatted as YYYY-MM-DDThh:mm:ssTZD where timezone offset is always +00:00.
21
 */
22
function jetpack_w3cdate_from_mysql( $mysql_date ) {
23
	return str_replace( ' ', 'T', $mysql_date ) . '+00:00';
24
}
25
26
/**
27
 * Get the maximum comment_date_gmt value for approved comments for the given post_id.
28
 *
29
 * @module sitemaps
30
 *
31
 * @param int $post_id Post identifier.
32
 *
33
 * @return string datetime MySQL value or null if no comment found.
34
 */
35
function jetpack_get_approved_comments_max_datetime( $post_id ) {
36
	global $wpdb;
37
38
	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 ) );
39
}
40
41
/**
42
 * Return the content type used to serve a Sitemap XML file.
43
 * Uses text/xml by default, possibly overridden by jetpack_sitemap_content_type filter.
44
 *
45
 * @module sitemaps
46
 *
47
 * @return string Internet media type for the sitemap XML.
48
 */
49
function jetpack_sitemap_content_type() {
50
	/**
51
	 * Filter the content type used to serve the XML sitemap file.
52
	 *
53
	 * @module sitemaps
54
	 *
55
	 * @since 3.9.0
56
	 *
57
	 * @param string $content_type By default, it's 'text/xml'.
58
	 */
59
	return apply_filters( 'jetpack_sitemap_content_type', 'text/xml' );
60
}
61
62
/**
63
 * Write an XML tag.
64
 *
65
 * @module sitemaps
66
 *
67
 * @param array $data Information to write an XML tag.
68
 */
69
function jetpack_print_sitemap_item( $data ) {
70
	jetpack_print_xml_tag( array( 'url' => $data ) );
71
}
72
73
/**
74
 * Write an opening tag and its matching closing tag.
75
 *
76
 * @module sitemaps
77
 *
78
 * @param array $array Information to write a tag, opening and closing it.
79
 */
80
function jetpack_print_xml_tag( $array ) {
81
	foreach ( $array as $key => $value ) {
82
		if ( is_array( $value ) ) {
83
			echo "<$key>";
84
			jetpack_print_xml_tag( $value );
85
			echo "</$key>";
86
		} else {
87
			echo "<$key>" . esc_html( $value ) . "</$key>";
88
		}
89
	}
90
}
91
92
/**
93
 * Convert an array to a SimpleXML child of the passed tree.
94
 *
95
 * @module sitemaps
96
 *
97
 * @param array $data array containing element value pairs, including other arrays, for XML contruction.
98
 * @param SimpleXMLElement $tree A SimpleXMLElement class object used to attach new children.
99
 *
100
 * @return SimpleXMLElement full tree with new children mapped from array.
101
 */
102
function jetpack_sitemap_array_to_simplexml( $data, &$tree ) {
103
	$doc_namespaces = $tree->getDocNamespaces();
104
105
	foreach ( $data as $key => $value ) {
106
		// Allow namespaced keys by use of colon in $key, namespaces must be part of the document
107
		$namespace = null;
108
		if ( false !== strpos( $key, ':' ) && 'image' != $key ) {
109
			list( $namespace_prefix, $key ) = explode( ':', $key );
110
			if ( isset( $doc_namespaces[ $namespace_prefix ] ) ) {
111
				$namespace = $doc_namespaces[ $namespace_prefix ];
112
			}
113
		}
114
115
		if ( 'image' != $key ) {
116
			if ( is_array( $value ) ) {
117
				$child = $tree->addChild( $key, null, $namespace );
118
				jetpack_sitemap_array_to_simplexml( $value, $child );
119
			} else {
120
				$tree->addChild( $key, esc_html( $value ), $namespace );
121
			}
122
		} elseif ( is_array( $value ) ) {
123
			foreach ( $value as $image ) {
124
				$child = $tree->addChild( $key, null, $namespace );
125
				jetpack_sitemap_array_to_simplexml( $image, $child );
126
			}
127
		}
128
	}
129
130
	return $tree;
131
}
132
133
/**
134
 * Define an array of attribute value pairs for use inside the root element of an XML document.
135
 * Intended for mapping namespace and namespace URI values.
136
 * Passes array through jetpack_sitemap_ns for other functions to add their own namespaces.
137
 *
138
 * @module sitemaps
139
 *
140
 * @return array array of attribute value pairs passed through the jetpack_sitemap_ns filter
141
 */
142
function jetpack_sitemap_namespaces() {
143
	/**
144
	 * Filter the attribute value pairs used for namespace and namespace URI mappings.
145
	 *
146
	 * @module sitemaps
147
	 *
148
	 * @since 3.9.0
149
	 *
150
	 * @param array $namespaces Associative array with namespaces and namespace URIs.
151
	 */
152
	return apply_filters( 'jetpack_sitemap_ns', array(
153
		'xmlns:xsi'          => 'http://www.w3.org/2001/XMLSchema-instance',
154
		'xsi:schemaLocation' => 'http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd',
155
		'xmlns'              => 'http://www.sitemaps.org/schemas/sitemap/0.9',
156
		// Mobile namespace from http://support.google.com/webmasters/bin/answer.py?hl=en&answer=34648
157
		'xmlns:mobile'       => 'http://www.google.com/schemas/sitemap-mobile/1.0',
158
		'xmlns:image'        => 'http://www.google.com/schemas/sitemap-image/1.1',
159
	) );
160
}
161
162
/**
163
 * Start sitemap XML document, writing its heading and <urlset> tag with namespaces.
164
 *
165
 * @module sitemaps
166
 *
167
 * @param $charset string Charset for current XML document.
168
 *
169
 * @return string
170
 */
171
function jetpack_sitemap_initstr( $charset ) {
172
	// URL to XSLT
173
	$xsl = get_option( 'permalink_structure' ) ? home_url( '/sitemap.xsl' ) : home_url( '/?jetpack-sitemap-xsl=true' );
174
175
	$initstr = '<?xml version="1.0" encoding="' . $charset . '"?>' . "\n";
176
	$initstr .= '<?xml-stylesheet type="text/xsl" href="' . esc_url( $xsl ) . '"?>' . "\n";
177
	$initstr .= '<!-- generator="jetpack-' . JETPACK__VERSION . '" -->' . "\n";
178
	$initstr .= '<urlset';
179
	foreach ( jetpack_sitemap_namespaces() as $attribute => $value ) {
180
		$initstr .= ' ' . esc_html( $attribute ) . '="' . esc_attr( $value ) . '"';
181
	}
182
	$initstr .= ' />';
183
184
	return $initstr;
185
}
186
187
/**
188
 * Load XSLT for sitemap.
189
 *
190
 * @module sitemaps
191
 *
192
 * @param string $type XSLT to load.
193
 */
194
function jetpack_load_xsl( $type = '' ) {
195
196
	$transient_xsl = empty( $type ) ? 'jetpack_sitemap_xsl' : "jetpack_{$type}_sitemap_xsl";
197
198
	$xsl = get_transient( $transient_xsl );
199
200
	if ( $xsl ) {
201
		header( 'Content-Type: ' . jetpack_sitemap_content_type(), true );
202
		echo $xsl;
203
		die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_load_xsl() 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...
204
	}
205
206
	// Populate $xsl. Use $type.
207
	include_once JETPACK__PLUGIN_DIR . 'modules/sitemaps/sitemap-xsl.php';
208
209
	if ( ! empty( $xsl ) ) {
210
		set_transient( $transient_xsl, $xsl, DAY_IN_SECONDS );
211
		echo $xsl;
212
	}
213
214
	die();
0 ignored issues
show
Coding Style Compatibility introduced by
The function jetpack_load_xsl() 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...
215
}
216
217
/**
218
 * Responds with an XSLT to stylize sitemap.
219
 *
220
 * @module sitemaps
221
 */
222
function jetpack_print_sitemap_xsl() {
223
	jetpack_load_xsl();
224
}
225
226
/**
227
 * Responds with an XSLT to stylize news sitemap.
228
 *
229
 * @module sitemaps
230
 */
231
function jetpack_print_news_sitemap_xsl() {
232
	jetpack_load_xsl( 'news' );
233
}
234
235
/**
236
 * Print an XML sitemap conforming to the Sitemaps.org protocol.
237
 * Outputs an XML list of up to the latest 1000 posts.
238
 *
239
 * @module sitemaps
240
 *
241
 * @link http://sitemaps.org/protocol.php Sitemaps.org protocol.
242
 */
243
function jetpack_print_sitemap() {
244
	global $wpdb;
245
246
	$xml = get_transient( 'jetpack_sitemap' );
247
248
	if ( $xml ) {
249
		header( 'Content-Type: ' . jetpack_sitemap_content_type(), true );
250
		echo $xml;
251
		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...
252
	}
253
254
	// Compatibility with PHP 5.3 and older
255
	if ( ! defined( 'ENT_XML1' ) ) {
256
		define( 'ENT_XML1', 16 );
257
	}
258
259
	/**
260
	 * Filter the post types that will be included in sitemap.
261
	 *
262
	 * @module sitemaps
263
	 *
264
	 * @since 3.9.0
265
	 *
266
	 * @param array $post_types Array of post types.
267
	 */
268
	$post_types    = apply_filters( 'jetpack_sitemap_post_types', array( 'post', 'page' ) );
0 ignored issues
show
Coding Style introduced by
Equals sign not aligned correctly; expected 1 space but found 4 spaces

This check looks for improperly formatted assignments.

Every assignment must have exactly one space before and one space after the equals operator.

To illustrate:

$a = "a";
$ab = "ab";
$abc = "abc";

will have no issues, while

$a   = "a";
$ab  = "ab";
$abc = "abc";

will report issues in lines 1 and 2.

Loading history...
269
270
	$post_types_in = array();
271
	foreach ( (array) $post_types as $post_type ) {
272
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
273
	}
274
	$post_types_in = join( ",", $post_types_in );
275
276
	// use direct query instead because get_posts was acting too heavy for our needs
277
	//$posts = get_posts( array( 'numberposts'=>1000, 'post_type'=>$post_types, 'post_status'=>'published' ) );
278
	$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" );
279
	if ( empty( $posts ) ) {
280
		status_header( 404 );
281
	}
282
	header( 'Content-Type: ' . jetpack_sitemap_content_type() );
283
	$initstr = jetpack_sitemap_initstr( get_bloginfo( 'charset' ) );
284
	$tree    = simplexml_load_string( $initstr );
285
	// If we did not get a valid string, force UTF-8 and try again.
286
	if ( false === $tree ) {
287
		$initstr = jetpack_sitemap_initstr( 'UTF-8' );
288
		$tree    = simplexml_load_string( $initstr );
289
	}
290
291
	unset( $initstr );
292
	$latest_mod = '';
293
	foreach ( $posts as $post ) {
294
295
		/**
296
		 * Filter condition to allow skipping specific posts in sitemap.
297
		 *
298
		 * @module sitemaps
299
		 *
300
		 * @since 3.9.0
301
		 *
302
		 * @param bool $skip Current boolean. False by default, so no post is skipped.
303
		 * @param WP_POST $post Current post object.
304
		 */
305
		if ( apply_filters( 'jetpack_sitemap_skip_post', false, $post ) ) {
306
			continue;
307
		}
308
309
		$post_latest_mod = null;
310
		$url             = array( 'loc' => esc_url( get_permalink( $post->ID ) ) );
311
312
		// If this post is configured to be the site home, skip since it's added separately later
313
		if ( untrailingslashit( get_permalink( $post->ID ) ) == untrailingslashit( get_option( 'home' ) ) ) {
314
			continue;
315
		}
316
317
		// Mobile node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=34648
318
		$url['mobile:mobile'] = '';
319
320
		// Image node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=178636
321
		// These attachments were produced with batch SQL earlier in the script
322
		if ( ! post_password_required( $post->ID ) ) {
323
324
			$media = array();
325
			$methods = array(
326
				'from_thumbnail'  => false,
327
				'from_slideshow'  => false,
328
				'from_gallery'    => false,
329
				'from_attachment' => false,
330
				'from_html'       => false,
331
			);
332
			foreach ( $methods as $method => $value ) {
333
				$methods[ $method ] = true;
334
				$images_collected = Jetpack_PostImages::get_images( $post->ID, $methods );
335
				if ( is_array( $images_collected ) ) {
336
					$media = array_merge( $media, $images_collected );
337
				}
338
				$methods[ $method ] = false;
339
			}
340
341
			$images = array();
342
343
			foreach ( $media as $item ) {
344
				if ( ! isset( $item['type'] ) || 'image' != $item['type'] ) {
345
					continue;
346
				}
347
				$one_image = array();
348
349
				if ( isset( $item['src'] ) ) {
350
					$one_image['image:loc'] = esc_url( $item['src'] );
351
					$one_image['image:title'] = sanitize_title_with_dashes( $name = pathinfo( $item['src'], PATHINFO_FILENAME ) );
352
				}
353
354
				$images[] = $one_image;
355
			}
356
357
			if ( ! empty( $images ) ) {
358
				$url['image:image'] = $images;
359
			}
360
		}
361
362
		if ( $post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ) {
363
			$post_latest_mod = $post->post_modified_gmt;
364
		}
365
		if ( $post->comment_count > 0 ) {
366
			// last modified based on last comment
367
			$latest_comment_datetime = jetpack_get_approved_comments_max_datetime( $post->ID );
368
			if ( ! empty( $latest_comment_datetime ) ) {
369
				if ( is_null( $post_latest_mod ) || $latest_comment_datetime > $post_latest_mod ) {
370
					$post_latest_mod = $latest_comment_datetime;
371
				}
372
			}
373
			unset( $latest_comment_datetime );
374
		}
375
		if ( ! empty( $post_latest_mod ) ) {
376
			$latest_mod     = max( $latest_mod, $post_latest_mod );
377
			$url['lastmod'] = jetpack_w3cdate_from_mysql( $post_latest_mod );
378
		}
379
		unset( $post_latest_mod );
380
		if ( $post->post_type == 'page' ) {
381
			$url['changefreq'] = 'weekly';
382
			$url['priority']   = '0.6'; // set page priority above default priority of 0.5
383
		} else {
384
			$url['changefreq'] = 'monthly';
385
		}
386
		/**
387
		 * Filter associative array with data to build <url> node and its descendants for current post.
388
		 *
389
		 * @module sitemaps
390
		 *
391
		 * @since 3.9.0
392
		 *
393
		 * @param array $url Data to build parent and children nodes for current post.
394
		 * @param int $post_id Current post ID.
395
		 */
396
		$url_node = apply_filters( 'jetpack_sitemap_url', $url, $post->ID );
397
		jetpack_sitemap_array_to_simplexml( array( 'url' => $url_node ), $tree );
398
		unset( $url );
399
	}
400
	$blog_home = array(
401
		'loc'        => esc_url( get_option( 'home' ) ),
402
		'changefreq' => 'daily',
403
		'priority'   => '1.0'
404
	);
405
	if ( ! empty( $latest_mod ) ) {
406
		$blog_home['lastmod'] = jetpack_w3cdate_from_mysql( $latest_mod );
407
		header( 'Last-Modified:' . mysql2date( 'D, d M Y H:i:s', $latest_mod, 0 ) . ' GMT' );
408
	}
409
	/**
410
	 * Filter associative array with data to build <url> node and its descendants for site home.
411
	 *
412
	 * @module sitemaps
413
	 *
414
	 * @since 3.9.0
415
	 *
416
	 * @param array $blog_home Data to build parent and children nodes for site home.
417
	 */
418
	$url_node = apply_filters( 'jetpack_sitemap_url_home', $blog_home );
419
	jetpack_sitemap_array_to_simplexml( array( 'url' => $url_node ), $tree );
420
	unset( $blog_home );
421
422
	/**
423
	 * Filter data before rendering it as XML.
424
	 *
425
	 * @module sitemaps
426
	 *
427
	 * @since 3.9.0
428
	 *
429
	 * @param SimpleXMLElement $tree Data tree for sitemap.
430
	 * @param string $latest_mod Date of last modification.
431
	 */
432
	$tree = apply_filters( 'jetpack_print_sitemap', $tree, $latest_mod );
433
434
	$xml = $tree->asXML();
435
	unset( $tree );
436
	if ( ! empty( $xml ) ) {
437
		set_transient( 'jetpack_sitemap', $xml, DAY_IN_SECONDS );
438
		echo $xml;
439
	}
440
441
	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...
442
}
443
444
/**
445
 * Prints the news XML sitemap conforming to the Sitemaps.org protocol.
446
 * Outputs an XML list of up to 1000 posts published in the last 2 days.
447
 *
448
 * @module sitemaps
449
 *
450
 * @link http://sitemaps.org/protocol.php Sitemaps.org protocol.
451
 */
452
function jetpack_print_news_sitemap() {
453
454
	$xml = get_transient( 'jetpack_news_sitemap' );
455
456
	if ( $xml ) {
457
		header( 'Content-Type: application/xml' );
458
		echo $xml;
459
		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...
460
	}
461
462
	global $wpdb;
463
464
	/**
465
	 * Filter post types to be included in news sitemap.
466
	 *
467
	 * @module sitemaps
468
	 *
469
	 * @since 3.9.0
470
	 *
471
	 * @param array $post_types Array with post types to include in news sitemap.
472
	 */
473
	$post_types = apply_filters( 'jetpack_sitemap_news_sitemap_post_types', array( 'post' ) );
474
	if ( empty( $post_types ) ) {
475
		return;
476
	}
477
478
	$post_types_in = array();
479
	foreach ( $post_types as $post_type ) {
480
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
481
	}
482
	$post_types_in_string = implode( ', ', $post_types_in );
483
484
	/**
485
	 * Filter limit of entries to include in news sitemap.
486
	 *
487
	 * @module sitemaps
488
	 *
489
	 * @since 3.9.0
490
	 *
491
	 * @param int $count Number of entries to include in news sitemap.
492
	 */
493
	$limit        = apply_filters( 'jetpack_sitemap_news_sitemap_count', 1000 );
494
	$cur_datetime = current_time( 'mysql', true );
495
496
	$query = $wpdb->prepare( "
497
		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
498
		FROM
499
			$wpdb->posts AS p LEFT JOIN $wpdb->term_relationships AS r ON p.ID = r.object_id
500
			LEFT JOIN $wpdb->term_taxonomy AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'post_tag'
501
			LEFT JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
502
		WHERE
503
			post_status='publish' AND post_type IN ( {$post_types_in_string} ) AND post_date_gmt > (%s - INTERVAL 2 DAY)
504
		GROUP BY p.ID
505
		ORDER BY p.post_date_gmt DESC LIMIT %d", $cur_datetime, $limit );
506
507
	// URL to XSLT
508
	$xsl = get_option( 'permalink_structure' ) ? home_url( 'news-sitemap.xsl' ) : home_url( '/?jetpack-news-sitemap-xsl=true' );
509
510
	// Unless it's zh-cn for Simplified Chinese or zh-tw for Traditional Chinese,
511
	// trim national variety so an ISO 639 language code as required by Google.
512
	$language_code = strtolower( get_locale() );
513
	if ( in_array( $language_code, array( 'zh_tw', 'zh_cn' ) ) ) {
514
		$language_code = str_replace( '_', '-', $language_code );
515
	} else {
516
		$language_code = preg_replace( '/(_.*)$/i', '', $language_code );
517
	}
518
519
	header( 'Content-Type: application/xml' );
520
	ob_start();
521
	echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
522
	echo '<?xml-stylesheet type="text/xsl" href="' . esc_url( $xsl ) . '"?>' . "\n";
523
	echo '<!-- generator="jetpack-' . JETPACK__VERSION . '" -->' . "\n";
524
	?>
525
	<!-- generator="jetpack" -->
526
	<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
527
	        xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
528
	        xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
529
	        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
530
	        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
531
		>
532
		<?php
533
		$posts = $wpdb->get_results( $query );
534
		foreach ( $posts as $post ):
535
536
			/**
537
			 * Filter condition to allow skipping specific posts in news sitemap.
538
			 *
539
			 * @module sitemaps
540
			 *
541
			 * @since 3.9.0
542
			 *
543
			 * @param bool $skip Current boolean. False by default, so no post is skipped.
544
			 * @param WP_POST $post Current post object.
545
			 */
546
			if ( apply_filters( 'jetpack_sitemap_news_skip_post', false, $post ) ) {
547
				continue;
548
			}
549
550
			$GLOBALS['post']                       = $post;
551
			$url                                   = array();
552
			$url['loc']                            = get_permalink( $post->ID );
553
			$news                                  = array();
554
			$news['news:publication']['news:name'] = get_bloginfo_rss( 'name' );
555
			$news['news:publication']['news:language'] = $language_code;
556
			$news['news:publication_date'] = jetpack_w3cdate_from_mysql( $post->post_date_gmt );
557
			$news['news:title']            = get_the_title_rss();
558
			if ( $post->keywords ) {
559
				$news['news:keywords'] = html_entity_decode( ent2ncr( $post->keywords ), ENT_HTML5 );
560
			}
561
			$url['news:news'] = $news;
562
563
			// Add image to sitemap
564
			$post_thumbnail = Jetpack_PostImages::get_image( $post->ID );
565
			if ( isset( $post_thumbnail['src'] ) ) {
566
				$url['image:image'] = array( 'image:loc' => esc_url( $post_thumbnail['src'] ) );
567
			}
568
569
			/**
570
			 * Filter associative array with data to build <url> node and its descendants for current post in news sitemap.
571
			 *
572
			 * @module sitemaps
573
			 *
574
			 * @since 3.9.0
575
			 *
576
			 * @param array $url Data to build parent and children nodes for current post.
577
			 * @param int $post_id Current post ID.
578
			 */
579
			$url = apply_filters( 'jetpack_sitemap_news_sitemap_item', $url, $post );
580
581
			if ( empty( $url ) ) {
582
				continue;
583
			}
584
585
			jetpack_print_sitemap_item( $url );
586
		endforeach;
587
		?>
588
	</urlset>
589
	<?php
590
	$xml = ob_get_contents();
591
	ob_end_clean();
592
	if ( ! empty( $xml ) ) {
593
		set_transient( 'jetpack_news_sitemap', $xml, DAY_IN_SECONDS );
594
		echo $xml;
595
	}
596
597
	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...
598
}
599
600
/**
601
 * Absolute URL of the current blog's sitemap.
602
 *
603
 * @module sitemaps
604
 *
605
 * @return string Sitemap URL.
606
 */
607 View Code Duplication
function jetpack_sitemap_uri() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
608
	if ( get_option( 'permalink_structure' ) ) {
609
		$sitemap_url = home_url( '/sitemap.xml' );
610
	} else {
611
		$sitemap_url = home_url( '/?jetpack-sitemap=true' );
612
	}
613
	/**
614
	 * Filter sitemap URL relative to home URL.
615
	 *
616
	 * @module sitemaps
617
	 *
618
	 * @since 3.9.0
619
	 *
620
	 * @param string $sitemap_url Sitemap URL.
621
	 */
622
	return apply_filters( 'jetpack_sitemap_location', $sitemap_url );
623
}
624
625
/**
626
 * Absolute URL of the current blog's news sitemap.
627
 *
628
 * @module sitemaps
629
 */
630 View Code Duplication
function jetpack_news_sitemap_uri() {
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
631
	if ( get_option( 'permalink_structure' ) ) {
632
		$news_sitemap_url = home_url( '/news-sitemap.xml' );
633
	} else {
634
		$news_sitemap_url = home_url( '/?jetpack-news-sitemap=true' );
635
	}
636
	/**
637
	 * Filter news sitemap URL relative to home URL.
638
	 *
639
	 * @module sitemaps
640
	 *
641
	 * @since 3.9.0
642
	 *
643
	 * @param string $news_sitemap_url News sitemap URL.
644
	 */
645
	return apply_filters( 'jetpack_news_sitemap_location', $news_sitemap_url );
646
}
647
648
/**
649
 * Output the default sitemap URL.
650
 *
651
 * @module sitemaps
652
 */
653
function jetpack_sitemap_discovery() {
654
	echo 'Sitemap: ' . esc_url( jetpack_sitemap_uri() ) . PHP_EOL;
655
}
656
657
/**
658
 * Output the news sitemap URL.
659
 *
660
 * @module sitemaps
661
 */
662
function jetpack_news_sitemap_discovery() {
663
	echo 'Sitemap: ' . esc_url( jetpack_news_sitemap_uri() ) . PHP_EOL . PHP_EOL;
664
}
665
666
/**
667
 * Clear the sitemap cache when a sitemap action has changed.
668
 *
669
 * @module sitemaps
670
 *
671
 * @param int $post_id unique post identifier. not used.
672
 */
673
function jetpack_sitemap_handle_update( $post_id ) {
0 ignored issues
show
Unused Code introduced by
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...
674
	delete_transient( 'jetpack_sitemap' );
675
	delete_transient( 'jetpack_news_sitemap' );
676
}
677
678
/**
679
 * Clear sitemap cache when an entry changes. Make sitemaps discoverable to robots. Render sitemaps.
680
 *
681
 * @module sitemaps
682
 */
683
function jetpack_sitemap_initialize() {
684
	add_action( 'publish_post', 'jetpack_sitemap_handle_update', 12, 1 );
685
	add_action( 'publish_page', 'jetpack_sitemap_handle_update', 12, 1 );
686
	add_action( 'trash_post', 'jetpack_sitemap_handle_update', 12, 1 );
687
	add_action( 'deleted_post', 'jetpack_sitemap_handle_update', 12, 1 );
688
689
	/**
690
	 * Filter whether to make the default sitemap discoverable to robots or not.
691
	 *
692
	 * @module sitemaps
693
	 *
694
	 * @since 3.9.0
695
	 *
696
	 * @param bool $discover_sitemap Make default sitemap discoverable to robots.
697
	 */
698
	$discover_sitemap = apply_filters( 'jetpack_sitemap_generate', true );
699 View Code Duplication
	if ( $discover_sitemap ) {
700
		add_action( 'do_robotstxt', 'jetpack_sitemap_discovery', 5, 0 );
701
702
		if ( get_option( 'permalink_structure' ) ) {
703
			/** This filter is documented in modules/sitemaps/sitemaps.php */
704
			$sitemap = apply_filters( 'jetpack_sitemap_location', home_url( '/sitemap.xml' ) );
705
			$sitemap = parse_url( $sitemap, PHP_URL_PATH );
706
		} else {
707
			/** This filter is documented in modules/sitemaps/sitemaps.php */
708
			$sitemap = apply_filters( 'jetpack_sitemap_location', home_url( '/?jetpack-sitemap=true' ) );
709
			$sitemap = preg_replace( '/(=.*?)$/i', '', parse_url( $sitemap, PHP_URL_QUERY ) );
710
		}
711
712
		// Sitemap XML
713
		if ( preg_match( '#(' . $sitemap . ')$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET[ $sitemap ] ) && 'true' == $_GET[ $sitemap ] ) ) {
714
			// run later so things like custom post types have been registered
715
			add_action( 'init', 'jetpack_print_sitemap', 999 );
716
		}
717
718
		// XSLT for sitemap
719
		if ( preg_match( '#(/sitemap\.xsl)$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET['jetpack-sitemap-xsl'] ) && 'true' == $_GET['jetpack-sitemap-xsl'] ) ) {
720
			add_action( 'init', 'jetpack_print_sitemap_xsl' );
721
		}
722
	}
723
724
	/**
725
	 * Filter whether to make the news sitemap discoverable to robots or not.
726
	 *
727
	 * @module sitemaps
728
	 *
729
	 * @since 3.9.0
730
	 *
731
	 * @param bool $discover_news_sitemap Make default news sitemap discoverable to robots.
732
	 */
733
	$discover_news_sitemap = apply_filters( 'jetpack_news_sitemap_generate', true );
734 View Code Duplication
	if ( $discover_news_sitemap ) {
735
		add_action( 'do_robotstxt', 'jetpack_news_sitemap_discovery', 5, 0 );
736
737
		if ( get_option( 'permalink_structure' ) ) {
738
			/** This filter is documented in modules/sitemaps/sitemaps.php */
739
			$sitemap = apply_filters( 'jetpack_news_sitemap_location', home_url( '/news-sitemap.xml' ) );
740
			$sitemap = parse_url( $sitemap, PHP_URL_PATH );
741
		} else {
742
			/** This filter is documented in modules/sitemaps/sitemaps.php */
743
			$sitemap = apply_filters( 'jetpack_news_sitemap_location', home_url( '/?jetpack-news-sitemap=true' ) );
744
			$sitemap = preg_replace( '/(=.*?)$/i', '', parse_url( $sitemap, PHP_URL_QUERY ) );
745
		}
746
747
		// News Sitemap XML
748
		if ( preg_match( '#(' . $sitemap . ')$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET[ $sitemap ] ) && 'true' == $_GET[ $sitemap ] ) ) {
749
			// run later so things like custom post types have been registered
750
			add_action( 'init', 'jetpack_print_news_sitemap', 999 );
751
		}
752
753
		// XSLT for sitemap
754
		if ( preg_match( '#(/news-sitemap\.xsl)$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET['jetpack-news-sitemap-xsl'] ) && 'true' == $_GET['jetpack-news-sitemap-xsl'] ) ) {
755
			add_action( 'init', 'jetpack_print_news_sitemap_xsl' );
756
		}
757
	}
758
}
759
760
// Initialize sitemaps once themes can filter the initialization.
761
add_action( 'after_setup_theme', 'jetpack_sitemap_initialize' );