[ Index ]

PHP Cross Reference of WordPress Trunk (Updated Daily)

Search

title

Body

[close]

/wp-includes/sitemaps/ -> class-wp-sitemaps.php (source)

   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  #[AllowDynamicProperties]
  18  class WP_Sitemaps {
  19      /**
  20       * The main index of supported sitemaps.
  21       *
  22       * @since 5.5.0
  23       *
  24       * @var WP_Sitemaps_Index
  25       */
  26      public $index;
  27  
  28      /**
  29       * The main registry of supported sitemaps.
  30       *
  31       * @since 5.5.0
  32       *
  33       * @var WP_Sitemaps_Registry
  34       */
  35      public $registry;
  36  
  37      /**
  38       * An instance of the renderer class.
  39       *
  40       * @since 5.5.0
  41       *
  42       * @var WP_Sitemaps_Renderer
  43       */
  44      public $renderer;
  45  
  46      /**
  47       * WP_Sitemaps constructor.
  48       *
  49       * @since 5.5.0
  50       */
  51  	public function __construct() {
  52          $this->registry = new WP_Sitemaps_Registry();
  53          $this->renderer = new WP_Sitemaps_Renderer();
  54          $this->index    = new WP_Sitemaps_Index( $this->registry );
  55      }
  56  
  57      /**
  58       * Initiates all sitemap functionality.
  59       *
  60       * If sitemaps are disabled, only the rewrite rules will be registered
  61       * by this method, in order to properly send 404s.
  62       *
  63       * @since 5.5.0
  64       */
  65  	public function init() {
  66          // These will all fire on the init hook.
  67          $this->register_rewrites();
  68  
  69          add_action( 'template_redirect', array( $this, 'render_sitemaps' ) );
  70  
  71          if ( ! $this->sitemaps_enabled() ) {
  72              return;
  73          }
  74  
  75          $this->register_sitemaps();
  76  
  77          // Add additional action callbacks.
  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.
 102           *                         Defaults 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 routes for providers.
 139          add_rewrite_rule(
 140              '^wp-sitemap-([a-z]+?)-([a-z\d_-]+?)-(\d+?)\.xml$',
 141              'index.php?sitemap=$matches[1]&sitemap-subtype=$matches[2]&paged=$matches[3]',
 142              'top'
 143          );
 144          add_rewrite_rule(
 145              '^wp-sitemap-([a-z]+?)-(\d+?)\.xml$',
 146              'index.php?sitemap=$matches[1]&paged=$matches[2]',
 147              'top'
 148          );
 149      }
 150  
 151      /**
 152       * Renders sitemap templates based on rewrite rules.
 153       *
 154       * @since 5.5.0
 155       */
 156  	public function render_sitemaps() {
 157          /*
 158           * Bail early if this isn't a sitemap route.
 159           *
 160           * This runs on every front-end request, so it comes before any
 161           * sanitizing. The raw query vars are tested here, matching
 162           * WP::handle_404(), which exempts sitemap requests from its own 404 on
 163           * the same basis. Testing the sanitized values instead would let a
 164           * request that handle_404() exempted fall through both, leaving it a 200.
 165           */
 166          if ( ! get_query_var( 'sitemap' ) ) {
 167              return;
 168          }
 169  
 170          $sitemap        = sanitize_text_field( get_query_var( 'sitemap' ) );
 171          $object_subtype = sanitize_text_field( get_query_var( 'sitemap-subtype' ) );
 172          $paged          = absint( get_query_var( 'paged' ) );
 173  
 174          // Force a 404 and bail early if the route did not survive sanitizing.
 175          if ( ! $sitemap ) {
 176              $this->send_404();
 177              return;
 178          }
 179  
 180          if ( ! $this->sitemaps_enabled() ) {
 181              $this->send_404();
 182              return;
 183          }
 184  
 185          // Render the index.
 186          if ( 'index' === $sitemap ) {
 187              $sitemap_list = $this->index->get_sitemap_list();
 188  
 189              $this->renderer->render_index( $sitemap_list );
 190              exit;
 191          }
 192  
 193          $provider = $this->registry->get_provider( $sitemap );
 194  
 195          // Force a 404 and bail early if the requested provider is not registered.
 196          if ( ! $provider ) {
 197              $this->send_404();
 198              return;
 199          }
 200  
 201          if ( empty( $paged ) ) {
 202              $paged = 1;
 203          }
 204  
 205          // Force a 404 and bail early if the sub-type query variable is set to an invalid value.
 206          if ( $object_subtype && ! array_key_exists( $object_subtype, $provider->get_object_subtypes() ) ) {
 207              $this->send_404();
 208              return;
 209          }
 210  
 211          $url_list = $provider->get_url_list( $paged, $object_subtype );
 212  
 213          // Force a 404 and bail early if the requested page is out of range.
 214          if ( $paged > $provider->get_max_num_pages( $object_subtype ) ) {
 215              $this->send_404();
 216              return;
 217          }
 218  
 219          $this->renderer->render_sitemap( $url_list );
 220          if ( ! defined( 'WP_RUN_CORE_TESTS' ) || ! WP_RUN_CORE_TESTS ) {
 221              exit;
 222          }
 223      }
 224  
 225      /**
 226       * Sends a 404 for a sitemap route that cannot be served.
 227       *
 228       * WP::handle_404() exempts sitemap requests, so every sitemap 404 is issued
 229       * here instead. That includes the no-cache headers handle_404() sends with
 230       * its own 404, so an intermediary does not retain a 404 for a route that
 231       * becomes valid once the site has more content.
 232       *
 233       * @since 7.1.1
 234       *
 235       * @global WP_Query $wp_query WordPress Query object.
 236       */
 237  	private function send_404(): void {
 238          global $wp_query;
 239  
 240          $wp_query->set_404();
 241          status_header( 404 );
 242          nocache_headers();
 243      }
 244  
 245      /**
 246       * Redirects a URL to the wp-sitemap.xml
 247       *
 248       * @since 5.5.0
 249       * @deprecated 6.7.0 Deprecated in favor of {@see WP_Rewrite::rewrite_rules()}
 250       *
 251       * @param bool     $bypass Pass-through of the pre_handle_404 filter value.
 252       * @param WP_Query $query  The WP_Query object.
 253       * @return bool Bypass value.
 254       */
 255  	public function redirect_sitemapxml( $bypass, $query ) {
 256          _deprecated_function( __FUNCTION__, '6.7.0' );
 257  
 258          // If a plugin has already utilized the pre_handle_404 function, return without action to avoid conflicts.
 259          if ( $bypass ) {
 260              return $bypass;
 261          }
 262  
 263          // 'pagename' is for most permalink types, name is for when the %postname% is used as a top-level field.
 264          if ( 'sitemap-xml' === $query->get( 'pagename' )
 265              || 'sitemap-xml' === $query->get( 'name' )
 266          ) {
 267              wp_safe_redirect( $this->index->get_index_url() );
 268              exit();
 269          }
 270  
 271          return $bypass;
 272      }
 273  
 274      /**
 275       * Adds the sitemap index to robots.txt.
 276       *
 277       * @since 5.5.0
 278       *
 279       * @param string $output    robots.txt output.
 280       * @param bool   $is_public Whether the site is public.
 281       * @return string The robots.txt output.
 282       */
 283  	public function add_robots( $output, $is_public ) {
 284          if ( $is_public ) {
 285              $output .= "\nSitemap: " . esc_url( $this->index->get_index_url() ) . "\n";
 286          }
 287  
 288          return $output;
 289      }
 290  }


Generated : Tue Nov 3 08:20:36 2026 Cross-referenced by PHPXref