1
|
|
|
<?php |
|
|
|
|
2
|
|
|
/** |
3
|
|
|
* Class for managing cache |
4
|
|
|
* |
5
|
|
|
* @package Give |
6
|
|
|
* @subpackage Classes/Give_Cache |
7
|
|
|
* @copyright Copyright (c) 2017, WordImpress |
8
|
|
|
* @license https://opensource.org/licenses/gpl-license GNU Public License |
9
|
|
|
* @since 1.8.7 |
10
|
|
|
*/ |
11
|
|
|
|
12
|
|
|
// Exit if accessed directly. |
13
|
|
|
if ( ! defined( 'ABSPATH' ) ) { |
14
|
|
|
exit; |
15
|
|
|
} |
16
|
|
|
|
17
|
|
|
class Give_Cache { |
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Instance. |
20
|
|
|
* |
21
|
|
|
* @since 1.8.7 |
22
|
|
|
* @access static |
23
|
|
|
* @var |
24
|
|
|
*/ |
25
|
|
|
static private $instance; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Singleton pattern. |
29
|
|
|
* |
30
|
|
|
* @since 1.8.7 |
31
|
|
|
* @access private |
32
|
|
|
* Give_Cache constructor. |
33
|
|
|
*/ |
34
|
|
|
private function __construct() { |
35
|
|
|
} |
36
|
|
|
|
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Get instance. |
40
|
|
|
* |
41
|
|
|
* @since 1.8.7 |
42
|
|
|
* @access public |
43
|
|
|
* @return static |
44
|
|
|
*/ |
45
|
|
|
public static function get_instance() { |
46
|
|
|
if ( null === static::$instance ) { |
|
|
|
|
47
|
|
|
self::$instance = new static(); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
return self::$instance; |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* Setup hooks. |
55
|
|
|
* |
56
|
|
|
* @since 1.8.7 |
57
|
|
|
* @access public |
58
|
|
|
*/ |
59
|
|
|
public function setup_hooks() { |
60
|
|
|
// weekly delete all expired cache. |
61
|
|
|
add_action( 'give_weekly_scheduled_events', array( $this, 'delete_all_expired' ) ); |
62
|
|
|
} |
63
|
|
|
|
64
|
|
|
/** |
65
|
|
|
* Get cache key. |
66
|
|
|
* |
67
|
|
|
* @since 1.8.7 |
68
|
|
|
* |
69
|
|
|
* @param string $action Cache key prefix. |
70
|
|
|
* @param array $query_args (optional) Query array. |
71
|
|
|
* |
72
|
|
|
* @return string |
73
|
|
|
*/ |
74
|
|
|
|
75
|
|
|
public static function get_key( $action, $query_args = null ) { |
76
|
|
|
$cache_key = "give_cache_{$action}"; |
77
|
|
|
|
78
|
|
|
// Bailout. |
79
|
|
|
if ( ! empty( $query_args ) ) { |
80
|
|
|
$cache_key = "{$cache_key}_" . substr( md5( serialize( $query_args ) ), 0, 15 ); |
81
|
|
|
} |
82
|
|
|
|
83
|
|
|
return $cache_key; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Get cache. |
88
|
|
|
* |
89
|
|
|
* @since 1.8.7 |
90
|
|
|
* |
91
|
|
|
* @param string $cache_key |
92
|
|
|
* @param bool $custom_key |
93
|
|
|
* @param mixed $query_args |
94
|
|
|
* |
95
|
|
|
* @return mixed |
96
|
|
|
*/ |
97
|
|
|
|
98
|
|
|
public static function get( $cache_key, $custom_key = false, $query_args = array() ) { |
99
|
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) { |
100
|
|
|
if ( ! $custom_key ) { |
101
|
|
|
return new WP_Error( 'give_invalid_cache_key', __( 'Cache key format should be give_cache_*', 'give' ) ); |
102
|
|
|
} |
103
|
|
|
|
104
|
|
|
$cache_key = self::get_key( $cache_key, $query_args ); |
105
|
|
|
} |
106
|
|
|
|
107
|
|
|
$option = get_option( $cache_key ); |
108
|
|
|
|
109
|
|
|
// Backward compatibility (<1.8.7). |
|
|
|
|
110
|
|
|
if ( ! is_array( $option ) || empty( $option ) || ! array_key_exists( 'expiration', $option ) ) { |
111
|
|
|
return $option; |
112
|
|
|
} |
113
|
|
|
|
114
|
|
|
// Get current time. |
115
|
|
|
$current_time = current_time( 'timestamp', 1 ); |
116
|
|
|
|
117
|
|
|
if ( empty( $option['expiration'] ) || ( $current_time < $option['expiration'] ) ) { |
118
|
|
|
$option = $option['data']; |
119
|
|
|
} else { |
120
|
|
|
$option = false; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
return $option; |
124
|
|
|
} |
125
|
|
|
|
126
|
|
|
/** |
127
|
|
|
* Set cache. |
128
|
|
|
* |
129
|
|
|
* @since 1.8.7 |
130
|
|
|
* |
131
|
|
|
* @param string $cache_key |
132
|
|
|
* @param mixed $data |
133
|
|
|
* @param int|null $expiration Timestamp should be in GMT format. |
134
|
|
|
* @param bool $custom_key |
135
|
|
|
* @param mixed $query_args |
136
|
|
|
* |
137
|
|
|
* @return mixed |
138
|
|
|
*/ |
139
|
|
|
|
140
|
|
|
public static function set( $cache_key, $data, $expiration = null, $custom_key = false, $query_args = array() ) { |
141
|
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) { |
142
|
|
|
if ( ! $custom_key ) { |
143
|
|
|
return new WP_Error( 'give_invalid_cache_key', __( 'Cache key format should be give_cache_*', 'give' ) ); |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
$cache_key = self::get_key( $cache_key, $query_args ); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
$option_value = array( |
150
|
|
|
'data' => $data, |
151
|
|
|
'expiration' => ! is_null( $expiration ) |
152
|
|
|
? ( $expiration + current_time( 'timestamp', 1 ) ) |
153
|
|
|
: null, |
154
|
|
|
); |
155
|
|
|
|
156
|
|
|
$result = add_option( $cache_key, $option_value, '', 'no' ); |
157
|
|
|
|
158
|
|
|
return $result; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* Delete cache. |
163
|
|
|
* |
164
|
|
|
* @since 1.8.7 |
165
|
|
|
* |
166
|
|
|
* @param string|array $cache_keys |
167
|
|
|
* |
168
|
|
|
* @return bool|WP_Error |
169
|
|
|
*/ |
170
|
|
|
|
171
|
|
|
public static function delete( $cache_keys ) { |
172
|
|
|
$result = true; |
173
|
|
|
$invalid_keys = array(); |
174
|
|
|
|
175
|
|
|
if ( ! empty( $cache_keys ) ) { |
176
|
|
|
$cache_keys = is_array( $cache_keys ) ? $cache_keys : array( $cache_keys ); |
177
|
|
|
|
178
|
|
|
foreach ( $cache_keys as $cache_key ) { |
179
|
|
|
if ( ! self::is_valid_cache_key( $cache_key ) ) { |
180
|
|
|
$invalid_keys[] = $cache_key; |
181
|
|
|
$result = false; |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
delete_option( $cache_key ); |
185
|
|
|
} |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
if( ! $result ) { |
189
|
|
|
$result = new WP_Error( |
190
|
|
|
'give_invalid_cache_key', |
191
|
|
|
__( 'Cache key format should be give_cache_*', 'give' ), |
192
|
|
|
$invalid_keys |
193
|
|
|
); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
return $result; |
197
|
|
|
} |
198
|
|
|
|
199
|
|
|
/** |
200
|
|
|
* Delete all logging cache. |
201
|
|
|
* |
202
|
|
|
* @since 1.8.7 |
203
|
|
|
* @access public |
204
|
|
|
* @global wpdb $wpdb |
205
|
|
|
* |
206
|
|
|
* @param bool $force If set to true then all cached values will be delete instead of only expired |
207
|
|
|
* |
208
|
|
|
* @return bool |
|
|
|
|
209
|
|
|
*/ |
210
|
|
|
public static function delete_all_expired( $force = false ) { |
211
|
|
|
global $wpdb; |
|
|
|
|
212
|
|
|
$options = $wpdb->get_results( |
213
|
|
|
$wpdb->prepare( |
214
|
|
|
"SELECT option_name, option_value |
215
|
|
|
FROM {$wpdb->options} |
216
|
|
|
Where option_name |
217
|
|
|
LIKE '%%%s%%'", |
218
|
|
|
'give_cache' |
219
|
|
|
), |
220
|
|
|
ARRAY_A |
221
|
|
|
); |
222
|
|
|
|
223
|
|
|
// Bailout. |
224
|
|
|
if ( empty( $options ) ) { |
225
|
|
|
return false; |
226
|
|
|
} |
227
|
|
|
|
228
|
|
|
$current_time = current_time( 'timestamp', 1 ); |
229
|
|
|
|
230
|
|
|
// Delete log cache. |
231
|
|
|
foreach ( $options as $option ) { |
232
|
|
|
$option['option_value'] = maybe_unserialize( $option['option_value'] ); |
233
|
|
|
|
234
|
|
|
if ( |
235
|
|
|
( |
236
|
|
|
! self::is_valid_cache_key( $option['option_name'] ) |
237
|
|
|
|| ! is_array( $option['option_value'] ) // Backward compatibility (<1.8.7). |
|
|
|
|
238
|
|
|
|| ! array_key_exists( 'expiration', $option['option_value'] ) // Backward compatibility (<1.8.7). |
|
|
|
|
239
|
|
|
|| empty( $option['option_value']['expiration'] ) |
240
|
|
|
|| ( $current_time < $option['option_value']['expiration'] ) |
241
|
|
|
) |
242
|
|
|
&& ! $force |
243
|
|
|
) { |
244
|
|
|
continue; |
245
|
|
|
} |
246
|
|
|
|
247
|
|
|
self::delete( $option['option_name'] ); |
248
|
|
|
} |
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
|
252
|
|
|
/** |
253
|
|
|
* Get list of options like. |
254
|
|
|
* |
255
|
|
|
* @since 1.8.7 |
256
|
|
|
* @access public |
257
|
|
|
* |
258
|
|
|
* @param string $option_name |
259
|
|
|
* @param bool $fields |
260
|
|
|
* |
261
|
|
|
* @return array |
262
|
|
|
*/ |
263
|
|
|
public static function get_options_like( $option_name, $fields = false ) { |
264
|
|
|
global $wpdb; |
|
|
|
|
265
|
|
|
|
266
|
|
|
if ( empty( $option_name ) ) { |
267
|
|
|
return array(); |
268
|
|
|
} |
269
|
|
|
|
270
|
|
|
$field_names = $fields ? 'option_name, option_value' : 'option_name'; |
271
|
|
|
|
272
|
|
|
if ( $fields ) { |
273
|
|
|
$options = $wpdb->get_results( |
274
|
|
|
$wpdb->prepare( |
275
|
|
|
"SELECT {$field_names } |
276
|
|
|
FROM {$wpdb->options} |
277
|
|
|
Where option_name |
278
|
|
|
LIKE '%%%s%%'", |
279
|
|
|
"give_cache_{$option_name}" |
280
|
|
|
), |
281
|
|
|
ARRAY_A |
282
|
|
|
); |
283
|
|
|
} else { |
284
|
|
|
$options = $wpdb->get_col( |
285
|
|
|
$wpdb->prepare( |
286
|
|
|
"SELECT * |
287
|
|
|
FROM {$wpdb->options} |
288
|
|
|
Where option_name |
289
|
|
|
LIKE '%%%s%%'", |
290
|
|
|
"give_cache_{$option_name}" |
291
|
|
|
), |
292
|
|
|
1 |
293
|
|
|
); |
294
|
|
|
} |
295
|
|
|
|
296
|
|
|
if ( ! empty( $options ) && $fields ) { |
297
|
|
|
foreach ( $options as $index => $option ) { |
298
|
|
|
$option['option_value'] = maybe_unserialize( $option['option_value'] ); |
299
|
|
|
$options[ $index ] = $option; |
300
|
|
|
} |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
return $options; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* Check cache key validity. |
308
|
|
|
* |
309
|
|
|
* @since 1.8.7 |
310
|
|
|
* @access public |
311
|
|
|
* |
312
|
|
|
* @param $cache_key |
313
|
|
|
* |
314
|
|
|
* @return bool|int |
315
|
|
|
*/ |
316
|
|
|
public static function is_valid_cache_key( $cache_key ) { |
317
|
|
|
return ( false !== strpos( $cache_key, 'give_cache_' ) ); |
318
|
|
|
} |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
// Initialize |
322
|
|
|
Give_Cache::get_instance()->setup_hooks(); |
323
|
|
|
|
324
|
|
|
// @todo implement this with all possible cache |
325
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.