PluginProbe
Customify / 2.0.0
Customify v2.0.0
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 2.0.0, at class-pixcustomify.php

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