PluginProbe
BlockSpare – Gutenberg Blocks, AI Content Generator & Site Builder for News, Magazine & Blogs / 2.6.6
BlockSpare – Gutenberg Blocks, AI Content Generator & Site Builder for News, Magazine & Blogs v2.6.6
5.0.1 4.1.0 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 2.1.2 2.5.0 2.5.3 All 39 releases
← All changes | freemius/includes/class-fs-options.php +430 -430 1.3.0 → 2.6.6 View file →
@@ -1,431 +1,431 @@
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_Options
15 - *
16 - * A wrapper class for handling network level and single site level options.
17 - */
18 - class FS_Options {
19 - /**
20 - * @var string
21 - */
22 - private $_id;
23 -
24 - /**
25 - * @var array[string]FS_Options {
26 - * @key string
27 - * @value FS_Options
28 - * }
29 - */
30 - private static $_instances;
31 -
32 - /**
33 - * @var FS_Option_Manager Site level options.
34 - */
35 - private $_options;
36 -
37 - /**
38 - * @var FS_Option_Manager Network level options.
39 - */
40 - private $_network_options;
41 -
42 - /**
43 - * @var int The ID of the blog that is associated with the current site level options.
44 - */
45 - private $_blog_id = 0;
46 -
47 - /**
48 - * @var bool
49 - */
50 - private $_is_multisite;
51 -
52 - /**
53 - * @var string[] Lazy collection of params on the site level.
54 - */
55 - private static $_SITE_OPTIONS_MAP;
56 -
57 - /**
58 - * @author Leo Fajardo (@leorw)
59 - * @since 2.0.0
60 - *
61 - * @param string $id
62 - * @param bool $load
63 - *
64 - * @return FS_Options
65 - */
66 - static function instance( $id, $load = false ) {
67 - if ( ! isset( self::$_instances[ $id ] ) ) {
68 - self::$_instances[ $id ] = new FS_Options( $id, $load );
69 - }
70 -
71 - return self::$_instances[ $id ];
72 - }
73 -
74 - /**
75 - * @author Leo Fajardo (@leorw)
76 - * @since 2.0.0
77 - *
78 - * @param string $id
79 - * @param bool $load
80 - */
81 - private function __construct( $id, $load = false ) {
82 - $this->_id = $id;
83 - $this->_is_multisite = is_multisite();
84 -
85 - if ( $this->_is_multisite ) {
86 - $this->_blog_id = get_current_blog_id();
87 - $this->_network_options = FS_Option_Manager::get_manager( $id, $load, true );
88 - }
89 -
90 - $this->_options = FS_Option_Manager::get_manager( $id, $load, $this->_blog_id );
91 - }
92 -
93 - /**
94 - * Switch the context of the site level options manager.
95 - *
96 - * @author Vova Feldman (@svovaf)
97 - * @since 2.0.0
98 - *
99 - * @param $blog_id
100 - */
101 - function set_site_blog_context( $blog_id ) {
102 - $this->_blog_id = $blog_id;
103 -
104 - $this->_options = FS_Option_Manager::get_manager( $this->_id, false, $this->_blog_id );
105 - }
106 -
107 - /**
108 - * @author Leo Fajardo (@leorw)
109 - *
110 - * @param string $option
111 - * @param mixed $default
112 - * @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::$_SITE_LEVEL_PARAMS).
113 - *
114 - * @return mixed
115 - */
116 - function get_option( $option, $default = null, $network_level_or_blog_id = null ) {
117 - if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
118 - return $this->_network_options->get_option( $option, $default );
119 - }
120 -
121 - $site_options = $this->get_site_options( $network_level_or_blog_id );
122 -
123 - return $site_options->get_option( $option, $default );
124 - }
125 -
126 - /**
127 - * @author Leo Fajardo (@leorw)
128 - * @since 2.0.0
129 - *
130 - * @param string $option
131 - * @param mixed $value
132 - * @param bool $flush
133 - * @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::$_SITE_LEVEL_PARAMS).
134 - */
135 - function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) {
136 - if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
137 - $this->_network_options->set_option( $option, $value, $flush );
138 - } else {
139 - $site_options = $this->get_site_options( $network_level_or_blog_id );
140 - $site_options->set_option( $option, $value, $flush );
141 - }
142 - }
143 -
144 - /**
145 - * @author Vova Feldman (@svovaf)
146 - * @since 2.0.0
147 - *
148 - * @param string $option
149 - * @param bool $flush
150 - * @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::$_SITE_LEVEL_PARAMS).
151 - */
152 - function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) {
153 - if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
154 - $this->_network_options->unset_option( $option, $flush );
155 - } else {
156 - $site_options = $this->get_site_options( $network_level_or_blog_id );
157 - $site_options->unset_option( $option, $flush );
158 - }
159 - }
160 -
161 - /**
162 - * @author Leo Fajardo (@leorw)
163 - * @since 2.0.0
164 - *
165 - * @param bool $flush
166 - * @param bool $network_level
167 - */
168 - function load( $flush = false, $network_level = true ) {
169 - if ( $this->_is_multisite && $network_level ) {
170 - $this->_network_options->load( $flush );
171 - } else {
172 - $this->_options->load( $flush );
173 - }
174 - }
175 -
176 - /**
177 - * @author Leo Fajardo (@leorw)
178 - * @since 2.0.0
179 - *
180 - * @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`, store both network storage and the current context blog storage.
181 - */
182 - function store( $network_level_or_blog_id = null ) {
183 - if ( ! $this->_is_multisite ||
184 - false === $network_level_or_blog_id ||
185 - 0 == $network_level_or_blog_id ||
186 - is_null( $network_level_or_blog_id )
187 - ) {
188 - $site_options = $this->get_site_options( $network_level_or_blog_id );
189 - $site_options->store();
190 - }
191 -
192 - if ( $this->_is_multisite &&
193 - ( is_null( $network_level_or_blog_id ) || true === $network_level_or_blog_id )
194 - ) {
195 - $this->_network_options->store();
196 - }
197 - }
198 -
199 - /**
200 - * @author Vova Feldman (@svovaf)
201 - * @since 2.0.0
202 - *
203 - * @param int|null|bool $network_level_or_blog_id
204 - * @param bool $flush
205 - */
206 - function clear( $network_level_or_blog_id = null, $flush = false ) {
207 - if ( ! $this->_is_multisite ||
208 - false === $network_level_or_blog_id ||
209 - is_null( $network_level_or_blog_id ) ||
210 - is_numeric( $network_level_or_blog_id )
211 - ) {
212 - $site_options = $this->get_site_options( $network_level_or_blog_id );
213 - $site_options->clear( $flush );
214 - }
215 -
216 - if ( $this->_is_multisite &&
217 - ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
218 - ) {
219 - $this->_network_options->clear( $flush );
220 - }
221 - }
222 -
223 - /**
224 - * Migration script to the new storage data structure that is network compatible.
225 - *
226 - * IMPORTANT:
227 - * This method should be executed only after it is determined if this is a network
228 - * level compatible product activation.
229 - *
230 - * @author Vova Feldman (@svovaf)
231 - * @since 2.0.0
232 - *
233 - * @param int $blog_id
234 - */
235 - function migrate_to_network( $blog_id = 0 ) {
236 - if ( ! $this->_is_multisite ) {
237 - return;
238 - }
239 -
240 - $updated = false;
241 -
242 - $site_options = $this->get_site_options( $blog_id );
243 -
244 - $keys = $site_options->get_options_keys();
245 -
246 - foreach ( $keys as $option ) {
247 - if ( $this->is_site_option( $option ) ||
248 - // Don't move admin notices to the network storage.
249 - in_array($option, array(
250 - // Don't move admin notices to the network storage.
251 - 'admin_notices',
252 - // Don't migrate the module specific data, it will be migrated by the FS_Storage.
253 - 'plugin_data',
254 - 'theme_data',
255 - ))
256 - ) {
257 - continue;
258 - }
259 -
260 - $option_updated = false;
261 -
262 - // Migrate option to the network storage.
263 - $site_option = $site_options->get_option( $option );
264 -
265 - if ( ! $this->_network_options->has_option( $option ) ) {
266 - // Option not set on the network level, so just set it.
267 - $this->_network_options->set_option( $option, $site_option, false );
268 -
269 - $option_updated = true;
270 - } else {
271 - // Option already set on the network level, so we need to merge it inelegantly.
272 - $network_option = $this->_network_options->get_option( $option );
273 -
274 - if ( is_array( $network_option ) && is_array( $site_option ) ) {
275 - // Option is an array.
276 - foreach ( $site_option as $key => $value ) {
277 - if ( ! isset( $network_option[ $key ] ) ) {
278 - $network_option[ $key ] = $value;
279 -
280 - $option_updated = true;
281 - } else if ( is_array( $network_option[ $key ] ) && is_array( $value ) ) {
282 - if ( empty( $network_option[ $key ] ) ) {
283 - $network_option[ $key ] = $value;
284 -
285 - $option_updated = true;
286 - } else if ( empty( $value ) ) {
287 - // Do nothing.
288 - } else {
289 - reset($value);
290 - $first_key = key($value);
291 - if ( $value[$first_key] instanceof FS_Entity ) {
292 - // Merge entities by IDs.
293 - $network_entities_ids = array();
294 - foreach ( $network_option[ $key ] as $entity ) {
295 - $network_entities_ids[ $entity->id ] = true;
296 - }
297 -
298 - foreach ( $value as $entity ) {
299 - if ( ! isset( $network_entities_ids[ $entity->id ] ) ) {
300 - $network_option[ $key ][] = $entity;
301 -
302 - $option_updated = true;
303 - }
304 - }
305 - }
306 - }
307 - }
308 - }
309 - }
310 -
311 - if ( $option_updated ) {
312 - $this->_network_options->set_option( $option, $network_option, false );
313 - }
314 - }
315 -
316 - /**
317 - * Remove the option from site level storage.
318 - *
319 - * IMPORTANT:
320 - * The line below is intentionally commented since we want to preserve the option
321 - * on the site storage level for "downgrade compatibility". Basically, if the user
322 - * will downgrade to an older version of the plugin with the prev storage structure,
323 - * it will continue working.
324 - *
325 - * @todo After a few releases we can remove this.
326 - */
327 -// $site_options->unset_option($option, false);
328 -
329 - if ( $option_updated ) {
330 - $updated = true;
331 - }
332 - }
333 -
334 - if ( ! $updated ) {
335 - return;
336 - }
337 -
338 - // Update network level storage.
339 - $this->_network_options->store();
340 -// $site_options->store();
341 - }
342 -
343 -
344 - #--------------------------------------------------------------------------------
345 - #region Helper Methods
346 - #--------------------------------------------------------------------------------
347 -
348 - /**
349 - * We don't want to load the map right away since it's not even needed in a non-MS environment.
350 - *
351 - * @author Vova Feldman (@svovaf)
352 - * @since 2.0.0
353 - */
354 - private static function load_site_options_map() {
355 - self::$_SITE_OPTIONS_MAP = array(
356 - 'sites' => true,
357 - 'theme_sites' => true,
358 - 'unique_id' => true,
359 - 'active_plugins' => true,
360 - );
361 - }
362 -
363 - /**
364 - * @author Vova Feldman (@svovaf)
365 - * @since 2.0.0
366 - *
367 - * @param string $option
368 - *
369 - * @return bool
370 - */
371 - private function is_site_option( $option ) {
372 - if ( WP_FS__ACCOUNTS_OPTION_NAME != $this->_id ) {
373 - return false;
374 - }
375 -
376 - if ( ! isset( self::$_SITE_OPTIONS_MAP ) ) {
377 - self::load_site_options_map();
378 - }
379 -
380 - return isset( self::$_SITE_OPTIONS_MAP[ $option ] );
381 - }
382 -
383 - /**
384 - * @author Vova Feldman (@svovaf)
385 - * @since 2.0.0
386 - *
387 - * @param int $blog_id
388 - *
389 - * @return FS_Option_Manager
390 - */
391 - private function get_site_options( $blog_id = 0 ) {
392 - if ( 0 == $blog_id || $blog_id == $this->_blog_id ) {
393 - return $this->_options;
394 - }
395 -
396 - return FS_Option_Manager::get_manager( $this->_id, true, $blog_id );
397 - }
398 -
399 - /**
400 - * Check if an option should be stored on the MS network storage.
401 - *
402 - * @author Vova Feldman (@svovaf)
403 - * @since 2.0.0
404 - *
405 - * @param string $option
406 - * @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::$_SITE_LEVEL_PARAMS).
407 - *
408 - * @return bool
409 - */
410 - private function should_use_network_storage( $option, $network_level_or_blog_id = null ) {
411 - if ( ! $this->_is_multisite ) {
412 - // Not a multisite environment.
413 - return false;
414 - }
415 -
416 - if ( is_numeric( $network_level_or_blog_id ) ) {
417 - // Explicitly asked to use a specified blog storage.
418 - return false;
419 - }
420 -
421 - if ( is_bool( $network_level_or_blog_id ) ) {
422 - // Explicitly specified whether should use the network or blog level storage.
423 - return $network_level_or_blog_id;
424 - }
425 -
426 - // Determine which storage to use based on the option.
427 - return ! $this->is_site_option( $option );
428 - }
429 -
430 - #endregion
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_Options
15 + *
16 + * A wrapper class for handling network level and single site level options.
17 + */
18 + class FS_Options {
19 + /**
20 + * @var string
21 + */
22 + private $_id;
23 +
24 + /**
25 + * @var array[string]FS_Options {
26 + * @key string
27 + * @value FS_Options
28 + * }
29 + */
30 + private static $_instances;
31 +
32 + /**
33 + * @var FS_Option_Manager Site level options.
34 + */
35 + private $_options;
36 +
37 + /**
38 + * @var FS_Option_Manager Network level options.
39 + */
40 + private $_network_options;
41 +
42 + /**
43 + * @var int The ID of the blog that is associated with the current site level options.
44 + */
45 + private $_blog_id = 0;
46 +
47 + /**
48 + * @var bool
49 + */
50 + private $_is_multisite;
51 +
52 + /**
53 + * @var string[] Lazy collection of params on the site level.
54 + */
55 + private static $_SITE_OPTIONS_MAP;
56 +
57 + /**
58 + * @author Leo Fajardo (@leorw)
59 + * @since 2.0.0
60 + *
61 + * @param string $id
62 + * @param bool $load
63 + *
64 + * @return FS_Options
65 + */
66 + static function instance( $id, $load = false ) {
67 + if ( ! isset( self::$_instances[ $id ] ) ) {
68 + self::$_instances[ $id ] = new FS_Options( $id, $load );
69 + }
70 +
71 + return self::$_instances[ $id ];
72 + }
73 +
74 + /**
75 + * @author Leo Fajardo (@leorw)
76 + * @since 2.0.0
77 + *
78 + * @param string $id
79 + * @param bool $load
80 + */
81 + private function __construct( $id, $load = false ) {
82 + $this->_id = $id;
83 + $this->_is_multisite = is_multisite();
84 +
85 + if ( $this->_is_multisite ) {
86 + $this->_blog_id = get_current_blog_id();
87 + $this->_network_options = FS_Option_Manager::get_manager( $id, $load, true );
88 + }
89 +
90 + $this->_options = FS_Option_Manager::get_manager( $id, $load, $this->_blog_id );
91 + }
92 +
93 + /**
94 + * Switch the context of the site level options manager.
95 + *
96 + * @author Vova Feldman (@svovaf)
97 + * @since 2.0.0
98 + *
99 + * @param $blog_id
100 + */
101 + function set_site_blog_context( $blog_id ) {
102 + $this->_blog_id = $blog_id;
103 +
104 + $this->_options = FS_Option_Manager::get_manager( $this->_id, false, $this->_blog_id );
105 + }
106 +
107 + /**
108 + * @author Leo Fajardo (@leorw)
109 + *
110 + * @param string $option
111 + * @param mixed $default
112 + * @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::$_SITE_LEVEL_PARAMS).
113 + *
114 + * @return mixed
115 + */
116 + function get_option( $option, $default = null, $network_level_or_blog_id = null ) {
117 + if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
118 + return $this->_network_options->get_option( $option, $default );
119 + }
120 +
121 + $site_options = $this->get_site_options( $network_level_or_blog_id );
122 +
123 + return $site_options->get_option( $option, $default );
124 + }
125 +
126 + /**
127 + * @author Leo Fajardo (@leorw)
128 + * @since 2.0.0
129 + *
130 + * @param string $option
131 + * @param mixed $value
132 + * @param bool $flush
133 + * @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::$_SITE_LEVEL_PARAMS).
134 + */
135 + function set_option( $option, $value, $flush = false, $network_level_or_blog_id = null ) {
136 + if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
137 + $this->_network_options->set_option( $option, $value, $flush );
138 + } else {
139 + $site_options = $this->get_site_options( $network_level_or_blog_id );
140 + $site_options->set_option( $option, $value, $flush );
141 + }
142 + }
143 +
144 + /**
145 + * @author Vova Feldman (@svovaf)
146 + * @since 2.0.0
147 + *
148 + * @param string $option
149 + * @param bool $flush
150 + * @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::$_SITE_LEVEL_PARAMS).
151 + */
152 + function unset_option( $option, $flush = false, $network_level_or_blog_id = null ) {
153 + if ( $this->should_use_network_storage( $option, $network_level_or_blog_id ) ) {
154 + $this->_network_options->unset_option( $option, $flush );
155 + } else {
156 + $site_options = $this->get_site_options( $network_level_or_blog_id );
157 + $site_options->unset_option( $option, $flush );
158 + }
159 + }
160 +
161 + /**
162 + * @author Leo Fajardo (@leorw)
163 + * @since 2.0.0
164 + *
165 + * @param bool $flush
166 + * @param bool $network_level
167 + */
168 + function load( $flush = false, $network_level = true ) {
169 + if ( $this->_is_multisite && $network_level ) {
170 + $this->_network_options->load( $flush );
171 + } else {
172 + $this->_options->load( $flush );
173 + }
174 + }
175 +
176 + /**
177 + * @author Leo Fajardo (@leorw)
178 + * @since 2.0.0
179 + *
180 + * @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`, store both network storage and the current context blog storage.
181 + */
182 + function store( $network_level_or_blog_id = null ) {
183 + if ( ! $this->_is_multisite ||
184 + false === $network_level_or_blog_id ||
185 + 0 == $network_level_or_blog_id ||
186 + is_null( $network_level_or_blog_id )
187 + ) {
188 + $site_options = $this->get_site_options( $network_level_or_blog_id );
189 + $site_options->store();
190 + }
191 +
192 + if ( $this->_is_multisite &&
193 + ( is_null( $network_level_or_blog_id ) || true === $network_level_or_blog_id )
194 + ) {
195 + $this->_network_options->store();
196 + }
197 + }
198 +
199 + /**
200 + * @author Vova Feldman (@svovaf)
201 + * @since 2.0.0
202 + *
203 + * @param int|null|bool $network_level_or_blog_id
204 + * @param bool $flush
205 + */
206 + function clear( $network_level_or_blog_id = null, $flush = false ) {
207 + if ( ! $this->_is_multisite ||
208 + false === $network_level_or_blog_id ||
209 + is_null( $network_level_or_blog_id ) ||
210 + is_numeric( $network_level_or_blog_id )
211 + ) {
212 + $site_options = $this->get_site_options( $network_level_or_blog_id );
213 + $site_options->clear( $flush );
214 + }
215 +
216 + if ( $this->_is_multisite &&
217 + ( true === $network_level_or_blog_id || is_null( $network_level_or_blog_id ) )
218 + ) {
219 + $this->_network_options->clear( $flush );
220 + }
221 + }
222 +
223 + /**
224 + * Migration script to the new storage data structure that is network compatible.
225 + *
226 + * IMPORTANT:
227 + * This method should be executed only after it is determined if this is a network
228 + * level compatible product activation.
229 + *
230 + * @author Vova Feldman (@svovaf)
231 + * @since 2.0.0
232 + *
233 + * @param int $blog_id
234 + */
235 + function migrate_to_network( $blog_id = 0 ) {
236 + if ( ! $this->_is_multisite ) {
237 + return;
238 + }
239 +
240 + $updated = false;
241 +
242 + $site_options = $this->get_site_options( $blog_id );
243 +
244 + $keys = $site_options->get_options_keys();
245 +
246 + foreach ( $keys as $option ) {
247 + if ( $this->is_site_option( $option ) ||
248 + // Don't move admin notices to the network storage.
249 + in_array($option, array(
250 + // Don't move admin notices to the network storage.
251 + 'admin_notices',
252 + // Don't migrate the module specific data, it will be migrated by the FS_Storage.
253 + 'plugin_data',
254 + 'theme_data',
255 + ))
256 + ) {
257 + continue;
258 + }
259 +
260 + $option_updated = false;
261 +
262 + // Migrate option to the network storage.
263 + $site_option = $site_options->get_option( $option );
264 +
265 + if ( ! $this->_network_options->has_option( $option ) ) {
266 + // Option not set on the network level, so just set it.
267 + $this->_network_options->set_option( $option, $site_option, false );
268 +
269 + $option_updated = true;
270 + } else {
271 + // Option already set on the network level, so we need to merge it inelegantly.
272 + $network_option = $this->_network_options->get_option( $option );
273 +
274 + if ( is_array( $network_option ) && is_array( $site_option ) ) {
275 + // Option is an array.
276 + foreach ( $site_option as $key => $value ) {
277 + if ( ! isset( $network_option[ $key ] ) ) {
278 + $network_option[ $key ] = $value;
279 +
280 + $option_updated = true;
281 + } else if ( is_array( $network_option[ $key ] ) && is_array( $value ) ) {
282 + if ( empty( $network_option[ $key ] ) ) {
283 + $network_option[ $key ] = $value;
284 +
285 + $option_updated = true;
286 + } else if ( empty( $value ) ) {
287 + // Do nothing.
288 + } else {
289 + reset($value);
290 + $first_key = key($value);
291 + if ( $value[$first_key] instanceof FS_Entity ) {
292 + // Merge entities by IDs.
293 + $network_entities_ids = array();
294 + foreach ( $network_option[ $key ] as $entity ) {
295 + $network_entities_ids[ $entity->id ] = true;
296 + }
297 +
298 + foreach ( $value as $entity ) {
299 + if ( ! isset( $network_entities_ids[ $entity->id ] ) ) {
300 + $network_option[ $key ][] = $entity;
301 +
302 + $option_updated = true;
303 + }
304 + }
305 + }
306 + }
307 + }
308 + }
309 + }
310 +
311 + if ( $option_updated ) {
312 + $this->_network_options->set_option( $option, $network_option, false );
313 + }
314 + }
315 +
316 + /**
317 + * Remove the option from site level storage.
318 + *
319 + * IMPORTANT:
320 + * The line below is intentionally commented since we want to preserve the option
321 + * on the site storage level for "downgrade compatibility". Basically, if the user
322 + * will downgrade to an older version of the plugin with the prev storage structure,
323 + * it will continue working.
324 + *
325 + * @todo After a few releases we can remove this.
326 + */
327 +// $site_options->unset_option($option, false);
328 +
329 + if ( $option_updated ) {
330 + $updated = true;
331 + }
332 + }
333 +
334 + if ( ! $updated ) {
335 + return;
336 + }
337 +
338 + // Update network level storage.
339 + $this->_network_options->store();
340 +// $site_options->store();
341 + }
342 +
343 +
344 + #--------------------------------------------------------------------------------
345 + #region Helper Methods
346 + #--------------------------------------------------------------------------------
347 +
348 + /**
349 + * We don't want to load the map right away since it's not even needed in a non-MS environment.
350 + *
351 + * @author Vova Feldman (@svovaf)
352 + * @since 2.0.0
353 + */
354 + private static function load_site_options_map() {
355 + self::$_SITE_OPTIONS_MAP = array(
356 + 'sites' => true,
357 + 'theme_sites' => true,
358 + 'unique_id' => true,
359 + 'active_plugins' => true,
360 + );
361 + }
362 +
363 + /**
364 + * @author Vova Feldman (@svovaf)
365 + * @since 2.0.0
366 + *
367 + * @param string $option
368 + *
369 + * @return bool
370 + */
371 + private function is_site_option( $option ) {
372 + if ( WP_FS__ACCOUNTS_OPTION_NAME != $this->_id ) {
373 + return false;
374 + }
375 +
376 + if ( ! isset( self::$_SITE_OPTIONS_MAP ) ) {
377 + self::load_site_options_map();
378 + }
379 +
380 + return isset( self::$_SITE_OPTIONS_MAP[ $option ] );
381 + }
382 +
383 + /**
384 + * @author Vova Feldman (@svovaf)
385 + * @since 2.0.0
386 + *
387 + * @param int $blog_id
388 + *
389 + * @return FS_Option_Manager
390 + */
391 + private function get_site_options( $blog_id = 0 ) {
392 + if ( 0 == $blog_id || $blog_id == $this->_blog_id ) {
393 + return $this->_options;
394 + }
395 +
396 + return FS_Option_Manager::get_manager( $this->_id, true, $blog_id );
397 + }
398 +
399 + /**
400 + * Check if an option should be stored on the MS network storage.
401 + *
402 + * @author Vova Feldman (@svovaf)
403 + * @since 2.0.0
404 + *
405 + * @param string $option
406 + * @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::$_SITE_LEVEL_PARAMS).
407 + *
408 + * @return bool
409 + */
410 + private function should_use_network_storage( $option, $network_level_or_blog_id = null ) {
411 + if ( ! $this->_is_multisite ) {
412 + // Not a multisite environment.
413 + return false;
414 + }
415 +
416 + if ( is_numeric( $network_level_or_blog_id ) ) {
417 + // Explicitly asked to use a specified blog storage.
418 + return false;
419 + }
420 +
421 + if ( is_bool( $network_level_or_blog_id ) ) {
422 + // Explicitly specified whether should use the network or blog level storage.
423 + return $network_level_or_blog_id;
424 + }
425 +
426 + // Determine which storage to use based on the option.
427 + return ! $this->is_site_option( $option );
428 + }
429 +
430 + #endregion
431 431 }