PluginProbe ʕ •ᴥ•ʔ
Photo Gallery by FooGallery : Responsive Image Gallery, Masonry Gallery & Carousel / trunk
Photo Gallery by FooGallery : Responsive Image Gallery, Masonry Gallery & Carousel vtrunk
trunk 1.10.3 2.0.24 2.1.34 2.2.44 2.3.3 2.4.32 3.0.6 3.1.11 3.1.12 3.1.13 3.1.20 3.1.25 3.1.26 3.1.26.1 3.1.26.2
foogallery / freemius / includes / managers / class-fs-option-manager.php
foogallery / freemius / includes / managers Last commit date
class-fs-admin-menu-manager.php 8 months ago class-fs-admin-notice-manager.php 8 months ago class-fs-cache-manager.php 3 years ago class-fs-checkout-manager.php 8 months ago class-fs-clone-manager.php 8 months ago class-fs-contact-form-manager.php 8 months ago class-fs-debug-manager.php 8 months ago class-fs-gdpr-manager.php 3 years ago class-fs-key-value-storage.php 3 years ago class-fs-license-manager.php 3 years ago class-fs-option-manager.php 3 years ago class-fs-permission-manager.php 3 years ago class-fs-plan-manager.php 8 months ago class-fs-plugin-manager.php 3 years ago index.php 3 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