/bp-core/bp-core-cache.php

  1. <?php 
  2. /** 
  3. * BuddyPress Core Caching Functions. 
  4. * 
  5. * Caching functions handle the clearing of cached objects and pages on specific 
  6. * actions throughout BuddyPress. 
  7. * 
  8. * @package BuddyPress 
  9. * @supackage Cache 
  10. * @since 1.5.0 
  11. */ 
  12.  
  13. // Exit if accessed directly. 
  14. defined( 'ABSPATH' ) || exit; 
  15.  
  16. /** 
  17. * Prune the WP Super Cache. 
  18. * 
  19. * When WP Super Cache is installed, this function will clear cached pages 
  20. * so that success/error messages or time-sensitive content are not cached. 
  21. * 
  22. * @since 1.0.0 
  23. * 
  24. * @see prune_super_cache() 
  25. * 
  26. * @return int 
  27. */ 
  28. function bp_core_clear_cache() { 
  29. global $cache_path; 
  30.  
  31. if ( function_exists( 'prune_super_cache' ) ) { 
  32.  
  33. /** 
  34. * Fires before the pruning of WP Super Cache. 
  35. * 
  36. * @since 1.0.0 
  37. */ 
  38. do_action( 'bp_core_clear_cache' ); 
  39. return prune_super_cache( $cache_path, true ); 
  40.  
  41. /** 
  42. * Clear all cached objects for a user, or those that a user is part of. 
  43. * 
  44. * @since 1.0.0 
  45. * 
  46. * @param string $user_id User ID to delete cache for. 
  47. */ 
  48. function bp_core_clear_user_object_cache( $user_id ) { 
  49. wp_cache_delete( 'bp_user_' . $user_id, 'bp' ); 
  50.  
  51. /** 
  52. * Clear member count caches and transients. 
  53. * 
  54. * @since 1.6.0 
  55. */ 
  56. function bp_core_clear_member_count_caches() { 
  57. wp_cache_delete( 'bp_total_member_count', 'bp' ); 
  58. delete_transient( 'bp_active_member_count' ); 
  59. add_action( 'bp_core_activated_user', 'bp_core_clear_member_count_caches' ); 
  60. add_action( 'bp_core_process_spammer_status', 'bp_core_clear_member_count_caches' ); 
  61. add_action( 'bp_core_deleted_account', 'bp_core_clear_member_count_caches' ); 
  62. add_action( 'bp_first_activity_for_member', 'bp_core_clear_member_count_caches' ); 
  63. add_action( 'deleted_user', 'bp_core_clear_member_count_caches' ); 
  64.  
  65. /** 
  66. * Clear the directory_pages cache when one of the pages is updated. 
  67. * 
  68. * @since 2.0.0 
  69. * 
  70. * @param int $post_id ID of the page that was saved. 
  71. */ 
  72. function bp_core_clear_directory_pages_cache_page_edit( $post_id ) { 
  73. if ( ! bp_is_root_blog() ) { 
  74. return; 
  75.  
  76. // Bail if BP is not defined here. 
  77. if ( ! buddypress() ) { 
  78. return; 
  79.  
  80. $page_ids = bp_core_get_directory_page_ids( 'all' ); 
  81.  
  82. if ( ! in_array( $post_id, (array) $page_ids ) ) { 
  83. return; 
  84.  
  85. wp_cache_delete( 'directory_pages', 'bp_pages' ); 
  86. add_action( 'save_post', 'bp_core_clear_directory_pages_cache_page_edit' ); 
  87.  
  88. /** 
  89. * Clear the directory_pages cache when the bp-pages option is updated. 
  90. * 
  91. * @since 2.0.0 
  92. * 
  93. * @param string $option Option name. 
  94. */ 
  95. function bp_core_clear_directory_pages_cache_settings_edit( $option ) { 
  96. if ( 'bp-pages' === $option ) { 
  97. wp_cache_delete( 'directory_pages', 'bp_pages' ); 
  98. add_action( 'update_option', 'bp_core_clear_directory_pages_cache_settings_edit' ); 
  99.  
  100. /** 
  101. * Clear the root_blog_options cache when any of its options are updated. 
  102. * 
  103. * @since 2.0.0 
  104. * 
  105. * @param string $option Option name. 
  106. */ 
  107. function bp_core_clear_root_options_cache( $option ) { 
  108. foreach ( array( 'add_option', 'add_site_option', 'update_option', 'update_site_option' ) as $action ) { 
  109. remove_action( $action, 'bp_core_clear_root_options_cache' ); 
  110.  
  111. // Surrounding code prevents infinite loops on WP < 4.4. 
  112. $keys = array_keys( bp_get_default_options() ); 
  113.  
  114. foreach ( array( 'add_option', 'add_site_option', 'update_option', 'update_site_option' ) as $action ) { 
  115. add_action( $action, 'bp_core_clear_root_options_cache' ); 
  116.  
  117. $keys = array_merge( $keys, array( 
  118. 'registration',  
  119. 'avatar_default',  
  120. 'tags_blog_id',  
  121. 'sitewide_tags_blog',  
  122. 'registration',  
  123. 'fileupload_mask',  
  124. ) ); 
  125.  
  126. if ( in_array( $option, $keys ) ) { 
  127. wp_cache_delete( 'root_blog_options', 'bp' ); 
  128. add_action( 'update_option', 'bp_core_clear_root_options_cache' ); 
  129. add_action( 'update_site_option', 'bp_core_clear_root_options_cache' ); 
  130. add_action( 'add_option', 'bp_core_clear_root_options_cache' ); 
  131. add_action( 'add_site_option', 'bp_core_clear_root_options_cache' ); 
  132.  
  133. /** 
  134. * Determine which items from a list do not have cached values. 
  135. * 
  136. * @since 2.0.0 
  137. * 
  138. * @param array $item_ids ID list. 
  139. * @param string $cache_group The cache group to check against. 
  140. * @return array 
  141. */ 
  142. function bp_get_non_cached_ids( $item_ids, $cache_group ) { 
  143. $uncached = array(); 
  144.  
  145. foreach ( $item_ids as $item_id ) { 
  146. $item_id = (int) $item_id; 
  147. if ( false === wp_cache_get( $item_id, $cache_group ) ) { 
  148. $uncached[] = $item_id; 
  149.  
  150. return $uncached; 
  151.  
  152. /** 
  153. * Update the metadata cache for the specified objects. 
  154. * 
  155. * Based on WordPress's {@link update_meta_cache()}, this function primes the 
  156. * cache with metadata related to a set of objects. This is typically done when 
  157. * querying for a loop of objects; pre-fetching metadata for each queried 
  158. * object can lead to dramatic performance improvements when using metadata 
  159. * in the context of template loops. 
  160. * 
  161. * @since 1.6.0 
  162. * 
  163. * @global object $wpdb WordPress database object for queries.. 
  164. * 
  165. * @param array $args { 
  166. * Array of arguments. 
  167. * @type array|string $object_ids List of object IDs to fetch metadata for. 
  168. * Accepts an array or a comma-separated list of numeric IDs. 
  169. * @type string $object_type The type of object, eg 'groups' or 'activity'. 
  170. * @type string $meta_table The name of the metadata table being queried. 
  171. * @type string $object_column Optional. The name of the database column where IDs 
  172. * (those provided by $object_ids) are found. Eg, 'group_id' 
  173. * for the groups metadata tables. Default: $object_type . '_id'. 
  174. * @type string $cache_key_prefix Optional. The prefix to use when creating 
  175. * cache key names. Default: the value of $meta_table. 
  176. * } 
  177. * @return array|bool Metadata cache for the specified objects, or false on failure. 
  178. */ 
  179. function bp_update_meta_cache( $args = array() ) { 
  180. global $wpdb; 
  181.  
  182. $defaults = array( 
  183. 'object_ids' => array(), // Comma-separated list or array of item ids. 
  184. 'object_type' => '', // Canonical component id: groups, members, etc. 
  185. 'cache_group' => '', // Cache group. 
  186. 'meta_table' => '', // Name of the table containing the metadata. 
  187. 'object_column' => '', // DB column for the object ids (group_id, etc). 
  188. 'cache_key_prefix' => '' // Prefix to use when creating cache key names. Eg 'bp_groups_groupmeta'. 
  189. ); 
  190. $r = wp_parse_args( $args, $defaults ); 
  191. extract( $r ); 
  192.  
  193. if ( empty( $object_ids ) || empty( $object_type ) || empty( $meta_table ) || empty( $cache_group ) ) { 
  194. return false; 
  195.  
  196. if ( empty( $cache_key_prefix ) ) { 
  197. $cache_key_prefix = $meta_table; 
  198.  
  199. if ( empty( $object_column ) ) { 
  200. $object_column = $object_type . '_id'; 
  201.  
  202. if ( ! $cache_group ) { 
  203. return false; 
  204.  
  205. $object_ids = wp_parse_id_list( $object_ids ); 
  206. $uncached_ids = bp_get_non_cached_ids( $object_ids, $cache_group ); 
  207.  
  208. $cache = array(); 
  209.  
  210. // Get meta info. 
  211. if ( ! empty( $uncached_ids ) ) { 
  212. $id_list = join( ', ', wp_parse_id_list( $uncached_ids ) ); 
  213. $meta_list = $wpdb->get_results( esc_sql( "SELECT {$object_column}, meta_key, meta_value FROM {$meta_table} WHERE {$object_column} IN ({$id_list})" ), ARRAY_A ); 
  214.  
  215. if ( ! empty( $meta_list ) ) { 
  216. foreach ( $meta_list as $metarow ) { 
  217. $mpid = intval( $metarow[$object_column] ); 
  218. $mkey = $metarow['meta_key']; 
  219. $mval = $metarow['meta_value']; 
  220.  
  221. // Force subkeys to be array type. 
  222. if ( !isset( $cache[$mpid] ) || !is_array( $cache[$mpid] ) ) 
  223. $cache[$mpid] = array(); 
  224. if ( !isset( $cache[$mpid][$mkey] ) || !is_array( $cache[$mpid][$mkey] ) ) 
  225. $cache[$mpid][$mkey] = array(); 
  226.  
  227. // Add a value to the current pid/key. 
  228. $cache[$mpid][$mkey][] = $mval; 
  229.  
  230. foreach ( $uncached_ids as $uncached_id ) { 
  231. // Cache empty values as well. 
  232. if ( ! isset( $cache[ $uncached_id ] ) ) { 
  233. $cache[ $uncached_id ] = array(); 
  234.  
  235. wp_cache_set( $uncached_id, $cache[ $uncached_id ], $cache_group ); 
  236.  
  237. return $cache; 
  238.  
  239. /** 
  240. * Gets a value that has been cached using an incremented key. 
  241. * 
  242. * A utility function for use by query methods like BP_Activity_Activity::get(). 
  243. * 
  244. * @since 2.7.0 
  245. * @see bp_core_set_incremented_cache() 
  246. * 
  247. * @param string $key Unique key for the query. Usually a SQL string. 
  248. * @param string $group Cache group. Eg 'bp_activity'. 
  249. * @return array|bool False if no cached values are found, otherwise an array of IDs. 
  250. */ 
  251. function bp_core_get_incremented_cache( $key, $group ) { 
  252. $cache_key = bp_core_get_incremented_cache_key( $key, $group ); 
  253. return wp_cache_get( $cache_key, $group ); 
  254.  
  255. /** 
  256. * Caches a value using an incremented key. 
  257. * 
  258. * An "incremented key" is a cache key that is hashed with a unique incrementor,  
  259. * allowing for bulk invalidation. 
  260. * 
  261. * Use this method when caching data that should be invalidated whenever any 
  262. * object of a given type is created, updated, or deleted. This usually means 
  263. * data related to object queries, which can only reliably cached until the 
  264. * underlying set of objects has been modified. See, eg, BP_Activity_Activity::get(). 
  265. * 
  266. * @since 2.7.0 
  267. * 
  268. * @param string $key Unique key for the query. Usually a SQL string. 
  269. * @param string $group Cache group. Eg 'bp_activity'. 
  270. * @param array $ids Array of IDs. 
  271. * @return bool 
  272. */ 
  273. function bp_core_set_incremented_cache( $key, $group, $ids ) { 
  274. $cache_key = bp_core_get_incremented_cache_key( $key, $group ); 
  275. return wp_cache_set( $cache_key, $ids, $group ); 
  276.  
  277. /** 
  278. * Gets the key to be used when caching a value using an incremented cache key. 
  279. * 
  280. * The $key is hashed with a component-specific incrementor, which is used to 
  281. * invalidate multiple caches at once. 
  282.   
  283. * @since 2.7.0 
  284. * 
  285. * @param string $key Unique key for the query. Usually a SQL string. 
  286. * @param string $group Cache group. Eg 'bp_activity'. 
  287. * @return string 
  288. */ 
  289. function bp_core_get_incremented_cache_key( $key, $group ) { 
  290. $incrementor = bp_core_get_incrementor( $group ); 
  291. $cache_key = md5( $key . $incrementor ); 
  292. return $cache_key; 
  293.  
  294. /** 
  295. * Gets a group-specific cache incrementor. 
  296. * 
  297. * The incrementor is paired with query identifiers (like SQL strings) to 
  298. * create cache keys that can be invalidated en masse. 
  299. * 
  300. * If an incrementor does not yet exist for the given `$group`, one will 
  301. * be created. 
  302. * 
  303. * @since 2.7.0 
  304. * 
  305. * @param string $group Cache group. Eg 'bp_activity'. 
  306. * @return string 
  307. */ 
  308. function bp_core_get_incrementor( $group ) { 
  309. $incrementor = wp_cache_get( 'incrementor', $group ); 
  310. if ( ! $incrementor ) { 
  311. $incrementor = microtime(); 
  312. wp_cache_set( 'incrementor', $incrementor, $group ); 
  313.  
  314. return $incrementor; 
  315.  
  316. /** 
  317. * Reset a group-specific cache incrementor. 
  318. * 
  319. * Call this function when all incrementor-based caches associated with a given 
  320. * cache group should be invalidated. 
  321. * 
  322. * @since 2.7.0 
  323. * 
  324. * @param string $group Cache group. Eg 'bp_activity'. 
  325. * @return bool True on success, false on failure. 
  326. */ 
  327. function bp_core_reset_incrementor( $group ) { 
  328. return wp_cache_delete( 'incrementor', $group ); 
.