class-sitemaps-cache.php 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. /**
  3. * WPSEO plugin file.
  4. *
  5. * @package WPSEO\XML_Sitemaps
  6. */
  7. /**
  8. * Handles sitemaps caching and invalidation.
  9. *
  10. * @since 3.2
  11. */
  12. class WPSEO_Sitemaps_Cache {
  13. /** @var array $cache_clear Holds the options that, when updated, should cause the cache to clear. */
  14. protected static $cache_clear = array();
  15. /** @var bool $is_enabled Mirror of enabled status for static calls. */
  16. protected static $is_enabled = true;
  17. /** @var bool $clear_all Holds the flag to clear all cache. */
  18. protected static $clear_all = false;
  19. /** @var array $clear_types Holds the array of types to clear. */
  20. protected static $clear_types = array();
  21. /**
  22. * Hook methods for invalidation on necessary events.
  23. */
  24. public function __construct() {
  25. add_action( 'init', array( $this, 'init' ) );
  26. add_action( 'deleted_term_relationships', array( __CLASS__, 'invalidate' ) );
  27. add_action( 'update_option', array( __CLASS__, 'clear_on_option_update' ) );
  28. add_action( 'edited_terms', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
  29. add_action( 'clean_term_cache', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
  30. add_action( 'clean_object_term_cache', array( __CLASS__, 'invalidate_helper' ), 10, 2 );
  31. add_action( 'user_register', array( __CLASS__, 'invalidate_author' ) );
  32. add_action( 'delete_user', array( __CLASS__, 'invalidate_author' ) );
  33. add_action( 'shutdown', array( __CLASS__, 'clear_queued' ) );
  34. }
  35. /**
  36. * Setup context for static calls.
  37. */
  38. public function init() {
  39. self::$is_enabled = $this->is_enabled();
  40. }
  41. /**
  42. * If cache is enabled.
  43. *
  44. * @since 3.2
  45. *
  46. * @return boolean
  47. */
  48. public function is_enabled() {
  49. /**
  50. * Filter if XML sitemap transient cache is enabled.
  51. *
  52. * @param bool $unsigned Enable cache or not, defaults to true
  53. */
  54. return apply_filters( 'wpseo_enable_xml_sitemap_transient_caching', true );
  55. }
  56. /**
  57. * Retrieve the sitemap page from cache.
  58. *
  59. * @since 3.2
  60. *
  61. * @param string $type Sitemap type.
  62. * @param int $page Page number to retrieve.
  63. *
  64. * @return string|boolean
  65. */
  66. public function get_sitemap( $type, $page ) {
  67. $transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
  68. if ( false === $transient_key ) {
  69. return false;
  70. }
  71. return get_transient( $transient_key );
  72. }
  73. /**
  74. * Get the sitemap that is cached
  75. *
  76. * @param string $type Sitemap type.
  77. * @param int $page Page number to retrieve.
  78. *
  79. * @return null|WPSEO_Sitemap_Cache_Data Null on no cache found otherwise object containing sitemap and meta data.
  80. */
  81. public function get_sitemap_data( $type, $page ) {
  82. $sitemap = $this->get_sitemap( $type, $page );
  83. if ( empty( $sitemap ) ) {
  84. return null;
  85. }
  86. // Unserialize Cache Data object (is_serialized doesn't recognize classes).
  87. if ( is_string( $sitemap ) && 0 === strpos( $sitemap, 'C:24:"WPSEO_Sitemap_Cache_Data"' ) ) {
  88. $sitemap = unserialize( $sitemap );
  89. }
  90. // What we expect it to be if it is set.
  91. if ( $sitemap instanceof WPSEO_Sitemap_Cache_Data_Interface ) {
  92. return $sitemap;
  93. }
  94. return null;
  95. }
  96. /**
  97. * Store the sitemap page from cache.
  98. *
  99. * @since 3.2
  100. *
  101. * @param string $type Sitemap type.
  102. * @param int $page Page number to store.
  103. * @param string $sitemap Sitemap body to store.
  104. * @param bool $usable Is this a valid sitemap or a cache of an invalid sitemap.
  105. *
  106. * @return bool
  107. */
  108. public function store_sitemap( $type, $page, $sitemap, $usable = true ) {
  109. $transient_key = WPSEO_Sitemaps_Cache_Validator::get_storage_key( $type, $page );
  110. if ( false === $transient_key ) {
  111. return false;
  112. }
  113. $status = ( $usable ) ? WPSEO_Sitemap_Cache_Data::OK : WPSEO_Sitemap_Cache_Data::ERROR;
  114. $sitemap_data = new WPSEO_Sitemap_Cache_Data();
  115. $sitemap_data->set_sitemap( $sitemap );
  116. $sitemap_data->set_status( $status );
  117. return set_transient( $transient_key, $sitemap_data, DAY_IN_SECONDS );
  118. }
  119. /**
  120. * Delete cache transients for index and specific type.
  121. *
  122. * Always deletes the main index sitemaps cache, as that's always invalidated by any other change.
  123. *
  124. * @since 1.5.4
  125. * @since 3.2 Changed from function wpseo_invalidate_sitemap_cache() to method in this class.
  126. *
  127. * @param string $type Sitemap type to invalidate.
  128. *
  129. * @return void
  130. */
  131. public static function invalidate( $type ) {
  132. self::clear( array( $type ) );
  133. }
  134. /**
  135. * Helper to invalidate in hooks where type is passed as second argument.
  136. *
  137. * @since 3.2
  138. *
  139. * @param int $unused Unused term ID value.
  140. * @param string $type Taxonomy to invalidate.
  141. *
  142. * @return void
  143. */
  144. public static function invalidate_helper( $unused, $type ) {
  145. if (
  146. WPSEO_Options::get( 'noindex-' . $type ) === false ||
  147. WPSEO_Options::get( 'noindex-tax-' . $type ) === false
  148. ) {
  149. self::invalidate( $type );
  150. }
  151. }
  152. /**
  153. * Invalidate sitemap cache for authors.
  154. *
  155. * @param int $user_id User ID.
  156. */
  157. public static function invalidate_author( $user_id ) {
  158. $user = get_user_by( 'id', $user_id );
  159. if ( 'user_register' === current_action() ) {
  160. update_user_meta( $user_id, '_yoast_wpseo_profile_updated', time() );
  161. }
  162. if ( ! in_array( 'subscriber', $user->roles, true ) ) {
  163. self::invalidate( 'author' );
  164. }
  165. }
  166. /**
  167. * Invalidate sitemap cache for the post type of a post.
  168. *
  169. * Don't invalidate for revisions.
  170. *
  171. * @since 1.5.4
  172. * @since 3.2 Changed from function wpseo_invalidate_sitemap_cache_on_save_post() to method in this class.
  173. *
  174. * @param int $post_id Post ID to invalidate type for.
  175. *
  176. * @return void
  177. */
  178. public static function invalidate_post( $post_id ) {
  179. if ( wp_is_post_revision( $post_id ) ) {
  180. return;
  181. }
  182. self::invalidate( get_post_type( $post_id ) );
  183. }
  184. /**
  185. * Delete cache transients for given sitemaps types or all by default.
  186. *
  187. * @since 1.8.0
  188. * @since 3.2 Moved from WPSEO_Utils to this class.
  189. *
  190. * @param array $types Set of sitemap types to delete cache transients for.
  191. *
  192. * @return void
  193. */
  194. public static function clear( $types = array() ) {
  195. if ( ! self::$is_enabled ) {
  196. return;
  197. }
  198. // No types provided, clear all.
  199. if ( empty( $types ) ) {
  200. self::$clear_all = true;
  201. return;
  202. }
  203. // Always invalidate the index sitemap as well.
  204. if ( ! in_array( WPSEO_Sitemaps::SITEMAP_INDEX_TYPE, $types ) ) {
  205. array_unshift( $types, WPSEO_Sitemaps::SITEMAP_INDEX_TYPE );
  206. }
  207. foreach ( $types as $type ) {
  208. if ( ! in_array( $type, self::$clear_types ) ) {
  209. self::$clear_types[] = $type;
  210. }
  211. }
  212. }
  213. /**
  214. * Invalidate storage for cache types queued to clear.
  215. */
  216. public static function clear_queued() {
  217. if ( self::$clear_all ) {
  218. WPSEO_Sitemaps_Cache_Validator::invalidate_storage();
  219. self::$clear_all = false;
  220. self::$clear_types = array();
  221. return;
  222. }
  223. foreach ( self::$clear_types as $type ) {
  224. WPSEO_Sitemaps_Cache_Validator::invalidate_storage( $type );
  225. }
  226. self::$clear_types = array();
  227. }
  228. /**
  229. * Adds a hook that when given option is updated, the cache is cleared
  230. *
  231. * @since 3.2
  232. *
  233. * @param string $option Option name.
  234. * @param string $type Sitemap type.
  235. */
  236. public static function register_clear_on_option_update( $option, $type = '' ) {
  237. self::$cache_clear[ $option ] = $type;
  238. }
  239. /**
  240. * Clears the transient cache when a given option is updated, if that option has been registered before
  241. *
  242. * @since 3.2
  243. *
  244. * @param string $option The option name that's being updated.
  245. *
  246. * @return void
  247. */
  248. public static function clear_on_option_update( $option ) {
  249. if ( array_key_exists( $option, self::$cache_clear ) ) {
  250. if ( empty( self::$cache_clear[ $option ] ) ) {
  251. // Clear all caches.
  252. self::clear();
  253. }
  254. else {
  255. // Clear specific provided type(s).
  256. $types = (array) self::$cache_clear[ $option ];
  257. self::clear( $types );
  258. }
  259. }
  260. }
  261. }