class-author-sitemap-provider.php 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\XML_Sitemaps
  6. */
  7. /**
  8. * Sitemap provider for author archives.
  9. */
  10. class WPSEO_Author_Sitemap_Provider implements WPSEO_Sitemap_Provider {
  11. /**
  12. * Check if provider supports given item type.
  13. *
  14. * @param string $type Type string to check for.
  15. *
  16. * @return boolean
  17. */
  18. public function handles_type( $type ) {
  19. return $type === 'author';
  20. }
  21. /**
  22. * @param int $max_entries Entries per sitemap.
  23. *
  24. * @return array
  25. */
  26. public function get_index_links( $max_entries ) {
  27. if ( WPSEO_Options::get( 'disable-author', false ) || WPSEO_Options::get( 'noindex-author-wpseo', false ) ) {
  28. return array();
  29. }
  30. // @todo Consider doing this less often / when necessary. R.
  31. $this->update_user_meta();
  32. $has_exclude_filter = has_filter( 'wpseo_sitemap_exclude_author' );
  33. $query_arguments = array();
  34. if ( ! $has_exclude_filter ) { // We only need full users if legacy filter(s) hooked to exclusion logic. R.
  35. $query_arguments['fields'] = 'ID';
  36. }
  37. $users = $this->get_users( $query_arguments );
  38. if ( $has_exclude_filter ) {
  39. $users = $this->exclude_users( $users );
  40. $users = wp_list_pluck( $users, 'ID' );
  41. }
  42. if ( empty( $users ) ) {
  43. return array();
  44. }
  45. $index = array();
  46. $page = 1;
  47. $user_pages = array_chunk( $users, $max_entries );
  48. if ( count( $user_pages ) === 1 ) {
  49. $page = '';
  50. }
  51. foreach ( $user_pages as $users_page ) {
  52. $user_id = array_shift( $users_page ); // Time descending, first user on page is most recently updated.
  53. $user = get_user_by( 'id', $user_id );
  54. $index[] = array(
  55. 'loc' => WPSEO_Sitemaps_Router::get_base_url( 'author-sitemap' . $page . '.xml' ),
  56. 'lastmod' => '@' . $user->_yoast_wpseo_profile_updated, // @ for explicit timestamp format
  57. );
  58. $page++;
  59. }
  60. return $index;
  61. }
  62. /**
  63. * Retrieve users, taking account of all necessary exclusions.
  64. *
  65. * @param array $arguments Arguments to add.
  66. *
  67. * @return array
  68. */
  69. protected function get_users( $arguments = array() ) {
  70. global $wpdb;
  71. $defaults = array(
  72. // @todo Re-enable after plugin requirements raised to WP 4.6 with the fix.
  73. // 'who' => 'authors', Breaks meta keys, see https://core.trac.wordpress.org/ticket/36724#ticket R.
  74. 'meta_key' => '_yoast_wpseo_profile_updated',
  75. 'orderby' => 'meta_value_num',
  76. 'order' => 'DESC',
  77. 'meta_query' => array(
  78. 'relation' => 'AND',
  79. array(
  80. 'key' => $wpdb->get_blog_prefix() . 'user_level',
  81. 'value' => '0',
  82. 'compare' => '!=',
  83. ),
  84. array(
  85. 'relation' => 'OR',
  86. array(
  87. 'key' => 'wpseo_noindex_author',
  88. 'value' => 'on',
  89. 'compare' => '!=',
  90. ),
  91. array(
  92. 'key' => 'wpseo_noindex_author',
  93. 'compare' => 'NOT EXISTS',
  94. ),
  95. ),
  96. ),
  97. );
  98. if ( WPSEO_Options::get( 'noindex-author-noposts-wpseo', true ) ) {
  99. // $defaults['who'] = ''; // Otherwise it cancels out next argument.
  100. $defaults['has_published_posts'] = true;
  101. }
  102. return get_users( array_merge( $defaults, $arguments ) );
  103. }
  104. /**
  105. * Get set of sitemap link data.
  106. *
  107. * @param string $type Sitemap type.
  108. * @param int $max_entries Entries per sitemap.
  109. * @param int $current_page Current page of the sitemap.
  110. *
  111. * @return array
  112. */
  113. public function get_sitemap_links( $type, $max_entries, $current_page ) {
  114. $links = array();
  115. if ( WPSEO_Options::get( 'disable-author', false ) || WPSEO_Options::get( 'noindex-author-wpseo', false ) ) {
  116. return $links;
  117. }
  118. $users = $this->get_users( array(
  119. 'offset' => ( $current_page - 1 ) * $max_entries,
  120. 'number' => $max_entries,
  121. ) );
  122. $users = $this->exclude_users( $users );
  123. if ( empty( $users ) ) {
  124. $users = array();
  125. }
  126. $time = time();
  127. foreach ( $users as $user ) {
  128. $author_link = get_author_posts_url( $user->ID );
  129. if ( empty( $author_link ) ) {
  130. continue;
  131. }
  132. $mod = $time;
  133. if ( isset( $user->_yoast_wpseo_profile_updated ) ) {
  134. $mod = $user->_yoast_wpseo_profile_updated;
  135. }
  136. $url = array(
  137. 'loc' => $author_link,
  138. 'mod' => date( DATE_W3C, $mod ),
  139. // Deprecated, kept for backwards data compat. R.
  140. 'chf' => 'daily',
  141. 'pri' => 1,
  142. );
  143. /** This filter is documented at inc/sitemaps/class-post-type-sitemap-provider.php */
  144. $url = apply_filters( 'wpseo_sitemap_entry', $url, 'user', $user );
  145. if ( ! empty( $url ) ) {
  146. $links[] = $url;
  147. }
  148. }
  149. return $links;
  150. }
  151. /**
  152. * Update any users that don't have last profile update timestamp.
  153. *
  154. * @return int Count of users updated.
  155. */
  156. protected function update_user_meta() {
  157. $users = get_users( array(
  158. 'who' => 'authors',
  159. 'meta_query' => array(
  160. array(
  161. 'key' => '_yoast_wpseo_profile_updated',
  162. 'compare' => 'NOT EXISTS',
  163. ),
  164. ),
  165. ) );
  166. $time = time();
  167. foreach ( $users as $user ) {
  168. update_user_meta( $user->ID, '_yoast_wpseo_profile_updated', $time );
  169. }
  170. return count( $users );
  171. }
  172. /**
  173. * Wrap legacy filter to deduplicate calls.
  174. *
  175. * @param array $users Array of user objects to filter.
  176. *
  177. * @return array
  178. */
  179. protected function exclude_users( $users ) {
  180. /**
  181. * Filter the authors, included in XML sitemap.
  182. *
  183. * @param array $users Array of user objects to filter.
  184. */
  185. return apply_filters( 'wpseo_sitemap_exclude_author', $users );
  186. }
  187. }