PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.2
WebberZone Top 10 — Popular Posts v4.5.2
4.5.2 4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 All 118 releases
top-10 / includes / util / class-cache.php

class-cache.php in WebberZone Top 10 — Popular Posts 4.5.2, at includes/util/class-cache.php

400 lines 9.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Cache class.
4 *
5 * @package WebberZone\Top_Ten\Util
6 */
7
8 namespace WebberZone\Top_Ten\Util;
9
10 use WebberZone\Top_Ten\Frontend\Language_Handler;
11 use WebberZone\Top_Ten\Util\Hook_Registry;
12
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 /**
18 * Cache class.
19 *
20 * @since 3.3.0
21 */
22 class Cache {
23
24 /**
25 * Constructor class.
26 *
27 * @since 3.3.0
28 */
29 public function __construct() {
30 Hook_Registry::add_action( 'wp_ajax_tptn_clear_cache', array( $this, 'ajax_clearcache' ) );
31 }
32
33 /**
34 * Function to clear the Top 10 Cache with Ajax.
35 *
36 * @since 2.2.0
37 */
38 public function ajax_clearcache() {
39
40 $network_wide = isset( $_POST['network_wide'] ) && '1' === sanitize_key( wp_unslash( $_POST['network_wide'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
41 $capability = $network_wide ? 'manage_network_options' : 'manage_options';
42
43 if ( ! current_user_can( $capability ) ) {
44 wp_die();
45 }
46 check_ajax_referer( 'tptn-admin', 'security' );
47
48 $count = $network_wide ? self::delete_network() : $this->delete();
49
50 wp_send_json_success(
51 array(
52 /* translators: 1: Number of entries cleared. */
53 'message' => sprintf(
54 $network_wide
55 ? _n( '%s cache entry cleared across the network', '%s cache entries cleared across the network', $count, 'top-10' )
56 : _n( '%s entry cleared', '%s entries cleared', $count, 'top-10' ),
57 number_format_i18n( $count )
58 ),
59 )
60 );
61 }
62
63 /**
64 * Delete the Top 10 cache.
65 *
66 * @since 2.3.0
67 *
68 * @param array $transients Array of transients to delete.
69 * @return int Number of transients deleted.
70 */
71 public static function delete( $transients = array() ) {
72 $loop = 0;
73
74 $default_transients = self::get_keys();
75
76 if ( ! empty( $transients ) ) {
77 $transients = array_intersect( $default_transients, (array) $transients );
78 } else {
79 $transients = $default_transients;
80 }
81
82 foreach ( $transients as $transient ) {
83 $del = delete_transient( $transient );
84 if ( $del ) {
85 ++$loop;
86 }
87 }
88 return $loop;
89 }
90
91 /**
92 * Delete the Top 10 cache across all active network sites.
93 *
94 * @since 4.5.0
95 *
96 * @return int Number of transients deleted.
97 */
98 public static function delete_network() {
99 if ( ! is_multisite() ) {
100 return self::delete();
101 }
102
103 $site_ids = wp_list_pluck(
104 get_sites(
105 array(
106 'archived' => 0,
107 'spam' => 0,
108 'deleted' => 0,
109 'number' => 0,
110 )
111 ),
112 'blog_id'
113 );
114 $count = 0;
115 $current_blog_id = get_current_blog_id();
116
117 foreach ( $site_ids as $site_id ) {
118 $site_id = absint( $site_id );
119 $switched = $site_id !== $current_blog_id;
120 if ( $switched ) {
121 switch_to_blog( $site_id );
122 }
123
124 try {
125 $count += self::delete();
126 } finally {
127 if ( $switched ) {
128 restore_current_blog();
129 }
130 }
131 }
132
133 return $count;
134 }
135
136 /**
137 * Get the default meta keys used for the cache
138 *
139 * @return array Transient meta keys
140 */
141 public static function get_keys() {
142
143 $meta_keys = array(
144 'tptn_total',
145 'tptn_daily',
146 'tptn_total_shortcode',
147 'tptn_daily_shortcode',
148 'tptn_total_widget',
149 'tptn_daily_widget',
150 'tptn_total_manual',
151 'tptn_daily_manual',
152 );
153
154 $meta_keys = array_merge( $meta_keys, self::get_widget_keys() );
155
156 /**
157 * Filters the array containing the various cache keys.
158 *
159 * @since 1.9
160 *
161 * @param array $default_meta_keys Array of meta keys
162 */
163 return apply_filters( 'tptn_cache_keys', $meta_keys );
164 }
165
166 /**
167 * Get the cache key based on a list of parameters.
168 *
169 * @since 4.2.0
170 *
171 * @param mixed $attr Array of attributes typically.
172 * @return string Cache meta key
173 */
174 public static function get_key( $attr ): string {
175 $args = (array) $attr;
176
177 static $setting_types = null;
178 if ( null === $setting_types ) {
179 $setting_types = function_exists( 'tptn_get_registered_settings_types' ) ? tptn_get_registered_settings_types() : array();
180 }
181
182 // Remove args that don't affect query results.
183 $exclude_keys = array(
184 'after_list',
185 'after_list_item',
186 'before_list',
187 'before_list_item',
188 'blank_output',
189 'blank_output_text',
190 'cache',
191 'className',
192 'echo',
193 'excerpt_length',
194 'extra_class',
195 'heading',
196 'is_block',
197 'is_manual',
198 'is_shortcode',
199 'is_widget',
200 'link_new_window',
201 'link_nofollow',
202 'more_link_text',
203 'no_found_rows',
204 'other_attributes',
205 'post_types',
206 'post_id',
207 'postid',
208 'same_post_type',
209 'show_author',
210 'show_credit',
211 'show_date',
212 'show_excerpt',
213 'show_metabox',
214 'show_metabox_admins',
215 'suppress_filters',
216 'title',
217 'title_length',
218 );
219
220 foreach ( $exclude_keys as $key ) {
221 unset( $args[ $key ] );
222 }
223
224 // Remove any keys ending in _header or _desc, or with type 'header'.
225 foreach ( $args as $key => $value ) {
226 if ( '_header' === substr( $key, -7 ) || '_desc' === substr( $key, -5 ) ) {
227 unset( $args[ $key ] );
228 continue;
229 }
230
231 if ( isset( $setting_types[ $key ] ) && 'header' === $setting_types[ $key ] ) {
232 unset( $args[ $key ] );
233 }
234 }
235
236 // Define categories of types for normalization.
237 $id_array_types = array( 'postids', 'numbercsv', 'taxonomies' );
238 $string_array_types = array( 'posttypes', 'csv', 'multicheck' );
239 $numeric_types = array( 'number', 'checkbox', 'select', 'radio', 'radiodesc' );
240
241 // Process arguments based on their registered types.
242 foreach ( $args as $key => $value ) {
243 $type = $setting_types[ $key ] ?? '';
244
245 if ( in_array( $type, $numeric_types, true ) && is_numeric( $value ) ) {
246 $args[ $key ] = (int) $value;
247 } elseif ( in_array( $type, $id_array_types, true ) ) {
248 $args[ $key ] = is_array( $value ) ? $value : wp_parse_id_list( $value );
249 $args[ $key ] = array_unique( array_map( 'absint', $args[ $key ] ) );
250 $args[ $key ] = array_filter( $args[ $key ] );
251 sort( $args[ $key ] );
252 if ( empty( $args[ $key ] ) ) {
253 unset( $args[ $key ] );
254 }
255 } elseif ( in_array( $type, $string_array_types, true ) ) {
256 if ( is_string( $value ) && strpos( $value, '=' ) !== false ) {
257 parse_str( $value, $parsed );
258 $value = array_keys( $parsed );
259 } elseif ( is_string( $value ) ) {
260 $value = explode( ',', $value );
261 }
262 $args[ $key ] = is_array( $value ) ? $value : array( $value );
263 $args[ $key ] = array_unique( array_map( 'strval', $args[ $key ] ) );
264 $args[ $key ] = array_filter( $args[ $key ] );
265 sort( $args[ $key ] );
266 if ( empty( $args[ $key ] ) ) {
267 unset( $args[ $key ] );
268 }
269 }
270 }
271
272 // Fallback for known keys that might not be in $setting_types or need specific handling.
273 $id_arrays = array(
274 'author__in',
275 'author__not_in',
276 'category__and',
277 'category__in',
278 'category__not_in',
279 'cornerstone_post_ids',
280 'exclude_categories',
281 'exclude_on_categories',
282 'exclude_on_post_ids',
283 'exclude_post_ids',
284 'include_cat_ids',
285 'include_post_ids',
286 'manual_related',
287 'post__in',
288 'post__not_in',
289 'post_parent__in',
290 'post_parent__not_in',
291 'tag__and',
292 'tag__in',
293 'tag__not_in',
294 'tag_slug__and',
295 'tag_slug__in',
296 );
297
298 foreach ( $id_arrays as $key ) {
299 if ( array_key_exists( $key, $args ) && ! isset( $setting_types[ $key ] ) ) {
300 if ( null !== $args[ $key ] ) {
301 $args[ $key ] = is_array( $args[ $key ] ) ? $args[ $key ] : wp_parse_id_list( $args[ $key ] );
302 $args[ $key ] = array_unique( array_map( 'absint', $args[ $key ] ) );
303 $args[ $key ] = array_filter( $args[ $key ] );
304 sort( $args[ $key ] );
305
306 if ( empty( $args[ $key ] ) ) {
307 unset( $args[ $key ] );
308 }
309 } else {
310 unset( $args[ $key ] );
311 }
312 }
313 }
314
315 $string_arrays = array(
316 'exclude_cat_slugs',
317 'exclude_on_cat_slugs',
318 'exclude_on_post_types',
319 'post_name__in',
320 'post_status',
321 'post_type',
322 'same_taxes',
323 );
324
325 foreach ( $string_arrays as $key ) {
326 if ( array_key_exists( $key, $args ) && ! isset( $setting_types[ $key ] ) ) {
327 if ( null !== $args[ $key ] ) {
328 if ( is_string( $args[ $key ] ) && strpos( $args[ $key ], '=' ) !== false ) {
329 parse_str( $args[ $key ], $parsed );
330 $parsed_value = array_keys( $parsed );
331 } elseif ( is_string( $args[ $key ] ) ) {
332 $parsed_value = explode( ',', $args[ $key ] );
333 } else {
334 $parsed_value = $args[ $key ];
335 }
336 $args[ $key ] = is_array( $parsed_value ) ? $parsed_value : array( $parsed_value );
337 $args[ $key ] = array_unique( array_map( 'strval', $args[ $key ] ) );
338 $args[ $key ] = array_filter( $args[ $key ] );
339 sort( $args[ $key ] );
340
341 if ( empty( $args[ $key ] ) ) {
342 unset( $args[ $key ] );
343 }
344 } else {
345 unset( $args[ $key ] );
346 }
347 }
348 }
349
350 // Sort top-level arguments.
351 ksort( $args );
352
353 // Remove any remaining empty strings or null values.
354 foreach ( $args as $key => $value ) {
355 if ( '' === $value || null === $value ) {
356 unset( $args[ $key ] );
357 }
358 }
359
360 // Keep generated keys discoverable by get_widget_keys() and delete().
361 return 'tptn_cache_' . md5( Language_Handler::get_cache_language() . '|' . wp_json_encode( $args ) );
362 }
363
364 /**
365 * Get the transient names for the Top 10 widgets.
366 *
367 * @since 2.3.0
368 *
369 * @return array Top 10 Cache widget keys.
370 */
371 public static function get_widget_keys() {
372 global $wpdb;
373
374 $keys = array();
375
376 $sql = "
377 SELECT option_name
378 FROM {$wpdb->options}
379 WHERE `option_name` LIKE '_transient_tptn_%'
380 ";
381
382 $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
383
384 if ( is_array( $results ) ) {
385 foreach ( $results as $result ) {
386 $keys[] = str_replace( '_transient_', '', $result->option_name );
387 }
388 }
389
390 /**
391 * Filters the list of Top 10 cache keys found in the options table.
392 *
393 * @since 2.5.0
394 *
395 * @param string[] $keys Cache keys without the transient prefix.
396 */
397 return apply_filters( 'tptn_cache_get_widget_keys', $keys );
398 }
399 }
400