PluginProbe ʕ •ᴥ•ʔ
Auto Post Cleaner / 3.10.2
Auto Post Cleaner v3.10.2
3.12.0 3.13.1 3.2.4 3.2.5 3.3.0 3.3.10 3.3.11 3.3.8 3.4.2 3.5.3 3.6.0 3.7.0 3.7.1 3.7.2 3.7.3 3.7.5 3.7.6 3.8.0 3.9.0 3.9.4 3.9.6 3.9.7 trunk 3.0.0 3.1.0 3.10.1 3.10.2 3.11.4
delete-old-posts-programmatically / freemius / includes / managers / class-fs-option-manager.php
delete-old-posts-programmatically / freemius / includes / managers Last commit date
class-fs-admin-menu-manager.php 1 year ago class-fs-admin-notice-manager.php 1 year ago class-fs-cache-manager.php 5 years ago class-fs-checkout-manager.php 1 year ago class-fs-clone-manager.php 11 months ago class-fs-contact-form-manager.php 1 year ago class-fs-debug-manager.php 1 year ago class-fs-gdpr-manager.php 3 years ago class-fs-key-value-storage.php 3 years ago class-fs-license-manager.php 5 years ago class-fs-option-manager.php 3 years ago class-fs-permission-manager.php 3 years ago class-fs-plan-manager.php 2 years ago class-fs-plugin-manager.php 3 years ago index.php 5 years ago
class-fs-option-manager.php
477 lines
1 <?php
2 /**
3 * @package Freemius
4 * @copyright Copyright (c) 2015, Freemius, Inc.
5 * @license https://www.gnu.org/licenses/gpl-3.0.html GNU General Public License Version 3
6 * @since 1.0.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * 2-layer lazy options manager.
15 * layer 2: Memory
16 * layer 1: Database (options table). All options stored as one option record in the DB to reduce number of DB queries.
17 *
18 * If load() is not explicitly called, starts as empty manager. Same thing about saving the data - you have to explicitly call store().
19 *
20 * Class Freemius_Option_Manager
21 */
22 class FS_Option_Manager {
23 /**
24 * @var string
25 */
26 private $_id;
27 /**
28 * @var array|object
29 */
30 private $_options;
31 /**
32 * @var FS_Logger
33 */
34 private $_logger;
35
36 /**
37 * @since 2.0.0
38 * @var int The ID of the blog that is associated with the current site level options.
39 */
40 private $_blog_id = 0;
41
42 /**
43 * @since 2.0.0
44 * @var bool
45 */
46 private $_is_network_storage;
47
48 /**
49 * @var bool|null
50 */
51 private $_autoload;
52
53 /**
54 * @var array[string]FS_Option_Manager {
55 * @key string
56 * @value FS_Option_Manager
57 * }
58 */
59 private static $_MANAGERS = array();
60
61 /**
62 * @author Vova Feldman (@svovaf)
63 * @since 1.0.3
64 *
65 * @param string $id
66 * @param bool $load
67 * @param bool|int $network_level_or_blog_id Since 2.0.0
68 * @param bool|null $autoload
69 */
70 private function __construct(
71 $id,
72 $load = false,
73 $network_level_or_blog_id = false,
74 $autoload = null
75 ) {
76 $id = strtolower( $id );
77
78 $this->_logger = FS_Logger::get_logger( WP_FS__SLUG . '_opt_mngr_' . $id, WP_FS__DEBUG_SDK, WP_FS__ECHO_DEBUG_SDK );
79
80 $this->_logger->entrance();
81 $this->_logger->log( 'id = ' . $id );
82
83 $this->_id = $id;
84
85 $this->_autoload = $autoload;
86
87 if ( is_multisite() ) {
88 $this->_is_network_storage = ( true === $network_level_or_blog_id );
89
90 if ( is_numeric( $network_level_or_blog_id ) ) {
91 $this->_blog_id = $network_level_or_blog_id;
92 }
93 } else {
94 $this->_is_network_storage = false;
95 }
96
97 if ( $load ) {
98 $this->load();
99 }
100 }
101
102 /**
103 * @author Vova Feldman (@svovaf)
104 * @since 1.0.3
105 *
106 * @param string $id
107 * @param bool $load
108 * @param bool|int $network_level_or_blog_id Since 2.0.0
109 * @param bool|null $autoload
110 *
111 * @return \FS_Option_Manager
112 */
113 static function get_manager(
114 $id,
115 $load = false,
116 $network_level_or_blog_id = false,
117 $autoload = null
118 ) {
119 $key = strtolower( $id );
120
121 if ( is_multisite() ) {
122 if ( true === $network_level_or_blog_id ) {
123 $key .= ':ms';
124 } else if ( is_numeric( $network_level_or_blog_id ) && $network_level_or_blog_id > 0 ) {
125 $key .= ":{$network_level_or_blog_id}";
126 } else {
127 $network_level_or_blog_id = get_current_blog_id();
128
129 $key .= ":{$network_level_or_blog_id}";
130 }
131 }
132
133 if ( ! isset( self::$_MANAGERS[ $key ] ) ) {
134 self::$_MANAGERS[ $key ] = new FS_Option_Manager(
135 $id,
136 $load,
137 $network_level_or_blog_id,
138 $autoload
139 );
140 } // If load required but not yet loaded, load.
141 else if ( $load && ! self::$_MANAGERS[ $key ]->is_loaded() ) {
142 self::$_MANAGERS[ $key ]->load();
143 }
144
145 return self::$_MANAGERS[ $key ];
146 }
147
148 /**
149 * @author Vova Feldman (@svovaf)
150 * @since 1.0.3
151 *
152 * @param bool $flush
153 */
154 function load( $flush = false ) {
155 $this->_logger->entrance();
156
157 if ( ! $flush && isset( $this->_options ) ) {
158 return;
159 }
160
161 if ( isset( $this->_options ) ) {
162 // Clear prev options.
163 $this->clear();
164 }
165
166 $option_name = $this->get_option_manager_name();
167
168 if ( $this->_is_network_storage ) {
169 $this->_options = get_site_option( $option_name );
170 } else if ( $this->_blog_id > 0 ) {
171 $this->_options = get_blog_option( $this->_blog_id, $option_name );
172 } else {
173 $this->_options = get_option( $option_name );
174 }
175
176 if ( is_string( $this->_options ) ) {
177 $this->_options = json_decode( $this->_options );
178 }
179
180 // $this->_logger->info('get_option = ' . var_export($this->_options, true));
181
182 if ( false === $this->_options ) {
183 $this->clear();
184 }
185 }
186
187 /**
188 * @author Vova Feldman (@svovaf)
189 * @since 1.0.3
190 *
191 * @return bool
192 */
193 function is_loaded() {
194 return isset( $this->_options );
195 }
196
197 /**
198 * @author Vova Feldman (@svovaf)
199 * @since 1.0.3
200 *
201 * @return bool
202 */
203 function is_empty() {
204 return ( $this->is_loaded() && false === $this->_options );
205 }
206
207 /**
208 * @author Vova Feldman (@svovaf)
209 * @since 1.0.6
210 *
211 * @param bool $flush
212 */
213 function clear( $flush = false ) {
214 $this->_logger->entrance();
215
216 $this->_options = array();
217
218 if ( $flush ) {
219 $this->store();
220 }
221 }
222
223 /**
224 * Delete options manager from DB.
225 *
226 * @author Vova Feldman (@svovaf)
227 * @since 1.0.9
228 */
229 function delete() {
230 $option_name = $this->get_option_manager_name();
231
232 if ( $this->_is_network_storage ) {
233 delete_site_option( $option_name );
234 } else if ( $this->_blog_id > 0 ) {
235 delete_blog_option( $this->_blog_id, $option_name );
236 } else {
237 delete_option( $option_name );
238 }
239 }
240
241 /**
242 * @author Vova Feldman (@svovaf)
243 * @since 1.0.6
244 *
245 * @param string $option
246 * @param bool $flush
247 *
248 * @return bool
249 */
250 function has_option( $option, $flush = false ) {
251 if ( ! $this->is_loaded() || $flush ) {
252 $this->load( $flush );
253 }
254
255 return array_key_exists( $option, $this->_options );
256 }
257
258 /**
259 * @author Vova Feldman (@svovaf)
260 * @since 1.0.3
261 *
262 * @param string $option
263 * @param mixed $default
264 * @param bool $flush
265 *
266 * @return mixed
267 */
268 function get_option( $option, $default = null, $flush = false ) {
269 $this->_logger->entrance( 'option = ' . $option );
270
271 if ( ! $this->is_loaded() || $flush ) {
272 $this->load( $flush );
273 }
274
275 if ( is_array( $this->_options ) ) {
276 $value = isset( $this->_options[ $option ] ) ?
277 $this->_options[ $option ] :
278 $default;
279 } else if ( is_object( $this->_options ) ) {
280 $value = isset( $this->_options->{$option} ) ?
281 $this->_options->{$option} :
282 $default;
283 } else {
284 $value = $default;
285 }
286
287 /**
288 * If it's an object, return a clone of the object, otherwise,
289 * external changes of the object will actually change the value
290 * of the object in the option manager which may lead to an unexpected
291 * behaviour and data integrity when a store() call is triggered.
292 *
293 * Example:
294 * $object1 = $options->get_option( 'object1' );
295 * $object1->x = 123;
296 *
297 * $object2 = $options->get_option( 'object2' );
298 * $object2->y = 'dummy';
299 *
300 * $options->set_option( 'object2', $object2, true );
301 *
302 * If we don't return a clone of option 'object1', setting 'object2'
303 * will also store the updated value of 'object1' which is quite not
304 * an expected behaviour.
305 *
306 * @author Vova Feldman
307 */
308 return is_object( $value ) ? clone $value : $value;
309 }
310
311 /**
312 * @author Vova Feldman (@svovaf)
313 * @since 1.0.3
314 *
315 * @param string $option
316 * @param mixed $value
317 * @param bool $flush
318 */
319 function set_option( $option, $value, $flush = false ) {
320 $this->_logger->entrance( 'option = ' . $option );
321
322 if ( ! $this->is_loaded() ) {
323 $this->clear();
324 }
325
326 /**
327 * If it's an object, store a clone of the object, otherwise,
328 * external changes of the object will actually change the value
329 * of the object in the options manager which may lead to an unexpected
330 * behaviour and data integrity when a store() call is triggered.
331 *
332 * Example:
333 * $object1 = new stdClass();
334 * $object1->x = 123;
335 *
336 * $options->set_option( 'object1', $object1 );
337 *
338 * $object1->x = 456;
339 *
340 * $options->set_option( 'object2', $object2, true );
341 *
342 * If we don't set the option as a clone of option 'object1', setting 'object2'
343 * will also store the updated value of 'object1' ($object1->x = 456 instead of
344 * $object1->x = 123) which is quite not an expected behaviour.
345 *
346 * @author Vova Feldman
347 */
348 $copy = is_object( $value ) ? clone $value : $value;
349
350 if ( is_array( $this->_options ) ) {
351 $this->_options[ $option ] = $copy;
352 } else if ( is_object( $this->_options ) ) {
353 $this->_options->{$option} = $copy;
354 }
355
356 if ( $flush ) {
357 $this->store();
358 }
359 }
360
361 /**
362 * Unset option.
363 *
364 * @author Vova Feldman (@svovaf)
365 * @since 1.0.3
366 *
367 * @param string $option
368 * @param bool $flush
369 */
370 function unset_option( $option, $flush = false ) {
371 $this->_logger->entrance( 'option = ' . $option );
372
373 if ( is_array( $this->_options ) ) {
374 if ( ! isset( $this->_options[ $option ] ) ) {
375 return;
376 }
377
378 unset( $this->_options[ $option ] );
379
380 } else if ( is_object( $this->_options ) ) {
381 if ( ! isset( $this->_options->{$option} ) ) {
382 return;
383 }
384
385 unset( $this->_options->{$option} );
386 }
387
388 if ( $flush ) {
389 $this->store();
390 }
391 }
392
393 /**
394 * Dump options to database.
395 *
396 * @author Vova Feldman (@svovaf)
397 * @since 1.0.3
398 */
399 function store() {
400 $this->_logger->entrance();
401
402 $option_name = $this->get_option_manager_name();
403
404 if ( $this->_logger->is_on() ) {
405 $this->_logger->info( $option_name . ' = ' . var_export( $this->_options, true ) );
406 }
407
408 // Update DB.
409 if ( $this->_is_network_storage ) {
410 update_site_option( $option_name, $this->_options );
411 } else if ( $this->_blog_id > 0 ) {
412 update_blog_option( $this->_blog_id, $option_name, $this->_options );
413 } else {
414 update_option( $option_name, $this->_options, $this->_autoload );
415 }
416 }
417
418 /**
419 * Get options keys.
420 *
421 * @author Vova Feldman (@svovaf)
422 * @since 1.0.3
423 *
424 * @return string[]
425 */
426 function get_options_keys() {
427 if ( is_array( $this->_options ) ) {
428 return array_keys( $this->_options );
429 } else if ( is_object( $this->_options ) ) {
430 return array_keys( get_object_vars( $this->_options ) );
431 }
432
433 return array();
434 }
435
436 #--------------------------------------------------------------------------------
437 #region Migration
438 #--------------------------------------------------------------------------------
439
440 /**
441 * Migrate options from site level.
442 *
443 * @author Vova Feldman (@svovaf)
444 * @since 2.0.0
445 */
446 function migrate_to_network() {
447 $site_options = FS_Option_Manager::get_manager($this->_id, true, false);
448
449 $options = is_object( $site_options->_options ) ?
450 get_object_vars( $site_options->_options ) :
451 $site_options->_options;
452
453 if ( ! empty( $options ) ) {
454 foreach ( $options as $key => $val ) {
455 $this->set_option( $key, $val, false );
456 }
457
458 $this->store();
459 }
460 }
461
462 #endregion
463
464 #--------------------------------------------------------------------------------
465 #region Helper Methods
466 #--------------------------------------------------------------------------------
467
468 /**
469 * @return string
470 */
471 private function get_option_manager_name() {
472 return $this->_id;
473 }
474
475 #endregion
476 }
477