PluginProbe ʕ •ᴥ•ʔ
Royal Addons for Elementor – Addons and Templates Kit for Elementor / 1.7.1064
Royal Addons for Elementor – Addons and Templates Kit for Elementor v1.7.1064
1.7.1064 1.7.1063 1.7.1062 1.7.1061 1.7.1060 1.7.1059 1.7.1058 trunk 1.0.0 1.1.0 1.2 1.3 1.3.1 1.3.2 1.3.21 1.3.22 1.3.23 1.3.24 1.3.25 1.3.26 1.3.27 1.3.28 1.3.29 1.3.30 1.3.31 1.3.32 1.3.33 1.3.34 1.3.35 1.3.36 1.3.37 1.3.38 1.3.39 1.3.40 1.3.41 1.3.42 1.3.43 1.3.44 1.3.45 1.3.46 1.3.47 1.3.48 1.3.49 1.3.50 1.3.51 1.3.52 1.3.53 1.3.54 1.3.55 1.3.56 1.3.57 1.3.58 1.3.59 1.3.60 1.3.61 1.3.62 1.3.63 1.3.64 1.3.65 1.3.66 1.3.67 1.3.68 1.3.69 1.3.70 1.3.71 1.3.72 1.3.73 1.3.74 1.3.75 1.3.76 1.3.77 1.3.78 1.3.79 1.3.80 1.3.81 1.3.82 1.3.83 1.3.84 1.3.85 1.3.86 1.3.87 1.3.88 1.3.89 1.3.90 1.3.91 1.3.92 1.3.93 1.3.94 1.3.95 1.3.96 1.3.97 1.3.971 1.3.972 1.3.973 1.3.974 1.3.975 1.3.976 1.3.977 1.3.978 1.3.979 1.3.980 1.3.981 1.3.982 1.3.983 1.3.984 1.3.985 1.3.986 1.3.987 1.7.1 1.7.1001 1.7.1002 1.7.1003 1.7.1004 1.7.1005 1.7.1006 1.7.1007 1.7.1008 1.7.1009 1.7.1010 1.7.1011 1.7.1012 1.7.1013 1.7.1014 1.7.1015 1.7.1016 1.7.1017 1.7.1018 1.7.1019 1.7.1020 1.7.1021 1.7.1022 1.7.1023 1.7.1024 1.7.1025 1.7.1026 1.7.1027 1.7.1028 1.7.1029 1.7.1030 1.7.1031 1.7.1032 1.7.1033 1.7.1034 1.7.1035 1.7.1036 1.7.1037 1.7.1038 1.7.1039 1.7.1040 1.7.1041 1.7.1042 1.7.1043 1.7.1044 1.7.1045 1.7.1046 1.7.1047 1.7.1048 1.7.1049 1.7.1050 1.7.1051 1.7.1052 1.7.1053 1.7.1054 1.7.1055 1.7.1056 1.7.1057
royal-elementor-addons / freemius / includes / class-fs-storage.php
royal-elementor-addons / freemius / includes Last commit date
customizer 5 days ago debug 5 days ago entities 5 days ago managers 5 days ago sdk 5 days ago supplements 5 days ago class-freemius-abstract.php 5 days ago class-freemius.php 5 days ago class-fs-admin-notices.php 5 days ago class-fs-api.php 5 days ago class-fs-garbage-collector.php 5 days ago class-fs-lock.php 5 days ago class-fs-logger.php 5 days ago class-fs-options.php 5 days ago class-fs-plugin-updater.php 5 days ago class-fs-security.php 5 days ago class-fs-storage.php 5 days ago class-fs-user-lock.php 5 days ago fs-core-functions.php 5 days ago fs-essential-functions.php 5 days ago fs-html-escaping-functions.php 5 days ago fs-plugin-info-dialog.php 5 days ago index.php 5 days ago l10n.php 5 days ago
class-fs-storage.php
561 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.2.3
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit;
11 }
12
13 /**
14 * Class FS_Storage
15 *
16 * A wrapper class for handling network level and single site level storage.
17 *
18 * @property bool $is_network_activation
19 * @property int $network_install_blog_id
20 * @property bool|null $is_extensions_tracking_allowed
21 * @property bool|null $is_diagnostic_tracking_allowed
22 * @property object $sync_cron
23 * @property bool|int $install_timestamp
24 */
25 class FS_Storage {
26 /**
27 * @var FS_Storage[]
28 */
29 private static $_instances = array();
30 /**
31 * @var FS_Key_Value_Storage Site level storage.
32 */
33 private $_storage;
34
35 /**
36 * @var FS_Key_Value_Storage Network level storage.
37 */
38 private $_network_storage;
39
40 /**
41 * @var string
42 */
43 private $_module_type;
44
45 /**
46 * @var string
47 */
48 private $_module_slug;
49
50 /**
51 * @var int The ID of the blog that is associated with the current site level options.
52 */
53 private $_blog_id = 0;
54
55 /**
56 * @var bool
57 */
58 private $_is_multisite;
59
60 /**
61 * @var bool
62 */
63 private $_is_network_active = false;
64
65 /**
66 * @var bool
67 */
68 private $_is_delegated_connection = false;
69
70 /**
71 * @var array {
72 * @key string Option name.
73 * @value int If 0 store on the network level. If 1, store on the network level only if module was network level activated. If 2, store on the network level only if network activated and NOT delegated the connection.
74 * }
75 */
76 private static $_NETWORK_OPTIONS_MAP;
77
78 const OPTION_LEVEL_UNDEFINED = -1;
79 // The option should be stored on the network level.
80 const OPTION_LEVEL_NETWORK = 0;
81 // The option should be stored on the network level when the plugin is network-activated.
82 const OPTION_LEVEL_NETWORK_ACTIVATED = 1;
83 // The option should be stored on the network level when the plugin is network-activated and the opt-in connection was NOT delegated to the sub-site admin.
84 const OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED = 2;
85 // The option should be stored on the site level.
86 const OPTION_LEVEL_SITE = 3;
87
88 /**
89 * @author Leo Fajardo (@leorw)
90 *
91 * @param string $module_type
92 * @param string $slug
93 *
94 * @return FS_Storage
95 */
96 static function instance( $module_type, $slug ) {
97 $key = $module_type . ':' . $slug;
98
99 if ( ! isset( self::$_instances[ $key ] ) ) {
100 self::$_instances[ $key ] = new FS_Storage( $module_type, $slug );
101 }
102
103 return self::$_instances[ $key ];
104 }
105
106 /**
107 * @author Leo Fajardo (@leorw)
108 *
109 * @param string $module_type
110 * @param string $slug
111 */
112 private function __construct( $module_type, $slug ) {
113 $this->_module_type = $module_type;
114 $this->_module_slug = $slug;
115 $this->_is_multisite = is_multisite();
116
117 if ( $this->_is_multisite ) {
118 $this->_blog_id = get_current_blog_id();
119 $this->_network_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, true );
120 }
121
122 $this->_storage = FS_Key_Value_Storage::instance( $module_type . '_data', $slug, $this->_blog_id );
123 }
124
125 /**
126 * Tells this storage wrapper class that the context plugin is network active. This flag will affect how values
127 * are retrieved/stored from/into the storage.
128 *
129 * @author Leo Fajardo (@leorw)
130 *
131 * @param bool $is_network_active
132 * @param bool $is_delegated_connection
133 */
134 function set_network_active( $is_network_active = true, $is_delegated_connection = false ) {
135 $this->_is_network_active = $is_network_active;
136 $this->_is_delegated_connection = $is_delegated_connection;
137 }
138
139 /**
140 * Switch the context of the site level storage manager.
141 *
142 * @author Vova Feldman (@svovaf)
143 * @since 2.0.0
144 *
145 * @param int $blog_id
146 */
147 function set_site_blog_context( $blog_id ) {
148 $this->_storage = $this->get_site_storage( $blog_id );
149 $this->_blog_id = $blog_id;
150 }
151
152 /**
153 * @author Leo Fajardo (@leorw)
154 *
155 * @param string $key
156 * @param mixed $value
157 * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
158 * @param int $option_level Since 2.5.1
159 * @param bool $flush
160 */
161 function store(
162 $key,
163 $value,
164 $network_level_or_blog_id = null,
165 $option_level = self::OPTION_LEVEL_UNDEFINED,
166 $flush = true
167 ) {
168 if ( $this->should_use_network_storage( $key, $network_level_or_blog_id, $option_level ) ) {
169 $this->_network_storage->store( $key, $value, $flush );
170 } else {
171 $storage = $this->get_site_storage( $network_level_or_blog_id );
172 $storage->store( $key, $value, $flush );
173 }
174 }
175
176 /**
177 * @author Leo Fajardo (@leorw)
178 *
179 * @param bool $store
180 * @param string[] $exceptions Set of keys to keep and not clear.
181 * @param int|null|bool $network_level_or_blog_id
182 */
183 function clear_all( $store = true, $exceptions = array(), $network_level_or_blog_id = null ) {
184 if ( ! $this->_is_multisite ||
185 false === $network_level_or_blog_id ||
186 is_null( $network_level_or_blog_id ) ||
187 is_numeric( $network_level_or_blog_id )
188 ) {
189 $storage = $this->get_site_storage( $network_level_or_blog_id );
190 $storage->clear_all( $store, $exceptions );
191 }
192
193 if ( $this->_is_multisite &&
194 ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
195 ) {
196 $this->_network_storage->clear_all( $store, $exceptions );
197 }
198 }
199
200 /**
201 * @author Leo Fajardo (@leorw)
202 *
203 * @param string $key
204 * @param bool $store
205 * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
206 */
207 function remove( $key, $store = true, $network_level_or_blog_id = null ) {
208 if ( $this->should_use_network_storage( $key, $network_level_or_blog_id ) ) {
209 $this->_network_storage->remove( $key, $store );
210 } else {
211 $storage = $this->get_site_storage( $network_level_or_blog_id );
212 $storage->remove( $key, $store );
213 }
214 }
215
216 /**
217 * @author Leo Fajardo (@leorw)
218 *
219 * @param string $key
220 * @param mixed $default
221 * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
222 * @param int $option_level Since 2.5.1
223 *
224 * @return mixed
225 */
226 function get(
227 $key,
228 $default = false,
229 $network_level_or_blog_id = null,
230 $option_level = self::OPTION_LEVEL_UNDEFINED
231 ) {
232 if ( $this->should_use_network_storage( $key, $network_level_or_blog_id, $option_level ) ) {
233 return $this->_network_storage->get( $key, $default );
234 } else {
235 $storage = $this->get_site_storage( $network_level_or_blog_id );
236
237 return $storage->get( $key, $default );
238 }
239 }
240
241 /**
242 * Multisite activated:
243 * true: Save network storage.
244 * int: Save site specific storage.
245 * false|0: Save current site storage.
246 * null: Save network and current site storage.
247 * Site level activated:
248 * Save site storage.
249 *
250 * @author Vova Feldman (@svovaf)
251 * @since 2.0.0
252 *
253 * @param bool|int|null $network_level_or_blog_id
254 */
255 function save( $network_level_or_blog_id = null ) {
256 if ( $this->_is_network_active &&
257 ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
258 ) {
259 $this->_network_storage->save();
260 }
261
262 if ( ! $this->_is_network_active || true !== $network_level_or_blog_id ) {
263 $storage = $this->get_site_storage( $network_level_or_blog_id );
264 $storage->save();
265 }
266 }
267
268 /**
269 * @author Vova Feldman (@svovaf)
270 * @since 2.0.0
271 *
272 * @return string
273 */
274 function get_module_slug() {
275 return $this->_module_slug;
276 }
277
278 /**
279 * @author Vova Feldman (@svovaf)
280 * @since 2.0.0
281 *
282 * @return string
283 */
284 function get_module_type() {
285 return $this->_module_type;
286 }
287
288 /**
289 * Migration script to the new storage data structure that is network compatible.
290 *
291 * IMPORTANT:
292 * This method should be executed only after it is determined if this is a network
293 * level compatible product activation.
294 *
295 * @author Vova Feldman (@svovaf)
296 * @since 2.0.0
297 */
298 function migrate_to_network() {
299 if ( ! $this->_is_multisite ) {
300 return;
301 }
302
303 $updated = false;
304
305 if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
306 self::load_network_options_map();
307 }
308
309 foreach ( self::$_NETWORK_OPTIONS_MAP as $option => $storage_level ) {
310 if ( ! $this->is_multisite_option( $option ) ) {
311 continue;
312 }
313
314 if ( isset( $this->_storage->{$option} ) && ! isset( $this->_network_storage->{$option} ) ) {
315 // Migrate option to the network storage.
316 $this->_network_storage->store( $option, $this->_storage->{$option}, false );
317
318 $updated = true;
319 }
320 }
321
322 if ( ! $updated ) {
323 return;
324 }
325
326 // Update network level storage.
327 $this->_network_storage->save();
328 // $this->_storage->save();
329 }
330
331 #--------------------------------------------------------------------------------
332 #region Helper Methods
333 #--------------------------------------------------------------------------------
334
335 /**
336 * We don't want to load the map right away since it's not even needed in a non-MS environment.
337 *
338 * Example:
339 * array(
340 * 'option1' => 0, // Means that the option should always be stored on the network level.
341 * 'option2' => 1, // Means that the option should be stored on the network level only when the module was network level activated.
342 * 'option2' => 2, // Means that the option should be stored on the network level only when the module was network level activated AND the connection was NOT delegated.
343 * 'option3' => 3, // Means that the option should always be stored on the site level.
344 * )
345 *
346 * @author Vova Feldman (@svovaf)
347 * @since 2.0.0
348 */
349 private static function load_network_options_map() {
350 self::$_NETWORK_OPTIONS_MAP = array(
351 // Network level options.
352 'affiliate_application_data' => self::OPTION_LEVEL_NETWORK,
353 'beta_data' => self::OPTION_LEVEL_NETWORK,
354 'connectivity_test' => self::OPTION_LEVEL_NETWORK,
355 'handle_gdpr_admin_notice' => self::OPTION_LEVEL_NETWORK,
356 'has_trial_plan' => self::OPTION_LEVEL_NETWORK,
357 'install_sync_timestamp' => self::OPTION_LEVEL_NETWORK,
358 'install_sync_cron' => self::OPTION_LEVEL_NETWORK,
359 'is_anonymous_ms' => self::OPTION_LEVEL_NETWORK,
360 'is_network_activated' => self::OPTION_LEVEL_NETWORK,
361 'is_on' => self::OPTION_LEVEL_NETWORK,
362 'is_plugin_new_install' => self::OPTION_LEVEL_NETWORK,
363 'last_load_timestamp' => self::OPTION_LEVEL_NETWORK,
364 'network_install_blog_id' => self::OPTION_LEVEL_NETWORK,
365 'pending_sites_info' => self::OPTION_LEVEL_NETWORK,
366 'plugin_last_version' => self::OPTION_LEVEL_NETWORK,
367 'plugin_main_file' => self::OPTION_LEVEL_NETWORK,
368 'plugin_version' => self::OPTION_LEVEL_NETWORK,
369 'sdk_downgrade_mode' => self::OPTION_LEVEL_NETWORK,
370 'sdk_last_version' => self::OPTION_LEVEL_NETWORK,
371 'sdk_upgrade_mode' => self::OPTION_LEVEL_NETWORK,
372 'sdk_version' => self::OPTION_LEVEL_NETWORK,
373 'sticky_optin_added_ms' => self::OPTION_LEVEL_NETWORK,
374 'subscriptions' => self::OPTION_LEVEL_NETWORK,
375 'sync_timestamp' => self::OPTION_LEVEL_NETWORK,
376 'sync_cron' => self::OPTION_LEVEL_NETWORK,
377 'was_plugin_loaded' => self::OPTION_LEVEL_NETWORK,
378 'network_user_id' => self::OPTION_LEVEL_NETWORK,
379 'plugin_upgrade_mode' => self::OPTION_LEVEL_NETWORK,
380 'plugin_downgrade_mode' => self::OPTION_LEVEL_NETWORK,
381 'is_network_connected' => self::OPTION_LEVEL_NETWORK,
382 /**
383 * Special flag that is used when a super-admin upgrades to the new version of the SDK that supports network level integration, when the connection decision wasn't made for all the sites in the network.
384 */
385 'is_network_activation' => self::OPTION_LEVEL_NETWORK,
386 'license_migration' => self::OPTION_LEVEL_NETWORK,
387
388 // When network activated, then network level.
389 'install_timestamp' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
390 'prev_is_premium' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
391 'require_license_activation' => self::OPTION_LEVEL_NETWORK_ACTIVATED,
392
393 // If not network activated OR delegated, then site level.
394 'activation_timestamp' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
395 'expired_license_notice_shown' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
396 'is_whitelabeled' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
397 'last_license_key' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
398 'last_license_user_id' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
399 'prev_user_id' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
400 'sticky_optin_added' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
401 'uninstall_reason' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
402 'is_pending_activation' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
403 'pending_license_key' => self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED,
404
405 // Site level options.
406 'is_anonymous' => self::OPTION_LEVEL_SITE,
407 'clone_id' => self::OPTION_LEVEL_SITE,
408 );
409 }
410
411 /**
412 * This method will and should only be executed when is_multisite() is true.
413 *
414 * @author Vova Feldman (@svovaf)
415 * @since 2.0.0
416 *
417 * @param string $key
418 * @param int $option_level Since 2.5.1
419 *
420 * @return bool
421 */
422 private function is_multisite_option( $key, $option_level = self::OPTION_LEVEL_UNDEFINED ) {
423 if ( ! isset( self::$_NETWORK_OPTIONS_MAP ) ) {
424 self::load_network_options_map();
425 }
426
427 if (
428 self::OPTION_LEVEL_UNDEFINED === $option_level &&
429 isset( self::$_NETWORK_OPTIONS_MAP[ $key ] )
430 ) {
431 $option_level = self::$_NETWORK_OPTIONS_MAP[ $key ];
432 }
433
434 if ( self::OPTION_LEVEL_UNDEFINED === $option_level ) {
435 // Option not found -> use site level storage.
436 return false;
437 }
438
439 if ( self::OPTION_LEVEL_NETWORK === $option_level ) {
440 // Option found and set to always use the network level storage on a multisite.
441 return true;
442 }
443
444 if ( self::OPTION_LEVEL_SITE === $option_level ) {
445 // Option found and set to always use the site level storage on a multisite.
446 return false;
447 }
448
449 if ( ! $this->_is_network_active ) {
450 return false;
451 }
452
453 if ( self::OPTION_LEVEL_NETWORK_ACTIVATED === $option_level ) {
454 // Network activated.
455 return true;
456 }
457
458 if (
459 self::OPTION_LEVEL_NETWORK_ACTIVATED_NOT_DELEGATED === $option_level &&
460 ! $this->_is_delegated_connection
461 ) {
462 // Network activated and not delegated.
463 return true;
464 }
465
466 return false;
467 }
468
469 /**
470 * @author Leo Fajardo
471 *
472 * @param string $key
473 * @param null|bool|int $network_level_or_blog_id When an integer, use the given blog storage. When `true` use the multisite storage (if there's a network). When `false`, use the current context blog storage. When `null`, the decision which storage to use (MS vs. Current S) will be handled internally and determined based on the $option (based on self::$_BINARY_MAP).
474 * @param int $option_level Since 2.5.1
475 *
476 * @return bool
477 */
478 private function should_use_network_storage(
479 $key,
480 $network_level_or_blog_id = null,
481 $option_level = self::OPTION_LEVEL_UNDEFINED
482 ) {
483 if ( ! $this->_is_multisite ) {
484 // Not a multisite environment.
485 return false;
486 }
487
488 if ( is_numeric( $network_level_or_blog_id ) ) {
489 // Explicitly asked to use a specified blog storage.
490 return false;
491 }
492
493 if ( is_bool( $network_level_or_blog_id ) ) {
494 // Explicitly specified whether it should use the network or blog level storage.
495 return $network_level_or_blog_id;
496 }
497
498 // Determine which storage to use based on the option.
499 return $this->is_multisite_option( $key, $option_level );
500 }
501
502 /**
503 * @author Vova Feldman (@svovaf)
504 * @since 2.0.0
505 *
506 * @param int $blog_id
507 *
508 * @return \FS_Key_Value_Storage
509 */
510 private function get_site_storage( $blog_id = 0 ) {
511 if ( ! is_numeric( $blog_id ) ||
512 $blog_id == $this->_blog_id ||
513 0 == $blog_id
514 ) {
515 return $this->_storage;
516 }
517
518 return FS_Key_Value_Storage::instance(
519 $this->_module_type . '_data',
520 $this->_storage->get_secondary_id(),
521 $blog_id
522 );
523 }
524
525 #endregion
526
527 #--------------------------------------------------------------------------------
528 #region Magic methods
529 #--------------------------------------------------------------------------------
530
531 function __set( $k, $v ) {
532 if ( $this->should_use_network_storage( $k ) ) {
533 $this->_network_storage->{$k} = $v;
534 } else {
535 $this->_storage->{$k} = $v;
536 }
537 }
538
539 function __isset( $k ) {
540 return $this->should_use_network_storage( $k ) ?
541 isset( $this->_network_storage->{$k} ) :
542 isset( $this->_storage->{$k} );
543 }
544
545 function __unset( $k ) {
546 if ( $this->should_use_network_storage( $k ) ) {
547 unset( $this->_network_storage->{$k} );
548 } else {
549 unset( $this->_storage->{$k} );
550 }
551 }
552
553 function __get( $k ) {
554 return $this->should_use_network_storage( $k ) ?
555 $this->_network_storage->{$k} :
556 $this->_storage->{$k};
557 }
558
559 #endregion
560 }
561