Completed
Push — add/pathinfo-sitemap ( eb9d33...02fba8 )
by Jeremy
14:23 queued 04:10
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
	global $wp_rewrite;
173
	// URL to XSLT
174
	if ( $wp_rewrite->using_index_permalinks() ) {
175
		$xsl = home_url( '/index.php/sitemap.xsl' );
176
	} else if ( $wp_rewrite->using_permalinks() ) {
177
		$xsl = home_url( '/sitemap.xsl' );
178
	} else {
179
		$xsl = home_url( '/?jetpack-sitemap-xsl=true' );
180
	}
181
182
	$initstr = '<?xml version="1.0" encoding="' . $charset . '"?>' . "\n";
183
	$initstr .= '<?xml-stylesheet type="text/xsl" href="' . esc_url( $xsl ) . '"?>' . "\n";
184
	$initstr .= '<!-- generator="jetpack-' . JETPACK__VERSION . '" -->' . "\n";
185
	$initstr .= '<urlset';
186
	foreach ( jetpack_sitemap_namespaces() as $attribute => $value ) {
187
		$initstr .= ' ' . esc_html( $attribute ) . '="' . esc_attr( $value ) . '"';
188
	}
189
	$initstr .= ' />';
190
191
	return $initstr;
192
}
193
194
/**
195
 * Load XSLT for sitemap.
196
 *
197
 * @module sitemaps
198
 *
199
 * @param string $type XSLT to load.
200
 */
201
function jetpack_load_xsl( $type = '' ) {
202
203
	$transient_xsl = empty( $type ) ? 'jetpack_sitemap_xsl' : "jetpack_{$type}_sitemap_xsl";
204
205
	$xsl = get_transient( $transient_xsl );
206
207
	if ( $xsl ) {
208
		header( 'Content-Type: ' . jetpack_sitemap_content_type(), true );
209
		echo $xsl;
210
		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...
211
	}
212
213
	// Populate $xsl. Use $type.
214
	include_once JETPACK__PLUGIN_DIR . 'modules/sitemaps/sitemap-xsl.php';
215
216
	if ( ! empty( $xsl ) ) {
217
		set_transient( $transient_xsl, $xsl, DAY_IN_SECONDS );
218
		echo $xsl;
219
	}
220
221
	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...
222
}
223
224
/**
225
 * Responds with an XSLT to stylize sitemap.
226
 *
227
 * @module sitemaps
228
 */
229
function jetpack_print_sitemap_xsl() {
230
	jetpack_load_xsl();
231
}
232
233
/**
234
 * Responds with an XSLT to stylize news sitemap.
235
 *
236
 * @module sitemaps
237
 */
238
function jetpack_print_news_sitemap_xsl() {
239
	jetpack_load_xsl( 'news' );
240
}
241
242
/**
243
 * Print an XML sitemap conforming to the Sitemaps.org protocol.
244
 * Outputs an XML list of up to the latest 1000 posts.
245
 *
246
 * @module sitemaps
247
 *
248
 * @link http://sitemaps.org/protocol.php Sitemaps.org protocol.
249
 */
250
function jetpack_print_sitemap() {
251
	global $wpdb;
252
253
	$xml = get_transient( 'jetpack_sitemap' );
254
255
	if ( $xml ) {
256
		header( 'Content-Type: ' . jetpack_sitemap_content_type(), true );
257
		echo $xml;
258
		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...
259
	}
260
261
	// Compatibility with PHP 5.3 and older
262
	if ( ! defined( 'ENT_XML1' ) ) {
263
		define( 'ENT_XML1', 16 );
264
	}
265
266
	/**
267
	 * Filter the post types that will be included in sitemap.
268
	 *
269
	 * @module sitemaps
270
	 *
271
	 * @since 3.9.0
272
	 *
273
	 * @param array $post_types Array of post types.
274
	 */
275
	$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...
276
277
	$post_types_in = array();
278
	foreach ( (array) $post_types as $post_type ) {
279
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
280
	}
281
	$post_types_in = join( ",", $post_types_in );
282
283
	// use direct query instead because get_posts was acting too heavy for our needs
284
	//$posts = get_posts( array( 'numberposts'=>1000, 'post_type'=>$post_types, 'post_status'=>'published' ) );
285
	$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" );
286
	if ( empty( $posts ) ) {
287
		status_header( 404 );
288
	}
289
	header( 'Content-Type: ' . jetpack_sitemap_content_type() );
290
	$initstr = jetpack_sitemap_initstr( get_bloginfo( 'charset' ) );
291
	$tree    = simplexml_load_string( $initstr );
292
	// If we did not get a valid string, force UTF-8 and try again.
293
	if ( false === $tree ) {
294
		$initstr = jetpack_sitemap_initstr( 'UTF-8' );
295
		$tree    = simplexml_load_string( $initstr );
296
	}
297
298
	unset( $initstr );
299
	$latest_mod = '';
300
	foreach ( $posts as $post ) {
301
302
		/**
303
		 * Filter condition to allow skipping specific posts in sitemap.
304
		 *
305
		 * @module sitemaps
306
		 *
307
		 * @since 3.9.0
308
		 *
309
		 * @param bool $skip Current boolean. False by default, so no post is skipped.
310
		 * @param WP_POST $post Current post object.
311
		 */
312
		if ( apply_filters( 'jetpack_sitemap_skip_post', false, $post ) ) {
313
			continue;
314
		}
315
316
		$post_latest_mod = null;
317
		$url             = array( 'loc' => esc_url( get_permalink( $post->ID ) ) );
318
319
		// If this post is configured to be the site home, skip since it's added separately later
320
		if ( untrailingslashit( get_permalink( $post->ID ) ) == untrailingslashit( get_option( 'home' ) ) ) {
321
			continue;
322
		}
323
324
		// Mobile node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=34648
325
		$url['mobile:mobile'] = '';
326
327
		// Image node specified in http://support.google.com/webmasters/bin/answer.py?hl=en&answer=178636
328
		// These attachments were produced with batch SQL earlier in the script
329
		if ( ! post_password_required( $post->ID ) ) {
330
331
			$media = array();
332
			$methods = array(
333
				'from_thumbnail'  => false,
334
				'from_slideshow'  => false,
335
				'from_gallery'    => false,
336
				'from_attachment' => false,
337
				'from_html'       => false,
338
			);
339
			foreach ( $methods as $method => $value ) {
340
				$methods[ $method ] = true;
341
				$images_collected = Jetpack_PostImages::get_images( $post->ID, $methods );
342
				if ( is_array( $images_collected ) ) {
343
					$media = array_merge( $media, $images_collected );
344
				}
345
				$methods[ $method ] = false;
346
			}
347
348
			$images = array();
349
350
			foreach ( $media as $item ) {
351
				if ( ! isset( $item['type'] ) || 'image' != $item['type'] ) {
352
					continue;
353
				}
354
				$one_image = array();
355
356
				if ( isset( $item['src'] ) ) {
357
					$one_image['image:loc'] = esc_url( $item['src'] );
358
					$one_image['image:title'] = sanitize_title_with_dashes( $name = pathinfo( $item['src'], PATHINFO_FILENAME ) );
359
				}
360
361
				$images[] = $one_image;
362
			}
363
364
			if ( ! empty( $images ) ) {
365
				$url['image:image'] = $images;
366
			}
367
		}
368
369
		if ( $post->post_modified_gmt && $post->post_modified_gmt != '0000-00-00 00:00:00' ) {
370
			$post_latest_mod = $post->post_modified_gmt;
371
		}
372
		if ( $post->comment_count > 0 ) {
373
			// last modified based on last comment
374
			$latest_comment_datetime = jetpack_get_approved_comments_max_datetime( $post->ID );
375
			if ( ! empty( $latest_comment_datetime ) ) {
376
				if ( is_null( $post_latest_mod ) || $latest_comment_datetime > $post_latest_mod ) {
377
					$post_latest_mod = $latest_comment_datetime;
378
				}
379
			}
380
			unset( $latest_comment_datetime );
381
		}
382
		if ( ! empty( $post_latest_mod ) ) {
383
			$latest_mod     = max( $latest_mod, $post_latest_mod );
384
			$url['lastmod'] = jetpack_w3cdate_from_mysql( $post_latest_mod );
385
		}
386
		unset( $post_latest_mod );
387
		if ( $post->post_type == 'page' ) {
388
			$url['changefreq'] = 'weekly';
389
			$url['priority']   = '0.6'; // set page priority above default priority of 0.5
390
		} else {
391
			$url['changefreq'] = 'monthly';
392
		}
393
		/**
394
		 * Filter associative array with data to build <url> node and its descendants for current post.
395
		 *
396
		 * @module sitemaps
397
		 *
398
		 * @since 3.9.0
399
		 *
400
		 * @param array $url Data to build parent and children nodes for current post.
401
		 * @param int $post_id Current post ID.
402
		 */
403
		$url_node = apply_filters( 'jetpack_sitemap_url', $url, $post->ID );
404
		jetpack_sitemap_array_to_simplexml( array( 'url' => $url_node ), $tree );
405
		unset( $url );
406
	}
407
	$blog_home = array(
408
		'loc'        => esc_url( get_option( 'home' ) ),
409
		'changefreq' => 'daily',
410
		'priority'   => '1.0'
411
	);
412
	if ( ! empty( $latest_mod ) ) {
413
		$blog_home['lastmod'] = jetpack_w3cdate_from_mysql( $latest_mod );
414
		header( 'Last-Modified:' . mysql2date( 'D, d M Y H:i:s', $latest_mod, 0 ) . ' GMT' );
415
	}
416
	/**
417
	 * Filter associative array with data to build <url> node and its descendants for site home.
418
	 *
419
	 * @module sitemaps
420
	 *
421
	 * @since 3.9.0
422
	 *
423
	 * @param array $blog_home Data to build parent and children nodes for site home.
424
	 */
425
	$url_node = apply_filters( 'jetpack_sitemap_url_home', $blog_home );
426
	jetpack_sitemap_array_to_simplexml( array( 'url' => $url_node ), $tree );
427
	unset( $blog_home );
428
429
	/**
430
	 * Filter data before rendering it as XML.
431
	 *
432
	 * @module sitemaps
433
	 *
434
	 * @since 3.9.0
435
	 *
436
	 * @param SimpleXMLElement $tree Data tree for sitemap.
437
	 * @param string $latest_mod Date of last modification.
438
	 */
439
	$tree = apply_filters( 'jetpack_print_sitemap', $tree, $latest_mod );
440
441
	$xml = $tree->asXML();
442
	unset( $tree );
443
	if ( ! empty( $xml ) ) {
444
		set_transient( 'jetpack_sitemap', $xml, DAY_IN_SECONDS );
445
		echo $xml;
446
	}
447
448
	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...
449
}
450
451
/**
452
 * Prints the news XML sitemap conforming to the Sitemaps.org protocol.
453
 * Outputs an XML list of up to 1000 posts published in the last 2 days.
454
 *
455
 * @module sitemaps
456
 *
457
 * @link http://sitemaps.org/protocol.php Sitemaps.org protocol.
458
 */
459
function jetpack_print_news_sitemap() {
460
461
	$xml = get_transient( 'jetpack_news_sitemap' );
462
463
	if ( $xml ) {
464
		header( 'Content-Type: application/xml' );
465
		echo $xml;
466
		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...
467
	}
468
469
	global $wpdb;
470
471
	/**
472
	 * Filter post types to be included in news sitemap.
473
	 *
474
	 * @module sitemaps
475
	 *
476
	 * @since 3.9.0
477
	 *
478
	 * @param array $post_types Array with post types to include in news sitemap.
479
	 */
480
	$post_types = apply_filters( 'jetpack_sitemap_news_sitemap_post_types', array( 'post' ) );
481
	if ( empty( $post_types ) ) {
482
		return;
483
	}
484
485
	$post_types_in = array();
486
	foreach ( $post_types as $post_type ) {
487
		$post_types_in[] = $wpdb->prepare( '%s', $post_type );
488
	}
489
	$post_types_in_string = implode( ', ', $post_types_in );
490
491
	/**
492
	 * Filter limit of entries to include in news sitemap.
493
	 *
494
	 * @module sitemaps
495
	 *
496
	 * @since 3.9.0
497
	 *
498
	 * @param int $count Number of entries to include in news sitemap.
499
	 */
500
	$limit        = apply_filters( 'jetpack_sitemap_news_sitemap_count', 1000 );
501
	$cur_datetime = current_time( 'mysql', true );
502
503
	$query = $wpdb->prepare( "
504
		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
505
		FROM
506
			$wpdb->posts AS p LEFT JOIN $wpdb->term_relationships AS r ON p.ID = r.object_id
507
			LEFT JOIN $wpdb->term_taxonomy AS tt ON r.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'post_tag'
508
			LEFT JOIN $wpdb->terms AS t ON tt.term_id = t.term_id
509
		WHERE
510
			post_status='publish' AND post_type IN ( {$post_types_in_string} ) AND post_date_gmt > (%s - INTERVAL 2 DAY)
511
		GROUP BY p.ID
512
		ORDER BY p.post_date_gmt DESC LIMIT %d", $cur_datetime, $limit );
513
514
	// URL to XSLT
515
	$xsl = get_option( 'permalink_structure' ) ? home_url( 'news-sitemap.xsl' ) : home_url( '/?jetpack-news-sitemap-xsl=true' );
516
517
	// Unless it's zh-cn for Simplified Chinese or zh-tw for Traditional Chinese,
518
	// trim national variety so an ISO 639 language code as required by Google.
519
	$language_code = strtolower( get_locale() );
520
	if ( in_array( $language_code, array( 'zh_tw', 'zh_cn' ) ) ) {
521
		$language_code = str_replace( '_', '-', $language_code );
522
	} else {
523
		$language_code = preg_replace( '/(_.*)$/i', '', $language_code );
524
	}
525
526
	header( 'Content-Type: application/xml' );
527
	ob_start();
528
	echo '<?xml version="1.0" encoding="UTF-8"?>' . "\n";
529
	echo '<?xml-stylesheet type="text/xsl" href="' . esc_url( $xsl ) . '"?>' . "\n";
530
	echo '<!-- generator="jetpack-' . JETPACK__VERSION . '" -->' . "\n";
531
	?>
532
	<!-- generator="jetpack" -->
533
	<urlset xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
534
	        xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9 http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd"
535
	        xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
536
	        xmlns:news="http://www.google.com/schemas/sitemap-news/0.9"
537
	        xmlns:image="http://www.google.com/schemas/sitemap-image/1.1"
538
		>
539
		<?php
540
		$posts = $wpdb->get_results( $query );
541
		foreach ( $posts as $post ):
542
543
			/**
544
			 * Filter condition to allow skipping specific posts in news sitemap.
545
			 *
546
			 * @module sitemaps
547
			 *
548
			 * @since 3.9.0
549
			 *
550
			 * @param bool $skip Current boolean. False by default, so no post is skipped.
551
			 * @param WP_POST $post Current post object.
552
			 */
553
			if ( apply_filters( 'jetpack_sitemap_news_skip_post', false, $post ) ) {
554
				continue;
555
			}
556
557
			$GLOBALS['post']                       = $post;
558
			$url                                   = array();
559
			$url['loc']                            = get_permalink( $post->ID );
560
			$news                                  = array();
561
			$news['news:publication']['news:name'] = get_bloginfo_rss( 'name' );
562
			$news['news:publication']['news:language'] = $language_code;
563
			$news['news:publication_date'] = jetpack_w3cdate_from_mysql( $post->post_date_gmt );
564
			$news['news:title']            = get_the_title_rss();
565
			if ( $post->keywords ) {
566
				$news['news:keywords'] = html_entity_decode( ent2ncr( $post->keywords ), ENT_HTML5 );
567
			}
568
			$url['news:news'] = $news;
569
570
			// Add image to sitemap
571
			$post_thumbnail = Jetpack_PostImages::get_image( $post->ID );
572
			if ( isset( $post_thumbnail['src'] ) ) {
573
				$url['image:image'] = array( 'image:loc' => esc_url( $post_thumbnail['src'] ) );
574
			}
575
576
			/**
577
			 * Filter associative array with data to build <url> node and its descendants for current post in news sitemap.
578
			 *
579
			 * @module sitemaps
580
			 *
581
			 * @since 3.9.0
582
			 *
583
			 * @param array $url Data to build parent and children nodes for current post.
584
			 * @param int $post_id Current post ID.
585
			 */
586
			$url = apply_filters( 'jetpack_sitemap_news_sitemap_item', $url, $post );
587
588
			if ( empty( $url ) ) {
589
				continue;
590
			}
591
592
			jetpack_print_sitemap_item( $url );
593
		endforeach;
594
		?>
595
	</urlset>
596
	<?php
597
	$xml = ob_get_contents();
598
	ob_end_clean();
599
	if ( ! empty( $xml ) ) {
600
		set_transient( 'jetpack_news_sitemap', $xml, DAY_IN_SECONDS );
601
		echo $xml;
602
	}
603
604
	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...
605
}
606
607
/**
608
 * Absolute URL of the current blog's sitemap.
609
 *
610
 * @module sitemaps
611
 *
612
 * @return string Sitemap URL.
613
 */
614 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...
615
	global $wp_rewrite;
616
617
	if ( $wp_rewrite->using_index_permalinks() ) {
618
		$sitemap_url = home_url( '/index.php/sitemap.xml' );
619
	} else if ( $wp_rewrite->using_permalinks() ) {
620
		$sitemap_url = home_url( '/sitemap.xml' );
621
	} else {
622
		$sitemap_url = home_url( '/?jetpack-sitemap=true' );
623
	}
624
625
	/**
626
	 * Filter sitemap URL relative to home URL.
627
	 *
628
	 * @module sitemaps
629
	 *
630
	 * @since 3.9.0
631
	 *
632
	 * @param string $sitemap_url Sitemap URL.
633
	 */
634
	return apply_filters( 'jetpack_sitemap_location', $sitemap_url );
635
}
636
637
/**
638
 * Absolute URL of the current blog's news sitemap.
639
 *
640
 * @module sitemaps
641
 */
642 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...
643
	global $wp_rewrite;
644
645
	if ( $wp_rewrite->using_index_permalinks() ) {
646
		$news_sitemap_url = home_url( '/index.php/news-sitemap.xml' );
647
	} else if ( $wp_rewrite->using_permalinks() ) {
648
		$news_sitemap_url = home_url( '/news-sitemap.xml' );
649
	} else {
650
		$news_sitemap_url = home_url( '/?jetpack-news-sitemap=true' );
651
	}
652
653
	/**
654
	 * Filter news sitemap URL relative to home URL.
655
	 *
656
	 * @module sitemaps
657
	 *
658
	 * @since 3.9.0
659
	 *
660
	 * @param string $news_sitemap_url News sitemap URL.
661
	 */
662
	return apply_filters( 'jetpack_news_sitemap_location', $news_sitemap_url );
663
}
664
665
/**
666
 * Output the default sitemap URL.
667
 *
668
 * @module sitemaps
669
 */
670
function jetpack_sitemap_discovery() {
671
	echo 'Sitemap: ' . esc_url( jetpack_sitemap_uri() ) . PHP_EOL;
672
}
673
674
/**
675
 * Output the news sitemap URL.
676
 *
677
 * @module sitemaps
678
 */
679
function jetpack_news_sitemap_discovery() {
680
	echo 'Sitemap: ' . esc_url( jetpack_news_sitemap_uri() ) . PHP_EOL . PHP_EOL;
681
}
682
683
/**
684
 * Clear the sitemap cache when a sitemap action has changed.
685
 *
686
 * @module sitemaps
687
 *
688
 * @param int $post_id unique post identifier. not used.
689
 */
690
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...
691
	delete_transient( 'jetpack_sitemap' );
692
	delete_transient( 'jetpack_news_sitemap' );
693
}
694
695
/**
696
 * Clear sitemap cache when an entry changes. Make sitemaps discoverable to robots. Render sitemaps.
697
 *
698
 * @module sitemaps
699
 */
700
function jetpack_sitemap_initialize() {
701
	add_action( 'publish_post', 'jetpack_sitemap_handle_update', 12, 1 );
702
	add_action( 'publish_page', 'jetpack_sitemap_handle_update', 12, 1 );
703
	add_action( 'trash_post', 'jetpack_sitemap_handle_update', 12, 1 );
704
	add_action( 'deleted_post', 'jetpack_sitemap_handle_update', 12, 1 );
705
706
	/**
707
	 * Filter whether to make the default sitemap discoverable to robots or not.
708
	 *
709
	 * @module sitemaps
710
	 *
711
	 * @since 3.9.0
712
	 *
713
	 * @param bool $discover_sitemap Make default sitemap discoverable to robots.
714
	 */
715
	$discover_sitemap = apply_filters( 'jetpack_sitemap_generate', true );
716 View Code Duplication
	if ( $discover_sitemap ) {
717
		add_action( 'do_robotstxt', 'jetpack_sitemap_discovery', 5, 0 );
718
719
		if ( get_option( 'permalink_structure' ) ) {
720
			/** This filter is documented in modules/sitemaps/sitemaps.php */
721
			$sitemap = apply_filters( 'jetpack_sitemap_location', home_url( '/sitemap.xml' ) );
722
			$sitemap = parse_url( $sitemap, PHP_URL_PATH );
723
		} else {
724
			/** This filter is documented in modules/sitemaps/sitemaps.php */
725
			$sitemap = apply_filters( 'jetpack_sitemap_location', home_url( '/?jetpack-sitemap=true' ) );
726
			$sitemap = preg_replace( '/(=.*?)$/i', '', parse_url( $sitemap, PHP_URL_QUERY ) );
727
		}
728
729
		// Sitemap XML
730
		if ( preg_match( '#(' . $sitemap . ')$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET[ $sitemap ] ) && 'true' == $_GET[ $sitemap ] ) ) {
731
			// run later so things like custom post types have been registered
732
			add_action( 'init', 'jetpack_print_sitemap', 999 );
733
		}
734
735
		// XSLT for sitemap
736
		if ( preg_match( '#(/sitemap\.xsl)$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET['jetpack-sitemap-xsl'] ) && 'true' == $_GET['jetpack-sitemap-xsl'] ) ) {
737
			add_action( 'init', 'jetpack_print_sitemap_xsl' );
738
		}
739
	}
740
741
	/**
742
	 * Filter whether to make the news sitemap discoverable to robots or not.
743
	 *
744
	 * @module sitemaps
745
	 *
746
	 * @since 3.9.0
747
	 *
748
	 * @param bool $discover_news_sitemap Make default news sitemap discoverable to robots.
749
	 */
750
	$discover_news_sitemap = apply_filters( 'jetpack_news_sitemap_generate', true );
751 View Code Duplication
	if ( $discover_news_sitemap ) {
752
		add_action( 'do_robotstxt', 'jetpack_news_sitemap_discovery', 5, 0 );
753
754
		if ( get_option( 'permalink_structure' ) ) {
755
			/** This filter is documented in modules/sitemaps/sitemaps.php */
756
			$sitemap = apply_filters( 'jetpack_news_sitemap_location', home_url( '/news-sitemap.xml' ) );
757
			$sitemap = parse_url( $sitemap, PHP_URL_PATH );
758
		} else {
759
			/** This filter is documented in modules/sitemaps/sitemaps.php */
760
			$sitemap = apply_filters( 'jetpack_news_sitemap_location', home_url( '/?jetpack-news-sitemap=true' ) );
761
			$sitemap = preg_replace( '/(=.*?)$/i', '', parse_url( $sitemap, PHP_URL_QUERY ) );
762
		}
763
764
		// News Sitemap XML
765
		if ( preg_match( '#(' . $sitemap . ')$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET[ $sitemap ] ) && 'true' == $_GET[ $sitemap ] ) ) {
766
			// run later so things like custom post types have been registered
767
			add_action( 'init', 'jetpack_print_news_sitemap', 999 );
768
		}
769
770
		// XSLT for sitemap
771
		if ( preg_match( '#(/news-sitemap\.xsl)$#i', $_SERVER['REQUEST_URI'] ) || ( isset( $_GET['jetpack-news-sitemap-xsl'] ) && 'true' == $_GET['jetpack-news-sitemap-xsl'] ) ) {
772
			add_action( 'init', 'jetpack_print_news_sitemap_xsl' );
773
		}
774
	}
775
}
776
777
// Initialize sitemaps once themes can filter the initialization.
778
add_action( 'after_setup_theme', 'jetpack_sitemap_initialize' );
779