PluginProbe
Customify / 1.7.1
Customify v1.7.1
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 / class-pixcustomify.php

class-pixcustomify.php in Customify 1.7.1, at class-pixcustomify.php

2,301 lines 67.9 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-2017 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 * Slug of the plugin screen.
42 * @since 1.0.0
43 * @var string
44 */
45 protected $plugin_screen_hook_suffix = null;
46
47 /**
48 * Path to the plugin.
49 * @since 1.0.0
50 * @var string
51 */
52 protected $plugin_basepath = null;
53
54 public $display_admin_menu = false;
55
56 private $config;
57
58 private $customizer_config;
59
60 public $plugin_settings;
61
62 protected $localized = array();
63
64 protected $current_values = array();
65
66 protected $options_list = array();
67
68 protected $media_queries = array();
69
70 protected $opt_name;
71
72 protected $typo_settings;
73
74 protected $google_fonts = null;
75
76 protected $theme_fonts = null;
77
78 // these properties will get 'px' as a default unit
79 protected static $pixel_dependent_css_properties = array(
80 'width',
81 'max-width',
82 'min-width',
83
84 'height',
85 'max-height',
86 'min-height',
87
88 'padding',
89 'padding-left',
90 'padding-right',
91 'padding-top',
92 'padding-bottom',
93
94 'margin',
95 'margin-right',
96 'margin-left',
97 'margin-top',
98 'margin-bottom',
99
100 'right',
101 'left',
102 'top',
103 'bottom',
104
105 'font-size',
106 'letter-spacing',
107
108 'border-size',
109 'border-width',
110 'border-bottom-width',
111 'border-left-width',
112 'border-right-width',
113 'border-top-width'
114 );
115
116 protected $jetpack_default_modules = array();
117 protected $jetpack_blocked_modules = array();
118 protected $jetpack_sharing_default_options = array();
119
120 /**
121 * The main plugin file.
122 * @var string
123 * @access public
124 * @since 1.5.0
125 */
126 public $file;
127
128 /**
129 * Style Manager class object.
130 * @var Customify_Style_Manager
131 * @access public
132 * @since 1.0.0
133 */
134 public $style_manager = null;
135
136 /**
137 * Minimal Required PHP Version
138 * @var string
139 * @access private
140 * @since 1.5.0
141 */
142 private $minimalRequiredPhpVersion = 5.2;
143
144 protected function __construct( $file, $version = '1.0.0' ) {
145 //the main plugin file (the one that loads all this)
146 $this->file = $file;
147 //the current plugin version
148 $this->_version = $version;
149
150 // Remember our base path
151 $this->plugin_basepath = plugin_dir_path( $file );
152
153 if ( $this->php_version_check() ) {
154 // Only load and run the init function if we know PHP version can parse it.
155 $this->init();
156 }
157 }
158
159 /**
160 * Initialize plugin
161 */
162 private function init() {
163 // Load the config file
164 $this->config = $this->get_config();
165 // Load the plugin's settings from the DB
166 $this->plugin_settings = get_option( $this->config['settings-key'] );
167
168 /* Initialize the Style Manager logic. */
169 require_once( $this->plugin_basepath . 'includes/class-customify-style-manager.php' );
170 if ( is_null( $this->style_manager ) ) {
171 $this->style_manager = Customify_Style_Manager::instance( $this );
172 }
173
174 // Register all the needed hooks
175 $this->register_hooks();
176 }
177
178 /**
179 * Register our actions and filters
180 */
181 function register_hooks() {
182 /*
183 * Register hooks that are fired when the plugin is activated, deactivated, and uninstalled, respectively.
184 */
185 register_activation_hook( $this->file, array( $this, 'activate' ) );
186 register_deactivation_hook( $this->file, array( $this, 'deactivate' ) );
187
188 /*
189 * Load plugin text domain
190 */
191 add_action( 'init', array( $this, 'load_plugin_textdomain' ) );
192
193 /*
194 * Prepare and load the configuration
195 */
196 $this->init_plugin_configs();
197
198 // We need to load the configuration as late as possible so we allow all that want to influence it
199 // We need the init hook and not after_setup_theme because there a number of plugins that fire up on init (like certain modules from Jetpack)
200 // We need to be able to load things like components configs depending on those firing up or not
201 // DO NOT TRY to use the Customify values before this!
202 add_action( 'init', array( $this, 'load_plugin_configs' ), 15 );
203
204 /*
205 * Now setup the admin side of things
206 */
207 // Starting with the menu item for this plugin
208 add_action( 'admin_menu', array( $this, 'add_plugin_admin_menu' ) );
209
210 // Add an action link pointing to the options page.
211 $plugin_basename = plugin_basename( plugin_dir_path( $this->file ) . 'pixcustomify.php' );
212 add_filter( 'plugin_action_links_' . $plugin_basename, array( $this, 'add_action_links' ) );
213
214 // Load admin style sheet and JavaScript.
215 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_styles' ) );
216 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_admin_scripts' ) );
217
218 /*
219 * Now it's time for the Customizer logic to kick in
220 */
221 // Styles for the Customizer
222 add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_styles' ), 10 );
223 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_styles' ), 10 );
224 // Scripts enqueued in the Customizer
225 add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 15 );
226 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 15 );
227
228 // Scripts enqueued only in the theme preview
229 add_action( 'customize_preview_init', array( $this, 'customizer_live_preview_register_scripts' ), 10 );
230 add_action( 'customize_preview_init', array( $this, 'customizer_live_preview_enqueue_scripts' ), 99999 );
231
232 // Add extra settings data to _wpCustomizeSettings.settings of the parent window.
233 add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_pane_settings_additional_data' ), 10000 );
234
235 // The frontend effects of the Customizer controls
236 $load_location = $this->get_plugin_setting( 'style_resources_location', 'wp_head' );
237
238 add_action( $load_location, array( $this, 'output_dynamic_style' ), 99 );
239 add_action( 'wp_head', array( $this, 'output_typography_dynamic_style' ), 10 );
240
241 add_action( 'customize_register', array( $this, 'remove_default_sections' ), 11 );
242 add_action( 'customize_register', array( $this, 'register_customizer' ), 12 );
243
244 if ( $this->get_plugin_setting( 'enable_editor_style', true ) ) {
245 add_action( 'admin_head', array( $this, 'add_customizer_settings_into_wp_editor' ) );
246 }
247
248 add_action( 'rest_api_init', array( $this, 'add_rest_routes_api' ) );
249
250 /*
251 * Development related
252 */
253 if ( defined( 'CUSTOMIFY_DEV_FORCE_DEFAULTS' ) && true === CUSTOMIFY_DEV_FORCE_DEFAULTS ) {
254 // If the development constant CUSTOMIFY_DEV_FORCE_DEFAULTS has been defined we will not save anything in the database
255 // Always go with the default
256 add_filter( 'customize_changeset_save_data', array( $this, 'prevent_changeset_save_in_devmode' ), 50, 2 );
257 // Add a JS to display a notification
258 add_action( 'customize_controls_print_footer_scripts', array( $this, 'prevent_changeset_save_in_devmode_notification' ), 100 );
259 }
260 }
261
262 /**
263 * Initialize Configs, Options and Values methods
264 */
265 function init_plugin_configs() {
266 $this->customizer_config = get_option( 'pixcustomify_config' );
267
268 // no option so go for default
269 if ( empty( $this->customizer_config ) ) {
270 $this->customizer_config = $this->get_config_option( 'default_options' );
271 }
272
273 if ( empty( $this->customizer_config ) ) {
274 $this->customizer_config = array();
275 }
276 }
277
278 /**
279 * Load the plugin configuration and options
280 */
281 function load_plugin_configs() {
282
283 // Allow themes or other plugins to filter the config.
284 $this->customizer_config = apply_filters( 'customify_filter_fields', $this->customizer_config );
285 $this->opt_name = $this->localized['options_name'] = $this->customizer_config['opt-name'];
286 $this->options_list = $this->get_options();
287
288 // Load the current options values.
289 $this->current_values = $this->get_current_values();
290
291 if ( $this->import_button_exists() ) {
292 $this->localized['import_rest_url'] = get_rest_url( '/customify/1.0/' );
293 $this->localized['import_rest_nonce'] = wp_create_nonce( 'wp_rest' );
294
295 $this->register_import_api();
296 }
297
298 $this->localized['theme_fonts'] = $this->theme_fonts = Customify_Font_Selector::instance()->get_theme_fonts();
299
300 $this->localized['ajax_url'] = admin_url( 'admin-ajax.php' );
301 $this->localized['style_manager_user_feedback_nonce'] = wp_create_nonce( 'customify_style_manager_user_feedback' );
302 $this->localized['style_manager_user_feedback_provided'] = $this->get_option( 'style_manager_user_feedback_provided', false );
303 }
304
305 public function get_version() {
306 return $this->_version;
307 }
308
309 public function get_slug() {
310 return $this->plugin_slug;
311 }
312
313 /**
314 * Fired when the plugin is activated.
315 * @since 1.0.0
316 *
317 * @param boolean $network_wide True if WPMU superadmin uses "Network Activate" action, false if WPMU is disabled or plugin is activated on an individual blog.
318 */
319 public static function activate( $network_wide ) {
320 //@todo Define activation functionality here
321 }
322
323 /**
324 * Fired when the plugin is deactivated.
325 * @since 1.0.0
326 *
327 * @param boolean $network_wide True if WPMU superadmin uses "Network Deactivate" action, false if WPMU is disabled or plugin is deactivated on an individual blog.
328 */
329 static function deactivate( $network_wide ) {
330 //@todo Define deactivation functionality here
331 }
332
333 /**
334 * Load the plugin text domain for translation.
335 * @since 1.0.0
336 */
337 function load_plugin_textdomain() {
338 $domain = $this->plugin_slug;
339 load_plugin_textdomain( $domain, false, basename( dirname( $this->file ) ) . '/languages/' );
340 }
341
342 /** === RESOURCES === **/
343
344 /**
345 * Register Customizer admin styles
346 */
347 function register_admin_customizer_styles() {
348 wp_register_style( 'customify_select2', plugins_url( 'js/select2/css/select2.css', $this->file ), array(), $this->_version );
349 wp_register_style( 'customify_style', plugins_url( 'css/customizer.css', $this->file ), array( 'customify_select2' ), $this->_version );
350 }
351
352 /**
353 * Enqueue Customizer admin styles
354 */
355 function enqueue_admin_customizer_styles() {
356 wp_enqueue_style( 'customify_style' );
357 }
358
359 /**
360 * Register Customizer admin scripts
361 */
362 function register_admin_customizer_scripts() {
363
364 wp_register_script( 'customify_select2', plugins_url( 'js/select2/js/select2.js', $this->file ), array( 'jquery' ), $this->_version );
365 wp_register_script( 'jquery-react', plugins_url( 'js/jquery-react.js', $this->file ), array( 'jquery' ), $this->_version );
366
367 wp_register_script( 'customify-scale', plugins_url( 'js/customizer/customify-scale.js', $this->file ), array( 'jquery' ), $this->_version );
368
369 wp_register_script( $this->plugin_slug . '-customizer-scripts', plugins_url( 'js/customizer.js', $this->file ), array(
370 'jquery',
371 'customify_select2',
372 'underscore',
373 'customize-controls',
374
375 'customify-scale',
376 ), $this->_version );
377 }
378
379 /**
380 * Enqueue Customizer admin scripts
381 */
382 function enqueue_admin_customizer_scripts() {
383 wp_enqueue_script( 'jquery-react' );
384 wp_enqueue_script( $this->plugin_slug . '-customizer-scripts' );
385
386 wp_localize_script( $this->plugin_slug . '-customizer-scripts', 'customify_settings', $this->localized );
387 }
388
389 /** Register Customizer scripts loaded only on previewer page */
390 function customizer_live_preview_register_scripts() {
391 wp_register_script( $this->plugin_slug . 'CSSOM', plugins_url( 'js/CSSOM.js', $this->file ), array( 'jquery' ), $this->_version, true );
392 wp_register_script( $this->plugin_slug . 'cssUpdate', plugins_url( 'js/jquery.cssUpdate.js', $this->file ), array(), $this->_version, true );
393 wp_register_script( $this->plugin_slug . '-previewer-scripts', plugins_url( 'js/customizer_preview.js', $this->file ), array(
394 'jquery',
395 'customize-preview',
396 $this->plugin_slug . 'CSSOM',
397 $this->plugin_slug . 'cssUpdate'
398 ), $this->_version, true );
399 }
400
401 /** Enqueue Customizer scripts loaded only on previewer page */
402 function customizer_live_preview_enqueue_scripts() {
403 wp_enqueue_script( $this->plugin_slug . '-previewer-scripts' );
404
405 // when a live preview field is in action we need to know which props need 'px' as defaults
406 $this->localized['px_dependent_css_props'] = self::$pixel_dependent_css_properties;
407
408 wp_localize_script( $this->plugin_slug . '-previewer-scripts', 'customify_settings', $this->localized );
409 }
410
411 /**
412 * Add dynamic style only on the previewer page
413 */
414
415 /**
416 * Settings page styles
417 */
418 function enqueue_admin_styles() {
419
420 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
421 return;
422 }
423
424 $screen = get_current_screen();
425 if ( $screen->id == $this->plugin_screen_hook_suffix ) {
426 wp_enqueue_style( $this->plugin_slug . '-admin-styles', plugins_url( 'css/admin.css', $this->file ), array(), $this->_version );
427 }
428 }
429
430 /**
431 * Settings page scripts
432 */
433 function enqueue_admin_scripts() {
434
435 if ( ! isset( $this->plugin_screen_hook_suffix ) ) {
436 return;
437 }
438
439 $screen = get_current_screen();
440 if ( $screen->id == $this->plugin_screen_hook_suffix ) {
441 wp_enqueue_script( $this->plugin_slug . '-admin-script', plugins_url( 'js/admin.js', $this->file ), array( 'jquery' ), $this->_version );
442 wp_localize_script( $this->plugin_slug . '-admin-script', 'customify_settings', array(
443 'ajax_url' => admin_url( 'admin-ajax.php' ),
444 'wp_rest' => array(
445 'root' => esc_url_raw( rest_url() ),
446 'nonce' => wp_create_nonce( 'wp_rest' ),
447 'customify_settings_nonce' => wp_create_nonce( 'customify_settings_nonce' )
448 ),
449 ) );
450 }
451
452 wp_localize_script( $this->plugin_slug . '-customizer-scripts', 'WP_API_Settings', array(
453 'root' => esc_url_raw( rest_url() ),
454 'nonce' => wp_create_nonce( 'wp_rest' )
455 ) );
456 }
457
458 function add_rest_routes_api(){
459 register_rest_route( 'customify/v1', '/delete_theme_mod', array(
460 'methods' => 'POST',
461 'callback' => array( $this, 'delete_theme_mod' ),
462 'permission_callback' => array( $this, 'permission_nonce_callback' ),
463 ) );
464 }
465
466 function delete_theme_mod(){
467 if ( ! current_user_can( 'manage_options' ) ) {
468 wp_send_json_error('You don\'t have admin privileges.');
469 }
470
471 $config = apply_filters('customify_filter_fields', array() );
472
473 if ( empty( $config['opt-name'] ) ) {
474 wp_send_json_error('no option key');
475 }
476
477 $key = $config['opt-name'];
478
479 remove_theme_mod( $key );
480
481 wp_send_json_success('Deleted ' . $key . ' theme mod!');
482 }
483
484 function permission_nonce_callback() {
485 return wp_verify_nonce( $this->get_nonce(), 'customify_settings_nonce' );
486 }
487
488 private function get_nonce() {
489 $nonce = null;
490
491 if ( isset( $_REQUEST['customify_settings_nonce'] ) ) {
492 $nonce = wp_unslash( $_REQUEST['customify_settings_nonce'] );
493 } elseif ( isset( $_POST['customify_settings_nonce'] ) ) {
494 $nonce = wp_unslash( $_POST['customify_settings_nonce'] );
495 }
496
497 return $nonce;
498 }
499
500 /**
501 * Public style generated by customizer
502 */
503 function output_dynamic_style() {
504 $custom_css = '';
505
506 foreach ( $this->options_list as $option_id => $option ) {
507
508 if ( isset( $option['css'] ) && ! empty( $option['css'] ) ) {
509 // now process each
510 $custom_css .= $this->convert_setting_to_css( $option_id, $option['css'] );
511 }
512
513 if ( isset( $option['type'] ) && $option['type'] === 'custom_background' ) {
514 $option['value'] = $this->get_option( $option_id );
515 $custom_css .= $this->process_custom_background_field_output( $option_id, $option ) . PHP_EOL;
516 }
517 }
518
519 if ( ! empty( $this->media_queries ) ) {
520
521 foreach ( $this->media_queries as $media_query => $properties ) {
522
523 if ( empty( $properties ) ) {
524 continue;
525 }
526
527 $custom_css .= PHP_EOL . '@media ' . $media_query . " { " . PHP_EOL . PHP_EOL;
528
529 foreach ( $properties as $key => $property ) {
530 $property_settings = $property['property'];
531 $property_value = $property['value'];
532 $custom_css .= "\t" . $this->proccess_css_property( $property_settings, $property_value ) . PHP_EOL;
533 }
534
535 $custom_css .= "}" . PHP_EOL;
536
537 }
538 }
539 ?>
540 <style id="customify_output_style">
541 <?php echo apply_filters( 'customify_dynamic_style', $custom_css ); ?>
542 </style><?php
543
544 /**
545 * from now on we output only style tags only for the preview purpose
546 * so don't cry if you see 30+ style tags for each section
547 */
548 if ( ! isset( $GLOBALS['wp_customize'] ) ) {
549 return;
550 }
551
552 foreach ( $this->options_list as $option_id => $options ) {
553
554 if ( isset( $options['type'] ) && $options['type'] === 'custom_background' ) {
555 $options['value'] = $this->get_option( $option_id );
556 $custom_background_output = $this->process_custom_background_field_output( $option_id, $options ); ?>
557
558 <style id="custom_background_output_for_<?php echo sanitize_html_class( $option_id ); ?>">
559 <?php
560 if ( isset( $custom_background_output ) && ! empty( $custom_background_output )) {
561 echo $custom_background_output;
562 } ?>
563 </style>
564 <?php }
565
566 if ( ! isset( $options['live'] ) || $options['live'] !== true ) {
567 continue;
568 }
569
570 $this_value = $this->get_option( $option_id );
571 if ( ! empty( $options['css'] ) ) {
572 foreach ( $options['css'] as $key => $properties_set ) {
573 // We need to use a class because we may have multiple <style>s with the same "ID" for example
574 // when targeting the same property but with different selectors.
575 ?>
576 <style class="dynamic_setting_<?php echo sanitize_html_class( $option_id ) . '_property_' . str_replace( '-', '_', $properties_set['property'] ); ?>"
577 type="text/css"><?php
578
579 if ( isset( $properties_set['media'] ) && ! empty( $properties_set['media'] ) ) {
580 echo '@media '. $properties_set['media'] . " {" . PHP_EOL;
581 }
582
583 if ( isset( $properties_set['selector'] ) && isset( $properties_set['property'] ) ) {
584 echo $this->proccess_css_property($properties_set, $this_value) . PHP_EOL;
585 }
586
587 if ( isset( $properties_set['media'] ) && ! empty( $properties_set['media'] ) ) {
588 echo "}" . PHP_EOL;
589 } ?>
590 </style>
591 <?php }
592 }
593 }
594 }
595
596 protected function load_google_fonts() {
597 $fonts_path = plugin_dir_path( $this->file ) . 'features/customizer/controls/resources/google.fonts.php';
598
599 if ( file_exists( $fonts_path ) ) {
600 $this->google_fonts = require( $fonts_path );
601 }
602
603 if ( ! empty( $this->google_fonts ) ) {
604 return $this->google_fonts;
605 }
606
607 return false;
608 }
609
610 function output_typography_dynamic_style() {
611 $this->get_typography_fields( $this->options_list, 'type', 'typography', $this->typo_settings );
612
613 if ( empty( $this->typo_settings ) ) {
614 return;
615 }
616
617 $families = '';
618
619 foreach ( $this->typo_settings as $id => $font ) {
620 if ( isset ( $font['value'] ) ) {
621
622 $load_all_weights = false;
623 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
624 $load_all_weights = true;
625 }
626
627 // shim the time when this was an array
628 // @todo Is this really needed? Or does it make sense?
629 if ( is_array( $font['value'] ) ) {
630 $font['value'] = stripslashes_deep( $font['value'] );
631 $font['value'] = json_encode( $font['value'] );
632 }
633
634 $value = wp_unslash( PixCustomifyPlugin::decodeURIComponent( $font['value'] ) );
635 if ( is_string( $value ) ) {
636 $value = json_decode( $value, true );
637 }
638
639 // In case the value is still null, try default value (mostly for google fonts)
640 if ( $value === null || ! is_array( $value ) ) {
641 $value = $this->get_font_defaults_value( str_replace( '"', '', $font['value'] ) );
642 }
643
644 // Bail if by this time we don't have a value of some sort
645 if ( empty( $value ) ) {
646 continue;
647 }
648
649 // Handle special logic for when the $value array is not an associative array
650 if ( ! $this->is_assoc( $value ) ) {
651 $value = $this->standardize_non_associative_font_default( $value );
652 }
653
654 // Bail if empty or we don't have an array
655 if ( empty( $value ) || ! is_array( $value ) ) {
656 continue;
657 }
658
659 if ( isset( $value['font_family'] ) && isset( $value['type'] ) && $value['type'] == 'google' ) {
660 $families .= "'" . $value['font_family'];
661
662 if ( $load_all_weights && is_array( $value['variants'] ) ) {
663 $families .= ":" . implode( ',', $value['variants'] );
664 } elseif ( isset( $value['selected_variants'] ) && ! empty( $value['selected_variants'] ) ) {
665 if ( is_array( $value['selected_variants'] ) ) {
666 $families .= ":" . implode( ',', $value['selected_variants'] );
667 } elseif ( is_string( $value['selected_variants'] ) || is_numeric( $value['selected_variants'] ) ) {
668 $families .= ":" . $value['selected_variants'];
669 }
670 } elseif ( isset( $value['variants'] ) && ! empty( $value['variants'] ) ) {
671 if ( is_array( $value['variants'] ) ) {
672 $families .= ":" . implode( ',', $value['variants'] );
673 } else {
674 $families .= ":" . $value['variants'];
675 }
676 }
677
678 if ( isset( $value['selected_subsets'] ) && ! empty( $value['selected_subsets'] ) ) {
679 if ( is_array( $value['selected_subsets'] ) ) {
680 $families .= ":" . implode( ',', $value['selected_subsets'] );
681 } else {
682 $families .= ":" . $value['selected_subsets'];
683 }
684 } elseif ( isset( $value['subsets'] ) && ! empty( $value['subsets'] ) ) {
685 if ( is_array( $value['subsets'] ) ) {
686 $families .= ":" . implode( ',', $value['subsets'] );
687 } else {
688 $families .= ":" . $value['subsets'];
689 }
690 }
691
692 $families .= '\',';
693 }
694 }
695 }
696
697 if ( ! empty ( $families ) && $this->get_plugin_setting( 'typography', '1' ) && $this->get_plugin_setting( 'typography_google_fonts', 1 ) ) { ?>
698 <script type="text/javascript">
699 if (typeof WebFont !== 'undefined') {<?php // if there is a WebFont object, use it ?>
700 WebFont.load({
701 google: {families: [<?php echo( rtrim( $families, ',' ) ); ?>]},
702 classes: false,
703 events: false
704 });
705 } else {<?php // basically when we don't have the WebFont object we create the google script dynamically ?>
706
707 var tk = document.createElement('script');
708 tk.src = '//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
709 tk.type = 'text/javascript';
710
711 tk.onload = tk.onreadystatechange = function () {
712 WebFont.load({
713 google: {families: [<?php echo( rtrim( $families, ',' ) ); ?>]},
714 classes: false,
715 events: false
716 });
717 };
718
719 var s = document.getElementsByTagName('script')[0];
720 s.parentNode.insertBefore(tk, s);
721 }
722 </script>
723 <?php } ?>
724 <style id="customify_typography_output_style">
725 <?php
726 foreach ( $this->typo_settings as $key => $font ) {
727 $load_all_weights = false;
728 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
729 $load_all_weights = true;
730 }
731
732 if ( isset( $font['selector'] ) && isset( $font['value'] ) && ! empty( $font['value'] ) ) {
733 // Make sure that the value is in the proper format
734 $value = PixCustomifyPlugin::decodeURIComponent( $font['value'] );
735 if ( is_string( $value ) ) {
736 $value = json_decode( $value, true );
737 }
738
739 // In case the value is null (most probably because the json_decode failed),
740 // try the default value (mostly for google fonts)
741 if ( $value === null ) {
742 $value = $this->get_font_defaults_value( $font['value'] );
743 }
744
745 // Shim the old case when the default was only the font name
746 if ( ! empty( $value ) && is_string( $value ) ) {
747 $value = array( 'font_family' => $value );
748 }
749
750 // Handle special logic for when the $value array is not an associative array
751 if ( ! $this->is_assoc( $value ) ) {
752 $value = $this->standardize_non_associative_font_default( $value );
753 }
754
755 // Bail if empty or we don't have an array
756 if ( empty( $value ) || ! is_array( $value ) ) {
757 continue;
758 }
759
760 $selected_variant = '';
761 if ( ! empty( $value['selected_variants'] ) ) {
762 if ( is_array( $value['selected_variants'] ) ) {
763 $selected_variant = $value['selected_variants'][0];
764 } else {
765 $selected_variant = $value['selected_variants'];
766 }
767 }
768
769 // First handle the case where we have the font-family in the selected variant (usually this means a custom font from our Fonto plugin)
770 if ( ! empty( $selected_variant ) && is_array( $selected_variant ) && ! empty( $selected_variant['font-family'] ) ) {
771 // The variant's font-family
772 echo $font['selector'] . " {\nfont-family: " . $selected_variant['font-family'] . ";\n";
773
774 if ( ! $load_all_weights ) {
775 // If this is a custom font (like from our plugin Fonto) with individual styles & weights - i.e. the font-family says it all
776 // we need to "force" the font-weight and font-style
777 if ( ! empty( $value['type'] ) && 'custom_individual' == $value['type'] ) {
778 $selected_variant['font-weight'] = '400 !important';
779 $selected_variant['font-style'] = 'normal !important';
780 }
781
782 // Output the font weight, if available
783 if ( ! empty( $selected_variant['font-weight'] ) ) {
784 echo "font-weight: " . $selected_variant['font-weight'] . ";\n";
785 }
786
787 // Output the font style, if available
788 if ( ! empty( $selected_variant['font-style'] ) ) {
789 echo "font-style: " . $selected_variant['font-style'] . ";\n";
790 }
791 }
792
793 echo "}\n";
794 } elseif ( isset( $value['font_family'] ) ) {
795 // The selected font family
796 echo $font['selector'] . " {\n font-family: " . $value['font_family'] . ";\n";
797
798 if ( ! empty( $selected_variant ) && ! $load_all_weights ) {
799 $weight_and_style = strtolower( $selected_variant );
800
801 $italic_font = false;
802
803 //determine if this is an italic font (the $weight_and_style is usually like '400' or '400italic' )
804 if ( strpos( $weight_and_style, 'italic' ) !== false ) {
805 $weight_and_style = str_replace( 'italic', '', $weight_and_style);
806 $italic_font = true;
807 }
808
809 if ( ! empty( $weight_and_style ) ) {
810 //a little bit of sanity check - in case it's not a number
811 if( $weight_and_style === 'regular' ) {
812 $weight_and_style = 'normal';
813 }
814 echo "font-weight: " . $weight_and_style . ";\n";
815 }
816
817 if ( $italic_font ) {
818 echo "font-style: italic;\n";
819 }
820 }
821
822 echo "}\n";
823 }
824 }
825 } ?>
826 </style>
827 <?php }
828
829 /**
830 * Handle special logic for when the $value array is not an associative array
831 * Return a new associative array with proper keys
832 */
833 public function standardize_non_associative_font_default( $value ) {
834 // If the value provided is not array, simply return it
835 if ( ! is_array( $value ) ) {
836 return $value;
837 }
838
839 $new_value = array();
840
841 // Let's determine some type of font
842 if ( ! isset( $value[2] ) || 'google' == $value[2] ) {
843 $new_value = $this->get_font_defaults_value( $value[0] );
844 } else {
845 $new_value['type'] = $value[2];
846 }
847
848 if ( null == $new_value ) {
849 $new_value = array();
850 }
851
852 // The first entry is the font-family
853 if ( isset( $value[0] ) ) {
854 $new_value['font_family'] = $value[0];
855 }
856
857 // In case we don't have an associative array
858 // The second entry is the variants
859 if ( isset( $value[1] ) ) {
860 $new_value['selected_variants'] = $value[1];
861 }
862
863 return $new_value;
864 }
865
866 /**
867 *
868 * @param $font_name
869 *
870 * @return null
871 */
872 public function get_font_defaults_value( $font_name ) {
873
874 if ( empty( $this->google_fonts ) ) {
875 $this->load_google_fonts();
876 }
877
878 if ( isset( $this->google_fonts[ $font_name ] ) ) {
879 $value = $this->google_fonts[ $font_name ];
880 $value['font_family'] = $font_name;
881 $value['type'] = 'google';
882
883 return $value;
884 } elseif ( isset( $this->theme_fonts[ $font_name ] ) ) {
885 $value['type'] = 'theme_font';
886 $value['src'] = $this->theme_fonts[ $font_name ]['src'];
887 $value['variants'] = $this->theme_fonts[ $font_name ]['variants'];
888 $value['font_family'] = $this->theme_fonts[ $font_name ]['family'];
889
890 return $value;
891 }
892
893 return null;
894 }
895
896 /**
897 * Turn css options into a valid CSS output
898 *
899 * @param $option_id
900 * @param array $css_config
901 *
902 * @return string
903 */
904 protected function convert_setting_to_css( $option_id, $css_config = array() ) {
905 $output = '';
906
907 $this_value = $this->get_option( $option_id );
908
909 if ( empty( $css_config ) ) {
910 return $output;
911 }
912
913 foreach ( $css_config as $css_property ) {
914
915 if ( isset( $css_property['media'] ) && ! empty( $css_property['media'] ) ) {
916 $this->media_queries[ $css_property['media'] ][ $option_id ] = array(
917 'property' => $css_property,
918 'value' => $this_value
919 );
920 continue;
921 }
922
923 if ( isset( $css_property['selector'] ) && isset( $css_property['property'] ) ) {
924 $output .= $this->proccess_css_property( $css_property, $this_value ) . PHP_EOL;
925 }
926 }
927
928 return $output;
929 }
930
931 protected function proccess_css_property( $css_property, $this_value ) {
932 $unit = '';
933
934 if ( isset( $css_property['unit'] ) ) {
935 $unit = $css_property['unit'];
936 }
937
938 // if the unit isn't specified but the property should have a unit force 'px' as it
939 if ( empty( $unit ) && in_array( $css_property['property'], self::$pixel_dependent_css_properties ) ) {
940 $unit = 'px';
941 }
942 // lose the tons of tabs
943 $css_property['selector'] = trim( preg_replace( '/\t+/', '', $css_property['selector'] ) );
944
945 $this_property_output = $css_property['selector'] . ' { ' . $css_property['property'] . ': ' . $this_value . $unit . "; }" . PHP_EOL;
946
947 // Handle the value filter callback.
948 if ( isset( $css_property['filter_value_cb'] ) ) {
949 $this_value = $this->maybe_apply_filter( $css_property['filter_value_cb'], $this_value );
950 }
951
952 // Handle output callback.
953 if ( isset( $css_property['callback_filter'] ) && is_callable( $css_property['callback_filter'] ) ) {
954 $this_property_output = call_user_func( $css_property['callback_filter'], $this_value, $css_property['selector'], $css_property['property'], $unit );
955 }
956
957 return $this_property_output;
958 }
959
960 /**
961 * Apply a filter (config) to a value.
962 *
963 * We currently handle filters like these:
964 * // Elaborate filter config
965 * array(
966 * 'callback' => 'is_post_type_archive',
967 * // The arguments we should pass to the check function.
968 * // Think post types, taxonomies, or nothing if that is the case.
969 * // It can be an array of values or a single value.
970 * 'args' => array(
971 * 'jetpack-portfolio',
972 * ),
973 * ),
974 * // Simple filter - just the function name
975 * 'is_404',
976 *
977 * @param array|string $filter
978 * @param mixed $value The value to apply the filter to.
979 *
980 * @return mixed The filtered value.
981 */
982 public function maybe_apply_filter( $filter, $value ) {
983 // Let's get some obvious things off the table.
984 // On invalid data, we just return what we've received.
985 if ( empty( $filter ) ) {
986 return $value;
987 }
988
989 // First, we handle the shorthand version: just a function name
990 if ( is_string( $filter ) && is_callable( $filter ) ) {
991 $value = call_user_func( $filter );
992 } elseif ( is_array( $filter ) && ! empty( $filter['callback'] ) && is_callable( $filter['callback'] ) ) {
993 if ( empty( $filter['args'] ) ) {
994 $filter['args'] = array();
995 }
996 // The value is always the first argument.
997 $filter['args'] = array( $value ) + $filter['args'];
998
999 $value = call_user_func_array( $filter['callback'], $filter['args'] );
1000 }
1001
1002 return $value;
1003 }
1004
1005 protected function process_custom_background_field_output( $option_id, $options ) {
1006 $selector = $output = '';
1007
1008 if ( ! isset( $options['value'] ) ) {
1009 return false;
1010 }
1011 $value = $options['value'];
1012
1013 if ( ! isset( $options['output'] ) ) {
1014 return $selector;
1015 } elseif ( is_string( $options['output'] ) ) {
1016 $selector = $options['output'];
1017 } elseif ( is_array( $options['output'] ) ) {
1018 $selector = implode( ' ', $options['output'] );
1019 }
1020
1021
1022 $output .= $selector . " {";
1023 if ( isset( $value['background-image'] ) && ! empty( $value['background-image'] ) ) {
1024 $output .= "background-image: url( " . $value['background-image'] . ");";
1025 } else {
1026 $output .= "background-image: none;";
1027 }
1028
1029 if ( isset( $value['background-repeat'] ) && ! empty( $value['background-repeat'] ) ) {
1030 $output .= "background-repeat:" . $value['background-repeat'] . ";";
1031 }
1032
1033 if ( isset( $value['background-position'] ) && ! empty( $value['background-position'] ) ) {
1034 $output .= "background-position:" . $value['background-position'] . ";";
1035 }
1036
1037 if ( isset( $value['background-size'] ) && ! empty( $value['background-size'] ) ) {
1038 $output .= "background-size:" . $value['background-size'] . ";";
1039 }
1040
1041 if ( isset( $value['background-attachment'] ) && ! empty( $value['background-attachment'] ) ) {
1042 $output .= "background-attachment:" . $value['background-attachment'] . ";";
1043 }
1044 $output .= "}\n";
1045
1046 return $output;
1047 }
1048
1049 /**
1050 * add our customizer styling edits into the wp_editor
1051 */
1052 function add_customizer_settings_into_wp_editor() {
1053
1054 ob_start();
1055 $this->output_typography_dynamic_style();
1056 $this->output_dynamic_style();
1057
1058 $custom_css = ob_get_clean(); ?>
1059 <script type="text/javascript">
1060 /* <![CDATA[ */
1061 (function ($) {
1062 $(window).load(function () {
1063 /**
1064 * @param iframe_id the id of the frame you want to append the style
1065 * @param style_element the style element you want to append
1066 */
1067 var append_script_to_iframe = function (ifrm_id, scriptEl) {
1068 var myIframe = document.getElementById(ifrm_id);
1069
1070 var script = myIframe.contentWindow.document.createElement("script");
1071 script.type = "text/javascript";
1072 script.innerHTML = scriptEl.innerHTML;
1073
1074 myIframe.contentWindow.document.head.appendChild(script);
1075 };
1076
1077 var append_style_to_iframe = function (ifrm_id, styleElment) {
1078 var ifrm = window.frames[ifrm_id];
1079 ifrm = ( ifrm.contentDocument || ifrm.contentDocument || ifrm.document );
1080 var head = ifrm.getElementsByTagName('head')[0];
1081
1082 if (typeof styleElment !== "undefined") {
1083 head.appendChild(styleElment);
1084 }
1085 };
1086
1087 var xmlString = <?php echo json_encode( str_replace( "\n", "", $custom_css ) ); ?>,
1088 parser = new DOMParser(),
1089 doc = parser.parseFromString(xmlString, "text/html");
1090
1091 if (typeof window.frames['content_ifr'] !== 'undefined') {
1092
1093 $.each(doc.head.childNodes, function (key, el) {
1094 if (typeof el !== "undefined" && typeof el.tagName !== "undefined") {
1095
1096 switch (el.tagName) {
1097 case 'STYLE' :
1098 append_style_to_iframe('content_ifr', el);
1099 break;
1100 case 'SCRIPT' :
1101 append_script_to_iframe('content_ifr', el);
1102 break;
1103 default:
1104 break;
1105 }
1106 }
1107 });
1108 }
1109 });
1110 })(jQuery);
1111 /* ]]> */
1112 </script>
1113 <?php }
1114
1115 /**
1116 * Register the administration menu for this plugin into the WordPress Dashboard menu.
1117 */
1118 function add_plugin_admin_menu() {
1119 $this->plugin_screen_hook_suffix = add_options_page( __( 'Customify', $this->plugin_slug ), __( 'Customify', $this->plugin_slug ), 'edit_plugins', $this->plugin_slug, array(
1120 $this,
1121 'display_plugin_admin_page'
1122 ) );
1123 }
1124
1125 /**
1126 * Render the settings page for this plugin.
1127 */
1128 function display_plugin_admin_page() {
1129 include_once( 'views/admin.php' );
1130 }
1131
1132 /**
1133 * Add settings action link to the plugins page.
1134 */
1135 function add_action_links( $links ) {
1136 return array_merge( array( 'settings' => '<a href="' . admin_url( 'options-general.php?page=pixcustomify' ) . '">' . __( 'Settings', $this->plugin_slug ) . '</a>' ), $links );
1137 }
1138
1139 protected function register_customizer_controls() {
1140
1141 // first get the base customizer extend class
1142 require_once( $this->get_base_path() . '/features/customizer/class-Pix_Customize_Control.php' );
1143
1144 // now get all the controls
1145 $path = $this->get_base_path() . '/features/customizer/controls/';
1146 pixcustomify::require_all( $path );
1147 }
1148
1149 /**
1150 * @param WP_Customize_Manager $wp_customize
1151 */
1152 function register_customizer( $wp_customize ) {
1153
1154 $this->register_customizer_controls();
1155
1156 $customizer_settings = $this->customizer_config;
1157
1158 if ( ! empty ( $customizer_settings ) ) {
1159
1160 // first check the very needed options name
1161 if ( empty( $customizer_settings['opt-name'] ) ) {
1162 return;
1163 }
1164 $options_name = $customizer_settings['opt-name'];
1165 $wp_customize->options_key = $options_name;
1166
1167 // let's check if we have sections or panels
1168 if ( isset( $customizer_settings['panels'] ) && ! empty( $customizer_settings['panels'] ) ) {
1169
1170 foreach ( $customizer_settings['panels'] as $panel_id => $panel_config ) {
1171
1172 if ( ! empty( $panel_id ) && isset( $panel_config['sections'] ) && ! empty( $panel_config['sections'] ) ) {
1173
1174 // If we have been explicitly given a panel ID we will use that
1175 if ( ! empty( $panel_config['panel_id'] ) ) {
1176 $panel_id = $panel_config['panel_id'];
1177 } else {
1178 $panel_id = $options_name . '[' . $panel_id . ']';
1179 }
1180
1181 $panel_args = array(
1182 'priority' => 10,
1183 'capability' => 'edit_theme_options',
1184 'title' => __( 'Panel title is required', 'pixcustomify' ),
1185 'description' => __( 'Description of what this panel does.', 'pixcustomify' ),
1186 );
1187
1188 if ( isset( $panel_config['priority'] ) && ! empty( $panel_config['priority'] ) ) {
1189 $panel_args['priority'] = $panel_config['priority'];
1190 }
1191
1192 if ( isset( $panel_config['title'] ) && ! empty( $panel_config['title'] ) ) {
1193 $panel_args['title'] = $panel_config['title'];
1194 }
1195
1196 if ( isset( $panel_config['description'] ) && ! empty( $panel_config['description'] ) ) {
1197 $panel_args['description'] = $panel_config['description'];
1198 }
1199
1200 $wp_customize->add_panel( $panel_id, $panel_args );
1201
1202 foreach ( $panel_config['sections'] as $section_id => $section_config ) {
1203 if ( ! empty( $section_id ) && isset( $section_config['options'] ) && ! empty( $section_config['options'] ) ) {
1204 $this->register_section( $panel_id, $section_id, $options_name, $section_config, $wp_customize );
1205 }
1206 }
1207 }
1208 }
1209 }
1210
1211 if ( isset( $customizer_settings['sections'] ) && ! empty( $customizer_settings['sections'] ) ) {
1212
1213 foreach ( $customizer_settings['sections'] as $section_id => $section_config ) {
1214 if ( ! empty( $section_id ) && isset( $section_config['options'] ) && ! empty( $section_config['options'] ) ) {
1215 $this->register_section( $panel_id = false, $section_id, $options_name, $section_config, $wp_customize );
1216 }
1217 }
1218 }
1219
1220 if ( $this->plugin_settings['enable_reset_buttons'] ) {
1221 // create a toolbar section which will be present all the time
1222 $reset_section_settings = array(
1223 'title' => 'Customify Toolbox',
1224 'capability' => 'manage_options',
1225 'priority' => 999999999,
1226 'options' => array(
1227 'reset_all_button' => array(
1228 'type' => 'button',
1229 'label' => 'Reset Customify',
1230 'action' => 'reset_customify',
1231 'value' => 'Reset'
1232 ),
1233 )
1234 );
1235
1236 $wp_customize->add_section(
1237 'customify_toolbar',
1238 $reset_section_settings
1239 );
1240
1241 $wp_customize->add_setting(
1242 'reset_customify',
1243 array()
1244 );
1245 $wp_customize->add_control( new Pix_Customize_Button_Control(
1246 $wp_customize,
1247 'reset_customify',
1248 array(
1249 'label' => __( 'Reset All Customify Options to Default', 'customify' ),
1250 'section' => 'customify_toolbar',
1251 'settings' => 'reset_customify',
1252 'action' => 'reset_customify',
1253 )
1254 ) );
1255 }
1256
1257 // register typekit options
1258 if ( isset( $customizer_settings['typekit_options'] ) ) {
1259
1260 // create a toolbar section which will be present all the time
1261 $reset_section_settings = array(
1262 'title' => 'Customify Typekit Options',
1263 'capability' => 'manage_options',
1264 'options' => array(
1265 'typkit_user' => array(
1266 'type' => 'text',
1267 'label' => 'Typekit Username',
1268 ),
1269 'typkit_password' => array(
1270 'type' => 'text',
1271 'label' => 'Typekit Username',
1272 ),
1273 )
1274 );
1275 }
1276 }
1277
1278 do_action( 'customify_create_custom_control', $wp_customize );
1279 }
1280
1281 /**
1282 * @param string $panel_id
1283 * @param string $section_key
1284 * @param string $options_name
1285 * @param array $section_config
1286 * @param WP_Customize_Manager $wp_customize
1287 */
1288 protected function register_section( $panel_id, $section_key, $options_name, $section_config, $wp_customize ) {
1289
1290 if ( isset( $this->plugin_settings['disable_customify_sections'] ) && isset( $this->plugin_settings['disable_customify_sections'][ $section_key ] ) ) {
1291 return;
1292 }
1293
1294 // Merge the section settings with the defaults
1295 $section_args = wp_parse_args( $section_config, array(
1296 'priority' => 10,
1297 'panel' => $panel_id,
1298 'capability' => 'edit_theme_options',
1299 'theme_supports' => '',
1300 'title' => esc_html__( 'Title Section is required', 'customify' ),
1301 'description' => '',
1302 'type' => 'default',
1303 'description_hidden' => false,
1304 ) );
1305
1306 // If we have been explicitly given a section ID we will use that
1307 if ( ! empty( $section_config['section_id'] ) ) {
1308 $section_id = $section_config['section_id'];
1309 } else {
1310 $section_id = $options_name . '[' . $section_key . ']';
1311 }
1312
1313 // Add the new section to the Customizer
1314 $wp_customize->add_section( $section_id, $section_args );
1315
1316 // Now go through each section option and add the fields
1317 foreach ( $section_config['options'] as $option_id => $option_config ) {
1318
1319 if ( empty( $option_id ) || ! isset( $option_config['type'] ) ) {
1320 continue;
1321 }
1322
1323 // If we have been explicitly given a setting ID we will use that
1324 if ( ! empty( $option_config['setting_id'] ) ) {
1325 $setting_id = $option_config['setting_id'];
1326 } else {
1327 $setting_id = $options_name . '[' . $option_id . ']';
1328 }
1329
1330 // Add the option config to the localized array so we can pass the info to JS.
1331 // @todo Maybe we should ensure that the connected_fields configs passed here follow the same format and logic as the ones in ::customize_pane_settings_additional_data() thus maybe having the data in the same place.
1332 $this->localized['settings'][ $setting_id ] = $option_config;
1333
1334 // Generate a safe option ID (not the final setting ID) to us in HTML attributes like ID or class
1335 $this->localized['settings'][ $setting_id ]['html_safe_option_id'] = sanitize_html_class( $option_id );
1336
1337 $this->register_field( $section_id, $setting_id, $option_config, $wp_customize );
1338 }
1339
1340 }
1341
1342 /**
1343 * Register a Customizer field (setting and control).
1344 *
1345 * @see WP_Customize_Setting
1346 * @see WP_Customize_Control
1347 *
1348 * @param string $section_id
1349 * @param string $setting_id
1350 * @param array $field_config
1351 * @param WP_Customize_Manager $wp_customize
1352 */
1353 protected function register_field( $section_id, $setting_id, $field_config, $wp_customize ) {
1354
1355 $add_control = true;
1356 // defaults
1357 $setting_args = array(
1358 'default' => '',
1359 'capability' => 'edit_theme_options',
1360 'transport' => 'refresh',
1361 );
1362 $control_args = array(
1363 'priority' => 10,
1364 'label' => '',
1365 'section' => $section_id,
1366 'settings' => $setting_id,
1367 );
1368
1369 // sanitize settings
1370 if ( ! empty( $field_config['live'] ) || $field_config['type'] === 'font' ) {
1371 $setting_args['transport'] = 'postMessage';
1372 }
1373
1374 if ( isset( $field_config['default'] ) ) {
1375 $setting_args['default'] = $field_config['default'];
1376 }
1377
1378 if ( ! empty( $field_config['capability'] ) ) {
1379 $setting_args['capability'] = $field_config['capability'];
1380 }
1381
1382 // If the setting defines it's own type we will respect that, otherwise we will follow the global plugin setting.
1383 if ( ! empty( $field_config['setting_type'] ) ) {
1384 if ( 'option' === $field_config['setting_type'] ) {
1385 $setting_args['type'] = 'option';
1386 }
1387 } elseif ( $this->plugin_settings['values_store_mod'] === 'option' ) {
1388 $setting_args['type'] = 'option';
1389 }
1390
1391 // if we arrive here this means we have a custom field control
1392 switch ( $field_config['type'] ) {
1393
1394 case 'checkbox':
1395
1396 $setting_args['sanitize_callback'] = array( $this, 'setting_sanitize_checkbox' );
1397 break;
1398
1399 default:
1400 break;
1401 }
1402
1403 if ( ! empty( $field_config['sanitize_callback'] ) && is_callable( $field_config['sanitize_callback'] ) ) {
1404 $setting_args['sanitize_callback'] = $field_config['sanitize_callback'];
1405 }
1406
1407 // Add the setting
1408 $wp_customize->add_setting( $setting_id, $setting_args );
1409
1410 // now sanitize the control
1411 if ( ! empty( $field_config['label'] ) ) {
1412 $control_args['label'] = $field_config['label'];
1413 }
1414
1415 if ( ! empty( $field_config['priority'] ) ) {
1416 $control_args['priority'] = $field_config['priority'];
1417 }
1418
1419 if ( ! empty( $field_config['desc'] ) ) {
1420 $control_args['description'] = $field_config['desc'];
1421 }
1422
1423 if ( ! empty( $field_config['active_callback'] ) ) {
1424 $control_args['active_callback'] = $field_config['active_callback'];
1425 }
1426
1427
1428 $control_args['type'] = $field_config['type'];
1429
1430 // select the control type
1431 // but first init a default
1432 $control_class_name = 'Pix_Customize_Text_Control';
1433
1434 // If is a standard wp field type call it here and skip the rest.
1435 if ( in_array( $field_config['type'], array(
1436 'checkbox',
1437 'dropdown-pages',
1438 'url',
1439 'date',
1440 'time',
1441 'datetime',
1442 'week',
1443 'search'
1444 ) ) ) {
1445 $wp_customize->add_control( $setting_id . '_control', $control_args );
1446
1447 return;
1448 } elseif ( in_array( $field_config['type'], array(
1449 'radio',
1450 'select'
1451 ) ) && ! empty( $field_config['choices'] )
1452 ) {
1453 $control_args['choices'] = $field_config['choices'];
1454 $wp_customize->add_control( $setting_id . '_control', $control_args );
1455
1456 return;
1457 } elseif ( in_array( $field_config['type'], array( 'range' ) ) && ! empty( $field_config['input_attrs'] ) ) {
1458
1459 $control_args['input_attrs'] = $field_config['input_attrs'];
1460
1461 $wp_customize->add_control( $setting_id . '_control', $control_args );
1462 }
1463
1464 // If we arrive here this means we have a custom field control.
1465 switch ( $field_config['type'] ) {
1466
1467 case 'text':
1468 if ( isset( $field_config['live'] ) ) {
1469 $control_args['live'] = $field_config['live'];
1470 }
1471
1472 $control_class_name = 'Pix_Customize_Text_Control';
1473 break;
1474
1475 case 'textarea':
1476 if ( isset( $field_config['live'] ) ) {
1477 $control_args['live'] = $field_config['live'];
1478 }
1479
1480 $control_class_name = 'Pix_Customize_Textarea_Control';
1481 break;
1482
1483 case 'color':
1484 $control_class_name = 'WP_Customize_Color_Control';
1485 break;
1486
1487 case 'color_drop':
1488 $control_class_name = 'Pix_Customize_Color_Drop_Control';
1489 break;
1490
1491 case 'ace_editor':
1492 if ( isset( $field_config['live'] ) ) {
1493 $control_args['live'] = $field_config['live'];
1494 }
1495
1496 if ( isset( $field_config['editor_type'] ) ) {
1497 $control_args['editor_type'] = $field_config['editor_type'];
1498 }
1499
1500 $control_class_name = 'Pix_Customize_Ace_Editor_Control';
1501 break;
1502
1503 case 'upload':
1504 $control_class_name = 'WP_Customize_Upload_Control';
1505 break;
1506
1507 case 'image':
1508 $control_class_name = 'WP_Customize_Image_Control';
1509 break;
1510
1511 case 'media':
1512 $control_class_name = 'WP_Customize_Media_Control';
1513 break;
1514
1515 case 'custom_background':
1516 if ( isset( $field_config['field'] ) ) {
1517 $control_args['field'] = $field_config['field'];
1518 }
1519
1520 $control_class_name = 'Pix_Customize_Background_Control';
1521 break;
1522
1523 case 'cropped_media':
1524 if ( isset( $field_config['width'] ) ) {
1525 $control_args['width'] = $field_config['width'];
1526 }
1527
1528 if ( isset( $field_config['height'] ) ) {
1529 $control_args['height'] = $field_config['height'];
1530 }
1531
1532 if ( isset( $field_config['flex_width'] ) ) {
1533 $control_args['flex_width'] = $field_config['flex_width'];
1534 }
1535
1536 if ( isset( $field_config['flex_height'] ) ) {
1537 $control_args['flex_height'] = $field_config['flex_height'];
1538 }
1539
1540 $control_class_name = 'WP_Customize_Cropped_Image_Control';
1541 break;
1542
1543 // Custom types
1544 case 'typography' :
1545 $use_typography = $this->get_plugin_setting( 'typography', '1' );
1546
1547 if ( $use_typography === false ) {
1548 $add_control = false;
1549 continue;
1550 }
1551
1552 $control_class_name = 'Pix_Customize_Typography_Control';
1553
1554 if ( isset( $field_config['backup'] ) ) {
1555 $control_args['backup'] = $field_config['backup'];
1556 }
1557
1558 if ( isset( $field_config['font_weight'] ) ) {
1559 $control_args['font_weight'] = $field_config['font_weight'];
1560 }
1561
1562 if ( isset( $field_config['subsets'] ) ) {
1563 $control_args['subsets'] = $field_config['subsets'];
1564 }
1565
1566 if ( isset( $field_config['recommended'] ) ) {
1567 $control_args['recommended'] = array_flip( $field_config['recommended'] );
1568 }
1569
1570 if ( isset( $field_config['load_all_weights'] ) ) {
1571 $control_args['load_all_weights'] = $field_config['load_all_weights'];
1572 }
1573
1574 if ( isset( $field_config['default'] ) ) {
1575 $control_args['default'] = $field_config['default'];
1576 }
1577
1578 break;
1579
1580 case 'font' :
1581 $use_typography = $this->get_plugin_setting( 'typography', '1' );
1582
1583 if ( $use_typography === false ) {
1584 $add_control = false;
1585 continue;
1586 }
1587
1588 $control_class_name = 'Pix_Customize_Font_Control';
1589
1590 if ( isset( $field_config['backup'] ) ) {
1591 $control_args['backup'] = $field_config['backup'];
1592 }
1593
1594 if ( isset( $field_config['font_weight'] ) ) {
1595 $control_args['font_weight'] = $field_config['font_weight'];
1596 }
1597
1598 if ( isset( $field_config['subsets'] ) ) {
1599 $control_args['subsets'] = $field_config['subsets'];
1600 }
1601
1602 if ( isset( $field_config['recommended'] ) ) {
1603 $control_args['recommended'] = array_flip( $field_config['recommended'] );
1604 }
1605
1606 if ( isset( $field_config['load_all_weights'] ) ) {
1607 $control_args['load_all_weights'] = $field_config['load_all_weights'];
1608 }
1609
1610 if ( isset( $field_config['default'] ) ) {
1611 $control_args['default'] = $field_config['default'];
1612 }
1613
1614 if ( isset( $field_config['fields'] ) ) {
1615 $control_args['fields'] = $field_config['fields'];
1616 }
1617 $control_args['live'] = true;
1618
1619 break;
1620
1621 case 'select2' :
1622 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1623 return;
1624 }
1625
1626 $control_args['choices'] = $field_config['choices'];
1627
1628 $control_class_name = 'Pix_Customize_Select2_Control';
1629 break;
1630
1631 case 'preset' :
1632 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1633 return;
1634 }
1635
1636 $control_args['choices'] = $field_config['choices'];
1637
1638 if ( isset( $field_config['choices_type'] ) || ! empty( $field_config['choices_type'] ) ) {
1639 $control_args['choices_type'] = $field_config['choices_type'];
1640 }
1641
1642 if ( isset( $field_config['desc'] ) || ! empty( $field_config['desc'] ) ) {
1643 $control_args['description'] = $field_config['desc'];
1644 }
1645
1646
1647 $control_class_name = 'Pix_Customize_Preset_Control';
1648 break;
1649
1650 case 'radio_image' :
1651 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1652 return;
1653 }
1654
1655 $control_args['choices'] = $field_config['choices'];
1656
1657 if ( isset( $field_config['choices_type'] ) || ! empty( $field_config['choices_type'] ) ) {
1658 $control_args['choices_type'] = $field_config['choices_type'];
1659 }
1660
1661 if ( isset( $field_config['desc'] ) || ! empty( $field_config['desc'] ) ) {
1662 $control_args['description'] = $field_config['desc'];
1663 }
1664
1665
1666 $control_class_name = 'Pix_Customize_Radio_Image_Control';
1667 break;
1668
1669 case 'button' :
1670 if ( ! isset( $field_config['action'] ) || empty( $field_config['action'] ) ) {
1671 return;
1672 }
1673
1674 $control_args['action'] = $field_config['action'];
1675
1676 $control_class_name = 'Pix_Customize_Button_Control';
1677
1678 break;
1679
1680 case 'html' :
1681 if ( isset( $field_config['html'] ) || ! empty( $field_config['html'] ) ) {
1682 $control_args['html'] = $field_config['html'];
1683 }
1684
1685 $control_class_name = 'Pix_Customize_HTML_Control';
1686 break;
1687
1688 case 'import_demo_data' :
1689 if ( isset( $field_config['html'] ) || ! empty( $field_config['html'] ) ) {
1690 $control_args['html'] = $field_config['html'];
1691 }
1692
1693 if ( ! isset( $field_config['label'] ) || empty( $field_config['label'] ) ) {
1694 $control_args['label'] = esc_html__( 'Import', 'customify' );
1695 } else {
1696 $control_args['label'] = $field_config['label'];
1697 }
1698
1699 if ( isset( $field_config['notices'] ) && ! empty( $field_config['notices'] ) ) {
1700 $control_args['notices'] = $field_config['notices'];
1701 }
1702
1703 $control_class_name = 'Pix_Customize_Import_Demo_Data_Control';
1704 break;
1705
1706 default:
1707 // if we don't have a real control just quit, it doesn't even matter
1708 return;
1709 break;
1710 }
1711
1712 $this_control = new $control_class_name(
1713 $wp_customize,
1714 $setting_id . '_control',
1715 $control_args
1716 );
1717
1718 if ( $add_control ) {
1719 $wp_customize->add_control( $this_control );
1720 }
1721 }
1722
1723 /**
1724 * Remove the sections selected by user
1725 *
1726 * @param WP_Customize_Manager $wp_customize
1727 */
1728 function remove_default_sections( $wp_customize ) {
1729 global $wp_registered_sidebars;
1730
1731 $to_remove = $this->get_plugin_setting( 'disable_default_sections' );
1732
1733 if ( ! empty( $to_remove ) ) {
1734 foreach ( $to_remove as $section => $nothing ) {
1735
1736 if ( $section === 'widgets' ) {
1737 foreach ( $wp_registered_sidebars as $widget => $settings ) {
1738 $wp_customize->remove_section( 'sidebar-widgets-' . $widget );
1739 }
1740 continue;
1741 }
1742
1743 $wp_customize->remove_section( $section );
1744 }
1745 }
1746 }
1747
1748 /**
1749 * Print JavaScript for adding additional data to _wpCustomizeSettings.settings object of the main window (not the preview window).
1750 */
1751 public function customize_pane_settings_additional_data() {
1752 /**
1753 * @global WP_Customize_Manager $wp_customize
1754 */
1755 global $wp_customize;
1756
1757 // Without an options name we can't do much.
1758 if ( empty( $this->customizer_config['opt-name'] ) ) {
1759 return;
1760 }
1761
1762 $options_name = $this->customizer_config['opt-name'];
1763 $customizer_settings = $wp_customize->settings();
1764 ?>
1765 <script type="text/javascript">
1766 if ( 'undefined' === typeof _wpCustomizeSettings.settings ) {
1767 _wpCustomizeSettings.settings = {};
1768 }
1769
1770 <?php
1771 echo "(function ( sAdditional ){\n";
1772
1773 $options = $this->get_options();
1774 foreach ( $options as $option_id => $option_config ) {
1775 // If we have been explicitly given a setting ID we will use that
1776 if ( ! empty( $option_config['setting_id'] ) ) {
1777 $setting_id = $option_config['setting_id'];
1778 } else {
1779 $setting_id = $options_name . '[' . $option_id . ']';
1780 }
1781 // @todo Right now we only handle the connected_fields key - make this more dynamic by adding the keys that are not returned by WP_Customize_Setting->json()
1782 if ( ! empty( $customizer_settings[ $setting_id ] ) && ! empty( $option_config['connected_fields'] ) ) {
1783 // Pass through all the connected fields and make sure the id is in the final format
1784 $connected_fields = array();
1785 foreach ( $option_config['connected_fields'] as $key => $connected_field_config ) {
1786 $connected_field_data = array();
1787
1788 if ( is_string( $connected_field_config ) ) {
1789 $connected_field_id = $connected_field_config;
1790 } elseif ( is_array( $connected_field_config ) ) {
1791 // We have a full blown connected field config
1792 if ( is_string( $key ) ) {
1793 $connected_field_id = $key;
1794 } else {
1795 continue;
1796 }
1797
1798 // We will pass to JS all the configured connected field details.
1799 $connected_field_data = $connected_field_config;
1800 }
1801
1802 // Continue if we don't have a connected field ID to work with.
1803 if ( empty( $connected_field_id ) ) {
1804 continue;
1805 }
1806
1807 // If the connected setting is not one of our's, we will use it's ID as it is.
1808 if ( ! array_key_exists( $connected_field_id, $options ) ) {
1809 $connected_field_data['setting_id'] = $connected_field_id;
1810 }
1811 // If the connected setting specifies a setting ID, we will not prefix it and use it as it is.
1812 elseif ( ! empty( $options[ $connected_field_id ] ) && ! empty( $options[ $connected_field_id ]['setting_id'] ) ) {
1813 $connected_field_data['setting_id'] = $options[ $connected_field_id ]['setting_id'];
1814 } else {
1815 $connected_field_data['setting_id'] = $options_name . '[' . $connected_field_id . ']';
1816 }
1817
1818 $connected_fields[] = $connected_field_data;
1819 }
1820
1821 printf(
1822 "sAdditional[%s].%s = %s;\n",
1823 wp_json_encode( $setting_id ),
1824 'connected_fields',
1825 wp_json_encode( $connected_fields, JSON_FORCE_OBJECT )
1826 );
1827 }
1828 }
1829 echo "})( _wpCustomizeSettings.settings );\n";
1830 ?>
1831 </script>
1832 <?php
1833 }
1834
1835 public function get_base_path() {
1836 return plugin_dir_path( $this->file );
1837 }
1838
1839 public function get_typography_fields( $array, $key, $value, &$results, $input_key = 0 ) {
1840 if ( ! is_array( $array ) ) {
1841 return;
1842 }
1843
1844 if ( isset( $array[ $key ] ) && $array[ $key ] == $value ) {
1845 $results[ $input_key ] = $array;
1846
1847 $default = null;
1848
1849 if ( isset( $array['default'] ) && is_array( $array['default'] ) ) {
1850 $default = json_encode( $array['default'] );
1851 }
1852
1853 $results[ $input_key ]['value'] = $this->get_option( $input_key, $default );
1854 }
1855
1856 foreach ( $array as $i => $subarray ) {
1857 $this->get_typography_fields( $subarray, $key, $value, $results, $i );
1858 }
1859 }
1860
1861 function get_options_key() {
1862 if ( ! empty( $this->opt_name ) ) {
1863 return $this->opt_name;
1864 }
1865
1866 return false;
1867 }
1868
1869 /**
1870 * Use this function when you need to know if an import button is used
1871 * @return bool
1872 */
1873 function import_button_exists() {
1874
1875 if ( empty( $this->options_list ) ) {
1876 $this->options_list = $this->get_options();
1877 }
1878
1879 foreach ( $this->options_list as $option ) {
1880 if ( isset( $option['type'] ) && 'import_demo_data' === $option['type'] ) {
1881 return true;
1882 break;
1883 }
1884 }
1885
1886 return false;
1887 }
1888
1889 /** == Helpers == */
1890
1891 protected function get_current_values( $opt_name = null ) {
1892 // Fallback to the global $opt_name
1893 if ( empty( $opt_name ) ) {
1894 $opt_name = $this->opt_name;
1895 }
1896
1897 // Bail as we have nothing to work with
1898 if ( empty( $opt_name ) ) {
1899 return false;
1900 }
1901
1902 $store_type = $this->get_plugin_setting( 'values_store_mod', 'option' );
1903 if ( $store_type === 'option' ) {
1904 return get_option( $opt_name );
1905 } elseif ( $store_type === 'theme_mod' ) {
1906 return get_theme_mod( $opt_name );
1907 }
1908
1909 return false;
1910 }
1911
1912 public function get_options() {
1913
1914 $settings = array();
1915
1916 if ( isset ( $this->customizer_config['panels'] ) ) {
1917
1918 foreach ( $this->customizer_config['panels'] as $pane_id => $panel_settings ) {
1919
1920 if ( isset( $panel_settings['sections'] ) ) {
1921 foreach ( $panel_settings['sections'] as $section_id => $section_settings ) {
1922 if ( isset( $section_settings['options'] ) ) {
1923 foreach ( $section_settings['options'] as $option_id => $option ) {
1924 $settings[ $option_id ] = $option;
1925 if ( isset( $this->current_values[ $option_id ] ) ) {
1926 $settings[ $option_id ]['value'] = $this->current_values[ $option_id ];
1927 }
1928 }
1929 }
1930 }
1931 }
1932 }
1933 }
1934
1935 if ( isset ( $this->customizer_config['sections'] ) ) {
1936 foreach ( $this->customizer_config['sections'] as $section_id => $section_settings ) {
1937 if ( isset( $section_settings['options'] ) ) {
1938 foreach ( $section_settings['options'] as $option_id => $option ) {
1939 $settings[ $option_id ] = $option;
1940 if ( isset( $this->current_values[ $option_id ] ) ) {
1941 $settings[ $option_id ]['value'] = $this->current_values[ $option_id ];
1942 }
1943 }
1944 }
1945 }
1946 }
1947
1948 return $settings;
1949 }
1950
1951 protected function get_value( $option, $alt_opt_name ) {
1952 global $wp_customize;
1953
1954 $opt_name = $this->opt_name;
1955 $values = $this->current_values;
1956
1957 // In case someone asked for a DB value too early but it has given us the opt_name under which to search, let's do it
1958 if ( empty( $opt_name ) && ! empty( $alt_opt_name ) ) {
1959 $opt_name = $alt_opt_name;
1960 $values = $this->get_current_values( $opt_name );
1961 }
1962
1963 if ( ! empty( $wp_customize ) && method_exists( $wp_customize, 'get_setting' ) ) {
1964
1965 $option_key = $opt_name . '[' . $option . ']';
1966 $setting = $wp_customize->get_setting( $option_key );
1967 if ( ! empty( $setting ) ) {
1968 $value = $setting->value();
1969
1970 return $value;
1971 }
1972 }
1973
1974 // shim
1975 if ( strpos( $option, $opt_name . '[' ) !== false ) {
1976 // get only the setting id
1977 $option = explode( '[', $option );
1978 $option = rtrim( $option[1], ']' );
1979 }
1980
1981 if ( isset( $values[ $option ] ) ) {
1982 return $values[ $option ];
1983 }
1984
1985 return null;
1986 }
1987
1988 /**
1989 * A public function to get an option's value.
1990 * If there is a value and return it.
1991 * Otherwise try to get the default parameter or the default from config.
1992 *
1993 * @param $option
1994 * @param mixed $default Optional.
1995 * @param string $alt_opt_name Optional. We can use this to bypass the fact that the DB values are loaded on after_setup_theme, if we know what to look for.
1996 *
1997 * @return bool|null|string
1998 */
1999 public function get_option( $option, $default = null, $alt_opt_name = null ) {
2000 // If the development constant CUSTOMIFY_DEV_FORCE_DEFAULTS has been defined we will not retrieve anything from the database
2001 // Always go with the default
2002 if ( defined( 'CUSTOMIFY_DEV_FORCE_DEFAULTS' ) && true === CUSTOMIFY_DEV_FORCE_DEFAULTS ) {
2003 $return = null;
2004 } else {
2005 $return = $this->get_value( $option, $alt_opt_name );
2006 }
2007
2008 if ( $return !== null ) {
2009 return $return;
2010 } elseif ( $default !== null ) {
2011 return $default;
2012 } elseif ( isset( $this->options_list[ $option ] ) && isset( $this->options_list[ $option ]['default'] ) ) {
2013 return $this->options_list[ $option ]['default'];
2014 }
2015
2016 return null;
2017 }
2018
2019 public function has_option( $option ) {
2020
2021 if ( isset( $this->options_list[ $option ] ) ) {
2022 return true;
2023 }
2024
2025 return false;
2026 }
2027
2028 public function get_customizer_config() {
2029 return $this->customizer_config;
2030 }
2031
2032 /**
2033 * Get the Customify configuration of a certain option.
2034 *
2035 * @param string $option_id
2036 *
2037 * @return array|false The option config or false on failure.
2038 */
2039 public function get_option_customizer_config( $option_id ) {
2040 // We need to search for the option configured under the given id (the array key)
2041 if ( isset ( $this->customizer_config['panels'] ) ) {
2042 foreach ( $this->customizer_config['panels'] as $panel_id => $panel_settings ) {
2043 if ( isset( $panel_settings['sections'] ) ) {
2044 foreach ( $panel_settings['sections'] as $section_id => $section_settings ) {
2045 if ( isset( $section_settings['options'] ) ) {
2046 foreach ( $section_settings['options'] as $id => $option_config ) {
2047 if ( $id === $option_id ) {
2048 return $option_config;
2049 }
2050 }
2051 }
2052 }
2053 }
2054 }
2055 }
2056
2057 if ( isset ( $this->customizer_config['sections'] ) ) {
2058 foreach ( $this->customizer_config['sections'] as $section_id => $section_settings ) {
2059 if ( isset( $section_settings['options'] ) ) {
2060 foreach ( $section_settings['options'] as $id => $option_config ) {
2061 if ( $id === $option_id ) {
2062 return $option_config;
2063 }
2064 }
2065 }
2066 }
2067 }
2068
2069 return false;
2070 }
2071
2072 protected function get_config() {
2073 if ( file_exists( $this->get_base_path() . 'plugin-config.php' ) ) {
2074 return include( $this->get_base_path() . 'plugin-config.php' );
2075 }
2076
2077 return false;
2078 }
2079
2080 /**
2081 * Get an option's value from the config file
2082 *
2083 * @param $option
2084 * @param null $default
2085 *
2086 * @return bool|null
2087 */
2088 public function get_config_option( $option, $default = null ) {
2089
2090 if ( isset( $this->config[ $option ] ) ) {
2091 return $this->config[ $option ];
2092 } elseif ( $default !== null ) {
2093 return $default;
2094 }
2095
2096 return false;
2097 }
2098
2099 public function get_plugin_setting( $option, $default = null ) {
2100
2101 if ( isset( $this->plugin_settings[ $option ] ) ) {
2102 return $this->plugin_settings[ $option ];
2103 } elseif ( $default !== null ) {
2104 return $default;
2105 }
2106
2107 return false;
2108 }
2109
2110 /**
2111 * Sanitize functions
2112 */
2113
2114 /**
2115 * Sanitize the checkbox.
2116 *
2117 * @param boolean $input .
2118 *
2119 * @return boolean true if is 1 or '1', false if anything else
2120 */
2121 function setting_sanitize_checkbox( $input ) {
2122 if ( 1 == $input ) {
2123 return true;
2124 } else {
2125 return false;
2126 }
2127 }
2128
2129 /**
2130 * Checks whether an array is associative or not
2131 *
2132 * @param array $array
2133 *
2134 * @return bool
2135 */
2136 public function is_assoc( $array ) {
2137
2138 if ( ! is_array( $array ) ) {
2139 return false;
2140 }
2141
2142 // Keys of the array
2143 $keys = array_keys( $array );
2144
2145 // If the array keys of the keys match the keys, then the array must
2146 // not be associative (e.g. the keys array looked like {0:0, 1:1...}).
2147 return array_keys( $keys ) !== $keys;
2148 }
2149
2150 function register_import_api() {
2151
2152 include_once( $this->get_base_path() . '/features/class-Customify_Importer.php' );
2153 $controller = new Customify_Importer_Controller();
2154 $controller->init();
2155 }
2156
2157 function get_options_configs() {
2158 return $this->options_list;
2159 }
2160
2161 /**
2162 * Does the same thing the JS encodeURIComponent() does
2163 *
2164 * @param string $str
2165 *
2166 * @return string
2167 */
2168 public static function encodeURIComponent( $str ) {
2169 //if we get an array we just let it be
2170 if ( is_string( $str ) ) {
2171 $revert = array( '%21' => '!', '%2A' => '*', '%27' => "'", '%28' => '(', '%29' => ')' );
2172
2173 $str = strtr( rawurlencode( $str ), $revert );
2174 } else {
2175 var_dump( 'boooom' );
2176 die;
2177 }
2178
2179 return $str;
2180 }
2181
2182 /**
2183 * Does the same thing the JS decodeURIComponent() does
2184 *
2185 * @param string $str
2186 *
2187 * @return string
2188 */
2189 public static function decodeURIComponent( $str ) {
2190 // If we get an array we just let it be
2191 if ( is_string( $str ) ) {
2192 $revert = array( '!' => '%21', '*' => '%2A', "'" => '%27', '(' => '%28', ')' => '%29' );
2193 $str = rawurldecode( strtr( $str, $revert ) );
2194 }
2195
2196 return $str;
2197 }
2198
2199 /**
2200 * PHP version check
2201 */
2202 protected function php_version_check() {
2203
2204 if ( version_compare( phpversion(), $this->minimalRequiredPhpVersion ) < 0 ) {
2205 add_action( 'admin_notices', array( $this, 'notice_php_version_wrong' ) );
2206
2207 return false;
2208 }
2209
2210 return true;
2211 }
2212
2213 /**
2214 * Prevent saving of plugin options in the Customizer
2215 *
2216 * @param array $data The data to save
2217 * @param array $filter_context
2218 *
2219 * @return array
2220 */
2221 public function prevent_changeset_save_in_devmode( $data, $filter_context ) {
2222 // Get the options key
2223 $options_key = $this->customizer_config['opt-name'];
2224 if ( ! empty( $options_key ) ) {
2225 // Remove any Customify data thus preventing it from saving
2226 foreach ( $data as $key => $value ) {
2227 if ( false !== strpos( $key, $options_key ) ) {
2228 unset( $data[$key] );
2229 }
2230 }
2231 }
2232
2233 return $data;
2234 }
2235
2236 public function prevent_changeset_save_in_devmode_notification() { ?>
2237 <script type="application/javascript">
2238 (function ( $, exports, wp ) {
2239 'use strict';
2240 // when the customizer is ready add our notification
2241 wp.customize.bind('ready', function () {
2242 wp.customize.notifications.add( 'customify_force_defaults', new wp.customize.Notification(
2243 'customify_force_defaults',
2244 {
2245 type: 'warning',
2246 message: '<strong style="margin-bottom: ">Customify: Development Mode</strong><p>All the options are switched to default. While they are changing in the live preview, they will not be kept when publish.</p>'
2247 }
2248 ) );
2249 });
2250 })(jQuery, window, wp);
2251 </script>
2252 <?php }
2253
2254 /**
2255 * Return an instance of this class.
2256 * @since 1.0.0
2257 * @return PixCustomifyPlugin A single instance of this class.
2258 */
2259 /**
2260 * Main PixCustomifyPlugin Instance
2261 *
2262 * Ensures only one instance of PixCustomifyPlugin is loaded or can be loaded.
2263 *
2264 * @since 1.0.0
2265 * @static
2266 *
2267 * @param string $file File.
2268 * @param string $version Version.
2269 *
2270 * @see PixCustomifyPlugin()
2271 * @return PixCustomifyPlugin Main PixCustomifyPlugin instance
2272 */
2273 public static function instance( $file = '', $version = '1.0.0' ) {
2274 // If the single instance hasn't been set, set it now.
2275 if ( is_null( self::$_instance ) ) {
2276 self::$_instance = new self( $file, $version );
2277 }
2278
2279 return self::$_instance;
2280 }
2281
2282 /**
2283 * Cloning is forbidden.
2284 *
2285 * @since 1.5.0
2286 */
2287 public function __clone() {
2288
2289 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), esc_html( $this->_version ) );
2290 } // End __clone ()
2291
2292 /**
2293 * Unserializing instances of this class is forbidden.
2294 *
2295 * @since 1.5.0
2296 */
2297 public function __wakeup() {
2298
2299 _doing_it_wrong( __FUNCTION__, esc_html( __( 'Cheatin&#8217; huh?' ) ), esc_html( $this->_version ) );
2300 } // End __wakeup ()
2301 }