PluginProbe
Customify / 2.5.2
Customify v2.5.2
2.10.9 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.7.1 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.0.1 1.6.5 1.7.0 1.7.1 All 77 releases
customify / includes / class-pixcustomify.php

class-pixcustomify.php in Customify 2.5.2, at includes/class-pixcustomify.php

958 lines 29.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * PixCustomify.
4 * @package PixCustomify
5 * @author Pixelgrade <contact@pixelgrade.com>
6 * @license GPL-2.0+
7 * @link https://pixelgrade.com
8 * @copyright 2014-2018 Pixelgrade
9 */
10
11 /**
12 * Plugin class.
13 * @package PixCustomify
14 * @author Pixelgrade <contact@pixelgrade.com>
15 */
16 class PixCustomifyPlugin {
17
18 /**
19 * Plugin version, used for cache-busting of style and script file references.
20 * @since 1.5.0
21 * @const string
22 */
23 protected $_version;
24 /**
25 * Unique identifier for your plugin.
26 * Use this value (not the variable name) as the text domain when internationalizing strings of text. It should
27 * match the Text Domain file header in the main plugin file.
28 * @since 1.0.0
29 * @var string
30 */
31 protected $plugin_slug = 'customify';
32
33 /**
34 * Instance of this class.
35 * @since 1.5.0
36 * @var object
37 */
38 protected static $_instance = null;
39
40 /**
41 * The main plugin file.
42 * @var string
43 * @access public
44 * @since 1.5.0
45 */
46 public $file;
47
48 /**
49 * Settings class object.
50 * @var Customify_Settings
51 * @access public
52 * @since 2.4.0
53 */
54 public $settings = null;
55
56 /**
57 * Customizer class object to handle customizer controls and logic.
58 * @var PixCustomify_Customizer
59 * @access public
60 * @since 2.4.0
61 */
62 public $customizer = null;
63
64 /**
65 * Style Manager class object.
66 * @var Customify_Style_Manager
67 * @access public
68 * @since 1.0.0
69 */
70 public $style_manager = null;
71
72 /**
73 * Gutenberg class object.
74 * @var Customify_Gutenberg
75 * @access public
76 * @since 2.2.0
77 */
78 public $gutenberg = null;
79
80 protected $options_minimal_details = array();
81 protected $options_details = array();
82
83 protected $opt_name;
84
85 private $customizer_config = array();
86
87 /**
88 * Minimal Required PHP Version
89 * @var string
90 * @access private
91 * @since 1.5.0
92 */
93 private $minimalRequiredPhpVersion = '5.3';
94
95 protected function __construct( $file, $version = '1.0.0' ) {
96 //the main plugin file (the one that loads all this)
97 $this->file = $file;
98 //the current plugin version
99 $this->_version = $version;
100
101 if ( $this->php_version_check() ) {
102 // Only load and run the init function if we know PHP version can parse it.
103 $this->init();
104 }
105 }
106
107 /**
108 * Initialize plugin
109 */
110 private function init() {
111 // We don't want to put extra load on the heartbeat AJAX request.
112 if ( wp_doing_ajax() && isset( $_REQUEST['action'] ) && 'heartbeat' === $_REQUEST['action'] ) {
113 return;
114 }
115
116 // Handle the install and uninstall logic
117 register_activation_hook( $this->get_file(), array( 'PixCustomifyPlugin', 'install' ) );
118
119 /* Initialize the plugin settings logic. */
120 require_once( $this->get_base_path() . 'includes/class-customify-settings.php' );
121 if ( is_null( $this->settings ) ) {
122 $this->settings = Customify_Settings::instance( $this->get_file(), $this->get_slug(), $this->get_version() );
123 }
124
125 /* Initialize the Customizer logic. */
126 require_once( $this->get_base_path() . 'includes/class-customify-customizer.php' );
127 if ( is_null( $this->customizer ) ) {
128 $this->customizer = PixCustomify_Customizer::instance();
129 }
130
131 /* Initialize the Style Manager logic. */
132 require_once( $this->get_base_path() . 'includes/class-customify-style-manager.php' );
133 if ( is_null( $this->style_manager ) ) {
134 $this->style_manager = Customify_Style_Manager::instance();
135 }
136
137 /* Initialize the Gutenberg logic. */
138 require_once( $this->get_base_path() . 'includes/class-customify-gutenberg.php' );
139 if ( is_null( $this->gutenberg ) ) {
140 $this->gutenberg = Customify_Gutenberg::instance();
141 }
142
143 // Register all the needed hooks
144 $this->register_hooks();
145 }
146
147 /**
148 * Register our actions and filters
149 */
150 function register_hooks() {
151
152 /*
153 * Load plugin text domain
154 */
155 add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
156
157 /*
158 * Load the upgrade logic.
159 */
160 add_action( 'admin_init', array( $this, 'upgrade' ) );
161
162 /*
163 * Handle the force clearing of the caches. We clear in a proactive manner.
164 */
165 add_action( 'activated_plugin', array( $this, 'invalidate_customizer_config_cache' ), 1 );
166 add_action( 'activated_plugin', array( $this, 'invalidate_options_details_cache' ), 1 );
167 add_action( 'activated_plugin', array( $this, 'invalidate_customizer_opt_name_cache' ), 1 );
168
169 add_action( 'deactivated_plugin', array( $this, 'invalidate_customizer_config_cache' ), 1 );
170 add_action( 'deactivated_plugin', array( $this, 'invalidate_options_details_cache' ), 1 );
171 add_action( 'deactivated_plugin', array( $this, 'invalidate_customizer_opt_name_cache' ), 1 );
172
173 add_action( 'switch_theme', array( $this, 'invalidate_customizer_config_cache' ), 1 );
174 add_action( 'switch_theme', array( $this, 'invalidate_options_details_cache' ), 1 );
175 add_action( 'switch_theme', array( $this, 'invalidate_customizer_opt_name_cache' ), 1 );
176
177 add_action( 'upgrader_process_complete', array( $this, 'invalidate_customizer_config_cache' ), 1 );
178 add_action( 'upgrader_process_complete', array( $this, 'invalidate_options_details_cache' ), 1 );
179 add_action( 'upgrader_process_complete', array( $this, 'invalidate_customizer_opt_name_cache' ), 1 );
180
181 // Whenever we update data from the Customizer, we will invalidate the options details (that include the value).
182 add_filter( 'customize_changeset_save_data', array( $this, 'filter_invalidate_options_details_cache' ), 50, 1 );
183
184 // We also want to invalidate the cache whenever the Pixelgrade Care license is updated since it may unlock new features
185 // and so unlock new Customify options.
186 add_filter( 'pre_set_theme_mod_pixcare_license', array( $this, 'filter_invalidate_customizer_config_cache' ), 10, 1 );
187 add_filter( 'pre_set_theme_mod_pixcare_license', array( $this, 'filter_invalidate_options_details_cache' ), 10, 1 );
188 add_filter( 'pre_set_theme_mod_pixcare_license', array( $this, 'filter_invalidate_customizer_opt_name_cache' ), 10, 1 );
189 }
190
191 /**
192 * Handle the logic to upgrade between versions. It will run only one per version change.
193 */
194 public function upgrade() {
195 $customify_dbversion = get_option( 'customify_dbversion', '0.0.1' );
196 if ( $this->get_version() === $customify_dbversion ) {
197 return;
198 }
199
200 // For versions, previous of version 2.0.0 (the Color Palettes v2.0 release).
201 if ( version_compare( $customify_dbversion, '2.0.0', '<' ) ) {
202 // Delete the option holding the fact that the user offered feedback.
203 delete_option( 'style_manager_user_feedback_provided' );
204 }
205
206 // Put the current version in the database.
207 update_option( 'customify_dbversion', $this->get_version(), true );
208 }
209
210 public function get_options_key( $skip_cache = false ) {
211 if ( ! empty( $this->opt_name ) ) {
212 return $this->opt_name;
213 }
214
215 if ( $this->should_force_skip_cache() ) {
216 $skip_cache = true;
217 }
218
219 // First try and get the cached data
220 $data = get_option( $this->get_customizer_opt_name_cache_key() );
221 $expire_timestamp = false;
222
223 // Only try to get the expire timestamp if we really need to.
224 if ( true !== $skip_cache && false !== $data ) {
225 // Get the cache data expiration timestamp.
226 $expire_timestamp = get_option( $this->get_customizer_opt_name_cache_key() . '_timestamp' );
227 }
228
229 // The data isn't set, is expired or we were instructed to skip the cache; we need to regenerate the config.
230 if ( true === $skip_cache || false === $data || false === $expire_timestamp || $expire_timestamp < time() ) {
231
232 $data = $this->get_customizer_config( 'opt-name' );
233
234 if ( true !== $skip_cache ) {
235 // Cache the data in an option for 6 hours, but only if we are not supposed to skip the cache entirely.
236 update_option( $this->get_customizer_opt_name_cache_key(), $data, true );
237 update_option( $this->get_customizer_opt_name_cache_key() . '_timestamp', time() + 6 * HOUR_IN_SECONDS, true );
238 }
239 }
240
241 $this->opt_name = $data;
242 return $data;
243 }
244
245 private function get_customizer_opt_name_cache_key() {
246 return 'customify_customizer_opt_name';
247 }
248
249 public function invalidate_customizer_opt_name_cache() {
250 update_option( $this->get_customizer_opt_name_cache_key() . '_timestamp' , time() - 24 * HOUR_IN_SECONDS, true );
251
252 $this->clear_locally_cached_data();
253 }
254
255 public function filter_invalidate_customizer_opt_name_cache( $value ) {
256 $this->invalidate_customizer_opt_name_cache();
257
258 return $value;
259 }
260
261
262 public function get_options_details( $only_minimal_details = false, $skip_cache = false ) {
263
264 // If we already have the data, do as little as possible.
265 if ( true === $only_minimal_details && ! empty( $this->options_minimal_details ) ) {
266 return $this->options_minimal_details;
267 }
268 if ( ! empty( $this->options_details ) ) {
269 return $this->options_details;
270 }
271
272 if ( $this->should_force_skip_cache() ) {
273 $skip_cache = true;
274 }
275
276 // We will first look for cached data
277
278 $data = $this->options_minimal_details = get_option( $this->get_options_minimal_details_cache_key() );
279 if ( false !== $data && false === $only_minimal_details ) {
280 $extra_details_data = get_option( $this->get_options_extra_details_cache_key() );
281 if ( is_array( $extra_details_data ) ) {
282 $data = $this->options_details = Customify_Array::array_merge_recursive_distinct( $data, $extra_details_data );
283 } else {
284 // Something is wrong with the extra details and we need to regenerate.
285 $this->invalidate_options_details_cache();
286 }
287 }
288
289 // For performance reasons, we will use the cached data (even if stale)
290 // when a user is not logged in or a user without administrative capabilities is logged in.
291 if ( false !== $data && false === $skip_cache && ! current_user_can( 'manage_options' ) ) {
292 return $data;
293 }
294
295 $expire_timestamp = false;
296
297 // Only try to get the expire timestamp if we really need to.
298 if ( true !== $skip_cache && false !== $data ) {
299 // Get the cached data expiration timestamp.
300 $expire_timestamp = get_option( $this->get_options_details_cache_timestamp_key() );
301 }
302
303 // The data isn't set, is expired or we were instructed to skip the cache; we need to regenerate the config.
304 if ( true === $skip_cache || false === $data || false === $expire_timestamp || $expire_timestamp < time() ) {
305 $options_minimal_details = array();
306 $options_extra_details = array();
307
308 $minimal_detail_keys = array(
309 'type',
310 'setting_type',
311 'setting_id',
312 'default',
313 'css',
314 'output',
315 'value',
316 'load_all_weights',
317 'selector',
318 'callback',
319 'active_callback',
320 );
321
322 $customizer_config = $this->get_customizer_config();
323
324 if ( isset ( $customizer_config['panels'] ) ) {
325 foreach ( $customizer_config['panels'] as $pane_id => $panel_settings ) {
326 if ( isset( $panel_settings['sections'] ) ) {
327 foreach ( $panel_settings['sections'] as $section_id => $section_settings ) {
328 if ( isset( $section_settings['options'] ) ) {
329 foreach ( $section_settings['options'] as $option_id => $option_config ) {
330 if ( is_array( $option_config ) ) {
331 foreach ( $option_config as $key => $value ) {
332 if ( in_array( $key, $minimal_detail_keys ) ) {
333 $options_minimal_details[ $option_id ][ $key ] = $value;
334 } else {
335 $options_extra_details[ $option_id ][ $key ] = $value;
336 }
337 }
338
339 $options_minimal_details[ $option_id ]['value'] = $this->get_option( $option_id, null, $option_config );
340 }
341 }
342 }
343 }
344 }
345 }
346 }
347
348 if ( isset ( $customizer_config['sections'] ) ) {
349 foreach ( $customizer_config['sections'] as $section_id => $section_settings ) {
350 if ( isset( $section_settings['options'] ) ) {
351 foreach ( $section_settings['options'] as $option_id => $option_config ) {
352 if ( is_array( $option_config ) ) {
353 foreach ( $option_config as $key => $value ) {
354 if ( in_array( $key, $minimal_detail_keys ) ) {
355 $options_minimal_details[ $option_id ][ $key ] = $value;
356 } else {
357 $options_extra_details[ $option_id ][ $key ] = $value;
358 }
359 }
360
361 $options_minimal_details[ $option_id ]['value'] = $this->get_option( $option_id, null, $option_config );
362 }
363 }
364 }
365 }
366 }
367
368 if ( true !== $skip_cache ) {
369 // Cache the data for 6 hours, but only if we are not supposed to skip the cache entirely.
370 update_option( $this->get_options_minimal_details_cache_key(), $options_minimal_details, true );
371 update_option( $this->get_options_extra_details_cache_key(), $options_extra_details, false ); // we will not autoload extra details for performance reasons.
372 update_option( $this->get_options_details_cache_timestamp_key(), time() + 6 * HOUR_IN_SECONDS, true );
373 }
374
375 $data = $this->options_minimal_details = $options_minimal_details;
376 $this->options_details = Customify_Array::array_merge_recursive_distinct( $options_minimal_details, $options_extra_details );
377 if ( false === $only_minimal_details ) {
378 $data = $this->options_details;
379 }
380 }
381
382 return $data;
383 }
384
385 private function should_force_skip_cache() {
386 // If our development constant is defined and true, we will always skip the cache, except for AJAX calls.
387 // Other, more specific cases may impose skipping the cache also on AJAX calls.
388 if ( ! wp_doing_ajax()
389 && defined('CUSTOMIFY_ALWAYS_GENERATE_CUSTOMIZER_CONFIG' )
390 && true === CUSTOMIFY_ALWAYS_GENERATE_CUSTOMIZER_CONFIG ) {
391 return true;
392 }
393
394 // If we are in the Customizer and the request has a $_POST['customized'] parameter, we will skip the cache
395 // since this means that the preview is being reloaded with temporary settings values.
396 if ( ! empty( $_POST['customized'] ) ) {
397 return true;
398 }
399
400 // If we are currently previewing a theme without being actually active, we should not use cached data.
401
402 if ( ! empty( $_REQUEST['theme'] ) || ! empty( $_REQUEST['customize_theme'] ) ) {
403 return true;
404 }
405
406 /** @var WP_Customize_Manager $wp_customize */
407 global $wp_customize;
408 if ( ! empty( $wp_customize )
409 && method_exists( $wp_customize, 'is_theme_active' )
410 && ! $wp_customize->is_theme_active() ) {
411
412 return true;
413 }
414
415 return false;
416 }
417
418 /**
419 * This will clear any instance properties that are used as local cache during a request to avoid
420 * fetching the data from DB on each method call.
421 *
422 * This may be called during a request when something happens that (potentially) invalidates our data mid-request.
423 */
424 public function clear_locally_cached_data() {
425 $this->opt_name = null;
426
427 $this->customizer_config = null;
428
429 $this->options_minimal_details = null;
430 $this->options_details = null;
431 }
432
433 private function get_options_minimal_details_cache_key() {
434 return 'customify_options_minimal_details';
435 }
436
437 private function get_options_extra_details_cache_key() {
438 return 'customify_options_extra_details';
439 }
440
441 private function get_options_details_cache_timestamp_key() {
442 return 'customify_options_details_timestamp';
443 }
444
445 public function invalidate_options_details_cache() {
446 update_option( $this->get_options_details_cache_timestamp_key(), time() - 24 * HOUR_IN_SECONDS, true );
447
448 $this->clear_locally_cached_data();
449 }
450
451 public function filter_invalidate_options_details_cache( $value ) {
452 $this->invalidate_options_details_cache();
453
454 return $value;
455 }
456
457 public function has_option( $option ) {
458
459 $options_details = $this->get_options_details(true);
460 if ( isset( $options_details[ $option ] ) ) {
461 return true;
462 }
463
464 return false;
465 }
466
467 public function get_customizer_config( $key = false ) {
468 $customizer_config = $this->load_customizer_config();
469
470 if ( false !== $key ) {
471 if ( is_array( $customizer_config ) && isset( $customizer_config[ $key ] ) ) {
472 return $customizer_config[ $key ];
473 }
474
475 return null;
476 }
477
478 return $customizer_config;
479 }
480
481 /**
482 * Set the customizer configuration.
483 *
484 * @since 2.2.1
485 *
486 * @param bool $skip_cache Optional. Whether to use the cached config or generate a new one.
487 * @return array
488 */
489 protected function load_customizer_config( $skip_cache = false ) {
490 if ( ! empty( $this->customizer_config ) ) {
491 return $this->customizer_config;
492 }
493
494 if ( $this->should_force_skip_cache() ) {
495 $skip_cache = true;
496 }
497
498 // First try and get the cached data
499 $data = get_option( $this->get_customizer_config_cache_key() );
500
501 // For performance reasons, we will use the cached data (even if stale)
502 // when a user is not logged in or a user without administrative capabilities is logged in.
503 if ( false !== $data && false === $skip_cache && ! current_user_can( 'manage_options' ) ) {
504 $this->customizer_config = $data;
505 return $data;
506 }
507
508 $expire_timestamp = false;
509
510 // Only try to get the expire timestamp if we really need to.
511 if ( true !== $skip_cache && false !== $data ) {
512 // Get the cache data expiration timestamp.
513 $expire_timestamp = get_option( $this->get_customizer_config_cache_key() . '_timestamp' );
514 }
515
516 // The data isn't set, is expired or we were instructed to skip the cache; we need to regenerate the config.
517 if ( true === $skip_cache || false === $data || false === $expire_timestamp || $expire_timestamp < time() ) {
518 // Allow themes or other plugins to filter the config.
519 $data = apply_filters( 'customify_filter_fields', array() );
520 // We apply a second filter for those that wish to work with the final config and not rely on a a huge priority number.
521 $data = apply_filters( 'customify_final_config', $data );
522
523 if ( true !== $skip_cache ) {
524 // Cache the data in an option for 6 hours, but only if we are not supposed to skip the cache entirely.
525 update_option( $this->get_customizer_config_cache_key(), $data, false );
526 update_option( $this->get_customizer_config_cache_key() . '_timestamp', time() + 6 * HOUR_IN_SECONDS, true );
527 }
528 }
529
530 $this->customizer_config = $data;
531 return $data;
532 }
533
534 private function get_customizer_config_cache_key() {
535 return 'customify_customizer_config';
536 }
537
538 public function invalidate_customizer_config_cache() {
539 update_option( $this->get_customizer_config_cache_key() . '_timestamp' , time() - 24 * HOUR_IN_SECONDS, true );
540
541 $this->clear_locally_cached_data();
542 }
543
544 /**
545 * Invalidate the customizer config cache, when hooked via a filter (just pass through the value).
546 *
547 * @since 2.4.0
548 *
549 * @param mixed $value
550 * @return mixed
551 */
552 public function filter_invalidate_customizer_config_cache( $value ) {
553 $this->invalidate_customizer_config_cache();
554
555 return $value;
556 }
557
558 /**
559 * Get the Customify configuration (and value, hence "details") of a certain option.
560 *
561 * @param string $option_id
562 * @param bool $minimal_details Optional. Whether to return only the minimum amount of details (mainly what is needed on the frontend).
563 * The advantage is that these details are cached, thus skipping the customizer_config!
564 * @param bool $skip_cache Optional.
565 *
566 * @return array|false The option config or false on failure.
567 */
568 public function get_option_details( $option_id, $minimal_details = false, $skip_cache = false ) {
569 if ( empty( $option_id ) ) {
570 return false;
571 }
572
573 $options_details = $this->get_options_details( $minimal_details, $skip_cache );
574 if ( ! empty( $options_details ) && is_array( $options_details ) && isset( $options_details[ $option_id ] ) ) {
575 return $options_details[ $option_id ];
576 }
577
578 return false;
579 }
580
581 /**
582 * This is just a wrapper for get_options_details() for backwards compatibility.
583 *
584 * @param bool $only_minimal_details
585 * @param bool $skip_cache
586 *
587 * @return array|mixed|void
588 */
589 public function get_options_configs( $only_minimal_details = false, $skip_cache = false ) {
590 return $this->get_options_details( $only_minimal_details, $skip_cache );
591 }
592
593 /**
594 * Get the value of a setting ID saved in a wp_options array entry.
595 *
596 * @param string $option_id This is only the option ID, that may differ from setting ID ( like in `body_font` vs `rosa_opt[body_font]`)
597 * @param string $setting_id We will use this to get the Customizer value, when in that context.
598 *
599 * @return mixed|null
600 */
601 protected function get_option_mod_value( $option_id, $setting_id ) {
602 global $wp_customize;
603
604 if ( empty( $option_id ) || empty( $setting_id ) ) {
605 return null;
606 }
607
608 if ( ! empty( $wp_customize ) && method_exists( $wp_customize, 'get_setting' ) ) {
609 $setting = $wp_customize->get_setting( $setting_id );
610 if ( ! empty( $setting ) ) {
611 return $setting->value();
612 }
613 }
614
615 $values = get_option( $this->get_options_key() );
616
617 if ( ! empty( $values ) && is_array( $values ) && isset( $values[ $option_id ] ) ) {
618 return $values[ $option_id ];
619 }
620
621 return null;
622 }
623
624 /**
625 * Get the value of a certain setting ID saved in the theme mod array.
626 *
627 * @param string $option_id This is only the option ID, that may differ from setting ID ( like in `body_font` vs `rosa_opt[body_font]`)
628 * @param string $setting_id We will use this to get the Customizer value, when in that context.
629 *
630 * @return mixed|null
631 */
632 protected function get_theme_mod_value( $option_id, $setting_id ) {
633 global $wp_customize;
634
635 if ( empty( $option_id ) || empty( $setting_id ) ) {
636 return null;
637 }
638
639 if ( ! empty( $wp_customize ) && method_exists( $wp_customize, 'get_setting' ) ) {
640 $setting = $wp_customize->get_setting( $setting_id );
641 if ( ! empty( $setting ) ) {
642 return $setting->value();
643 }
644 }
645
646 $values = get_theme_mod( $this->get_options_key() );
647
648 if ( ! empty( $values ) && is_array( $values ) && isset( $values[ $option_id ] ) ) {
649 return $values[ $option_id ];
650 }
651
652 return null;
653 }
654
655 /**
656 * A public function to get an option's value.
657 * If there is a value and return it.
658 * Otherwise try to get the default parameter or the default from config.
659 *
660 * @param $option_id
661 * @param mixed $default Optional.
662 * @param array $option_details Optional.
663 *
664 * @return bool|null|string
665 */
666 public function get_option( $option_id, $default = null, $option_details = null ) {
667
668 if ( null === $option_details ) {
669 // Get the field config.
670 $option_details = $this->get_option_details( $option_id, true );
671 }
672
673 // If the development constant CUSTOMIFY_DEV_FORCE_DEFAULTS has been defined we will not retrieve anything from the database
674 // Always go with the default
675 if ( defined( 'CUSTOMIFY_DEV_FORCE_DEFAULTS' )
676 && true === CUSTOMIFY_DEV_FORCE_DEFAULTS
677 && ! $this->skip_dev_mode_force_defaults( $option_id, $option_details ) ) {
678
679 $value = null;
680 } else {
681
682 if ( empty( $option_id ) || empty( $option_details ) || ! is_array( $option_details ) ) {
683 $value = null;
684 } elseif ( isset( $option_details['value'] ) ) {
685 // If we already have the value cached in the option details, we will use that.
686 $value = $option_details['value'];
687 } else {
688 $value = null;
689
690 /*
691 * First determine the setting ID.
692 */
693 $setting_id = $this->get_options_key() . '[' . $option_id . ']';
694 // If we have been explicitly given a setting ID we will use that.
695 if ( ! empty( $option_details['setting_id'] ) ) {
696 $setting_id = $option_details['setting_id'];
697 }
698
699 /*
700 * Second, try to get the stored value of the setting.
701 */
702
703 // If we have a setting that directly declares it (not deduced like when registering fields in the Customizer)
704 // should be saved in the wp_options table, not in theme_mods, we will attempt to fetch it directly, first.
705 if ( isset( $option_details['setting_type'] ) && $option_details['setting_type'] === 'option' ) {
706 $value = get_option( $setting_id, null );
707 }
708
709 // If we don't have a value, we will grab the setting value from the array of values stored in either
710 // a wp_option entry or in the theme_mods.
711 // The "save as array" behavior happens even in the case of 'option' setting type if
712 // the setting ID is of the form 'rosa_option[some_key]' (aka a multidimensional setting ID).
713 if ( null === $value ) {
714 if ( PixCustomifyPlugin()->settings->get_plugin_setting( 'values_store_mod' ) === 'option' ) {
715 // Get the value stored in a option.
716 $value = $this->get_option_mod_value( $option_id, $setting_id );
717 } else {
718 // Get the value stored in theme_mods.
719 $value = $this->get_theme_mod_value( $option_id, $setting_id );
720 }
721 }
722 }
723 }
724
725 // If we have a non-null value, return it.
726 if ( $value !== null ) {
727 return $value;
728 }
729
730 // If we have a non-null default, return it.
731 if ( $default !== null ) {
732 return $default;
733 }
734
735 // Finally, attempt to use the default value set in the config, if available.
736 if ( ! empty( $option_details ) && is_array( $option_details ) && isset( $option_details['default'] ) ) {
737 return $option_details['default'];
738 }
739
740 return null;
741 }
742
743 /**
744 * Determine if we should NOT enforce the CUSTOMIFY_DEV_FORCE_DEFAULTS behavior on a certain option.
745 *
746 * @param string $option_id
747 * @param array $option_config Optional.
748 *
749 * @return bool
750 */
751 public function skip_dev_mode_force_defaults( $option_id, $option_config = null ) {
752 // Preprocess the $option_id.
753 if ( false !== strpos( $option_id, '::' ) ) {
754 $option_id = substr( $option_id, strpos( $option_id, '::' ) + 2 );
755 }
756 if ( false !== strpos( $option_id, '[' ) ) {
757 $option_id = explode( '[', $option_id );
758 $option_id = rtrim( $option_id[1], ']' );
759 }
760
761 if ( null === $option_config ) {
762 $option_config = $this->get_option_details( $option_id, true );
763 }
764 if ( empty( $option_config ) || ! is_array( $option_config ) ) {
765 return false;
766 }
767
768 // We will skip certain field types that generally don't have a default value.
769 if ( ! empty( $option_config['type'] ) ) {
770 switch ( $option_config['type'] ) {
771 case 'cropped_image':
772 case 'cropped_media':
773 case 'image':
774 case 'media':
775 case 'custom_background':
776 case 'upload':
777 return true;
778 break;
779 default:
780 break;
781 }
782 }
783
784 return false;
785 }
786
787 public function get_version() {
788 return $this->_version;
789 }
790
791 public function get_slug() {
792 return $this->plugin_slug;
793 }
794
795 public function get_file() {
796 return $this->file;
797 }
798
799 public function get_base_path() {
800 return wp_normalize_path( plugin_dir_path( $this->file ) );
801 }
802
803 /**
804 * Load the plugin text domain for translation.
805 * @since 1.0.0
806 */
807 function load_plugin_textdomain() {
808 $domain = $this->plugin_slug;
809 load_plugin_textdomain( $domain, false, basename( dirname( $this->file ) ) . '/languages/' );
810 }
811
812 /**
813 * Checks whether an array is associative or not
814 *
815 * @param array $array
816 *
817 * @return bool
818 */
819 public function is_assoc( $array ) {
820
821 if ( ! is_array( $array ) ) {
822 return false;
823 }
824
825 // Keys of the array
826 $keys = array_keys( $array );
827
828 // If the array keys of the keys match the keys, then the array must
829 // not be associative (e.g. the keys array looked like {0:0, 1:1...}).
830 return array_keys( $keys ) !== $keys;
831 }
832
833 /**
834 * Does the same thing the JS encodeURIComponent() does
835 *
836 * @param string $str
837 *
838 * @return string
839 */
840 public static function encodeURIComponent( $str ) {
841 //if we get an array we just let it be
842 if ( is_string( $str ) ) {
843 $revert = array( '%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')' );
844 $str = strtr( rawurlencode( $str ), $revert );
845 }
846
847 return $str;
848 }
849
850 /**
851 * Does the same thing the JS decodeURIComponent() does
852 *
853 * @param string $str
854 *
855 * @return string
856 */
857 public static function decodeURIComponent( $str ) {
858 // If we get an array we just let it be
859 if ( is_string( $str ) ) {
860 $revert = array( '!' => '%21', '*' => '%2A', "'" => '%27', '(' => '%28', ')' => '%29' );
861 $str = rawurldecode( strtr( $str, $revert ) );
862 }
863
864 return $str;
865 }
866
867 /**
868 * PHP version check
869 */
870 protected function php_version_check() {
871
872 if ( version_compare( phpversion(), $this->minimalRequiredPhpVersion ) < 0 ) {
873 add_action( 'admin_notices', array( $this, 'notice_php_version_wrong' ) );
874
875 return false;
876 }
877
878 return true;
879 }
880
881 /*
882 * Install everything needed
883 */
884 static public function install() {
885 $config = Customify_Settings::get_plugin_config();
886
887 $defaults = array(
888
889 # Hidden fields
890 'settings_saved_once' => '0',
891 # General
892 'values_store_mod' => 'theme_mod',
893
894 'typography' => true,
895 'typography_standard_fonts' => true,
896 'typography_google_fonts' => true,
897 'typography_group_google_fonts' => true,
898 'disable_default_sections' => array(),
899 'disable_customify_sections' => array(),
900 'enable_reset_buttons' => false,
901 'enable_editor_style' => true,
902 'style_resources_location' => 'wp_head'
903 );
904
905 $current_data = get_option( $config['settings-key'] );
906
907 if ( $current_data === false ) {
908 add_option( $config['settings-key'], $defaults );
909 } elseif ( count( array_diff_key( $defaults, $current_data ) ) != 0) {
910 $plugin_data = array_merge( $defaults, $current_data );
911 update_option( $config['settings-key'], $plugin_data );
912 }
913 }
914
915 /**
916 * Main PixCustomifyPlugin Instance
917 *
918 * Ensures only one instance of PixCustomifyPlugin is loaded or can be loaded.
919 *
920 * @since 1.0.0
921 * @static
922 *
923 * @param string $file File.
924 * @param string $version Version.
925 *
926 * @see PixCustomifyPlugin()
927 * @return PixCustomifyPlugin Main PixCustomifyPlugin instance
928 */
929 public static function instance( $file = '', $version = '1.0.0' ) {
930 // If the single instance hasn't been set, set it now.
931 if ( is_null( self::$_instance ) ) {
932 self::$_instance = new self( $file, $version );
933 }
934
935 return self::$_instance;
936 }
937
938 /**
939 * Cloning is forbidden.
940 *
941 * @since 1.5.0
942 */
943 public function __clone() {
944
945 _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
946 }
947
948 /**
949 * Unserializing instances of this class is forbidden.
950 *
951 * @since 1.5.0
952 */
953 public function __wakeup() {
954
955 _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
956 }
957 }
958