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

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

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