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

class-customify-customizer.php in Customify 2.5.1, at includes/class-customify-customizer.php

1,903 lines 60.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * This is the class that handles the overall logic for the Customizer.
4 *
5 * @see https://pixelgrade.com
6 * @author Pixelgrade
7 * @since 2.4.0
8 */
9
10 if ( ! defined( 'ABSPATH' ) ) {
11 exit; // Exit if accessed directly
12 }
13
14 if ( ! class_exists( 'PixCustomify_Customizer' ) ) :
15
16 class PixCustomify_Customizer {
17
18 /**
19 * Holds the only instance of this class.
20 * @var null|PixCustomify_Customizer
21 * @access protected
22 * @since 2.4.0
23 */
24 protected static $_instance = null;
25
26 protected $localized = array();
27
28 protected $typo_settings;
29
30 protected $google_fonts = null;
31
32 protected $theme_fonts = null;
33
34 protected $media_queries = array();
35
36 // these properties will get 'px' as a default unit
37 public static $pixel_dependent_css_properties = array(
38 'width',
39 'max-width',
40 'min-width',
41
42 'height',
43 'max-height',
44 'min-height',
45
46 'padding',
47 'padding-left',
48 'padding-right',
49 'padding-top',
50 'padding-bottom',
51
52 'margin',
53 'margin-right',
54 'margin-left',
55 'margin-top',
56 'margin-bottom',
57
58 'right',
59 'left',
60 'top',
61 'bottom',
62
63 'font-size',
64 'letter-spacing',
65
66 'border-size',
67 'border-width',
68 'border-bottom-width',
69 'border-left-width',
70 'border-right-width',
71 'border-top-width'
72 );
73
74 /**
75 * Constructor.
76 *
77 * @since 2.4.0
78 */
79 protected function __construct() {
80 // We will initialize the Customizer logic after the plugin has finished with it's configuration (at priority 15).
81 add_action( 'init', array( $this, 'init' ), 15 );
82 }
83
84 /**
85 * Initialize this module.
86 *
87 * @since 2.4.0
88 */
89 public function init() {
90
91 $this->localized['options_name'] = PixCustomifyPlugin()->get_options_key();
92
93 require_once( PixCustomifyPlugin()->get_base_path() . 'features/class-Font_Selector.php' );
94 $this->localized['theme_fonts'] = $this->theme_fonts = Customify_Font_Selector::instance()->get_theme_fonts();
95
96 $this->localized['ajax_url'] = admin_url( 'admin-ajax.php' );
97 $this->localized['style_manager_user_feedback_nonce'] = wp_create_nonce( 'customify_style_manager_user_feedback' );
98 $this->localized['style_manager_user_feedback_provided'] = get_option( 'style_manager_user_feedback_provided', false );
99
100 // Hook up.
101 $this->add_hooks();
102 }
103
104 /**
105 * Initiate our hooks
106 *
107 * @since 2.4.0
108 */
109 public function add_hooks() {
110
111 // Styles for the Customizer
112 add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_styles' ), 10 );
113 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_styles' ), 10 );
114 // Scripts enqueued in the Customizer
115 add_action( 'customize_controls_init', array( $this, 'register_admin_customizer_scripts' ), 15 );
116 add_action( 'customize_controls_enqueue_scripts', array( $this, 'enqueue_admin_customizer_scripts' ), 15 );
117
118 // Scripts enqueued only in the theme preview
119 add_action( 'customize_preview_init', array( $this, 'customizer_live_preview_register_scripts' ), 10 );
120 add_action( 'customize_preview_init', array( $this, 'customizer_live_preview_enqueue_scripts' ), 99999 );
121
122 // Add extra settings data to _wpCustomizeSettings.settings of the parent window.
123 add_action( 'customize_controls_print_footer_scripts', array( $this, 'customize_pane_settings_additional_data' ), 10000 );
124
125 // The frontend effects of the Customizer controls
126 $load_location = PixCustomifyPlugin()->settings->get_plugin_setting( 'style_resources_location', 'wp_head' );
127
128 add_action( $load_location, array( $this, 'output_dynamic_style' ), 99 );
129 add_action( 'wp_head', array( $this, 'output_typography_dynamic_script' ), 10 );
130 add_action( 'wp_head', array( $this, 'output_typography_dynamic_style' ), 10 );
131
132 add_action( 'customize_register', array( $this, 'remove_default_sections' ), 11 );
133 add_action( 'customize_register', array( $this, 'register_customizer' ), 12 );
134 // Maybe the theme has instructed us to do things like removing sections or controls.
135 add_action( 'customize_register', array( $this, 'maybe_process_config_extras' ), 13 );
136
137 if ( PixCustomifyPlugin()->settings->get_plugin_setting( 'enable_editor_style', true ) ) {
138 add_action( 'admin_enqueue_scripts', array( $this, 'script_to_add_customizer_settings_into_wp_editor' ), 10, 1 );
139 }
140
141 /*
142 * Development related
143 */
144 if ( defined( 'CUSTOMIFY_DEV_FORCE_DEFAULTS' ) && true === CUSTOMIFY_DEV_FORCE_DEFAULTS ) {
145 // If the development constant CUSTOMIFY_DEV_FORCE_DEFAULTS has been defined we will not save anything in the database
146 // Always go with the default
147 add_filter( 'customize_changeset_save_data', array( $this, 'prevent_changeset_save_in_devmode' ), 50, 1 );
148 // Add a JS to display a notification
149 add_action( 'customize_controls_print_footer_scripts', array( $this, 'prevent_changeset_save_in_devmode_notification' ), 100 );
150 }
151 }
152
153 /**
154 * Register Customizer admin styles
155 */
156 function register_admin_customizer_styles() {
157 wp_register_style( 'customify_select2', plugins_url( 'js/select2/css/select2.css', PixCustomifyPlugin()->get_file() ), array(), PixCustomifyPlugin()->get_version() );
158 wp_register_style( 'customify_style', plugins_url( 'css/customizer.css', PixCustomifyPlugin()->get_file() ), array( 'customify_select2', 'dashicons' ), PixCustomifyPlugin()->get_version() );
159 }
160
161 /**
162 * Enqueue Customizer admin styles
163 */
164 function enqueue_admin_customizer_styles() {
165 wp_enqueue_style( 'customify_style' );
166 }
167
168 /**
169 * Register Customizer admin scripts
170 */
171 function register_admin_customizer_scripts() {
172
173 wp_register_script( 'customify_select2', plugins_url( 'js/select2/js/select2.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version() );
174 wp_register_script( 'jquery-react', plugins_url( 'js/jquery-react.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version() );
175
176 wp_register_script( 'customify-scale', plugins_url( 'js/customizer/scale-iframe.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version() );
177 wp_register_script( 'customify-fontselectfields', plugins_url( 'js/customizer/font-select-fields.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version() );
178
179 wp_register_script( PixCustomifyPlugin()->get_slug() . '-customizer-scripts', plugins_url( 'js/customizer.js', PixCustomifyPlugin()->get_file() ), array(
180 'jquery',
181 'customify_select2',
182 'underscore',
183 'customize-controls',
184 'customify-fontselectfields',
185
186 'customify-scale',
187 ), PixCustomifyPlugin()->get_version() );
188 }
189
190 /**
191 * Enqueue Customizer admin scripts
192 */
193 function enqueue_admin_customizer_scripts() {
194 wp_enqueue_script( 'jquery-react' );
195 wp_enqueue_script( PixCustomifyPlugin()->get_slug() . '-customizer-scripts' );
196
197 wp_localize_script( PixCustomifyPlugin()->get_slug() . '-customizer-scripts', 'customify_settings', apply_filters( 'customify_localized_js_settings', $this->localized ) );
198 }
199
200 /** Register Customizer scripts loaded only on previewer page */
201 function customizer_live_preview_register_scripts() {
202 wp_register_script( PixCustomifyPlugin()->get_slug() . 'CSSOM', plugins_url( 'js/CSSOM.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version(), true );
203 wp_register_script( PixCustomifyPlugin()->get_slug() . 'cssUpdate', plugins_url( 'js/jquery.cssUpdate.js', PixCustomifyPlugin()->get_file() ), array( 'jquery' ), PixCustomifyPlugin()->get_version(), true );
204 wp_register_script( PixCustomifyPlugin()->get_slug() . '-previewer-scripts', plugins_url( 'js/customizer_preview.js', PixCustomifyPlugin()->get_file() ), array(
205 'jquery',
206 'customize-preview',
207 PixCustomifyPlugin()->get_slug() . 'CSSOM',
208 PixCustomifyPlugin()->get_slug() . 'cssUpdate'
209 ), PixCustomifyPlugin()->get_version(), true );
210 }
211
212 /** Enqueue Customizer scripts loaded only on previewer page */
213 function customizer_live_preview_enqueue_scripts() {
214 wp_enqueue_script( PixCustomifyPlugin()->get_slug() . '-previewer-scripts' );
215
216 // when a live preview field is in action we need to know which props need 'px' as defaults
217 $this->localized['px_dependent_css_props'] = self::$pixel_dependent_css_properties;
218
219 wp_localize_script( PixCustomifyPlugin()->get_slug() . '-previewer-scripts', 'customify_settings', $this->localized );
220 }
221
222 /**
223 * Prevent saving of plugin options in the Customizer
224 *
225 * @param array $data The data to save
226 *
227 * @return array
228 */
229 public function prevent_changeset_save_in_devmode( $data ) {
230 // Get the options key
231 $options_key = PixCustomifyPlugin()->get_options_key();
232 if ( ! empty( $options_key ) ) {
233 // Remove any Customify data thus preventing it from saving
234 foreach ( $data as $option_id => $value ) {
235 if ( false !== strpos( $option_id, $options_key ) && ! PixCustomifyPlugin()->skip_dev_mode_force_defaults( $option_id ) ) {
236 unset( $data[ $option_id ] );
237 }
238 }
239 }
240
241 return $data;
242 }
243
244 public function prevent_changeset_save_in_devmode_notification() { ?>
245 <script type="application/javascript">
246 (function ( $, exports, wp ) {
247 'use strict';
248 // when the customizer is ready add our notification
249 wp.customize.bind('ready', function () {
250 wp.customize.notifications.add( 'customify_force_defaults', new wp.customize.Notification(
251 'customify_force_defaults',
252 {
253 type: 'warning',
254 message: '<?php echo wp_kses_post( __( '<strong>Customify: Development Mode</strong><p>All options are switched to default. While they are changing in the live preview, they will not be kept when you hit publish.</p>', 'customify' ) ); ?>'
255 }
256 ) );
257 });
258 })(jQuery, window, wp);
259 </script>
260 <?php }
261
262 /**
263 * Output CSS style generated by customizer
264 */
265 function output_dynamic_style() { ?>
266 <style id="customify_output_style">
267 <?php echo $this->get_dynamic_style(); ?>
268 </style>
269 <?php
270
271 /**
272 * from now on we output only style tags only for the preview purpose
273 * so don't cry if you see 30+ style tags for each section
274 */
275 if ( ! isset( $GLOBALS['wp_customize'] ) ) {
276 return;
277 }
278
279 foreach ( PixCustomifyPlugin()->get_options_details( false, true ) as $option_id => $option_details ) {
280
281 if ( isset( $option_details['type'] ) && $option_details['type'] === 'custom_background' ) {
282 $custom_background_output = $this->process_custom_background_field_output( $option_details ); ?>
283
284 <style id="custom_background_output_for_<?php echo sanitize_html_class( $option_id ); ?>">
285 <?php
286 if ( ! empty( $custom_background_output )) {
287 echo $custom_background_output;
288 } ?>
289 </style>
290 <?php }
291
292 if ( ! isset( $option_details['live'] ) || $option_details['live'] !== true ) {
293 continue;
294 }
295
296 if ( ! empty( $option_details['css'] ) ) {
297 foreach ( $option_details['css'] as $key => $properties_set ) {
298 // We need to use a class because we may have multiple <style>s with the same "ID" for example
299 // when targeting the same property but with different selectors.
300 $unique_class = 'dynamic_setting_' . $option_id . '_property_' . str_replace( '-', '_', $properties_set['property'] ) . '_' . $key;
301
302 $inline_style = '<style class="' . sanitize_html_class( $unique_class ) . '" type="text/css">';
303
304 if ( isset( $properties_set['media'] ) && ! empty( $properties_set['media'] ) ) {
305 $inline_style .= '@media '. $properties_set['media'] . ' {';
306 }
307
308 if ( isset( $properties_set['selector'] ) && isset( $properties_set['property'] ) ) {
309 $css_output = $this->process_css_property($properties_set, $option_details['value']);
310 if ( ! empty( $css_output ) ) {
311 $inline_style .= $css_output;
312 }
313 }
314
315 if ( isset( $properties_set['media'] ) && ! empty( $properties_set['media'] ) ) {
316 $inline_style .= '}';
317 }
318 $inline_style .= '</style>';
319
320 echo $inline_style;
321 }
322 }
323 }
324 }
325
326 function get_dynamic_style() {
327 $custom_css = '';
328
329 foreach ( PixCustomifyPlugin()->get_options_details( true ) as $option_id => $option_details ) {
330
331 if ( isset( $option_details['css'] ) && ! empty( $option_details['css'] ) ) {
332 // now process each
333 $custom_css .= $this->convert_setting_to_css( $option_id, $option_details );
334 }
335
336 if ( isset( $option_details['type'] ) && $option_details['type'] === 'custom_background' ) {
337 $custom_css .= $this->process_custom_background_field_output( $option_details ) . "\n";
338 }
339 }
340
341 if ( ! empty( $this->media_queries ) ) {
342
343 foreach ( $this->media_queries as $media_query => $properties ) {
344
345 if ( empty( $properties ) ) {
346 continue;
347 }
348
349 $media_query_custom_css = '';
350
351 foreach ( $properties as $key => $property ) {
352 $property_settings = $property['property'];
353 $property_value = $property['value'];
354 $css_output = $this->process_css_property( $property_settings, $property_value );
355 if ( ! empty( $css_output ) ) {
356 $media_query_custom_css .= "\t" . $css_output . "\n";
357 }
358 }
359
360 if ( ! empty( $media_query_custom_css ) ) {
361 $media_query_custom_css = "\n" . '@media ' . $media_query . " { " . "\n" . "\n" . $media_query_custom_css . "}" . "\n";
362 }
363
364 if ( ! empty( $media_query_custom_css ) ) {
365 $custom_css .= $media_query_custom_css;
366 }
367
368 }
369 }
370
371 return apply_filters( 'customify_dynamic_style', $custom_css );
372 }
373
374 protected function load_google_fonts() {
375 $fonts_path = PixCustomifyPlugin()->get_base_path() . 'features/customizer/controls/resources/google.fonts.php';
376
377 if ( file_exists( $fonts_path ) ) {
378 $this->google_fonts = require( $fonts_path );
379 }
380
381 if ( ! empty( $this->google_fonts ) ) {
382 return $this->google_fonts;
383 }
384
385 return false;
386 }
387
388 function output_typography_dynamic_style() {
389 $style = $this->get_typography_dynamic_style();
390
391 if ( ! empty( $style ) ) { ?>
392 <style id="customify_typography_output_style">
393 <?php echo $style; ?>
394 </style>
395 <?php }
396 }
397
398 function get_typography_dynamic_style() {
399 $output = '';
400
401 $this->get_typography_fields( PixCustomifyPlugin()->get_options_details( true ), 'type', 'typography', $this->typo_settings );
402
403 if ( empty( $this->typo_settings ) ) {
404 return $output;
405 }
406
407 ob_start();
408 foreach ( $this->typo_settings as $font ) {
409 $selector = apply_filters( 'customify_typography_css_selector', $font['selector'], $font );
410
411 $load_all_weights = false;
412 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
413 $load_all_weights = true;
414 }
415
416 if ( isset( $selector ) && isset( $font['value'] ) && ! empty( $font['value'] ) ) {
417 // Make sure that the value is in the proper format
418 $value = PixCustomifyPlugin::decodeURIComponent( $font['value'] );
419 if ( is_string( $value ) ) {
420 $value = json_decode( $value, true );
421 }
422
423 // In case the value is null (most probably because the json_decode failed),
424 // try the default value (mostly for google fonts)
425 if ( $value === null ) {
426 $value = $this->get_font_defaults_value( $font['value'] );
427 }
428
429 // Shim the old case when the default was only the font name
430 if ( ! empty( $value ) && is_string( $value ) ) {
431 $value = array( 'font_family' => $value );
432 }
433
434 // Handle special logic for when the $value array is not an associative array
435 if ( ! PixCustomifyPlugin()->is_assoc( $value ) ) {
436 $value = $this->standardize_non_associative_font_default( $value );
437 }
438
439 // Bail if empty or we don't have an array
440 if ( empty( $value ) || ! is_array( $value ) ) {
441 continue;
442 }
443
444 $selected_variant = '';
445 if ( ! empty( $value['selected_variants'] ) ) {
446 if ( is_array( $value['selected_variants'] ) ) {
447 $selected_variant = $value['selected_variants'][0];
448 } else {
449 $selected_variant = $value['selected_variants'];
450 }
451 }
452
453 // First handle the case where we have the font-family in the selected variant (usually this means a custom font from our Fonto plugin)
454 if ( ! empty( $selected_variant ) && is_array( $selected_variant ) && ! empty( $selected_variant['font-family'] ) ) {
455 // The variant's font-family
456 echo $selector . " {\nfont-family: " . $selected_variant['font-family'] . ";\n";
457
458 if ( ! $load_all_weights ) {
459 // If this is a custom font (like from our plugin Fonto) with individual styles & weights - i.e. the font-family says it all
460 // we need to "force" the font-weight and font-style
461 if ( ! empty( $value['type'] ) && 'custom_individual' == $value['type'] ) {
462 $selected_variant['font-weight'] = '400 !important';
463 $selected_variant['font-style'] = 'normal !important';
464 }
465
466 // Output the font weight, if available
467 if ( ! empty( $selected_variant['font-weight'] ) ) {
468 echo "font-weight: " . $selected_variant['font-weight'] . ";\n";
469 }
470
471 // Output the font style, if available
472 if ( ! empty( $selected_variant['font-style'] ) ) {
473 echo "font-style: " . $selected_variant['font-style'] . ";\n";
474 }
475 }
476
477 echo "}\n";
478 } elseif ( isset( $value['font_family'] ) ) {
479 // The selected font family
480 echo $selector . " {\n font-family: " . $value['font_family'] . ";\n";
481
482 if ( ! empty( $selected_variant ) && ! $load_all_weights ) {
483 $weight_and_style = strtolower( $selected_variant );
484
485 $italic_font = false;
486
487 //determine if this is an italic font (the $weight_and_style is usually like '400' or '400italic' )
488 if ( strpos( $weight_and_style, 'italic' ) !== false ) {
489 $weight_and_style = str_replace( 'italic', '', $weight_and_style);
490 $italic_font = true;
491 }
492
493 if ( ! empty( $weight_and_style ) ) {
494 //a little bit of sanity check - in case it's not a number
495 if( $weight_and_style === 'regular' ) {
496 $weight_and_style = 'normal';
497 }
498 echo "font-weight: " . $weight_and_style . ";\n";
499 }
500
501 if ( $italic_font ) {
502 echo "font-style: italic;\n";
503 }
504 }
505
506 echo "}\n";
507 }
508 }
509 }
510
511 $output = ob_get_clean();
512
513 return $output;
514 }
515
516 function output_typography_dynamic_script() {
517
518 $script = $this->get_typography_dynamic_script();
519 if ( ! empty ( $script ) ) { ?>
520 <script type="text/javascript">
521 <?php echo $script; ?>
522 </script>
523 <?php }
524 }
525
526 function get_typography_dynamic_script() {
527 $output = '';
528
529 $this->get_typography_fields( PixCustomifyPlugin()->get_options_details( true ), 'type', 'typography', $this->typo_settings );
530
531 if ( empty( $this->typo_settings ) ) {
532 return $output;
533 }
534
535 $families = '';
536
537 foreach ( $this->typo_settings as $id => $font ) {
538 if ( isset ( $font['value'] ) ) {
539
540 $load_all_weights = false;
541 if ( isset( $font['load_all_weights'] ) && $font['load_all_weights'] == 'true' ) {
542 $load_all_weights = true;
543 }
544
545 // shim the time when this was an array
546 // @todo Is this really needed? Or does it make sense?
547 if ( is_array( $font['value'] ) ) {
548 $font['value'] = stripslashes_deep( $font['value'] );
549 $font['value'] = json_encode( $font['value'] );
550 }
551
552 $value = wp_unslash( PixCustomifyPlugin::decodeURIComponent( $font['value'] ) );
553 if ( is_string( $value ) ) {
554 $value = json_decode( $value, true );
555 }
556
557 // In case the value is still null, try default value (mostly for google fonts)
558 if ( $value === null || ! is_array( $value ) ) {
559 $value = $this->get_font_defaults_value( str_replace( '"', '', $font['value'] ) );
560 }
561
562 // Bail if by this time we don't have a value of some sort
563 if ( empty( $value ) ) {
564 continue;
565 }
566
567 // Handle special logic for when the $value array is not an associative array
568 if ( ! PixCustomifyPlugin()->is_assoc( $value ) ) {
569 $value = $this->standardize_non_associative_font_default( $value );
570 }
571
572 // Bail if empty or we don't have an array
573 if ( empty( $value ) || ! is_array( $value ) ) {
574 continue;
575 }
576
577 if ( isset( $value['font_family'] ) && isset( $value['type'] ) && $value['type'] == 'google' ) {
578 $families .= "'" . $value['font_family'];
579
580 if ( $load_all_weights && is_array( $value['variants'] ) ) {
581 $families .= ":" . implode( ',', $value['variants'] );
582 } elseif ( isset( $value['selected_variants'] ) && ! empty( $value['selected_variants'] ) ) {
583 if ( is_array( $value['selected_variants'] ) ) {
584 $families .= ":" . implode( ',', $value['selected_variants'] );
585 } elseif ( is_string( $value['selected_variants'] ) || is_numeric( $value['selected_variants'] ) ) {
586 $families .= ":" . $value['selected_variants'];
587 }
588 } elseif ( isset( $value['variants'] ) && ! empty( $value['variants'] ) ) {
589 if ( is_array( $value['variants'] ) ) {
590 $families .= ":" . implode( ',', $value['variants'] );
591 } else {
592 $families .= ":" . $value['variants'];
593 }
594 }
595
596 if ( isset( $value['selected_subsets'] ) && ! empty( $value['selected_subsets'] ) ) {
597 if ( is_array( $value['selected_subsets'] ) ) {
598 $families .= ":" . implode( ',', $value['selected_subsets'] );
599 } else {
600 $families .= ":" . $value['selected_subsets'];
601 }
602 } elseif ( isset( $value['subsets'] ) && ! empty( $value['subsets'] ) ) {
603 if ( is_array( $value['subsets'] ) ) {
604 $families .= ":" . implode( ',', $value['subsets'] );
605 } else {
606 $families .= ":" . $value['subsets'];
607 }
608 }
609
610 $families .= '\',';
611 }
612 }
613 }
614
615 if ( ! empty ( $families ) && PixCustomifyPlugin()->settings->get_plugin_setting( 'typography', '1' )
616 && PixCustomifyPlugin()->settings->get_plugin_setting( 'typography_google_fonts', 1 ) ) {
617 ob_start();
618 ?>
619 if (typeof WebFont !== 'undefined') {<?php // if there is a WebFont object, use it ?>
620 WebFont.load({
621 google: {families: [<?php echo( rtrim( $families, ',' ) ); ?>]},
622 classes: false,
623 events: false
624 });
625 } else {<?php // basically when we don't have the WebFont object we create the google script dynamically ?>
626
627 var tk = document.createElement('script');
628 tk.src = '//ajax.googleapis.com/ajax/libs/webfont/1/webfont.js';
629 tk.type = 'text/javascript';
630
631 tk.onload = tk.onreadystatechange = function () {
632 WebFont.load({
633 google: {families: [<?php echo( rtrim( $families, ',' ) ); ?>]},
634 classes: false,
635 events: false
636 });
637 };
638
639 var s = document.getElementsByTagName('script')[0];
640 s.parentNode.insertBefore(tk, s);
641 }<?php
642 $output = ob_get_clean();
643 }
644
645 return $output;
646 }
647
648 /**
649 * Handle special logic for when the $value array is not an associative array
650 * Return a new associative array with proper keys
651 */
652 public function standardize_non_associative_font_default( $value ) {
653 // If the value provided is not array, simply return it
654 if ( ! is_array( $value ) ) {
655 return $value;
656 }
657
658 $new_value = array();
659
660 // Let's determine some type of font
661 if ( ! isset( $value[2] ) || 'google' == $value[2] ) {
662 $new_value = $this->get_font_defaults_value( $value[0] );
663 } else {
664 $new_value['type'] = $value[2];
665 }
666
667 if ( null == $new_value ) {
668 $new_value = array();
669 }
670
671 // The first entry is the font-family
672 if ( isset( $value[0] ) ) {
673 $new_value['font_family'] = $value[0];
674 }
675
676 // In case we don't have an associative array
677 // The second entry is the variants
678 if ( isset( $value[1] ) ) {
679 $new_value['selected_variants'] = $value[1];
680 }
681
682 return $new_value;
683 }
684
685 /**
686 *
687 * @param $font_name
688 *
689 * @return null
690 */
691 public function get_font_defaults_value( $font_name ) {
692
693 if ( empty( $this->google_fonts ) ) {
694 $this->load_google_fonts();
695 }
696
697 if ( isset( $this->google_fonts[ $font_name ] ) ) {
698 $value = $this->google_fonts[ $font_name ];
699 $value['font_family'] = $font_name;
700 $value['type'] = 'google';
701
702 return $value;
703 } elseif ( isset( $this->theme_fonts[ $font_name ] ) ) {
704 $value['type'] = 'theme_font';
705 $value['src'] = $this->theme_fonts[ $font_name ]['src'];
706 $value['variants'] = $this->theme_fonts[ $font_name ]['variants'];
707 $value['font_family'] = $this->theme_fonts[ $font_name ]['family'];
708
709 return $value;
710 }
711
712 return null;
713 }
714
715 /**
716 * Turn css options into a valid CSS output
717 *
718 * @param $option_id
719 * @param array $option_details
720 *
721 * @return string
722 */
723 protected function convert_setting_to_css( $option_id, $option_details ) {
724 $output = '';
725
726 if ( empty( $option_details['css'] ) ) {
727 return $output;
728 }
729
730 foreach ( $option_details['css'] as $css_property ) {
731
732 if ( isset( $css_property['media'] ) && ! empty( $css_property['media'] ) ) {
733 $this->media_queries[ $css_property['media'] ][ $option_id ] = array(
734 'property' => $css_property,
735 'value' => $option_details['value']
736 );
737 continue;
738 }
739
740 if ( isset( $css_property['selector'] ) && isset( $css_property['property'] ) ) {
741 $output .= $this->process_css_property( $css_property, $option_details['value'] );
742 }
743 }
744
745 return $output;
746 }
747
748 protected function process_css_property( $css_property, $value ) {
749 $unit = '';
750
751 if ( isset( $css_property['unit'] ) ) {
752 $unit = $css_property['unit'];
753 }
754
755 // if the unit isn't specified but the property should have a unit force 'px' as it
756 if ( empty( $unit ) && in_array( $css_property['property'], self::$pixel_dependent_css_properties ) ) {
757 $unit = 'px';
758 }
759
760 // lose the tons of tabs
761 $css_property['selector'] = trim( preg_replace( '/\t+/', '', $css_property['selector'] ) );
762
763 $css_property['selector'] = apply_filters( 'customify_css_selector', $css_property['selector'], $css_property );
764
765 if ( empty( $css_property['selector'] ) ) {
766 return '';
767 }
768 $property_output = $css_property['selector'] . ' { ' . $css_property['property'] . ': ' . $value . $unit . "; }" . "\n";
769
770 // Handle the value filter callback.
771 if ( isset( $css_property['filter_value_cb'] ) ) {
772 $value = $this->maybe_apply_filter( $css_property['filter_value_cb'], $value );
773 }
774
775 // Handle output callback.
776 if ( isset( $css_property['callback_filter'] ) && is_callable( $css_property['callback_filter'] ) ) {
777 $property_output = call_user_func( $css_property['callback_filter'], $value, $css_property['selector'], $css_property['property'], $unit );
778 }
779
780 return $property_output;
781 }
782
783 /**
784 * Apply a filter (config) to a value.
785 *
786 * We currently handle filters like these:
787 * // Elaborate filter config
788 * array(
789 * 'callback' => 'is_post_type_archive',
790 * // The arguments we should pass to the check function.
791 * // Think post types, taxonomies, or nothing if that is the case.
792 * // It can be an array of values or a single value.
793 * 'args' => array(
794 * 'jetpack-portfolio',
795 * ),
796 * ),
797 * // Simple filter - just the function name
798 * 'is_404',
799 *
800 * @param array|string $filter
801 * @param mixed $value The value to apply the filter to.
802 *
803 * @return mixed The filtered value.
804 */
805 public function maybe_apply_filter( $filter, $value ) {
806 // Let's get some obvious things off the table.
807 // On invalid data, we just return what we've received.
808 if ( empty( $filter ) ) {
809 return $value;
810 }
811
812 // First, we handle the shorthand version: just a function name
813 if ( is_string( $filter ) && is_callable( $filter ) ) {
814 $value = call_user_func( $filter );
815 } elseif ( is_array( $filter ) && ! empty( $filter['callback'] ) && is_callable( $filter['callback'] ) ) {
816 if ( empty( $filter['args'] ) ) {
817 $filter['args'] = array();
818 }
819 // The value is always the first argument.
820 $filter['args'] = array( $value ) + $filter['args'];
821
822 $value = call_user_func_array( $filter['callback'], $filter['args'] );
823 }
824
825 return $value;
826 }
827
828 protected function process_custom_background_field_output( $option_details ) {
829 $selector = $output = '';
830
831 if ( ! isset( $option_details['value'] ) ) {
832 return false;
833 }
834 $value = $option_details['value'];
835
836 if ( ! isset( $option_details['output'] ) ) {
837 return $selector;
838 } elseif ( is_string( $option_details['output'] ) ) {
839 $selector = $option_details['output'];
840 } elseif ( is_array( $option_details['output'] ) ) {
841 $selector = implode( ' ', $option_details['output'] );
842 }
843
844 // Loose the ton of tabs.
845 $selector = trim( preg_replace( '/\t+/', '', $selector ) );
846
847 $output .= $selector . " {";
848 if ( isset( $value['background-image'] ) && ! empty( $value['background-image'] ) ) {
849 $output .= "background-image: url( " . $value['background-image'] . ");";
850 } else {
851 $output .= "background-image: none;";
852 }
853
854 if ( isset( $value['background-repeat'] ) && ! empty( $value['background-repeat'] ) ) {
855 $output .= "background-repeat:" . $value['background-repeat'] . ";";
856 }
857
858 if ( isset( $value['background-position'] ) && ! empty( $value['background-position'] ) ) {
859 $output .= "background-position:" . $value['background-position'] . ";";
860 }
861
862 if ( isset( $value['background-size'] ) && ! empty( $value['background-size'] ) ) {
863 $output .= "background-size:" . $value['background-size'] . ";";
864 }
865
866 if ( isset( $value['background-attachment'] ) && ! empty( $value['background-attachment'] ) ) {
867 $output .= "background-attachment:" . $value['background-attachment'] . ";";
868 }
869 $output .= "}\n";
870
871 return $output;
872 }
873
874 /**
875 * add our customizer styling edits into the wp_editor
876 */
877 function script_to_add_customizer_settings_into_wp_editor() {
878
879 ob_start();
880 $this->output_typography_dynamic_script();
881 $this->output_typography_dynamic_style();
882 $this->output_dynamic_style();
883
884 $custom_css = ob_get_clean();
885
886 ob_start(); ?>
887 (function ($) {
888 $(window).load(function () {
889 /**
890 * @param iframe_id the id of the frame you want to append the style
891 * @param style_element the style element you want to append - boooom
892 */
893 var append_script_to_iframe = function (ifrm_id, scriptEl) {
894 var myIframe = document.getElementById(ifrm_id);
895
896 var script = myIframe.contentWindow.document.createElement("script");
897 script.type = "text/javascript";
898 script.innerHTML = scriptEl.innerHTML;
899
900 myIframe.contentWindow.document.head.appendChild(script);
901 };
902
903 var append_style_to_iframe = function (ifrm_id, styleElement) {
904 var ifrm = window.frames[ifrm_id];
905 if ( typeof ifrm === "undefined" ) {
906 return;
907 }
908 ifrm = ( ifrm.contentDocument || ifrm.contentDocument || ifrm.document );
909 var head = ifrm.getElementsByTagName('head')[0];
910
911 if (typeof styleElement !== "undefined") {
912 head.appendChild(styleElement);
913 }
914 };
915
916 var xmlString = <?php echo json_encode( str_replace( "\n", "", $custom_css ) ); ?>,
917 parser = new DOMParser(),
918 doc = parser.parseFromString(xmlString, "text/html");
919
920 if (typeof window.frames['content_ifr'] !== 'undefined') {
921
922 $.each(doc.head.childNodes, function (key, el) {
923 if (typeof el !== "undefined" && typeof el.tagName !== "undefined") {
924
925 switch (el.tagName) {
926 case 'STYLE' :
927 append_style_to_iframe('content_ifr', el);
928 break;
929 case 'SCRIPT' :
930 append_script_to_iframe('content_ifr', el);
931 break;
932 default:
933 break;
934 }
935 }
936 });
937 }
938 });
939 })(jQuery);
940 <?php
941 $script = ob_get_clean();
942 wp_add_inline_script( 'editor', $script );
943
944 }
945
946 protected function register_customizer_controls() {
947
948 // first get the base customizer extend class
949 require_once( PixCustomifyPlugin()->get_base_path() . 'features/customizer/class-Pix_Customize_Control.php' );
950
951 // now get all the controls
952 $path = PixCustomifyPlugin()->get_base_path() . 'features/customizer/controls/';
953 pixcustomify::require_all( $path );
954 }
955
956 /**
957 * Maybe process certain "commands" from the config.
958 *
959 * Mainly things like removing sections, controls, etc.
960 *
961 * @since 1.9.0
962 *
963 * @param WP_Customize_Manager $wp_customize
964 */
965 public function maybe_process_config_extras( $wp_customize ) {
966 $customizer_config = PixCustomifyPlugin()->get_customizer_config();
967
968 // Bail if we have no external theme config data.
969 if ( empty( $customizer_config ) || ! is_array( $customizer_config ) ) {
970 return;
971 }
972
973 // Maybe remove panels
974 if ( ! empty( $customizer_config['remove_panels'] ) ) {
975 // Standardize it.
976 if ( is_string( $customizer_config['remove_panels'] ) ) {
977 $customizer_config['remove_panels'] = array( $customizer_config['remove_panels'] );
978 }
979
980 foreach ( $customizer_config['remove_panels'] as $panel_id ) {
981 $wp_customize->remove_panel( $panel_id );
982 }
983 }
984
985 // Maybe change panel props.
986 if ( ! empty( $customizer_config['change_panel_props'] ) ) {
987 foreach ( $customizer_config['change_panel_props'] as $panel_id => $panel_props ) {
988 if ( ! is_array( $panel_props ) ) {
989 continue;
990 }
991
992 $panel = $wp_customize->get_panel( $panel_id );
993 if ( empty( $panel ) || ! $panel instanceof WP_Customize_Panel ) {
994 continue;
995 }
996
997 $public_props = get_class_vars( get_class( $panel ) );
998 foreach ( $panel_props as $prop_name => $prop_value ) {
999
1000 if ( ! in_array( $prop_name, array_keys( $public_props ) ) ) {
1001 continue;
1002 }
1003
1004 $panel->$prop_name = $prop_value;
1005 }
1006 }
1007 }
1008
1009 // Maybe remove sections
1010 if ( ! empty( $customizer_config['remove_sections'] ) ) {
1011 // Standardize it.
1012 if ( is_string( $customizer_config['remove_sections'] ) ) {
1013 $customizer_config['remove_sections'] = array( $customizer_config['remove_sections'] );
1014 }
1015
1016 foreach ( $customizer_config['remove_sections'] as $section_id ) {
1017
1018 if ( 'widgets' === $section_id ) {
1019 global $wp_registered_sidebars;
1020
1021 foreach ( $wp_registered_sidebars as $widget => $settings ) {
1022 $wp_customize->remove_section( 'sidebar-widgets-' . $widget );
1023 }
1024 continue;
1025 }
1026
1027 $wp_customize->remove_section( $section_id );
1028 }
1029 }
1030
1031 // Maybe change section props.
1032 if ( ! empty( $customizer_config['change_section_props'] ) ) {
1033 foreach ( $customizer_config['change_section_props'] as $section_id => $section_props ) {
1034 if ( ! is_array( $section_props ) ) {
1035 continue;
1036 }
1037
1038 $section = $wp_customize->get_section( $section_id );
1039 if ( empty( $section ) || ! $section instanceof WP_Customize_Section ) {
1040 continue;
1041 }
1042
1043 $public_props = get_class_vars( get_class( $section ) );
1044 foreach ( $section_props as $prop_name => $prop_value ) {
1045
1046 if ( ! in_array( $prop_name, array_keys( $public_props ) ) ) {
1047 continue;
1048 }
1049
1050 $section->$prop_name = $prop_value;
1051 }
1052 }
1053 }
1054
1055 // Maybe remove settings
1056 if ( ! empty( $customizer_config['remove_settings'] ) ) {
1057 // Standardize it.
1058 if ( is_string( $customizer_config['remove_settings'] ) ) {
1059 $customizer_config['remove_settings'] = array( $customizer_config['remove_settings'] );
1060 }
1061
1062 foreach ( $customizer_config['remove_settings'] as $setting_id ) {
1063 $wp_customize->remove_setting( $setting_id );
1064 }
1065 }
1066
1067 // Maybe change setting props.
1068 if ( ! empty( $customizer_config['change_setting_props'] ) ) {
1069 foreach ( $customizer_config['change_setting_props'] as $setting_id => $setting_props ) {
1070 if ( ! is_array( $setting_props ) ) {
1071 continue;
1072 }
1073
1074 $setting = $wp_customize->get_setting( $setting_id );
1075 if ( empty( $setting ) || ! $setting instanceof WP_Customize_Setting ) {
1076 continue;
1077 }
1078
1079 $public_props = get_class_vars( get_class( $setting ) );
1080 foreach ( $setting_props as $prop_name => $prop_value ) {
1081
1082 if ( ! in_array( $prop_name, array_keys( $public_props ) ) ) {
1083 continue;
1084 }
1085
1086 $setting->$prop_name = $prop_value;
1087 }
1088 }
1089 }
1090
1091 // Maybe remove controls
1092 if ( ! empty( $customizer_config['remove_controls'] ) ) {
1093 // Standardize it.
1094 if ( is_string( $customizer_config['remove_controls'] ) ) {
1095 $customizer_config['remove_controls'] = array( $customizer_config['remove_controls'] );
1096 }
1097
1098 foreach ( $customizer_config['remove_controls'] as $control_id ) {
1099 $wp_customize->remove_control( $control_id );
1100 }
1101 }
1102
1103 // Maybe change control props.
1104 if ( ! empty( $customizer_config['change_control_props'] ) ) {
1105 foreach ( $customizer_config['change_control_props'] as $control_id => $control_props ) {
1106 if ( ! is_array( $control_props ) ) {
1107 continue;
1108 }
1109
1110 $control = $wp_customize->get_control( $control_id );
1111 if ( empty( $control ) || ! $control instanceof WP_Customize_Control ) {
1112 continue;
1113 }
1114
1115 $public_props = get_class_vars( get_class( $control ) );
1116 foreach ( $control_props as $prop_name => $prop_value ) {
1117
1118 if ( ! in_array( $prop_name, array_keys( $public_props ) ) ) {
1119 continue;
1120 }
1121
1122 $control->$prop_name = $prop_value;
1123 }
1124 }
1125 }
1126 }
1127
1128 /**
1129 * @param WP_Customize_Manager $wp_customize
1130 */
1131 function register_customizer( $wp_customize ) {
1132
1133 $this->register_customizer_controls();
1134
1135 $customizer_settings = PixCustomifyPlugin()->get_customizer_config();
1136
1137 if ( ! empty ( $customizer_settings ) ) {
1138
1139 // first check the very needed options name
1140 if ( empty( $customizer_settings['opt-name'] ) ) {
1141 return;
1142 }
1143 $options_name = $customizer_settings['opt-name'];
1144 $wp_customize->options_key = $options_name;
1145
1146 // let's check if we have sections or panels
1147 if ( isset( $customizer_settings['panels'] ) && ! empty( $customizer_settings['panels'] ) ) {
1148
1149 foreach ( $customizer_settings['panels'] as $panel_id => $panel_config ) {
1150
1151 if ( ! empty( $panel_id ) && isset( $panel_config['sections'] ) && ! empty( $panel_config['sections'] ) ) {
1152
1153 // If we have been explicitly given a panel ID we will use that
1154 if ( ! empty( $panel_config['panel_id'] ) ) {
1155 $panel_id = $panel_config['panel_id'];
1156 } else {
1157 $panel_id = $options_name . '[' . $panel_id . ']';
1158 }
1159
1160 $panel_args = array(
1161 'priority' => 10,
1162 'capability' => 'edit_theme_options',
1163 'title' => __( 'Panel title is required', 'customify' ),
1164 'description' => __( 'Description of what this panel does.', 'customify' ),
1165 'auto_expand_sole_section' => false,
1166 );
1167
1168 if ( isset( $panel_config['priority'] ) && ! empty( $panel_config['priority'] ) ) {
1169 $panel_args['priority'] = $panel_config['priority'];
1170 }
1171
1172 if ( isset( $panel_config['title'] ) && ! empty( $panel_config['title'] ) ) {
1173 $panel_args['title'] = $panel_config['title'];
1174 }
1175
1176 if ( isset( $panel_config['description'] ) && ! empty( $panel_config['description'] ) ) {
1177 $panel_args['description'] = $panel_config['description'];
1178 }
1179
1180 if ( isset( $panel_config['auto_expand_sole_section'] ) ) {
1181 $panel_args['auto_expand_sole_section'] = $panel_config['auto_expand_sole_section'];
1182 }
1183
1184
1185 $wp_customize->add_panel( $panel_id, $panel_args );
1186
1187 foreach ( $panel_config['sections'] as $section_id => $section_config ) {
1188 if ( ! empty( $section_id ) && isset( $section_config['options'] ) && ! empty( $section_config['options'] ) ) {
1189 $this->register_section( $panel_id, $section_id, $options_name, $section_config, $wp_customize );
1190 }
1191 }
1192 }
1193 }
1194 }
1195
1196 if ( isset( $customizer_settings['sections'] ) && ! empty( $customizer_settings['sections'] ) ) {
1197
1198 foreach ( $customizer_settings['sections'] as $section_id => $section_config ) {
1199 if ( ! empty( $section_id ) && isset( $section_config['options'] ) && ! empty( $section_config['options'] ) ) {
1200 $this->register_section( $panel_id = false, $section_id, $options_name, $section_config, $wp_customize );
1201 }
1202 }
1203 }
1204
1205 if ( PixCustomifyPlugin()->settings->get_plugin_setting('enable_reset_buttons') ) {
1206 // create a toolbar section which will be present all the time
1207 $reset_section_settings = array(
1208 'title' => 'Customify Toolbox',
1209 'capability' => 'manage_options',
1210 'priority' => 999999999,
1211 'options' => array(
1212 'reset_all_button' => array(
1213 'type' => 'button',
1214 'label' => 'Reset Customify',
1215 'action' => 'reset_customify',
1216 'value' => 'Reset'
1217 ),
1218 )
1219 );
1220
1221 $wp_customize->add_section(
1222 'customify_toolbar',
1223 $reset_section_settings
1224 );
1225
1226 $wp_customize->add_setting(
1227 'reset_customify',
1228 array()
1229 );
1230 $wp_customize->add_control( new Pix_Customize_Button_Control(
1231 $wp_customize,
1232 'reset_customify',
1233 array(
1234 'label' => __( 'Reset All Customify Options to Default', 'customify' ),
1235 'section' => 'customify_toolbar',
1236 'settings' => 'reset_customify',
1237 'action' => 'reset_customify',
1238 )
1239 ) );
1240 }
1241 }
1242
1243 do_action( 'customify_create_custom_control', $wp_customize );
1244 }
1245
1246 /**
1247 * @param string $panel_id
1248 * @param string $section_key
1249 * @param string $options_name
1250 * @param array $section_config
1251 * @param WP_Customize_Manager $wp_customize
1252 */
1253 protected function register_section( $panel_id, $section_key, $options_name, $section_config, $wp_customize ) {
1254
1255 // If we have been explicitly given a section ID we will use that
1256 if ( ! empty( $section_config['section_id'] ) ) {
1257 $section_id = $section_config['section_id'];
1258 } else {
1259 $section_id = $options_name . '[' . $section_key . ']';
1260 }
1261
1262 // Add the new section to the Customizer, but only if it is not already added.
1263 if ( ! $wp_customize->get_section( $section_id ) ) {
1264 // Merge the section settings with the defaults
1265 $section_args = wp_parse_args( $section_config, array(
1266 'priority' => 10,
1267 'panel' => $panel_id,
1268 'capability' => 'edit_theme_options',
1269 'theme_supports' => '',
1270 'title' => esc_html__( 'Title Section is required', 'customify' ),
1271 'description' => '',
1272 'type' => 'default',
1273 'description_hidden' => false,
1274 ) );
1275
1276 // Only add the section if it is not of type `hidden`
1277 if ( 'hidden' !== $section_args['type'] ) {
1278 $wp_customize->add_section( $section_id, $section_args );
1279 }
1280 }
1281
1282 // Now go through each section option and add the fields
1283 foreach ( $section_config['options'] as $option_id => $option_config ) {
1284
1285 if ( empty( $option_id ) || ! isset( $option_config['type'] ) ) {
1286 continue;
1287 }
1288
1289 // If we have been explicitly given a setting ID we will use that
1290 if ( ! empty( $option_config['setting_id'] ) ) {
1291 $setting_id = $option_config['setting_id'];
1292 } else {
1293 $setting_id = $options_name . '[' . $option_id . ']';
1294 }
1295
1296 // Add the option config to the localized array so we can pass the info to JS.
1297 // @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.
1298 $this->localized['settings'][ $setting_id ] = $option_config;
1299
1300 // Generate a safe option ID (not the final setting ID) to us in HTML attributes like ID or class
1301 $this->localized['settings'][ $setting_id ]['html_safe_option_id'] = sanitize_html_class( $option_id );
1302
1303 $this->register_field( $section_id, $setting_id, $option_config, $wp_customize );
1304 }
1305
1306 }
1307
1308 /**
1309 * Register a Customizer field (setting and control).
1310 *
1311 * @see WP_Customize_Setting
1312 * @see WP_Customize_Control
1313 *
1314 * @param string $section_id
1315 * @param string $setting_id
1316 * @param array $field_config
1317 * @param WP_Customize_Manager $wp_customize
1318 */
1319 protected function register_field( $section_id, $setting_id, $field_config, $wp_customize ) {
1320
1321 $add_control = true;
1322 // defaults
1323 $setting_args = array(
1324 'type' => 'theme_mod',
1325 'default' => '',
1326 'capability' => 'edit_theme_options',
1327 'transport' => 'refresh',
1328 );
1329 $control_args = array(
1330 'priority' => 10,
1331 'label' => '',
1332 'section' => $section_id,
1333 'settings' => $setting_id,
1334 );
1335
1336 // sanitize settings
1337 if ( ! empty( $field_config['live'] ) || $field_config['type'] === 'font' ) {
1338 $setting_args['transport'] = 'postMessage';
1339 }
1340
1341 if ( isset( $field_config['default'] ) ) {
1342 $setting_args['default'] = $field_config['default'];
1343 }
1344
1345 if ( ! empty( $field_config['capability'] ) ) {
1346 $setting_args['capability'] = $field_config['capability'];
1347 }
1348
1349 // If the setting defines it's own type we will respect that, otherwise we will follow the global plugin setting.
1350 if ( ! empty( $field_config['setting_type'] ) && 'option' === $field_config['setting_type'] ) {
1351 $setting_args['type'] = 'option';
1352 } elseif ( PixCustomifyPlugin()->settings->get_plugin_setting('values_store_mod') === 'option' ) {
1353 $setting_args['type'] = 'option';
1354 }
1355
1356 // if we arrive here this means we have a custom field control
1357 switch ( $field_config['type'] ) {
1358
1359 case 'checkbox':
1360
1361 $setting_args['sanitize_callback'] = array( $this, 'setting_sanitize_checkbox' );
1362 break;
1363
1364 default:
1365 break;
1366 }
1367
1368 if ( ! empty( $field_config['sanitize_callback'] ) && is_callable( $field_config['sanitize_callback'] ) ) {
1369 $setting_args['sanitize_callback'] = $field_config['sanitize_callback'];
1370 }
1371
1372 // Add the setting
1373 $wp_customize->add_setting( $setting_id, $setting_args );
1374
1375 // Stop the control registration, if we are presented with the right type.
1376 if ( 'hidden_control' === $field_config['type'] ) {
1377 return;
1378 }
1379
1380 $control_args['type'] = $field_config['type'];
1381
1382 // now sanitize the control
1383 if ( ! empty( $field_config['label'] ) ) {
1384 $control_args['label'] = $field_config['label'];
1385 }
1386
1387 if ( ! empty( $field_config['priority'] ) ) {
1388 $control_args['priority'] = $field_config['priority'];
1389 }
1390
1391 if ( ! empty( $field_config['desc'] ) ) {
1392 $control_args['description'] = $field_config['desc'];
1393 }
1394
1395 if ( ! empty( $field_config['active_callback'] ) ) {
1396 $control_args['active_callback'] = $field_config['active_callback'];
1397 }
1398
1399 // select the control type
1400 // but first init a default
1401 $control_class_name = 'Pix_Customize_Text_Control';
1402
1403 // If is a standard wp field type call it here and skip the rest.
1404 if ( in_array( $field_config['type'], array(
1405 'checkbox',
1406 'dropdown-pages',
1407 'url',
1408 'date',
1409 'time',
1410 'datetime',
1411 'week',
1412 'search'
1413 ) ) ) {
1414 $wp_customize->add_control( $setting_id . '_control', $control_args );
1415
1416 return;
1417 } elseif ( in_array( $field_config['type'], array(
1418 'radio',
1419 'select'
1420 ) ) && ! empty( $field_config['choices'] )
1421 ) {
1422 $control_args['choices'] = $field_config['choices'];
1423 $wp_customize->add_control( $setting_id . '_control', $control_args );
1424
1425 return;
1426 } elseif ( in_array( $field_config['type'], array( 'range' ) ) && ! empty( $field_config['input_attrs'] ) ) {
1427
1428 $control_args['input_attrs'] = $field_config['input_attrs'];
1429
1430 $wp_customize->add_control( $setting_id . '_control', $control_args );
1431 }
1432
1433 // If we arrive here this means we have a custom field control.
1434 switch ( $field_config['type'] ) {
1435
1436 case 'text':
1437 if ( isset( $field_config['live'] ) ) {
1438 $control_args['live'] = $field_config['live'];
1439 }
1440
1441 $control_class_name = 'Pix_Customize_Text_Control';
1442 break;
1443
1444 case 'textarea':
1445 if ( isset( $field_config['live'] ) ) {
1446 $control_args['live'] = $field_config['live'];
1447 }
1448
1449 $control_class_name = 'Pix_Customize_Textarea_Control';
1450 break;
1451
1452 case 'color':
1453 $control_class_name = 'WP_Customize_Color_Control';
1454 break;
1455
1456 case 'color_drop':
1457 $control_class_name = 'Pix_Customize_Color_Drop_Control';
1458 break;
1459
1460 case 'ace_editor':
1461 if ( isset( $field_config['live'] ) ) {
1462 $control_args['live'] = $field_config['live'];
1463 }
1464
1465 if ( isset( $field_config['editor_type'] ) ) {
1466 $control_args['editor_type'] = $field_config['editor_type'];
1467 }
1468
1469 $control_class_name = 'Pix_Customize_Ace_Editor_Control';
1470 break;
1471
1472 case 'upload':
1473 $control_class_name = 'WP_Customize_Upload_Control';
1474 break;
1475
1476 case 'image':
1477 $control_class_name = 'WP_Customize_Image_Control';
1478 break;
1479
1480 case 'media':
1481 $control_class_name = 'WP_Customize_Media_Control';
1482 break;
1483
1484 case 'custom_background':
1485 if ( isset( $field_config['field'] ) ) {
1486 $control_args['field'] = $field_config['field'];
1487 }
1488
1489 $control_class_name = 'Pix_Customize_Background_Control';
1490 break;
1491
1492 case 'cropped_image':
1493 case 'cropped_media': // 'cropped_media' no longer works
1494 if ( isset( $field_config['width'] ) ) {
1495 $control_args['width'] = $field_config['width'];
1496 }
1497
1498 if ( isset( $field_config['height'] ) ) {
1499 $control_args['height'] = $field_config['height'];
1500 }
1501
1502 if ( isset( $field_config['flex_width'] ) ) {
1503 $control_args['flex_width'] = $field_config['flex_width'];
1504 }
1505
1506 if ( isset( $field_config['flex_height'] ) ) {
1507 $control_args['flex_height'] = $field_config['flex_height'];
1508 }
1509
1510 if ( isset( $field_config['button_labels'] ) ) {
1511 $control_args['button_labels'] = $field_config['button_labels'];
1512 }
1513
1514 $control_class_name = 'WP_Customize_Cropped_Image_Control';
1515 break;
1516
1517 // Custom types
1518 case 'typography' :
1519 $use_typography = PixCustomifyPlugin()->settings->get_plugin_setting( 'typography', '1' );
1520
1521 if ( $use_typography === false ) {
1522 $add_control = false;
1523 break;
1524 }
1525
1526 $control_class_name = 'Pix_Customize_Typography_Control';
1527
1528 if ( isset( $field_config['backup'] ) ) {
1529 $control_args['backup'] = $field_config['backup'];
1530 }
1531
1532 if ( isset( $field_config['font_weight'] ) ) {
1533 $control_args['font_weight'] = $field_config['font_weight'];
1534 }
1535
1536 if ( isset( $field_config['subsets'] ) ) {
1537 $control_args['subsets'] = $field_config['subsets'];
1538 }
1539
1540 if ( isset( $field_config['recommended'] ) ) {
1541 $control_args['recommended'] = array_flip( $field_config['recommended'] );
1542 }
1543
1544 if ( isset( $field_config['load_all_weights'] ) ) {
1545 $control_args['load_all_weights'] = $field_config['load_all_weights'];
1546 }
1547
1548 if ( isset( $field_config['default'] ) ) {
1549 $control_args['default'] = $field_config['default'];
1550 }
1551
1552 break;
1553
1554 case 'font' :
1555 $use_typography = PixCustomifyPlugin()->settings->get_plugin_setting( 'typography', '1' );
1556
1557 if ( $use_typography === false ) {
1558 $add_control = false;
1559 break;
1560 }
1561
1562 $control_class_name = 'Pix_Customize_Font_Control';
1563
1564 if ( isset( $field_config['backup'] ) ) {
1565 $control_args['backup'] = $field_config['backup'];
1566 }
1567
1568 if ( isset( $field_config['font_weight'] ) ) {
1569 $control_args['font_weight'] = $field_config['font_weight'];
1570 }
1571
1572 if ( isset( $field_config['subsets'] ) ) {
1573 $control_args['subsets'] = $field_config['subsets'];
1574 }
1575
1576 if ( isset( $field_config['recommended'] ) ) {
1577 $control_args['recommended'] = array_flip( $field_config['recommended'] );
1578 }
1579
1580 if ( isset( $field_config['load_all_weights'] ) ) {
1581 $control_args['load_all_weights'] = $field_config['load_all_weights'];
1582 }
1583
1584 if ( isset( $field_config['default'] ) ) {
1585 $control_args['default'] = $field_config['default'];
1586 }
1587
1588 if ( isset( $field_config['fields'] ) ) {
1589 $control_args['fields'] = $field_config['fields'];
1590 }
1591 $control_args['live'] = true;
1592
1593 break;
1594
1595 case 'select2' :
1596 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1597 return;
1598 }
1599
1600 $control_args['choices'] = $field_config['choices'];
1601
1602 $control_class_name = 'Pix_Customize_Select2_Control';
1603 break;
1604
1605 case 'sm_radio' :
1606 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1607 return;
1608 }
1609
1610 $control_args['choices'] = $field_config['choices'];
1611
1612 $control_class_name = 'Pix_Customize_SM_radio_Control';
1613 break;
1614
1615 case 'sm_palette_filter' :
1616 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1617 return;
1618 }
1619
1620 $control_args['choices'] = $field_config['choices'];
1621
1622 $control_class_name = 'Pix_Customize_SM_palette_filter_Control';
1623 break;
1624
1625 case 'sm_switch' :
1626 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1627 return;
1628 }
1629
1630 $control_args['choices'] = $field_config['choices'];
1631
1632 $control_class_name = 'Pix_Customize_SM_switch_Control';
1633 break;
1634
1635 case 'preset' :
1636 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1637 return;
1638 }
1639
1640 $control_args['choices'] = $field_config['choices'];
1641
1642 if ( isset( $field_config['choices_type'] ) || ! empty( $field_config['choices_type'] ) ) {
1643 $control_args['choices_type'] = $field_config['choices_type'];
1644 }
1645
1646 if ( isset( $field_config['desc'] ) || ! empty( $field_config['desc'] ) ) {
1647 $control_args['description'] = $field_config['desc'];
1648 }
1649
1650
1651 $control_class_name = 'Pix_Customize_Preset_Control';
1652 break;
1653
1654 case 'radio_image' :
1655 if ( ! isset( $field_config['choices'] ) || empty( $field_config['choices'] ) ) {
1656 return;
1657 }
1658
1659 $control_args['choices'] = $field_config['choices'];
1660
1661 if ( isset( $field_config['choices_type'] ) || ! empty( $field_config['choices_type'] ) ) {
1662 $control_args['choices_type'] = $field_config['choices_type'];
1663 }
1664
1665 if ( isset( $field_config['desc'] ) || ! empty( $field_config['desc'] ) ) {
1666 $control_args['description'] = $field_config['desc'];
1667 }
1668
1669
1670 $control_class_name = 'Pix_Customize_Radio_Image_Control';
1671 break;
1672
1673 case 'button' :
1674 if ( ! isset( $field_config['action'] ) || empty( $field_config['action'] ) ) {
1675 return;
1676 }
1677
1678 $control_args['action'] = $field_config['action'];
1679
1680 $control_class_name = 'Pix_Customize_Button_Control';
1681
1682 break;
1683
1684 case 'html' :
1685 if ( isset( $field_config['html'] ) || ! empty( $field_config['html'] ) ) {
1686 $control_args['html'] = $field_config['html'];
1687 }
1688
1689 $control_class_name = 'Pix_Customize_HTML_Control';
1690 break;
1691
1692 default:
1693 // if we don't have a real control just quit, it doesn't even matter
1694 return;
1695 break;
1696 }
1697
1698 $this_control = new $control_class_name(
1699 $wp_customize,
1700 $setting_id . '_control',
1701 $control_args
1702 );
1703
1704 if ( $add_control ) {
1705 $wp_customize->add_control( $this_control );
1706 }
1707 }
1708
1709 /**
1710 * Remove the sections selected by user
1711 *
1712 * @param WP_Customize_Manager $wp_customize
1713 */
1714 function remove_default_sections( $wp_customize ) {
1715 global $wp_registered_sidebars;
1716
1717 $to_remove = PixCustomifyPlugin()->settings->get_plugin_setting( 'disable_default_sections' );
1718
1719 if ( ! empty( $to_remove ) ) {
1720 foreach ( $to_remove as $section => $nothing ) {
1721
1722 if ( $section === 'widgets' ) {
1723 foreach ( $wp_registered_sidebars as $widget => $settings ) {
1724 $wp_customize->remove_section( 'sidebar-widgets-' . $widget );
1725 }
1726 continue;
1727 }
1728
1729 $wp_customize->remove_section( $section );
1730 }
1731 }
1732 }
1733
1734 /**
1735 * Print JavaScript for adding additional data to _wpCustomizeSettings.settings object of the main window (not the preview window).
1736 */
1737 public function customize_pane_settings_additional_data() {
1738 /**
1739 * @global WP_Customize_Manager $wp_customize
1740 */
1741 global $wp_customize;
1742
1743 $options_name = PixCustomifyPlugin()->get_options_key();
1744 // Without an options name we can't do much.
1745 if ( empty( $options_name ) ) {
1746 return;
1747 }
1748
1749 $customizer_settings = $wp_customize->settings();
1750 ?>
1751 <script type="text/javascript">
1752 if ( 'undefined' === typeof _wpCustomizeSettings.settings ) {
1753 _wpCustomizeSettings.settings = {};
1754 }
1755
1756 <?php
1757 echo "(function ( sAdditional ){\n";
1758
1759 $options = PixCustomifyPlugin()->get_options_details();
1760 foreach ( $options as $option_id => $option_config ) {
1761 // If we have been explicitly given a setting ID we will use that
1762 if ( ! empty( $option_config['setting_id'] ) ) {
1763 $setting_id = $option_config['setting_id'];
1764 } else {
1765 $setting_id = $options_name . '[' . $option_id . ']';
1766 }
1767 // @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()
1768 if ( ! empty( $customizer_settings[ $setting_id ] ) && ! empty( $option_config['connected_fields'] ) ) {
1769 // Pass through all the connected fields and make sure the id is in the final format
1770 $connected_fields = array();
1771 foreach ( $option_config['connected_fields'] as $key => $connected_field_config ) {
1772 $connected_field_data = array();
1773
1774 if ( is_string( $connected_field_config ) ) {
1775 $connected_field_id = $connected_field_config;
1776 } elseif ( is_array( $connected_field_config ) ) {
1777 // We have a full blown connected field config
1778 if ( is_string( $key ) ) {
1779 $connected_field_id = $key;
1780 } else {
1781 continue;
1782 }
1783
1784 // We will pass to JS all the configured connected field details.
1785 $connected_field_data = $connected_field_config;
1786 }
1787
1788 // Continue if we don't have a connected field ID to work with.
1789 if ( empty( $connected_field_id ) ) {
1790 continue;
1791 }
1792
1793 // If the connected setting is not one of our's, we will use it's ID as it is.
1794 if ( ! array_key_exists( $connected_field_id, $options ) ) {
1795 $connected_field_data['setting_id'] = $connected_field_id;
1796 }
1797 // If the connected setting specifies a setting ID, we will not prefix it and use it as it is.
1798 elseif ( ! empty( $options[ $connected_field_id ] ) && ! empty( $options[ $connected_field_id ]['setting_id'] ) ) {
1799 $connected_field_data['setting_id'] = $options[ $connected_field_id ]['setting_id'];
1800 } else {
1801 $connected_field_data['setting_id'] = $options_name . '[' . $connected_field_id . ']';
1802 }
1803
1804 $connected_fields[] = $connected_field_data;
1805 }
1806
1807 printf(
1808 "sAdditional[%s].%s = %s;\n",
1809 wp_json_encode( $setting_id ),
1810 'connected_fields',
1811 wp_json_encode( $connected_fields, JSON_FORCE_OBJECT )
1812 );
1813 }
1814 }
1815 echo "})( _wpCustomizeSettings.settings );\n";
1816 ?>
1817 </script>
1818 <?php
1819 }
1820
1821 public function get_typography_fields( $fields_config, $key, $value, &$results, $input_key = 0 ) {
1822 if ( ! is_array( $fields_config ) ) {
1823 return;
1824 }
1825
1826 if ( isset( $fields_config[ $key ] ) && $fields_config[ $key ] == $value ) {
1827 $results[ $input_key ] = $fields_config;
1828
1829 $default = null;
1830
1831 if ( isset( $fields_config['default'] ) && is_array( $fields_config['default'] ) ) {
1832 $default = json_encode( $fields_config['default'] );
1833 }
1834
1835 $results[ $input_key ]['value'] = PixCustomifyPlugin()->get_option( $input_key, $default );
1836 }
1837
1838 foreach ( $fields_config as $i => $subarray ) {
1839 $this->get_typography_fields( $subarray, $key, $value, $results, $i );
1840 }
1841 }
1842
1843 /**
1844 * Sanitize functions
1845 */
1846
1847 /**
1848 * Sanitize the checkbox.
1849 *
1850 * @param boolean $input .
1851 *
1852 * @return boolean true if is 1 or '1', false if anything else
1853 */
1854 function setting_sanitize_checkbox( $input ) {
1855 if ( 1 == $input ) {
1856 return true;
1857 } else {
1858 return false;
1859 }
1860 }
1861
1862 /**
1863 * Main PixCustomify_Customizer Instance
1864 *
1865 * Ensures only one instance of PixCustomify_Customizer is loaded or can be loaded.
1866 *
1867 * @since 2.4.0
1868 * @static
1869 *
1870 * @return PixCustomify_Customizer Main PixCustomify_Customizer instance
1871 */
1872 public static function instance() {
1873
1874 if ( is_null( self::$_instance ) ) {
1875 self::$_instance = new self();
1876 }
1877
1878 return self::$_instance;
1879 } // End instance ()
1880
1881 /**
1882 * Cloning is forbidden.
1883 *
1884 * @since 2.4.0
1885 */
1886 public function __clone() {
1887
1888 _doing_it_wrong( __FUNCTION__,esc_html__( 'You should not do that!', 'customify' ), null );
1889 }
1890
1891 /**
1892 * Unserializing instances of this class is forbidden.
1893 *
1894 * @since 2.4.0
1895 */
1896 public function __wakeup() {
1897
1898 _doing_it_wrong( __FUNCTION__, esc_html__( 'You should not do that!', 'customify' ), null );
1899 }
1900 }
1901
1902 endif;
1903