diff options
author | Anthony G. Basile <blueness@gentoo.org> | 2017-09-20 09:54:07 -0400 |
---|---|---|
committer | Anthony G. Basile <blueness@gentoo.org> | 2017-09-20 09:54:07 -0400 |
commit | bb31fa2d44dbbe425fa9ce92d4e7be61a1146dfb (patch) | |
tree | 33456f5889d315ad2a520fcd33fe491e612588b4 /plugins/jetpack/modules/sitemaps | |
parent | akismet 4.0 (diff) | |
download | blogs-gentoo-bb31fa2d44dbbe425fa9ce92d4e7be61a1146dfb.tar.gz blogs-gentoo-bb31fa2d44dbbe425fa9ce92d4e7be61a1146dfb.tar.bz2 blogs-gentoo-bb31fa2d44dbbe425fa9ce92d4e7be61a1146dfb.zip |
jetpack 5.3
Signed-off-by: Anthony G. Basile <blueness@gentoo.org>
Diffstat (limited to 'plugins/jetpack/modules/sitemaps')
15 files changed, 996 insertions, 387 deletions
diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-fallback.php new file mode 100644 index 00000000..1cf73c09 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-fallback.php @@ -0,0 +1,146 @@ +<?php +/** + * The fallback buffer for users with no XML support. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing master sitemap xml files. + * + * @since 5.1.0 + */ +abstract class Jetpack_Sitemap_Buffer_Fallback extends Jetpack_Sitemap_Buffer { + + /** + * The buffer contents. + * + * @access protected + * @since 5.3.0 + * @var string The buffer contents. + */ + protected $buffer; + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + $this->is_full_flag = false; + $this->is_empty_flag = true; + $this->timestamp = $time; + + $this->finder = new Jetpack_Sitemap_Finder(); + + $this->item_capacity = max( 1, intval( $item_limit ) ); + $this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $this->contents() ); + } + + /** + * Append an item to the buffer, if there is room for it, + * and set is_empty_flag to false. If there is no room, + * we set is_full_flag to true. If $item is null, + * don't do anything and report success. + * + * @since 5.3.0 + * + * @param array $array The item to be added. + * + * @return bool True if the append succeeded, False if not. + */ + public function append( $array ) { + if ( is_null( $array ) ) { + return true; + } + + if ( $this->is_full_flag ) { + return false; + } + + if ( 0 >= $this->item_capacity || 0 >= $this->byte_capacity ) { + $this->is_full_flag = true; + return false; + } else { + $this->item_capacity -= 1; + $added_string = $this->array_to_xml_string( $array ); + $this->buffer .= $added_string; + $this->is_empty_flag = false; + + mbstring_binary_safe_encoding(); // So we can safely use strlen(). + $this->byte_capacity -= strlen( $added_string ); + reset_mbstring_encoding(); + + return true; + } + } + + /** + * Detect whether the buffer is empty. + * + * @since 5.3.0 + * + * @return bool True if the buffer is empty, false otherwise. + */ + public function is_empty() { + return $this->is_empty_flag; + } + + /** + * Retrieve the contents of the buffer. + * + * @since 5.3.0 + * + * @return string The contents of the buffer (with the footer included). + */ + public function contents() { + $root = $this->get_root_element(); + + return '<?xml version="1.0" encoding="UTF-8"?>' . PHP_EOL . $root[0] . $this->buffer . $root[1] . PHP_EOL; + } + + /** + * Legacy implementation of array to XML conversion without using DOMDocument. + * + * @param Array $array + * @return String $result + */ + public function array_to_xml_string( $array, $parent = null, $root = null ) { + $string = ''; + + foreach ( $array as $key => $value ) { + // Only allow a-z, A-Z, colon, underscore, and hyphen. + $tag = preg_replace( '/[^a-zA-Z:_-]/', '_', $key ); + + if ( is_array( $value ) ) { + $string .= "<$tag>"; + $string .= $this->array_to_xml_string( $value ); + $string .= "</$tag>"; + } elseif ( is_null( $value ) ) { + $string .= "<$tag />"; + } else { + $string .= "<$tag>" . htmlspecialchars( $value ) . "</$tag>"; + } + } + + return $string; + } + + /** + * Render an associative array of XML attribute key/value pairs. + * + * @access public + * @since 5.3.0 + * + * @param array $array Key/value array of attributes. + * + * @return string The rendered attribute string. + */ + public static function array_to_xml_attr_string( $array ) { + $string = ''; + + foreach ( $array as $key => $value ) { + $key = preg_replace( '/[^a-zA-Z:_-]/', '_', $key ); + $string .= ' ' . $key . '="' . esc_attr( $value ) . '"'; + } + + return $string; + } + +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-image-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-image-fallback.php new file mode 100644 index 00000000..1616574f --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-image-fallback.php @@ -0,0 +1,56 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Image + * extends the Jetpack_Sitemap_Buffer class to represent the single image sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap image xml files for users that have no libxml support. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Image extends Jetpack_Sitemap_Buffer_Fallback { + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the XML namespaces included in image sitemaps. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_image_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1', + ) + ); + + $sitemap_xsl_url = $this->finder->construct_sitemap_url( 'sitemap.xsl' ); + $jetpack_version = JETPACK__VERSION; + + $this->root = array( + "<!-- generator='jetpack-{$jetpack_version}' -->" . PHP_EOL + . "<?xml-stylesheet type='text/xsl' href='{$sitemap_xsl_url}'?>" . PHP_EOL + . '<urlset ' . $this->array_to_xml_attr_string( $namespaces ) . '>' . PHP_EOL, + '</urlset>' + ); + + $this->byte_capacity -= strlen( join( '', $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-image.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-image.php new file mode 100644 index 00000000..e452fcbf --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-image.php @@ -0,0 +1,68 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Image + * extends the Jetpack_Sitemap_Buffer class to represent the single image sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap image xml files. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Image extends Jetpack_Sitemap_Buffer { + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + parent::__construct( $item_limit, $byte_limit, $time ); + + $this->doc->appendChild( + $this->doc->createComment( "generator='jetpack-" . JETPACK__VERSION . "'" ) + ); + + $this->doc->appendChild( + $this->doc->createProcessingInstruction( + 'xml-stylesheet', + 'type="text/xsl" href="' . $this->finder->construct_sitemap_url( 'image-sitemap.xsl' ) . '"' + ) + ); + } + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the XML namespaces included in image sitemaps. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_image_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1', + ) + ); + + $this->root = $this->doc->createElement( 'urlset' ); + + foreach ( $namespaces as $name => $value ) { + $this->root->setAttribute( $name, $value ); + } + + $this->doc->appendChild( $this->root ); + $this->byte_capacity -= strlen( $this->doc->saveXML( $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-master-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-master-fallback.php new file mode 100644 index 00000000..af665547 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-master-fallback.php @@ -0,0 +1,38 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Master + * extends the Jetpack_Sitemap_Buffer class to represent the master sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing master sitemap xml files for users without libxml support. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Master extends Jetpack_Sitemap_Buffer_Fallback { + + protected function get_root_element() { + + if ( ! isset( $this->root ) ) { + + $sitemap_index_xsl_url = $this->finder->construct_sitemap_url( 'sitemap-index.xsl' ); + $jetpack_version = JETPACK__VERSION; + + $this->root = array( + "<!-- generator='jetpack-{$jetpack_version}' -->" . PHP_EOL + . "<?xml-stylesheet type='text/xsl' href='{$sitemap_index_xsl_url}'?>" . PHP_EOL + . "<sitemapindex xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>" . PHP_EOL, + '</sitemapindex>' + ); + + $this->byte_capacity -= strlen( join( '', $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-master.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-master.php new file mode 100644 index 00000000..fc6be602 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-master.php @@ -0,0 +1,44 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Master + * extends the Jetpack_Sitemap_Buffer class to represent the master sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing master sitemap xml files. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Master extends Jetpack_Sitemap_Buffer { + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + parent::__construct( $item_limit, $byte_limit, $time ); + + $this->doc->appendChild( + $this->doc->createComment( "generator='jetpack-" . JETPACK__VERSION . "'" ) + ); + + $this->doc->appendChild( + $this->doc->createProcessingInstruction( + 'xml-stylesheet', + 'type="text/xsl" href="' . $this->finder->construct_sitemap_url( 'sitemap-index.xsl' ) . '"' + ) + ); + } + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + $this->root = $this->doc->createElement( 'sitemapindex' ); + $this->root->setAttribute( 'xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9' ); + $this->doc->appendChild( $this->root ); + $this->byte_capacity -= strlen( $this->doc->saveXML( $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-news-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-news-fallback.php new file mode 100644 index 00000000..cca2c644 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-news-fallback.php @@ -0,0 +1,56 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_News + * extends the Jetpack_Sitemap_Buffer class to represent the single news sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap image xml files for users without libxml support. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_News extends Jetpack_Sitemap_Buffer_Fallback { + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the attribute value pairs used for namespace and namespace URI mappings. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_news_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:news' => 'http://www.google.com/schemas/sitemap-news/0.9', + ) + ); + + $jetpack_version = JETPACK__VERSION; + $news_sitemap_xsl_url = $this->finder->construct_sitemap_url( 'news-sitemap.xsl' ); + + $this->root = array( + "<!-- generator='jetpack-{$jetpack_version}' -->" . PHP_EOL + . "<?xml-stylesheet type='text/xsl' href='{$news_sitemap_xsl_url}'?>" . PHP_EOL + . '<urlset ' . $this->array_to_xml_attr_string( $namespaces ) . '>', + '</urlset>' + ); + + $this->byte_capacity -= strlen( join( '', $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-news.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-news.php new file mode 100644 index 00000000..0e5b0327 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-news.php @@ -0,0 +1,68 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_News + * extends the Jetpack_Sitemap_Buffer class to represent the single news sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap image xml files. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_News extends Jetpack_Sitemap_Buffer { + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + parent::__construct( $item_limit, $byte_limit, $time ); + + $this->doc->appendChild( + $this->doc->createComment( "generator='jetpack-" . JETPACK__VERSION . "'" ) + ); + + $this->doc->appendChild( + $this->doc->createProcessingInstruction( + 'xml-stylesheet', + 'type="text/xsl" href="' . $this->finder->construct_sitemap_url( 'news-sitemap.xsl' ) . '"' + ) + ); + } + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the attribute value pairs used for namespace and namespace URI mappings. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_news_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:news' => 'http://www.google.com/schemas/sitemap-news/0.9', + ) + ); + + $this->root = $this->doc->createElement( 'urlset' ); + + foreach ( $namespaces as $name => $value ) { + $this->root->setAttribute( $name, $value ); + } + + $this->doc->appendChild( $this->root ); + $this->byte_capacity -= strlen( $this->doc->saveXML( $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-page-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-page-fallback.php new file mode 100644 index 00000000..e64f31bc --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-page-fallback.php @@ -0,0 +1,55 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Page + * extends the Jetpack_Sitemap_Buffer class to represent the single page sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap page xml files for users with no libxml support. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Page extends Jetpack_Sitemap_Buffer_Fallback { + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the attribute value pairs used for namespace and namespace URI mappings. + * + * @module sitemaps + * + * @since 3.9.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + ) + ); + + $jetpack_version = JETPACK__VERSION; + $sitemap_xsl_url = $this->finder->construct_sitemap_url( 'sitemap.xsl' ); + + $this->root = array( + "<!-- generator='jetpack-{$jetpack_version}' -->" . PHP_EOL + . "<?xml-stylesheet type='text/xsl' href='{$sitemap_xsl_url}'?>" . PHP_EOL + . '<urlset ' . $this->array_to_xml_attr_string( $namespaces ) . '>', + '</urlset>' + ); + + $this->byte_capacity -= strlen( join( '', $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-page.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-page.php new file mode 100644 index 00000000..d6885900 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-page.php @@ -0,0 +1,67 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Page + * extends the Jetpack_Sitemap_Buffer class to represent the single page sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap page xml files. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Page extends Jetpack_Sitemap_Buffer { + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + parent::__construct( $item_limit, $byte_limit, $time ); + + $this->doc->appendChild( + $this->doc->createComment( "generator='jetpack-" . JETPACK__VERSION . "'" ) + ); + + $this->doc->appendChild( + $this->doc->createProcessingInstruction( + 'xml-stylesheet', + 'type="text/xsl" href="' . $this->finder->construct_sitemap_url( 'sitemap.xsl' ) . '"' + ) + ); + } + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the attribute value pairs used for namespace and namespace URI mappings. + * + * @module sitemaps + * + * @since 3.9.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + ) + ); + + $this->root = $this->doc->createElement( 'urlset' ); + + foreach ( $namespaces as $name => $value ) { + $this->root->setAttribute( $name, $value ); + } + + $this->doc->appendChild( $this->root ); + $this->byte_capacity -= strlen( $this->doc->saveXML( $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-video-fallback.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-video-fallback.php new file mode 100644 index 00000000..d211877d --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-video-fallback.php @@ -0,0 +1,56 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Video + * extends the Jetpack_Sitemap_Buffer class to represent the single video sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap video xml files for users without libxml support. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Video extends Jetpack_Sitemap_Buffer_Fallback { + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the XML namespaces included in video sitemaps. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_video_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1', + ) + ); + + $video_sitemap_xsl_url = $this->finder->construct_sitemap_url( 'video-sitemap.xsl' ); + $jetpack_version = JETPACK__VERSION; + + $this->root = array( + "<!-- generator='jetpack-{$jetpack_version}' -->" . PHP_EOL + . "<?xml-stylesheet type='text/xsl' href='{$video_sitemap_xsl_url}'?>" . PHP_EOL + . '<urlset ' . $this->array_to_xml_attr_string( $namespaces ) . '>', + '</urlset>' + ); + + $this->byte_capacity -= strlen( join( '', $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer-video.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer-video.php new file mode 100644 index 00000000..c6faff36 --- /dev/null +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer-video.php @@ -0,0 +1,68 @@ +<?php +/** + * Sitemaps (per the protocol) are essentially lists of XML fragments; + * lists which are subject to size constraints. The Jetpack_Sitemap_Buffer_Video + * extends the Jetpack_Sitemap_Buffer class to represent the single video sitemap + * buffer. + * + * @since 5.3.0 + * @package Jetpack + */ + +/** + * A buffer for constructing sitemap video xml files. + * + * @since 5.3.0 + */ +class Jetpack_Sitemap_Buffer_Video extends Jetpack_Sitemap_Buffer { + + public function __construct( $item_limit, $byte_limit, $time = '1970-01-01 00:00:00' ) { + parent::__construct( $item_limit, $byte_limit, $time ); + + $this->doc->appendChild( + $this->doc->createComment( "generator='jetpack-" . JETPACK__VERSION . "'" ) + ); + + $this->doc->appendChild( + $this->doc->createProcessingInstruction( + 'xml-stylesheet', + 'type="text/xsl" href="' . $this->finder->construct_sitemap_url( 'video-sitemap.xsl' ) . '"' + ) + ); + } + + protected function get_root_element() { + if ( ! isset( $this->root ) ) { + + /** + * Filter the XML namespaces included in video sitemaps. + * + * @module sitemaps + * + * @since 4.8.0 + * + * @param array $namespaces Associative array with namespaces and namespace URIs. + */ + $namespaces = apply_filters( + 'jetpack_sitemap_video_ns', + array( + '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', + 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', + 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1', + ) + ); + + $this->root = $this->doc->createElement( 'urlset' ); + + foreach ( $namespaces as $name => $value ) { + $this->root->setAttribute( $name, $value ); + } + + $this->doc->appendChild( $this->root ); + $this->byte_capacity -= strlen( $this->doc->saveXML( $this->root ) ); + } + + return $this->root; + } +} diff --git a/plugins/jetpack/modules/sitemaps/sitemap-buffer.php b/plugins/jetpack/modules/sitemaps/sitemap-buffer.php index f1a8d9b1..0853a49a 100644 --- a/plugins/jetpack/modules/sitemaps/sitemap-buffer.php +++ b/plugins/jetpack/modules/sitemaps/sitemap-buffer.php @@ -22,70 +22,80 @@ * * @since 4.8.0 */ -class Jetpack_Sitemap_Buffer { +abstract class Jetpack_Sitemap_Buffer { /** * Largest number of items the buffer can hold. * - * @access private + * @access protected * @since 4.8.0 * @var int $item_capacity The item capacity. */ - private $item_capacity; + protected $item_capacity; /** * Largest number of bytes the buffer can hold. * - * @access private + * @access protected * @since 4.8.0 * @var int $byte_capacity The byte capacity. */ - private $byte_capacity; + protected $byte_capacity; /** - * Footer text of the buffer; stored here so it can be appended when the buffer is full. + * Flag which detects when the buffer is full. * - * @access private + * @access protected * @since 4.8.0 - * @var string $footer_text The footer text. + * @var bool $is_full_flag The flag value. This flag is set to false on construction and only flipped to true if we've tried to add something and failed. */ - private $footer_text; + protected $is_full_flag; /** - * The buffer contents. + * Flag which detects when the buffer is empty. * - * @access private + * @access protected * @since 4.8.0 - * @var string The buffer contents. + * @var bool $is_empty_flag The flag value. This flag is set to true on construction and only flipped to false if we've tried to add something and succeeded. */ - private $buffer; + protected $is_empty_flag; /** - * Flag which detects when the buffer is full. + * The most recent timestamp seen by the buffer. * - * @access private + * @access protected * @since 4.8.0 - * @var bool $is_full_flag The flag value. This flag is set to false on construction and only flipped to true if we've tried to add something and failed. + * @var string $timestamp Must be in 'YYYY-MM-DD hh:mm:ss' format. */ - private $is_full_flag; + protected $timestamp; /** - * Flag which detects when the buffer is empty. + * The DOM document object that is currently being used to construct the XML doc. * - * @access private - * @since 4.8.0 - * @var bool $is_empty_flag The flag value. This flag is set to true on construction and only flipped to false if we've tried to add something and succeeded. + * @access protected + * @since 5.3.0 + * @var DOMDocument $doc */ - private $is_empty_flag; + protected $doc = null; /** - * The most recent timestamp seen by the buffer. + * The root DOM element object that holds everything inside. Do not use directly, call + * the get_root_element getter method instead. * - * @access private - * @since 4.8.0 - * @var string $timestamp Must be in 'YYYY-MM-DD hh:mm:ss' format. + * @access protected + * @since 5.3.0 + * @var DOMElement $doc + */ + protected $root = null; + + /** + * Helper class to construct sitemap paths. + * + * @since 5.3.0 + * @protected + * @var Jetpack_Sitemap_Finder */ - private $timestamp; + protected $finder; /** * Construct a new Jetpack_Sitemap_Buffer. @@ -94,32 +104,29 @@ class Jetpack_Sitemap_Buffer { * * @param int $item_limit The maximum size of the buffer in items. * @param int $byte_limit The maximum size of the buffer in bytes. - * @param string $header The string to prepend to the entire buffer. - * @param string $footer The string to append to the entire buffer. * @param string $time The initial datetime of the buffer. Must be in 'YYYY-MM-DD hh:mm:ss' format. */ - public function __construct( - $item_limit, - $byte_limit, - $header = '', - $footer = '', - $time - ) { - $this->item_capacity = max( 1, intval( $item_limit ) ); - - mbstring_binary_safe_encoding(); // So we can safely use strlen(). - $this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $header ) - strlen( $footer ); - reset_mbstring_encoding(); - - $this->footer_text = $footer; - $this->buffer = $header; + public function __construct( $item_limit, $byte_limit, $time ) { $this->is_full_flag = false; - $this->is_empty_flag = true; $this->timestamp = $time; - return; + + $this->finder = new Jetpack_Sitemap_Finder(); + $this->doc = new DOMDocument( '1.0', 'UTF-8' ); + + $this->item_capacity = max( 1, intval( $item_limit ) ); + $this->byte_capacity = max( 1, intval( $byte_limit ) ) - strlen( $this->doc->saveXML() ); } /** + * Returns a DOM element that contains all sitemap elements. + * + * @access protected + * @since 5.3.0 + * @return DOMElement $root + */ + abstract protected function get_root_element(); + + /** * Append an item to the buffer, if there is room for it, * and set is_empty_flag to false. If there is no room, * we set is_full_flag to true. If $item is null, @@ -132,24 +139,45 @@ class Jetpack_Sitemap_Buffer { * @return bool True if the append succeeded, False if not. */ public function try_to_add_item( $item ) { - if ( is_null( $item ) ) { + _deprecated_function( + 'Jetpack_Sitemap_Buffer::try_to_add_item', + '5.3.0', + 'Jetpack_Sitemap_Buffer::append' + ); + $this->append( $item ); + } + + /** + * Append an item to the buffer, if there is room for it, + * and set is_empty_flag to false. If there is no room, + * we set is_full_flag to true. If $item is null, + * don't do anything and report success. + * + * @since 5.3.0 + * + * @param array $array The item to be added. + * + * @return bool True if the append succeeded, False if not. + */ + public function append( $array ) { + if ( is_null( $array ) ) { return true; + } + + if ( $this->is_full_flag ) { + return false; + } + + if ( 0 >= $this->item_capacity || 0 >= $this->byte_capacity ) { + $this->is_full_flag = true; + return false; } else { + $this->item_capacity -= 1; + $added_element = $this->array_to_xml_string( $array, $this->get_root_element(), $this->doc ); - mbstring_binary_safe_encoding(); // So we can safely use strlen(). - $item_size = strlen( $item ); // Size in bytes. - reset_mbstring_encoding(); + $this->byte_capacity -= strlen( $this->doc->saveXML( $added_element ) ); - if ( 0 >= $this->item_capacity || 0 > $this->byte_capacity - $item_size ) { - $this->is_full_flag = true; - return false; - } else { - $this->is_empty_flag = false; - $this->item_capacity -= 1; - $this->byte_capacity -= $item_size; - $this->buffer .= $item; - return true; - } + return true; } } @@ -161,7 +189,21 @@ class Jetpack_Sitemap_Buffer { * @return string The contents of the buffer (with the footer included). */ public function contents() { - return $this->buffer . $this->footer_text; + if( $this->is_empty() ) { + // The sitemap should have at least the root element added to the DOM + $this->get_root_element(); + } + return $this->doc->saveXML(); + } + + /** + * Retrieve the document object. + * + * @since 5.3.0 + * @return DOMDocument $doc + */ + public function get_document() { + return $this->doc; } /** @@ -183,7 +225,10 @@ class Jetpack_Sitemap_Buffer { * @return bool True if the buffer is empty, false otherwise. */ public function is_empty() { - return $this->is_empty_flag; + return ( + ! isset( $this->root ) + || ! $this->root->hasChildNodes() + ); } /** @@ -195,7 +240,6 @@ class Jetpack_Sitemap_Buffer { */ public function view_time( $new_time ) { $this->timestamp = max( $this->timestamp, $new_time ); - return; } /** @@ -231,56 +275,52 @@ class Jetpack_Sitemap_Buffer { * ), |</html> * ) * - * @access public + * @access protected * @since 3.9.0 * @since 4.8.0 Rename, add $depth parameter, and change return type. + * @since 5.3.0 Refactor, remove $depth parameter, add $parent and $root, make access protected. * * @param array $array A recursive associative array of tag/child relationships. - * @param string $depth String to prepend to each line. For internal use only. + * @param DOMElement $parent (optional) an element to which new children should be added. + * @param DOMDocument $root (optional) the parent document. * - * @return string The rendered XML string. + * @return string|DOMDocument The rendered XML string or an object if root element is specified. */ - public static function array_to_xml_string( $array, $depth = '' ) { - $string = ''; - - foreach ( $array as $key => $value ) { + protected function array_to_xml_string( $array, $parent = null, $root = null ) { + $return_string = false; - // Only allow a-z, A-Z, colon, underscore, and hyphen. - $tag = preg_replace( '/[^a-zA-Z:_-]/', '_', $key ); - - if ( is_array( $value ) ) { - $string .= $depth . "<$tag>\n"; - $string .= self::array_to_xml_string( $value, $depth . ' ' ); - $string .= $depth . "</$tag>\n"; - } elseif ( is_null( $value ) ) { - $string .= $depth . "<$tag />\n"; - } else { - $string .= $depth . "<$tag>" . ent2ncr( $value ) . "</$tag>\n"; - } + if ( null === $parent ) { + $return_string = true; + $parent = $root = new DOMDocument(); } - return $string; - } + if ( is_array( $array ) ) { - /** - * Render an associative array of XML attribute key/value pairs. - * - * @access public - * @since 4.8.0 - * - * @param array $array Key/value array of attributes. - * - * @return string The rendered attribute string. - */ - public static function array_to_xml_attr_string( $array ) { - $string = ''; + foreach ( $array as $key => $value ) { + $element = $root->createElement( $key ); + $parent->appendChild( $element ); - foreach ( $array as $key => $value ) { - $key = preg_replace( '/[^a-zA-Z:_-]/', '_', $key ); - $string .= ' ' . $key . '="' . esc_attr( $value ) . '"'; + if ( is_array( $value ) ) { + foreach ( $value as $child_key => $child_value ) { + $child = $root->createElement( $child_key ); + $element->appendChild( $child ); + $child->appendChild( self::array_to_xml_string( $child_value, $child, $root ) ); + } + } else { + $element->appendChild( + $root->createTextNode( $value ) + ); + } + } + } else { + $element = $root->createTextNode( $array ); + $parent->appendChild( $element ); } - return $string; + if ( $return_string ) { + return $root->saveHTML(); + } else { + return $element; + } } - } diff --git a/plugins/jetpack/modules/sitemaps/sitemap-builder.php b/plugins/jetpack/modules/sitemaps/sitemap-builder.php index cfd7b9a1..9cf91c24 100644 --- a/plugins/jetpack/modules/sitemaps/sitemap-builder.php +++ b/plugins/jetpack/modules/sitemaps/sitemap-builder.php @@ -9,6 +9,22 @@ require_once dirname( __FILE__ ) . '/sitemap-constants.php'; require_once dirname( __FILE__ ) . '/sitemap-buffer.php'; + +if ( ! class_exists( 'DOMDocument' ) ) { + require_once dirname( __FILE__ ) . '/sitemap-buffer-fallback.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-image-fallback.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-master-fallback.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-news-fallback.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-page-fallback.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-video-fallback.php'; +} else { + require_once dirname( __FILE__ ) . '/sitemap-buffer-image.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-master.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-news.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-page.php'; + require_once dirname( __FILE__ ) . '/sitemap-buffer-video.php'; +} + require_once dirname( __FILE__ ) . '/sitemap-librarian.php'; require_once dirname( __FILE__ ) . '/sitemap-finder.php'; require_once dirname( __FILE__ ) . '/sitemap-state.php'; @@ -87,8 +103,6 @@ class Jetpack_Sitemap_Builder { array( 'post', 'page' ) ) ); - - return; } /** @@ -101,6 +115,17 @@ class Jetpack_Sitemap_Builder { public function update_sitemap() { if ( $this->logger ) { $this->logger->report( '-- Updating...' ); + if ( ! class_exists( 'DOMDocument' ) ) { + $this->logger->report( + __( + '-- WARNING: Jetpack can not load necessary XML manipulation libraries. ' + . 'This can happen if XML support in PHP is not enabled on your server. ' + . 'XML support is highly recommended for WordPress and Jetpack, please enable ' + . 'it or contact your hosting provider about it.', + 'jetpack' + ) + ); + } } for ( $i = 1; $i <= JP_SITEMAP_UPDATE_SIZE; $i++ ) { @@ -201,12 +226,10 @@ class Jetpack_Sitemap_Builder { JP_PAGE_SITEMAP_TYPE ); die(); - } + } // End switch(). // Unlock the state. Jetpack_Sitemap_State::unlock(); - - return; } /** @@ -280,8 +303,6 @@ class Jetpack_Sitemap_Builder { $this->librarian->delete_numbered_sitemap_rows_after( $state['number'] + 1, $sitemap_type ); - - return; } /** @@ -387,29 +408,13 @@ class Jetpack_Sitemap_Builder { * @since 4.8.0 */ private function build_master_sitemap( $max ) { - $sitemap_index_xsl_url = $this->finder->construct_sitemap_url( 'sitemap-index.xsl' ); - $jetpack_version = JETPACK__VERSION; - if ( $this->logger ) { $this->logger->report( '-- Building Master Sitemap.' ); } - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_Master( JP_SITEMAP_MAX_ITEMS, - JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$sitemap_index_xsl_url}'?> -<sitemapindex xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'> -HEADER - , - <<<FOOTER -</sitemapindex>\n -FOOTER - , - /* epoch */ - '1970-01-01 00:00:00' + JP_SITEMAP_MAX_BYTES ); if ( 0 < $max[ JP_PAGE_SITEMAP_TYPE ]['number'] ) { @@ -424,14 +429,14 @@ FOOTER $page['last_modified'] = jp_sitemap_datetime( $max[ JP_PAGE_SITEMAP_INDEX_TYPE ]['lastmod'] ); } - $buffer->try_to_add_item( Jetpack_Sitemap_Buffer::array_to_xml_string( + $buffer->append( array( 'sitemap' => array( 'loc' => $this->finder->construct_sitemap_url( $page['filename'] ), 'lastmod' => $page['last_modified'], ), ) - ) ); + ); } if ( 0 < $max[ JP_IMAGE_SITEMAP_TYPE ]['number'] ) { @@ -446,14 +451,14 @@ FOOTER $image['last_modified'] = jp_sitemap_datetime( $max[ JP_IMAGE_SITEMAP_INDEX_TYPE ]['lastmod'] ); } - $buffer->try_to_add_item( Jetpack_Sitemap_Buffer::array_to_xml_string( + $buffer->append( array( 'sitemap' => array( 'loc' => $this->finder->construct_sitemap_url( $image['filename'] ), 'lastmod' => $image['last_modified'], ), ) - ) ); + ); } if ( 0 < $max[ JP_VIDEO_SITEMAP_TYPE ]['number'] ) { @@ -468,14 +473,14 @@ FOOTER $video['last_modified'] = $max[ JP_VIDEO_SITEMAP_INDEX_TYPE ]['lastmod']; } - $buffer->try_to_add_item( Jetpack_Sitemap_Buffer::array_to_xml_string( + $buffer->append( array( 'sitemap' => array( 'loc' => $this->finder->construct_sitemap_url( $video['filename'] ), 'lastmod' => $video['last_modified'], ), ) - ) ); + ); } $this->librarian->store_sitemap_data( @@ -484,8 +489,6 @@ FOOTER $buffer->contents(), '' ); - - return; } /** @@ -514,46 +517,9 @@ FOOTER $this->logger->report( "-- Building $debug_name" ); } - $sitemap_xsl_url = $this->finder->construct_sitemap_url( 'sitemap.xsl' ); - - $jetpack_version = JETPACK__VERSION; - - $namespaces = Jetpack_Sitemap_Buffer::array_to_xml_attr_string( - /** - * Filter the attribute value pairs used for namespace and namespace URI mappings. - * - * @module sitemaps - * - * @since 3.9.0 - * - * @param array $namespaces Associative array with namespaces and namespace URIs. - */ - apply_filters( - 'jetpack_sitemap_ns', - array( - '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', - 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', - ) - ) - ); - - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_Page( JP_SITEMAP_MAX_ITEMS, - JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$sitemap_xsl_url}'?> -<urlset{$namespaces}>\n -HEADER - , - <<<FOOTER -</urlset>\n -FOOTER - , - /* epoch */ - '1970-01-01 00:00:00' + JP_SITEMAP_MAX_BYTES ); // Add entry for the main page (only if we're at the first one). @@ -576,7 +542,7 @@ FOOTER */ $item_array = apply_filters( 'jetpack_sitemap_url_home', $item_array ); - $buffer->try_to_add_item( Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ) ); + $buffer->append( $item_array ); } // Add as many items to the buffer as possible. @@ -593,7 +559,7 @@ FOOTER foreach ( $posts as $post ) { $current_item = $this->post_to_sitemap_item( $post ); - if ( true === $buffer->try_to_add_item( $current_item['xml'] ) ) { + if ( true === $buffer->append( $current_item['xml'] ) ) { $last_post_id = $post->ID; $buffer->view_time( $current_item['last_modified'] ); } else { @@ -613,13 +579,14 @@ FOOTER * @module sitemaps * * @since 3.9.0 + * @since 5.3.0 returns an element of DOMDocument type instead of SimpleXMLElement * - * @param SimpleXMLElement $tree Data tree for sitemap. + * @param DOMDocument $doc Data tree for sitemap. * @param string $last_modified Date of last modification. */ $tree = apply_filters( 'jetpack_print_sitemap', - simplexml_load_string( $buffer->contents() ), + $buffer->get_document(), $buffer->last_modified() ); @@ -627,7 +594,7 @@ FOOTER $this->librarian->store_sitemap_data( $number, JP_PAGE_SITEMAP_TYPE, - $tree->asXML(), + $buffer->contents(), $buffer->last_modified() ); @@ -668,47 +635,9 @@ FOOTER $this->logger->report( "-- Building $debug_name" ); } - $image_sitemap_xsl_url = $this->finder->construct_sitemap_url( 'image-sitemap.xsl' ); - - $jetpack_version = JETPACK__VERSION; - - $namespaces = Jetpack_Sitemap_Buffer::array_to_xml_attr_string( - /** - * Filter the XML namespaces included in image sitemaps. - * - * @module sitemaps - * - * @since 4.8.0 - * - * @param array $namespaces Associative array with namespaces and namespace URIs. - */ - apply_filters( - 'jetpack_sitemap_image_ns', - array( - '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', - 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', - 'xmlns:image' => 'http://www.google.com/schemas/sitemap-image/1.1', - ) - ) - ); - - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_Image( JP_SITEMAP_MAX_ITEMS, - JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$image_sitemap_xsl_url}'?> -<urlset{$namespaces}>\n -HEADER - , - <<<FOOTER -</urlset>\n -FOOTER - , - /* epoch */ - '1970-01-01 00:00:00' + JP_SITEMAP_MAX_BYTES ); // Add as many items to the buffer as possible. @@ -725,7 +654,7 @@ FOOTER foreach ( $posts as $post ) { $current_item = $this->image_post_to_sitemap_item( $post ); - if ( true === $buffer->try_to_add_item( $current_item['xml'] ) ) { + if ( true === $buffer->append( $current_item['xml'] ) ) { $last_post_id = $post->ID; $buffer->view_time( $current_item['last_modified'] ); } else { @@ -784,47 +713,9 @@ FOOTER $this->logger->report( "-- Building $debug_name" ); } - $video_sitemap_xsl_url = $this->finder->construct_sitemap_url( 'video-sitemap.xsl' ); - - $jetpack_version = JETPACK__VERSION; - - $namespaces = Jetpack_Sitemap_Buffer::array_to_xml_attr_string( - /** - * Filter the XML namespaces included in video sitemaps. - * - * @module sitemaps - * - * @since 4.8.0 - * - * @param array $namespaces Associative array with namespaces and namespace URIs. - */ - apply_filters( - 'jetpack_sitemap_video_ns', - array( - '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', - 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', - 'xmlns:video' => 'http://www.google.com/schemas/sitemap-video/1.1', - ) - ) - ); - - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_Video( JP_SITEMAP_MAX_ITEMS, - JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$video_sitemap_xsl_url}'?> -<urlset{$namespaces}>\n -HEADER - , - <<<FOOTER -</urlset>\n -FOOTER - , - /* epoch */ - '1970-01-01 00:00:00' + JP_SITEMAP_MAX_BYTES ); // Add as many items to the buffer as possible. @@ -841,7 +732,7 @@ FOOTER foreach ( $posts as $post ) { $current_item = $this->video_post_to_sitemap_item( $post ); - if ( true === $buffer->try_to_add_item( $current_item['xml'] ) ) { + if ( true === $buffer->append( $current_item['xml'] ) ) { $last_post_id = $post->ID; $buffer->view_time( $current_item['last_modified'] ); } else { @@ -908,25 +799,9 @@ FOOTER $this->logger->report( "-- Building $index_debug_name" ); } - $sitemap_index_xsl_url = $this->finder->construct_sitemap_url( 'sitemap-index.xsl' ); - - $jetpack_version = JETPACK__VERSION; - - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_Master( JP_SITEMAP_MAX_ITEMS, JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$sitemap_index_xsl_url}'?> -<sitemapindex xmlns='http://www.sitemaps.org/schemas/sitemap/0.9'>\n -HEADER - , - <<<FOOTER -</sitemapindex>\n -FOOTER - , - /* initial last_modified value */ $datetime ); @@ -944,7 +819,7 @@ FOOTER ), ); - $buffer->try_to_add_item( Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ) ); + $buffer->append( $item_array ); } // Add as many items to the buffer as possible. @@ -966,7 +841,7 @@ FOOTER $current_item = $this->sitemap_row_to_index_item( (array) $post ); // Try adding this item to the buffer. - if ( true === $buffer->try_to_add_item( $current_item['xml'] ) ) { + if ( true === $buffer->append( $current_item['xml'] ) ) { $last_sitemap_id = $post['ID']; $buffer->view_time( $current_item['last_modified'] ); } else { @@ -1023,7 +898,7 @@ FOOTER ); return array( - 'xml' => Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ), + 'xml' => $item_array, 'last_modified' => $row['post_date'], ); } @@ -1046,10 +921,6 @@ FOOTER $this->logger->report( 'Beginning news sitemap generation.' ); } - $news_sitemap_xsl_url = $this->finder->construct_sitemap_url( 'news-sitemap.xsl' ); - - $jetpack_version = JETPACK__VERSION; - /** * Filter limit of entries to include in news sitemap. * @@ -1064,43 +935,9 @@ FOOTER JP_NEWS_SITEMAP_MAX_ITEMS ); - $namespaces = Jetpack_Sitemap_Buffer::array_to_xml_attr_string( - /** - * Filter the attribute value pairs used for namespace and namespace URI mappings. - * - * @module sitemaps - * - * @since 4.8.0 - * - * @param array $namespaces Associative array with namespaces and namespace URIs. - */ - apply_filters( - 'jetpack_sitemap_news_ns', - array( - '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', - 'xmlns' => 'http://www.sitemaps.org/schemas/sitemap/0.9', - 'xmlns:news' => 'http://www.google.com/schemas/sitemap-news/0.9', - ) - ) - ); - - $buffer = new Jetpack_Sitemap_Buffer( + $buffer = new Jetpack_Sitemap_Buffer_News( min( $item_limit, JP_NEWS_SITEMAP_MAX_ITEMS ), - JP_SITEMAP_MAX_BYTES, - <<<HEADER -<?xml version='1.0' encoding='UTF-8'?> -<!-- generator='jetpack-{$jetpack_version}' --> -<?xml-stylesheet type='text/xsl' href='{$news_sitemap_xsl_url}'?> -<urlset{$namespaces}>\n -HEADER - , - <<<FOOTER -</urlset>\n -FOOTER - , - /* epoch */ - '1970-01-01 00:00:00' + JP_SITEMAP_MAX_BYTES ); $posts = $this->librarian->query_most_recent_posts( JP_NEWS_SITEMAP_MAX_ITEMS ); @@ -1108,7 +945,7 @@ FOOTER foreach ( $posts as $post ) { $current_item = $this->post_to_news_sitemap_item( $post ); - if ( false === $buffer->try_to_add_item( $current_item['xml'] ) ) { + if ( false === $buffer->append( $current_item['xml'] ) ) { break; } } @@ -1124,7 +961,7 @@ FOOTER $the_stored_news_sitemap, JP_NEWS_SITEMAP_INTERVAL ); - } + } // End if(). return $the_stored_news_sitemap; } @@ -1138,7 +975,7 @@ FOOTER * * @param WP_Post $post The post to be processed. * - * @return string An XML fragment representing the post URL. + * @return array An array representing the post URL. */ private function post_to_sitemap_item( $post ) { @@ -1200,7 +1037,7 @@ FOOTER $item_array = apply_filters( 'jetpack_sitemap_url', $item_array, $post->ID ); return array( - 'xml' => Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ), + 'xml' => $item_array, 'last_modified' => $last_modified, ); } @@ -1236,11 +1073,11 @@ FOOTER ); } - $url = esc_url( wp_get_attachment_url( $post->ID ) ); + $url = wp_get_attachment_url( $post->ID ); - $parent_url = esc_url( get_permalink( get_post( $post->post_parent ) ) ); + $parent_url = get_permalink( get_post( $post->post_parent ) ); if ( '' == $parent_url ) { // WPCS: loose comparison ok. - $parent_url = esc_url( get_permalink( $post ) ); + $parent_url = get_permalink( $post ); } $item_array = array( @@ -1252,16 +1089,9 @@ FOOTER ), ), ); - /** This filter is already documented in core/wp-includes/feed.php */ - $title = apply_filters( 'the_title_rss', $post->post_title ); - if ( '' !== $title ) { - $item_array['url']['image:image']['image:title'] = htmlentities( $title ); - } - /** This filter is already documented in core/wp-includes/feed.php */ - $caption = apply_filters( 'the_excerpt_rss', $post->post_excerpt ); - if ( '' !== $caption ) { - $item_array['url']['image:image']['image:caption'] = "<![CDATA[" . $caption . "]]>"; - } + + $item_array['url']['image:image']['image:title'] = $post->post_title; + $item_array['url']['image:image']['image:caption'] = $post->post_excerpt; /** * Filter associative array with data to build <url> node @@ -1281,7 +1111,7 @@ FOOTER ); return array( - 'xml' => Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ), + 'xml' => $item_array, 'last_modified' => $post->post_modified_gmt, ); } @@ -1323,11 +1153,11 @@ FOOTER $parent_url = esc_url( get_permalink( $post ) ); } - // Prepare the content like get_the_content_feed() + // Prepare the content like get_the_content_feed(). $content = $post->post_content; /** This filter is already documented in core/wp-includes/post-template.php */ $content = apply_filters( 'the_content', $content ); - $content = str_replace(']]>', ']]>', $content); + /** This filter is already documented in core/wp-includes/feed.php */ $content = apply_filters( 'the_content_feed', $content, 'rss2' ); @@ -1339,7 +1169,7 @@ FOOTER /** This filter is already documented in core/wp-includes/feed.php */ 'video:title' => apply_filters( 'the_title_rss', $post->post_title ), 'video:thumbnail_loc' => '', - 'video:description' => '<![CDATA[' . $content . ']]>', + 'video:description' => $content, 'video:content_loc' => esc_url( wp_get_attachment_url( $post->ID ) ), ), ), @@ -1366,7 +1196,7 @@ FOOTER ); return array( - 'xml' => Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ), + 'xml' => $item_array, 'last_modified' => $post->post_modified_gmt, ); } @@ -1430,7 +1260,7 @@ FOOTER 'lastmod' => jp_sitemap_datetime( $post->post_modified_gmt ), 'news:news' => array( 'news:publication' => array( - 'news:name' => esc_html( get_bloginfo( 'name' ) ), + 'news:name' => get_bloginfo( 'name' ), 'news:language' => $language, ), /** This filter is already documented in core/wp-includes/feed.php */ @@ -1459,8 +1289,7 @@ FOOTER ); return array( - 'xml' => Jetpack_Sitemap_Buffer::array_to_xml_string( $item_array ), + 'xml' => $item_array, ); } - } diff --git a/plugins/jetpack/modules/sitemaps/sitemap-librarian.php b/plugins/jetpack/modules/sitemaps/sitemap-librarian.php index ac895749..89a86830 100644 --- a/plugins/jetpack/modules/sitemaps/sitemap-librarian.php +++ b/plugins/jetpack/modules/sitemaps/sitemap-librarian.php @@ -39,7 +39,14 @@ class Jetpack_Sitemap_Librarian { * } */ public function read_sitemap_data( $name, $type ) { - $the_post = get_page_by_title( $name, 'OBJECT', $type ); + $post_array = get_posts( array( + 'numberposts' => 1, + 'title' => $name, + 'post_type' => $type, + 'post_status' => 'draft' + ) ); + + $the_post = array_shift( $post_array ); if ( null === $the_post ) { return null; @@ -49,15 +56,14 @@ class Jetpack_Sitemap_Librarian { 'timestamp' => $the_post->post_date, 'name' => $the_post->post_title, 'type' => $the_post->post_type, - 'text' => $the_post->post_content, + 'text' => base64_decode( $the_post->post_content ), ); } } /** * Store a sitemap of given type and index in the database. - * Note that the sitemap contents are run through esc_html before - * being stored, and the timestamp reencoded as 'Y-m-d H:i:s'. + * Note that the timestamp is reencoded as 'Y-m-d H:i:s'. * * If a sitemap with that type and name does not exist, create it. * If a sitemap with that type and name does exist, update it. @@ -73,27 +79,26 @@ class Jetpack_Sitemap_Librarian { public function store_sitemap_data( $index, $type, $contents, $timestamp ) { $name = jp_sitemap_filename( $type, $index ); - $the_post = get_page_by_title( $name, 'OBJECT', $type ); + $the_post = $this->read_sitemap_data( $name, $type ); if ( null === $the_post ) { // Post does not exist. wp_insert_post(array( 'post_title' => $name, - 'post_content' => esc_html( $contents ), + 'post_content' => base64_encode( $contents ), 'post_type' => $type, 'post_date' => date( 'Y-m-d H:i:s', strtotime( $timestamp ) ), )); } else { // Post does exist. wp_insert_post(array( - 'ID' => $the_post->ID, + 'ID' => $the_post['id'], 'post_title' => $name, - 'post_content' => esc_html( $contents ), + 'post_content' => base64_encode( $contents ), 'post_type' => $type, 'post_date' => date( 'Y-m-d H:i:s', strtotime( $timestamp ) ), )); } - return; } /** @@ -108,12 +113,12 @@ class Jetpack_Sitemap_Librarian { * @return bool 'true' if a row was deleted, 'false' otherwise. */ public function delete_sitemap_data( $name, $type ) { - $the_post = get_page_by_title( $name, 'OBJECT', $type ); + $the_post = $this->read_sitemap_data( $name, $type ); if ( null === $the_post ) { return false; } else { - wp_delete_post( $the_post->ID ); + wp_delete_post( $the_post['id'] ); return true; } } @@ -137,7 +142,7 @@ class Jetpack_Sitemap_Librarian { if ( null === $row ) { return ''; } else { - return wp_specialchars_decode( $row['text'], ENT_QUOTES ); + return $row['text']; } } @@ -159,8 +164,6 @@ class Jetpack_Sitemap_Librarian { $name = jp_sitemap_filename( $type, $position ); $any_left = $this->delete_sitemap_data( $name, $type ); } - - return; } /** @@ -170,35 +173,33 @@ class Jetpack_Sitemap_Librarian { * @since 4.8.0 */ public function delete_all_stored_sitemap_data() { - $this->delete_sitemap_data( - jp_sitemap_filename( JP_MASTER_SITEMAP_TYPE ), - JP_MASTER_SITEMAP_TYPE - ); - - $this->delete_numbered_sitemap_rows_after( - 0, JP_PAGE_SITEMAP_TYPE - ); - - $this->delete_numbered_sitemap_rows_after( - 0, JP_PAGE_SITEMAP_INDEX_TYPE - ); - - $this->delete_numbered_sitemap_rows_after( - 0, JP_IMAGE_SITEMAP_TYPE - ); - - $this->delete_numbered_sitemap_rows_after( - 0, JP_IMAGE_SITEMAP_INDEX_TYPE - ); - - $this->delete_numbered_sitemap_rows_after( - 0, JP_VIDEO_SITEMAP_TYPE - ); + $this->delete_sitemap_type_data( JP_MASTER_SITEMAP_TYPE ); + $this->delete_sitemap_type_data( JP_PAGE_SITEMAP_TYPE ); + $this->delete_sitemap_type_data( JP_PAGE_SITEMAP_INDEX_TYPE ); + $this->delete_sitemap_type_data( JP_IMAGE_SITEMAP_TYPE ); + $this->delete_sitemap_type_data( JP_IMAGE_SITEMAP_INDEX_TYPE ); + $this->delete_sitemap_type_data( JP_VIDEO_SITEMAP_TYPE ); + $this->delete_sitemap_type_data( JP_VIDEO_SITEMAP_INDEX_TYPE ); + } - $this->delete_numbered_sitemap_rows_after( - 0, JP_VIDEO_SITEMAP_INDEX_TYPE - ); - return; + /** + * Deletes all sitemap data of specific type + * + * @access protected + * @since 5.3.0 + * + * @param String $type + */ + protected function delete_sitemap_type_data( $type ) { + $ids = get_posts( array( + 'post_type' => $type, + 'post_status' => 'draft', + 'fields' => 'ids' + ) ); + + foreach( $ids as $id ) { + wp_trash_post( $id ); + } } /** diff --git a/plugins/jetpack/modules/sitemaps/sitemaps.php b/plugins/jetpack/modules/sitemaps/sitemaps.php index 3620957c..2c433a1d 100644 --- a/plugins/jetpack/modules/sitemaps/sitemaps.php +++ b/plugins/jetpack/modules/sitemaps/sitemaps.php @@ -108,6 +108,12 @@ class Jetpack_Sitemap_Manager { 10 ); + // In case we need to purge all sitemaps, we do this. + add_action( + 'jetpack_sitemaps_purge_data', + array( $this, 'callback_action_purge_data' ) + ); + /* * Module parameters are stored as options in the database. * This allows us to avoid having to process all of init @@ -434,6 +440,17 @@ class Jetpack_Sitemap_Manager { } /** + * Callback for resetting stored sitemap data. + * + * @access public + * @since 5.3.0 + */ + public function callback_action_purge_data() { + $this->callback_action_flush_news_sitemap_cache(); + $this->librarian->delete_all_stored_sitemap_data(); + } + + /** * Callback to set the sitemap location. * * @access public |