class-wp-sitemaps-posts.php 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. <?php
  2. /**
  3. * Sitemaps: WP_Sitemaps_Posts class
  4. *
  5. * Builds the sitemaps for the 'post' object type.
  6. *
  7. * @package WordPress
  8. * @subpackage Sitemaps
  9. * @since 5.5.0
  10. */
  11. /**
  12. * Posts XML sitemap provider.
  13. *
  14. * @since 5.5.0
  15. */
  16. class WP_Sitemaps_Posts extends WP_Sitemaps_Provider {
  17. /**
  18. * WP_Sitemaps_Posts constructor.
  19. *
  20. * @since 5.5.0
  21. */
  22. public function __construct() {
  23. $this->name = 'posts';
  24. $this->object_type = 'post';
  25. }
  26. /**
  27. * Returns the public post types, which excludes nav_items and similar types.
  28. * Attachments are also excluded. This includes custom post types with public = true.
  29. *
  30. * @since 5.5.0
  31. *
  32. * @return WP_Post_Type[] Array of registered post type objects keyed by their name.
  33. */
  34. public function get_object_subtypes() {
  35. $post_types = get_post_types( array( 'public' => true ), 'objects' );
  36. unset( $post_types['attachment'] );
  37. $post_types = array_filter( $post_types, 'is_post_type_viewable' );
  38. /**
  39. * Filters the list of post object sub types available within the sitemap.
  40. *
  41. * @since 5.5.0
  42. *
  43. * @param WP_Post_Type[] $post_types Array of registered post type objects keyed by their name.
  44. */
  45. return apply_filters( 'wp_sitemaps_post_types', $post_types );
  46. }
  47. /**
  48. * Gets a URL list for a post type sitemap.
  49. *
  50. * @since 5.5.0
  51. * @since 5.9.0 Renamed `$post_type` to `$object_subtype` to match parent class
  52. * for PHP 8 named parameter support.
  53. *
  54. * @param int $page_num Page of results.
  55. * @param string $object_subtype Optional. Post type name. Default empty.
  56. *
  57. * @return array[] Array of URL information for a sitemap.
  58. */
  59. public function get_url_list( $page_num, $object_subtype = '' ) {
  60. // Restores the more descriptive, specific name for use within this method.
  61. $post_type = $object_subtype;
  62. // Bail early if the queried post type is not supported.
  63. $supported_types = $this->get_object_subtypes();
  64. if ( ! isset( $supported_types[ $post_type ] ) ) {
  65. return array();
  66. }
  67. /**
  68. * Filters the posts URL list before it is generated.
  69. *
  70. * Returning a non-null value will effectively short-circuit the generation,
  71. * returning that value instead.
  72. *
  73. * @since 5.5.0
  74. *
  75. * @param array[]|null $url_list The URL list. Default null.
  76. * @param string $post_type Post type name.
  77. * @param int $page_num Page of results.
  78. */
  79. $url_list = apply_filters(
  80. 'wp_sitemaps_posts_pre_url_list',
  81. null,
  82. $post_type,
  83. $page_num
  84. );
  85. if ( null !== $url_list ) {
  86. return $url_list;
  87. }
  88. $args = $this->get_posts_query_args( $post_type );
  89. $args['paged'] = $page_num;
  90. $query = new WP_Query( $args );
  91. $url_list = array();
  92. /*
  93. * Add a URL for the homepage in the pages sitemap.
  94. * Shows only on the first page if the reading settings are set to display latest posts.
  95. */
  96. if ( 'page' === $post_type && 1 === $page_num && 'posts' === get_option( 'show_on_front' ) ) {
  97. // Extract the data needed for home URL to add to the array.
  98. $sitemap_entry = array(
  99. 'loc' => home_url( '/' ),
  100. );
  101. /**
  102. * Filters the sitemap entry for the home page when the 'show_on_front' option equals 'posts'.
  103. *
  104. * @since 5.5.0
  105. *
  106. * @param array $sitemap_entry Sitemap entry for the home page.
  107. */
  108. $sitemap_entry = apply_filters( 'wp_sitemaps_posts_show_on_front_entry', $sitemap_entry );
  109. $url_list[] = $sitemap_entry;
  110. }
  111. foreach ( $query->posts as $post ) {
  112. $sitemap_entry = array(
  113. 'loc' => get_permalink( $post ),
  114. );
  115. /**
  116. * Filters the sitemap entry for an individual post.
  117. *
  118. * @since 5.5.0
  119. *
  120. * @param array $sitemap_entry Sitemap entry for the post.
  121. * @param WP_Post $post Post object.
  122. * @param string $post_type Name of the post_type.
  123. */
  124. $sitemap_entry = apply_filters( 'wp_sitemaps_posts_entry', $sitemap_entry, $post, $post_type );
  125. $url_list[] = $sitemap_entry;
  126. }
  127. return $url_list;
  128. }
  129. /**
  130. * Gets the max number of pages available for the object type.
  131. *
  132. * @since 5.5.0
  133. * @since 5.9.0 Renamed `$post_type` to `$object_subtype` to match parent class
  134. * for PHP 8 named parameter support.
  135. *
  136. * @param string $object_subtype Optional. Post type name. Default empty.
  137. * @return int Total number of pages.
  138. */
  139. public function get_max_num_pages( $object_subtype = '' ) {
  140. if ( empty( $object_subtype ) ) {
  141. return 0;
  142. }
  143. // Restores the more descriptive, specific name for use within this method.
  144. $post_type = $object_subtype;
  145. /**
  146. * Filters the max number of pages before it is generated.
  147. *
  148. * Passing a non-null value will short-circuit the generation,
  149. * returning that value instead.
  150. *
  151. * @since 5.5.0
  152. *
  153. * @param int|null $max_num_pages The maximum number of pages. Default null.
  154. * @param string $post_type Post type name.
  155. */
  156. $max_num_pages = apply_filters( 'wp_sitemaps_posts_pre_max_num_pages', null, $post_type );
  157. if ( null !== $max_num_pages ) {
  158. return $max_num_pages;
  159. }
  160. $args = $this->get_posts_query_args( $post_type );
  161. $args['fields'] = 'ids';
  162. $args['no_found_rows'] = false;
  163. $query = new WP_Query( $args );
  164. $min_num_pages = ( 'page' === $post_type && 'posts' === get_option( 'show_on_front' ) ) ? 1 : 0;
  165. return isset( $query->max_num_pages ) ? max( $min_num_pages, $query->max_num_pages ) : 1;
  166. }
  167. /**
  168. * Returns the query args for retrieving posts to list in the sitemap.
  169. *
  170. * @since 5.5.0
  171. * @since 6.1.0 Added `ignore_sticky_posts` default parameter.
  172. *
  173. * @param string $post_type Post type name.
  174. * @return array Array of WP_Query arguments.
  175. */
  176. protected function get_posts_query_args( $post_type ) {
  177. /**
  178. * Filters the query arguments for post type sitemap queries.
  179. *
  180. * @see WP_Query for a full list of arguments.
  181. *
  182. * @since 5.5.0
  183. * @since 6.1.0 Added `ignore_sticky_posts` default parameter.
  184. *
  185. * @param array $args Array of WP_Query arguments.
  186. * @param string $post_type Post type name.
  187. */
  188. $args = apply_filters(
  189. 'wp_sitemaps_posts_query_args',
  190. array(
  191. 'orderby' => 'ID',
  192. 'order' => 'ASC',
  193. 'post_type' => $post_type,
  194. 'posts_per_page' => wp_sitemaps_get_max_urls( $this->object_type ),
  195. 'post_status' => array( 'publish' ),
  196. 'no_found_rows' => true,
  197. 'update_post_term_cache' => false,
  198. 'update_post_meta_cache' => false,
  199. 'ignore_sticky_posts' => true, // sticky posts will still appear, but they won't be moved to the front.
  200. ),
  201. $post_type
  202. );
  203. return $args;
  204. }
  205. }