wp/wp-includes/sitemaps/class-wp-sitemaps.php
changeset 16 a86126ab1dd4
child 21 48c4eec2b7e6
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
       
     1 <?php
       
     2 /**
       
     3  * Sitemaps: WP_Sitemaps class
       
     4  *
       
     5  * This is the main class integrating all other classes.
       
     6  *
       
     7  * @package WordPress
       
     8  * @subpackage Sitemaps
       
     9  * @since 5.5.0
       
    10  */
       
    11 
       
    12 /**
       
    13  * Class WP_Sitemaps.
       
    14  *
       
    15  * @since 5.5.0
       
    16  */
       
    17 class WP_Sitemaps {
       
    18 	/**
       
    19 	 * The main index of supported sitemaps.
       
    20 	 *
       
    21 	 * @since 5.5.0
       
    22 	 *
       
    23 	 * @var WP_Sitemaps_Index
       
    24 	 */
       
    25 	public $index;
       
    26 
       
    27 	/**
       
    28 	 * The main registry of supported sitemaps.
       
    29 	 *
       
    30 	 * @since 5.5.0
       
    31 	 *
       
    32 	 * @var WP_Sitemaps_Registry
       
    33 	 */
       
    34 	public $registry;
       
    35 
       
    36 	/**
       
    37 	 * An instance of the renderer class.
       
    38 	 *
       
    39 	 * @since 5.5.0
       
    40 	 *
       
    41 	 * @var WP_Sitemaps_Renderer
       
    42 	 */
       
    43 	public $renderer;
       
    44 
       
    45 	/**
       
    46 	 * WP_Sitemaps constructor.
       
    47 	 *
       
    48 	 * @since 5.5.0
       
    49 	 */
       
    50 	public function __construct() {
       
    51 		$this->registry = new WP_Sitemaps_Registry();
       
    52 		$this->renderer = new WP_Sitemaps_Renderer();
       
    53 		$this->index    = new WP_Sitemaps_Index( $this->registry );
       
    54 	}
       
    55 
       
    56 	/**
       
    57 	 * Initiates all sitemap functionality.
       
    58 	 *
       
    59 	 * If sitemaps are disabled, only the rewrite rules will be registered
       
    60 	 * by this method, in order to properly send 404s.
       
    61 	 *
       
    62 	 * @since 5.5.0
       
    63 	 */
       
    64 	public function init() {
       
    65 		// These will all fire on the init hook.
       
    66 		$this->register_rewrites();
       
    67 
       
    68 		add_action( 'template_redirect', array( $this, 'render_sitemaps' ) );
       
    69 
       
    70 		if ( ! $this->sitemaps_enabled() ) {
       
    71 			return;
       
    72 		}
       
    73 
       
    74 		$this->register_sitemaps();
       
    75 
       
    76 		// Add additional action callbacks.
       
    77 		add_filter( 'pre_handle_404', array( $this, 'redirect_sitemapxml' ), 10, 2 );
       
    78 		add_filter( 'robots_txt', array( $this, 'add_robots' ), 0, 2 );
       
    79 	}
       
    80 
       
    81 	/**
       
    82 	 * Determines whether sitemaps are enabled or not.
       
    83 	 *
       
    84 	 * @since 5.5.0
       
    85 	 *
       
    86 	 * @return bool Whether sitemaps are enabled.
       
    87 	 */
       
    88 	public function sitemaps_enabled() {
       
    89 		$is_enabled = (bool) get_option( 'blog_public' );
       
    90 
       
    91 		/**
       
    92 		 * Filters whether XML Sitemaps are enabled or not.
       
    93 		 *
       
    94 		 * When XML Sitemaps are disabled via this filter, rewrite rules are still
       
    95 		 * in place to ensure a 404 is returned.
       
    96 		 *
       
    97 		 * @see WP_Sitemaps::register_rewrites()
       
    98 		 *
       
    99 		 * @since 5.5.0
       
   100 		 *
       
   101 		 * @param bool $is_enabled Whether XML Sitemaps are enabled or not. Defaults
       
   102 		 * to true for public sites.
       
   103 		 */
       
   104 		return (bool) apply_filters( 'wp_sitemaps_enabled', $is_enabled );
       
   105 	}
       
   106 
       
   107 	/**
       
   108 	 * Registers and sets up the functionality for all supported sitemaps.
       
   109 	 *
       
   110 	 * @since 5.5.0
       
   111 	 */
       
   112 	public function register_sitemaps() {
       
   113 		$providers = array(
       
   114 			'posts'      => new WP_Sitemaps_Posts(),
       
   115 			'taxonomies' => new WP_Sitemaps_Taxonomies(),
       
   116 			'users'      => new WP_Sitemaps_Users(),
       
   117 		);
       
   118 
       
   119 		/* @var WP_Sitemaps_Provider $provider */
       
   120 		foreach ( $providers as $name => $provider ) {
       
   121 			$this->registry->add_provider( $name, $provider );
       
   122 		}
       
   123 	}
       
   124 
       
   125 	/**
       
   126 	 * Registers sitemap rewrite tags and routing rules.
       
   127 	 *
       
   128 	 * @since 5.5.0
       
   129 	 */
       
   130 	public function register_rewrites() {
       
   131 		// Add rewrite tags.
       
   132 		add_rewrite_tag( '%sitemap%', '([^?]+)' );
       
   133 		add_rewrite_tag( '%sitemap-subtype%', '([^?]+)' );
       
   134 
       
   135 		// Register index route.
       
   136 		add_rewrite_rule( '^wp-sitemap\.xml$', 'index.php?sitemap=index', 'top' );
       
   137 
       
   138 		// Register rewrites for the XSL stylesheet.
       
   139 		add_rewrite_tag( '%sitemap-stylesheet%', '([^?]+)' );
       
   140 		add_rewrite_rule( '^wp-sitemap\.xsl$', 'index.php?sitemap-stylesheet=sitemap', 'top' );
       
   141 		add_rewrite_rule( '^wp-sitemap-index\.xsl$', 'index.php?sitemap-stylesheet=index', 'top' );
       
   142 
       
   143 		// Register routes for providers.
       
   144 		add_rewrite_rule(
       
   145 			'^wp-sitemap-([a-z]+?)-([a-z\d_-]+?)-(\d+?)\.xml$',
       
   146 			'index.php?sitemap=$matches[1]&sitemap-subtype=$matches[2]&paged=$matches[3]',
       
   147 			'top'
       
   148 		);
       
   149 		add_rewrite_rule(
       
   150 			'^wp-sitemap-([a-z]+?)-(\d+?)\.xml$',
       
   151 			'index.php?sitemap=$matches[1]&paged=$matches[2]',
       
   152 			'top'
       
   153 		);
       
   154 	}
       
   155 
       
   156 	/**
       
   157 	 * Renders sitemap templates based on rewrite rules.
       
   158 	 *
       
   159 	 * @since 5.5.0
       
   160 	 *
       
   161 	 * @global WP_Query $wp_query WordPress Query object.
       
   162 	 */
       
   163 	public function render_sitemaps() {
       
   164 		global $wp_query;
       
   165 
       
   166 		$sitemap         = sanitize_text_field( get_query_var( 'sitemap' ) );
       
   167 		$object_subtype  = sanitize_text_field( get_query_var( 'sitemap-subtype' ) );
       
   168 		$stylesheet_type = sanitize_text_field( get_query_var( 'sitemap-stylesheet' ) );
       
   169 		$paged           = absint( get_query_var( 'paged' ) );
       
   170 
       
   171 		// Bail early if this isn't a sitemap or stylesheet route.
       
   172 		if ( ! ( $sitemap || $stylesheet_type ) ) {
       
   173 			return;
       
   174 		}
       
   175 
       
   176 		if ( ! $this->sitemaps_enabled() ) {
       
   177 			$wp_query->set_404();
       
   178 			status_header( 404 );
       
   179 			return;
       
   180 		}
       
   181 
       
   182 		// Render stylesheet if this is stylesheet route.
       
   183 		if ( $stylesheet_type ) {
       
   184 			$stylesheet = new WP_Sitemaps_Stylesheet();
       
   185 
       
   186 			$stylesheet->render_stylesheet( $stylesheet_type );
       
   187 			exit;
       
   188 		}
       
   189 
       
   190 		// Render the index.
       
   191 		if ( 'index' === $sitemap ) {
       
   192 			$sitemap_list = $this->index->get_sitemap_list();
       
   193 
       
   194 			$this->renderer->render_index( $sitemap_list );
       
   195 			exit;
       
   196 		}
       
   197 
       
   198 		$provider = $this->registry->get_provider( $sitemap );
       
   199 
       
   200 		if ( ! $provider ) {
       
   201 			return;
       
   202 		}
       
   203 
       
   204 		if ( empty( $paged ) ) {
       
   205 			$paged = 1;
       
   206 		}
       
   207 
       
   208 		$url_list = $provider->get_url_list( $paged, $object_subtype );
       
   209 
       
   210 		// Force a 404 and bail early if no URLs are present.
       
   211 		if ( empty( $url_list ) ) {
       
   212 			$wp_query->set_404();
       
   213 			status_header( 404 );
       
   214 			return;
       
   215 		}
       
   216 
       
   217 		$this->renderer->render_sitemap( $url_list );
       
   218 		exit;
       
   219 	}
       
   220 
       
   221 	/**
       
   222 	 * Redirects a URL to the wp-sitemap.xml
       
   223 	 *
       
   224 	 * @since 5.5.0
       
   225 	 *
       
   226 	 * @param bool     $bypass Pass-through of the pre_handle_404 filter value.
       
   227 	 * @param WP_Query $query  The WP_Query object.
       
   228 	 * @return bool Bypass value.
       
   229 	 */
       
   230 	public function redirect_sitemapxml( $bypass, $query ) {
       
   231 		// If a plugin has already utilized the pre_handle_404 function, return without action to avoid conflicts.
       
   232 		if ( $bypass ) {
       
   233 			return $bypass;
       
   234 		}
       
   235 
       
   236 		// 'pagename' is for most permalink types, name is for when the %postname% is used as a top-level field.
       
   237 		if ( 'sitemap-xml' === $query->get( 'pagename' )
       
   238 			|| 'sitemap-xml' === $query->get( 'name' )
       
   239 		) {
       
   240 			wp_safe_redirect( $this->index->get_index_url() );
       
   241 			exit();
       
   242 		}
       
   243 
       
   244 		return $bypass;
       
   245 	}
       
   246 
       
   247 	/**
       
   248 	 * Adds the sitemap index to robots.txt.
       
   249 	 *
       
   250 	 * @since 5.5.0
       
   251 	 *
       
   252 	 * @param string $output robots.txt output.
       
   253 	 * @param bool   $public Whether the site is public.
       
   254 	 * @return string The robots.txt output.
       
   255 	 */
       
   256 	public function add_robots( $output, $public ) {
       
   257 		if ( $public ) {
       
   258 			$output .= "\nSitemap: " . esc_url( $this->index->get_index_url() ) . "\n";
       
   259 		}
       
   260 
       
   261 		return $output;
       
   262 	}
       
   263 }