PluginProbe
Customify / 1.6.5
Customify v1.6.5
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.6.5, at class-pixcustomify.php

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