PageRenderTime 85ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/woocommerce-subscriptions-master/includes/class-wcs-cached-data-manager.php

https://bitbucket.org/tristangemus/tribe-demo
PHP | 306 lines | 166 code | 46 blank | 94 comment | 26 complexity | 148c309a942c8eb24376ce8cf53036f7 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * Subscription Cached Data Manager Class
  4. *
  5. * @class WCS_Cached_Data_Manager
  6. * @version 2.1.2
  7. * @package WooCommerce Subscriptions/Classes
  8. * @category Class
  9. * @author Prospress
  10. */
  11. class WCS_Cached_Data_Manager extends WCS_Cache_Manager {
  12. public $logger = null;
  13. public function __construct() {
  14. add_action( 'woocommerce_loaded', array( $this, 'load_logger' ) );
  15. // Add filters for update / delete / trash post to purge cache
  16. add_action( 'trashed_post', array( $this, 'purge_delete' ), 9999 ); // trashed posts aren't included in 'any' queries
  17. add_action( 'untrashed_post', array( $this, 'purge_delete' ), 9999 ); // however untrashed posts are
  18. add_action( 'before_delete_post', array( $this, 'purge_delete' ), 9999 ); // if forced delete is enabled
  19. add_action( 'update_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 );
  20. add_action( 'updated_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys
  21. add_action( 'deleted_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys
  22. add_action( 'added_post_meta', array( $this, 'purge_from_metadata' ), 9999, 4 ); // tied to '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys
  23. add_action( 'admin_init', array( $this, 'initialize_cron_check_size' ) ); // setup cron task to truncate big logs.
  24. add_filter( 'cron_schedules', array( $this, 'add_weekly_cron_schedule' ) ); // create a weekly cron schedule
  25. // Add actions to handle cache purge for users.
  26. add_action( 'save_post', array( $this, 'purge_delete' ), 9999, 2 );
  27. }
  28. /**
  29. * Attaches logger
  30. */
  31. public function load_logger() {
  32. $this->logger = new WC_Logger();
  33. }
  34. /**
  35. * Wrapper function around WC_Logger->log
  36. *
  37. * @param string $message Message to log
  38. */
  39. public function log( $message ) {
  40. if ( is_object( $this->logger ) && defined( 'WCS_DEBUG' ) && WCS_DEBUG ) {
  41. $this->logger->add( 'wcs-cache', $message );
  42. }
  43. }
  44. /**
  45. * Helper function for fetching cached data or updating and storing new data provided by callback.
  46. *
  47. * @param string $key The key to cache/fetch the data with
  48. * @param string|array $callback name of function, or array of class - method that fetches the data
  49. * @param array $params arguments passed to $callback
  50. * @param integer $expires number of seconds to keep the cache. Don't set it to 0, as the cache will be autoloaded. Default is a week.
  51. *
  52. * @return bool|mixed
  53. */
  54. public function cache_and_get( $key, $callback, $params = array(), $expires = WEEK_IN_SECONDS ) {
  55. $expires = absint( $expires );
  56. $data = get_transient( $key );
  57. // if there isn't a transient currently stored and we have a callback update function, fetch and store
  58. if ( false === $data && ! empty( $callback ) ) {
  59. $data = call_user_func_array( $callback, $params );
  60. set_transient( $key, $data, $expires );
  61. }
  62. return $data;
  63. }
  64. /**
  65. * Clearing cache when a post is deleted
  66. *
  67. * @param int $post_id The ID of a post
  68. * @param WP_Post $post The post object (on certain hooks).
  69. */
  70. public function purge_delete( $post_id, $post = null ) {
  71. $post_type = get_post_type( $post_id );
  72. if ( 'shop_order' === $post_type ) {
  73. foreach ( wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) ) as $subscription ) {
  74. $this->log( 'Calling purge delete on ' . current_filter() . ' for ' . $subscription->get_id() );
  75. $this->clear_related_order_cache( $subscription );
  76. }
  77. }
  78. if ( 'shop_subscription' === $post_type ) {
  79. // Purge wcs_do_subscriptions_exist cache, but only on the before_delete_post hook.
  80. if ( doing_action( 'before_delete_post' ) ) {
  81. $this->log( "Subscription {$post_id} deleted. Purging subscription cache." );
  82. $this->delete_cached( 'wcs_do_subscriptions_exist' );
  83. }
  84. // Purge cache for a specific user on the save_post hook.
  85. if ( doing_action( 'save_post' ) ) {
  86. $this->purge_subscription_user_cache( $post_id );
  87. }
  88. }
  89. }
  90. /**
  91. * When subscription related metadata is added / deleted / updated on an order, we need to invalidate the subscription related orders cache.
  92. *
  93. * @param $meta_id integer the ID of the meta in the meta table
  94. * @param $object_id integer the ID of the post we're updating on, only concerned with order IDs
  95. * @param $meta_key string the meta_key in the table, only concerned with '_subscription_renewal', '_subscription_resubscribe' & '_subscription_switch' keys
  96. * @param $meta_value mixed the ID of the subscription that relates to the order
  97. */
  98. public function purge_from_metadata( $meta_id, $object_id, $meta_key, $meta_value ) {
  99. static $combined_keys = null;
  100. static $order_keys = array(
  101. '_subscription_renewal' => 1,
  102. '_subscription_resubscribe' => 1,
  103. '_subscription_switch' => 1,
  104. );
  105. static $subscription_keys = array(
  106. '_customer_user' => 1,
  107. );
  108. if ( null === $combined_keys ) {
  109. $combined_keys = array_merge( $order_keys, $subscription_keys );
  110. }
  111. // Ensure we're handling a meta key we actually care about.
  112. if ( ! isset( $combined_keys[ $meta_key ] ) ) {
  113. return;
  114. }
  115. if ( 'shop_order' === get_post_type( $object_id ) && isset( $order_keys[ $meta_key ] ) ) {
  116. $this->log( sprintf(
  117. 'Calling purge from %1$s on object %2$s and meta value %3$s due to %4$s meta key.',
  118. current_filter(),
  119. $object_id,
  120. $meta_value,
  121. $meta_key
  122. ) );
  123. $this->clear_related_order_cache( $meta_value );
  124. } elseif ( 'shop_subscription' === get_post_type( $object_id ) && isset( $subscription_keys[ $meta_key ] ) ) {
  125. $this->purge_subscription_user_cache( $object_id );
  126. }
  127. }
  128. /**
  129. * Wrapper function to clear the cache that relates to related orders
  130. *
  131. * @param null $subscription_id
  132. */
  133. protected function clear_related_order_cache( $subscription_id ) {
  134. // if it's not a Subscription, we don't deal with it
  135. if ( is_object( $subscription_id ) && $subscription_id instanceof WC_Subscription ) {
  136. $subscription_id = $subscription_id->get_id();
  137. } elseif ( is_numeric( $subscription_id ) ) {
  138. $subscription_id = absint( $subscription_id );
  139. } else {
  140. return;
  141. }
  142. $key = 'wcs-related-orders-to-' . $subscription_id;
  143. $this->log( 'In the clearing, key being purged is this: ' . print_r( $key, true ) );
  144. $this->delete_cached( $key );
  145. }
  146. /**
  147. * Delete cached data with key
  148. *
  149. * @param string $key Key that needs deleting
  150. *
  151. * @return bool
  152. */
  153. public function delete_cached( $key ) {
  154. if ( ! is_string( $key ) || empty( $key ) ) {
  155. return false;
  156. }
  157. return delete_transient( $key );
  158. }
  159. /**
  160. * If the log is bigger than a threshold it will be
  161. * truncated to 0 bytes.
  162. */
  163. public static function cleanup_logs() {
  164. $file = wc_get_log_file_path( 'wcs-cache' );
  165. $max_cache_size = apply_filters( 'wcs_max_log_size', 50 * 1024 * 1024 );
  166. if ( filesize( $file ) >= $max_cache_size ) {
  167. $size_to_keep = apply_filters( 'wcs_log_size_to_keep', 25 * 1024 );
  168. $lines_to_keep = apply_filters( 'wcs_log_lines_to_keep', 1000 );
  169. $fp = fopen( $file, 'r' );
  170. fseek( $fp, -1 * $size_to_keep, SEEK_END );
  171. $data = '';
  172. while ( ! feof( $fp ) ) {
  173. $data .= fread( $fp, $size_to_keep );
  174. }
  175. fclose( $fp );
  176. // Remove first line (which is probably incomplete) and also any empty line
  177. $lines = explode( "\n", $data );
  178. $lines = array_filter( array_slice( $lines, 1 ) );
  179. $lines = array_slice( $lines, -1000 );
  180. $lines[] = '---- log file automatically truncated ' . gmdate( 'Y-m-d H:i:s' ) . ' ---';
  181. file_put_contents( $file, implode( "\n", $lines ), LOCK_EX );
  182. }
  183. }
  184. /**
  185. * Check once each week if the log file has exceeded the limits.
  186. *
  187. * @since 2.2.9
  188. */
  189. public function initialize_cron_check_size() {
  190. $hook = 'wcs_cleanup_big_logs';
  191. if ( ! wp_next_scheduled( $hook ) ) {
  192. wp_schedule_event( time(), 'weekly', $hook );
  193. }
  194. add_action( $hook, __CLASS__ . '::cleanup_logs' );
  195. }
  196. /**
  197. * Add a weekly schedule for clearing up the cache
  198. *
  199. * @param $scheduled array
  200. * @since 2.2.9
  201. */
  202. function add_weekly_cron_schedule( $schedules ) {
  203. if ( ! isset( $schedules['weekly'] ) ) {
  204. $schedules['weekly'] = array(
  205. 'interval' => WEEK_IN_SECONDS,
  206. 'display' => __( 'Weekly', 'woocommerce-subscriptions' ),
  207. );
  208. }
  209. return $schedules;
  210. }
  211. /**
  212. * Purge the cache for the subscription's user.
  213. *
  214. * @author Jeremy Pry
  215. *
  216. * @param int $subscription_id The subscription to purge.
  217. */
  218. protected function purge_subscription_user_cache( $subscription_id ) {
  219. $subscription = wcs_get_subscription( $subscription_id );
  220. $subscription_user_id = $subscription->get_user_id();
  221. $this->log( sprintf(
  222. 'Clearing cache for user ID %1$s on %2$s hook.',
  223. $subscription_user_id,
  224. current_action()
  225. ) );
  226. $this->delete_cached( "wcs_user_subscriptions_{$subscription_user_id}" );
  227. }
  228. /* Deprecated Functions */
  229. /**
  230. * Wrapper function to clear cache that relates to related orders
  231. *
  232. * @param null $subscription_id
  233. */
  234. public function wcs_clear_related_order_cache( $subscription_id = null ) {
  235. _deprecated_function( __METHOD__, '2.1.2', __CLASS__ . '::clear_related_order_cache( $subscription_id )' );
  236. $this->clear_related_order_cache( $subscription_id );
  237. }
  238. /**
  239. * Clearing for orders / subscriptions with sanitizing bits
  240. *
  241. * @param $post_id integer the ID of an order / subscription
  242. */
  243. public function purge_subscription_cache_on_update( $post_id ) {
  244. _deprecated_function( __METHOD__, '2.1.2', __CLASS__ . '::clear_related_order_cache( $subscription_id )' );
  245. $post_type = get_post_type( $post_id );
  246. if ( 'shop_subscription' === $post_type ) {
  247. $this->clear_related_order_cache( $post_id );
  248. } elseif ( 'shop_order' === $post_type ) {
  249. $subscriptions = wcs_get_subscriptions_for_order( $post_id, array( 'order_type' => 'any' ) );
  250. if ( empty( $subscriptions ) ) {
  251. $this->log( 'No subscriptions for this ID: ' . $post_id );
  252. } else {
  253. foreach ( $subscriptions as $subscription ) {
  254. $this->log( 'Got subscription, calling clear_related_order_cache for ' . $subscription->get_id() );
  255. $this->clear_related_order_cache( $subscription );
  256. }
  257. }
  258. }
  259. }
  260. }