wp/wp-includes/sitemaps/class-wp-sitemaps-renderer.php
changeset 16 a86126ab1dd4
child 21 48c4eec2b7e6
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
       
     1 <?php
       
     2 /**
       
     3  * Sitemaps: WP_Sitemaps_Renderer class
       
     4  *
       
     5  * Responsible for rendering Sitemaps data to XML in accordance with sitemap protocol.
       
     6  *
       
     7  * @package WordPress
       
     8  * @subpackage Sitemaps
       
     9  * @since 5.5.0
       
    10  */
       
    11 
       
    12 /**
       
    13  * Class WP_Sitemaps_Renderer
       
    14  *
       
    15  * @since 5.5.0
       
    16  */
       
    17 class WP_Sitemaps_Renderer {
       
    18 	/**
       
    19 	 * XSL stylesheet for styling a sitemap for web browsers.
       
    20 	 *
       
    21 	 * @since 5.5.0
       
    22 	 *
       
    23 	 * @var string
       
    24 	 */
       
    25 	protected $stylesheet = '';
       
    26 
       
    27 	/**
       
    28 	 * XSL stylesheet for styling a sitemap for web browsers.
       
    29 	 *
       
    30 	 * @since 5.5.0
       
    31 	 *
       
    32 	 * @var string
       
    33 	 */
       
    34 	protected $stylesheet_index = '';
       
    35 
       
    36 	/**
       
    37 	 * WP_Sitemaps_Renderer constructor.
       
    38 	 *
       
    39 	 * @since 5.5.0
       
    40 	 */
       
    41 	public function __construct() {
       
    42 		$stylesheet_url = $this->get_sitemap_stylesheet_url();
       
    43 
       
    44 		if ( $stylesheet_url ) {
       
    45 			$this->stylesheet = '<?xml-stylesheet type="text/xsl" href="' . esc_url( $stylesheet_url ) . '" ?>';
       
    46 		}
       
    47 
       
    48 		$stylesheet_index_url = $this->get_sitemap_index_stylesheet_url();
       
    49 
       
    50 		if ( $stylesheet_index_url ) {
       
    51 			$this->stylesheet_index = '<?xml-stylesheet type="text/xsl" href="' . esc_url( $stylesheet_index_url ) . '" ?>';
       
    52 		}
       
    53 	}
       
    54 
       
    55 	/**
       
    56 	 * Gets the URL for the sitemap stylesheet.
       
    57 	 *
       
    58 	 * @since 5.5.0
       
    59 	 *
       
    60 	 * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
       
    61 	 *
       
    62 	 * @return string The sitemap stylesheet URL.
       
    63 	 */
       
    64 	public function get_sitemap_stylesheet_url() {
       
    65 		global $wp_rewrite;
       
    66 
       
    67 		$sitemap_url = home_url( '/wp-sitemap.xsl' );
       
    68 
       
    69 		if ( ! $wp_rewrite->using_permalinks() ) {
       
    70 			$sitemap_url = home_url( '/?sitemap-stylesheet=sitemap' );
       
    71 		}
       
    72 
       
    73 		/**
       
    74 		 * Filters the URL for the sitemap stylesheet.
       
    75 		 *
       
    76 		 * If a falsey value is returned, no stylesheet will be used and
       
    77 		 * the "raw" XML of the sitemap will be displayed.
       
    78 		 *
       
    79 		 * @since 5.5.0
       
    80 		 *
       
    81 		 * @param string $sitemap_url Full URL for the sitemaps XSL file.
       
    82 		 */
       
    83 		return apply_filters( 'wp_sitemaps_stylesheet_url', $sitemap_url );
       
    84 	}
       
    85 
       
    86 	/**
       
    87 	 * Gets the URL for the sitemap index stylesheet.
       
    88 	 *
       
    89 	 * @since 5.5.0
       
    90 	 *
       
    91 	 * @global WP_Rewrite $wp_rewrite WordPress rewrite component.
       
    92 	 *
       
    93 	 * @return string The sitemap index stylesheet URL.
       
    94 	 */
       
    95 	public function get_sitemap_index_stylesheet_url() {
       
    96 		global $wp_rewrite;
       
    97 
       
    98 		$sitemap_url = home_url( '/wp-sitemap-index.xsl' );
       
    99 
       
   100 		if ( ! $wp_rewrite->using_permalinks() ) {
       
   101 			$sitemap_url = home_url( '/?sitemap-stylesheet=index' );
       
   102 		}
       
   103 
       
   104 		/**
       
   105 		 * Filters the URL for the sitemap index stylesheet.
       
   106 		 *
       
   107 		 * If a falsey value is returned, no stylesheet will be used and
       
   108 		 * the "raw" XML of the sitemap index will be displayed.
       
   109 		 *
       
   110 		 * @since 5.5.0
       
   111 		 *
       
   112 		 * @param string $sitemap_url Full URL for the sitemaps index XSL file.
       
   113 		 */
       
   114 		return apply_filters( 'wp_sitemaps_stylesheet_index_url', $sitemap_url );
       
   115 	}
       
   116 
       
   117 	/**
       
   118 	 * Renders a sitemap index.
       
   119 	 *
       
   120 	 * @since 5.5.0
       
   121 	 *
       
   122 	 * @param array $sitemaps Array of sitemap URLs.
       
   123 	 */
       
   124 	public function render_index( $sitemaps ) {
       
   125 		header( 'Content-type: application/xml; charset=UTF-8' );
       
   126 
       
   127 		$this->check_for_simple_xml_availability();
       
   128 
       
   129 		$index_xml = $this->get_sitemap_index_xml( $sitemaps );
       
   130 
       
   131 		if ( ! empty( $index_xml ) ) {
       
   132 			// All output is escaped within get_sitemap_index_xml().
       
   133 			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
       
   134 			echo $index_xml;
       
   135 		}
       
   136 	}
       
   137 
       
   138 	/**
       
   139 	 * Gets XML for a sitemap index.
       
   140 	 *
       
   141 	 * @since 5.5.0
       
   142 	 *
       
   143 	 * @param array $sitemaps Array of sitemap URLs.
       
   144 	 * @return string|false A well-formed XML string for a sitemap index. False on error.
       
   145 	 */
       
   146 	public function get_sitemap_index_xml( $sitemaps ) {
       
   147 		$sitemap_index = new SimpleXMLElement(
       
   148 			sprintf(
       
   149 				'%1$s%2$s%3$s',
       
   150 				'<?xml version="1.0" encoding="UTF-8" ?>',
       
   151 				$this->stylesheet_index,
       
   152 				'<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />'
       
   153 			)
       
   154 		);
       
   155 
       
   156 		foreach ( $sitemaps as $entry ) {
       
   157 			$sitemap = $sitemap_index->addChild( 'sitemap' );
       
   158 
       
   159 			// Add each element as a child node to the <sitemap> entry.
       
   160 			foreach ( $entry as $name => $value ) {
       
   161 				if ( 'loc' === $name ) {
       
   162 					$sitemap->addChild( $name, esc_url( $value ) );
       
   163 				} elseif ( 'lastmod' === $name ) {
       
   164 					$sitemap->addChild( $name, esc_xml( $value ) );
       
   165 				} else {
       
   166 					_doing_it_wrong(
       
   167 						__METHOD__,
       
   168 						sprintf(
       
   169 							/* translators: %s: List of element names. */
       
   170 							__( 'Fields other than %s are not currently supported for the sitemap index.' ),
       
   171 							implode( ',', array( 'loc', 'lastmod' ) )
       
   172 						),
       
   173 						'5.5.0'
       
   174 					);
       
   175 				}
       
   176 			}
       
   177 		}
       
   178 
       
   179 		return $sitemap_index->asXML();
       
   180 	}
       
   181 
       
   182 	/**
       
   183 	 * Renders a sitemap.
       
   184 	 *
       
   185 	 * @since 5.5.0
       
   186 	 *
       
   187 	 * @param array $url_list Array of URLs for a sitemap.
       
   188 	 */
       
   189 	public function render_sitemap( $url_list ) {
       
   190 		header( 'Content-type: application/xml; charset=UTF-8' );
       
   191 
       
   192 		$this->check_for_simple_xml_availability();
       
   193 
       
   194 		$sitemap_xml = $this->get_sitemap_xml( $url_list );
       
   195 
       
   196 		if ( ! empty( $sitemap_xml ) ) {
       
   197 			// All output is escaped within get_sitemap_xml().
       
   198 			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
       
   199 			echo $sitemap_xml;
       
   200 		}
       
   201 	}
       
   202 
       
   203 	/**
       
   204 	 * Gets XML for a sitemap.
       
   205 	 *
       
   206 	 * @since 5.5.0
       
   207 	 *
       
   208 	 * @param array $url_list Array of URLs for a sitemap.
       
   209 	 * @return string|false A well-formed XML string for a sitemap index. False on error.
       
   210 	 */
       
   211 	public function get_sitemap_xml( $url_list ) {
       
   212 		$urlset = new SimpleXMLElement(
       
   213 			sprintf(
       
   214 				'%1$s%2$s%3$s',
       
   215 				'<?xml version="1.0" encoding="UTF-8" ?>',
       
   216 				$this->stylesheet,
       
   217 				'<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" />'
       
   218 			)
       
   219 		);
       
   220 
       
   221 		foreach ( $url_list as $url_item ) {
       
   222 			$url = $urlset->addChild( 'url' );
       
   223 
       
   224 			// Add each element as a child node to the <url> entry.
       
   225 			foreach ( $url_item as $name => $value ) {
       
   226 				if ( 'loc' === $name ) {
       
   227 					$url->addChild( $name, esc_url( $value ) );
       
   228 				} elseif ( in_array( $name, array( 'lastmod', 'changefreq', 'priority' ), true ) ) {
       
   229 					$url->addChild( $name, esc_xml( $value ) );
       
   230 				} else {
       
   231 					_doing_it_wrong(
       
   232 						__METHOD__,
       
   233 						sprintf(
       
   234 							/* translators: %s: List of element names. */
       
   235 							__( 'Fields other than %s are not currently supported for sitemaps.' ),
       
   236 							implode( ',', array( 'loc', 'lastmod', 'changefreq', 'priority' ) )
       
   237 						),
       
   238 						'5.5.0'
       
   239 					);
       
   240 				}
       
   241 			}
       
   242 		}
       
   243 
       
   244 		return $urlset->asXML();
       
   245 	}
       
   246 
       
   247 	/**
       
   248 	 * Checks for the availability of the SimpleXML extension and errors if missing.
       
   249 	 *
       
   250 	 * @since 5.5.0
       
   251 	 */
       
   252 	private function check_for_simple_xml_availability() {
       
   253 		if ( ! class_exists( 'SimpleXMLElement' ) ) {
       
   254 			add_filter(
       
   255 				'wp_die_handler',
       
   256 				static function () {
       
   257 					return '_xml_wp_die_handler';
       
   258 				}
       
   259 			);
       
   260 
       
   261 			wp_die(
       
   262 				sprintf(
       
   263 					/* translators: %s: SimpleXML */
       
   264 					esc_xml( __( 'Could not generate XML sitemap due to missing %s extension' ) ),
       
   265 					'SimpleXML'
       
   266 				),
       
   267 				esc_xml( __( 'WordPress &rsaquo; Error' ) ),
       
   268 				array(
       
   269 					'response' => 501, // "Not implemented".
       
   270 				)
       
   271 			);
       
   272 		}
       
   273 	}
       
   274 }