balmet.com

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

class-redux-extension-customizer.php (25698B)


      1 <?php
      2 /**
      3  * Redux Customizer Extension Class
      4  * Short description.
      5  *
      6  * @package ReduxFramework/Extentions
      7  * @class Redux_Extension_Customizer
      8  * @version 4.0.0
      9  */
     10 
     11 defined( 'ABSPATH' ) || exit;
     12 
     13 // Don't duplicate me!
     14 if ( ! class_exists( 'Redux_Extension_Customizer', false ) ) {
     15 
     16 	/**
     17 	 * Main ReduxFramework customizer extension class
     18 	 *
     19 	 * @since       1.0.0
     20 	 */
     21 	class Redux_Extension_Customizer extends Redux_Extension_Abstract {
     22 
     23 		/**
     24 		 * Set extension version.
     25 		 *
     26 		 * @var string
     27 		 */
     28 		public static $version = '4.0.0';
     29 
     30 		/**
     31 		 * Set the name of the field.  Ideally, this will also be your extension's name.
     32 		 * Please use underscores and NOT dashes.
     33 		 *
     34 		 * @var string
     35 		 */
     36 		public $field_name = 'customizer';
     37 
     38 		/**
     39 		 * Set the friendly name of the extension.  This is for display purposes.  No underscores or dashes are required.
     40 		 *
     41 		 * @var string
     42 		 */
     43 		public $extension_name = 'Customizer';
     44 
     45 		/**
     46 		 * Set the minumum required version of Redux here (optional).
     47 		 *
     48 		 * Leave blank to require no minimum version.  This allows you to specify a minimum required version of
     49 		 * Redux in the event you do not want to support older versions.
     50 		 *
     51 		 * @var string
     52 		 */
     53 		private $minimum_redux_version = '4.0.0';
     54 
     55 		/**
     56 		 * Original options.
     57 		 *
     58 		 * @var array
     59 		 */
     60 		private $orig_options = array();
     61 
     62 		/**
     63 		 * Post values.
     64 		 *
     65 		 * @var array
     66 		 */
     67 		private static $post_values = array();
     68 
     69 		/**
     70 		 * Options array.
     71 		 *
     72 		 * @var array
     73 		 */
     74 		public $options = array();
     75 
     76 		/**
     77 		 * Redux_Extension_my_extension constructor.
     78 		 *
     79 		 * @param object $parent ReduxFramework pointer.
     80 		 */
     81 		public function __construct( $parent ) {
     82 			parent::__construct( $parent, __FILE__ );
     83 
     84 			if ( is_admin() && ! $this->is_minimum_version( $this->minimum_redux_version, self::$version, $this->extension_name ) ) {
     85 				return;
     86 			}
     87 
     88 			$this->add_field( 'customizer' );
     89 
     90 			$this->load();
     91 
     92 		}
     93 
     94 		/**
     95 		 * The customizer load code
     96 		 */
     97 		private function load() {
     98 			if ( false === $this->parent->args['customizer'] ) {
     99 				return;
    100 			}
    101 
    102 			// Override the Redux_Core class.
    103 			add_filter(
    104 				"redux/extension/{$this->parent->args['opt_name']}/customizer",
    105 				array(
    106 					$this,
    107 					'remove_core_customizer_class',
    108 				)
    109 			);
    110 
    111 			global $pagenow, $wp_customize;
    112 
    113 			if ( ! isset( $wp_customize ) && 'customize.php' !== $pagenow && 'admin-ajax.php' !== $pagenow ) {
    114 				return;
    115 			}
    116 
    117 			self::get_post_values();
    118 
    119 			// Create defaults array.
    120 			$defaults = array();
    121 
    122 			if ( isset( $_POST['wp_customize'] ) && 'on' === $_POST['wp_customize'] ) { // phpcs:ignore WordPress.Security.NonceVerification
    123 				$this->parent->args['customizer_only'] = true;
    124 			}
    125 
    126 			if ( isset( $_POST['wp_customize'] ) && 'on' === $_POST['wp_customize'] && isset( $_POST['customized'] ) && ! empty( $_POST['customized'] ) && ! isset( $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
    127 				add_action(
    128 					"redux/options/{$this->parent->args['opt_name']}/options",
    129 					array(
    130 						$this,
    131 						'override_values',
    132 					),
    133 					100
    134 				);
    135 			}
    136 
    137 			add_action( 'customize_register', array( $this, 'register_customizer_controls' ) ); // Create controls.
    138 			add_action( 'wp_head', array( $this, 'customize_preview_init' ) );
    139 
    140 			// phpcs:ignore Squiz.PHP.CommentedOutCode
    141 			// add_action( 'customize_save', array( $this, 'customizer_save_before' ) ); // Before save.
    142 			add_action( 'customize_save_after', array( &$this, 'customizer_save_after' ) ); // After save.
    143 
    144 			// Add global controls CSS file.
    145 			add_action( 'customize_controls_print_scripts', array( $this, 'enqueue_controls_css' ) );
    146 			add_action( 'customize_controls_init', array( $this, 'enqueue_panel_css' ) );
    147 			add_action( 'wp_enqueue_styles', array( $this, 'custom_css' ), 11 );
    148 		}
    149 
    150 		/**
    151 		 * Enqueue extension scripts/styles.
    152 		 */
    153 		public function enqueue_controls_css() {
    154 			$this->parent->enqueue_class->get_warnings_and_errors_array();
    155 			$this->parent->enqueue_class->init();
    156 
    157 			if ( $this->parent->args['dev_mode'] ) {
    158 				wp_enqueue_style(
    159 					'redux-extension-customizer',
    160 					$this->extension_url . 'redux-extension-customizer.css',
    161 					array(),
    162 					self::$version
    163 				);
    164 			}
    165 
    166 			wp_enqueue_script(
    167 				'redux-extension-customizer-js',
    168 				$this->extension_url . 'redux-extension-customizer' . Redux_Functions::is_min() . '.js',
    169 				array( 'jquery', 'redux-js' ),
    170 				self::$version,
    171 				true
    172 			);
    173 
    174 			$custom_css  = '#' . $this->parent->core_thread . '{line-height:0;border:0;}';
    175 			$custom_css .= '#' . $this->parent->core_instance . '{position:inherit!important;right:0!important;top:0!important;bottom:0!important;';
    176 			$custom_css .= 'left:0!important;text-align:center;margin-bottom:0;line-height:0;-webkit-transition:left ease-in-out .18s;transition:left ease-in-out .18s;}';
    177 			$custom_css .= '#' . $this->parent->core_instance . ' img{-webkit-transition:left ease-in-out .18s;transition:left ease-in-out .18s;}';
    178 
    179 			wp_add_inline_style( 'redux-extension-customizer-css', $custom_css );
    180 
    181 			wp_localize_script(
    182 				'redux-extension-customizer',
    183 				'redux_customizer',
    184 				array(
    185 					'body_class' => sanitize_html_class( 'admin-color-' . get_user_option( 'admin_color' ), 'fresh' ),
    186 				)
    187 			);
    188 		}
    189 
    190 		/**
    191 		 * Enqueue panel CSS>
    192 		 */
    193 		public function enqueue_panel_css() {
    194 
    195 		}
    196 
    197 		/**
    198 		 * Remove core customizer class.
    199 		 *
    200 		 * @param string $path Path to class.
    201 		 *
    202 		 * @return string
    203 		 */
    204 		public function remove_core_customizer_class( string $path ): string {
    205 			return '';
    206 		}
    207 
    208 		/**
    209 		 * Customize preview init.
    210 		 */
    211 		public function customize_preview_init() {
    212 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    213 			do_action( 'redux/customizer/live_preview' );
    214 		}
    215 
    216 		/**
    217 		 * Get post values.
    218 		 */
    219 		protected static function get_post_values() {
    220 			if ( empty( self::$post_values ) && isset( $_POST['customized'] ) && ! empty( $_POST['customized'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
    221 				self::$post_values = json_decode( stripslashes_deep( sanitize_text_field( wp_unslash( $_POST['customized'] ) ) ), true ); // phpcs:ignore WordPress.Security.NonceVerification
    222 			}
    223 		}
    224 
    225 		/**
    226 		 * Override customizer values.
    227 		 *
    228 		 * @param array $data Values.
    229 		 *
    230 		 * @return array
    231 		 */
    232 		public function override_values( array $data ): array {
    233 			self::get_post_values();
    234 
    235 			if ( isset( $_POST['customized'] ) && ! empty( self::$post_values ) ) { // phpcs:ignore WordPress.Security.NonceVerification
    236 				if ( is_array( self::$post_values ) ) {
    237 					foreach ( self::$post_values as $key => $value ) {
    238 						if ( strpos( $key, $this->parent->args['opt_name'] ) !== false ) {
    239 
    240 							$key          = str_replace( $this->parent->args['opt_name'] . '[', '', rtrim( $key, ']' ) );
    241 							$data[ $key ] = $value;
    242 
    243 							$GLOBALS[ $this->parent->args['global_variable'] ][ $key ] = $value;
    244 							$this->parent->options[ $key ]                             = $value;
    245 						}
    246 					}
    247 				}
    248 			}
    249 
    250 			return $data;
    251 		}
    252 
    253 		/**
    254 		 * Render Redux fields.
    255 		 *
    256 		 * @param object $control .
    257 		 */
    258 		public function render( $control ) {
    259 			$field_id = str_replace( $this->parent->args['opt_name'] . '-', '', $control->redux_id );
    260 			$field    = $this->options[ $field_id ];
    261 
    262 			if ( isset( $field['compiler'] ) && ! empty( $field['compiler'] ) ) {
    263 				echo '<tr class="compiler">';
    264 			} else {
    265 				echo '<tr>';
    266 			}
    267 			echo '<th scope="row">' . wp_kses_post( $this->parent->field_head[ $field['id'] ] ) . '</th>';
    268 			echo '<td>';
    269 
    270 			$field['name'] = $field['id'];
    271 			$this->parent->render_class->field_input( $field );
    272 			echo '</td>';
    273 			echo '</tr>';
    274 		}
    275 
    276 		// All sections, settings, and controls will be added here.
    277 
    278 		/**
    279 		 * Register customizer controls.
    280 		 *
    281 		 * @param WP_Customize_Manager $wp_customize .
    282 		 */
    283 		public function register_customizer_controls( WP_Customize_Manager $wp_customize ) {
    284 			if ( ! class_exists( 'Redux_Customizer_Section' ) ) {
    285 				require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-section.php';
    286 				if ( method_exists( $wp_customize, 'register_section_type' ) ) {
    287 					$wp_customize->register_section_type( 'Redux_Customizer_Section' );
    288 				}
    289 			}
    290 			if ( ! class_exists( 'Redux_Customizer_Panel' ) ) {
    291 				require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-panel.php';
    292 				if ( method_exists( $wp_customize, 'register_panel_type' ) ) {
    293 					$wp_customize->register_panel_type( 'Redux_Customizer_Panel' );
    294 				}
    295 			}
    296 			if ( ! class_exists( 'Redux_Customizer_Control' ) ) {
    297 				require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-control.php';
    298 			}
    299 
    300 			require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-fields.php';
    301 			require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-section-dev.php';
    302 			require_once dirname( __FILE__ ) . '/inc/class-redux-customizer-control-dev.php';
    303 
    304 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    305 			do_action( 'redux/extension/customizer/control/includes' );
    306 
    307 			$order = array(
    308 				'heading' => - 500,
    309 				'option'  => - 500,
    310 			);
    311 
    312 			$defaults = array(
    313 				'default-color'          => '',
    314 				'default-image'          => '',
    315 				'wp-head-callback'       => '',
    316 				'admin-head-callback'    => '',
    317 				'admin-preview-callback' => '',
    318 			);
    319 
    320 			$panel = '';
    321 
    322 			$this->parent->args['options_api'] = false;
    323 			$this->parent->_register_settings();
    324 
    325 			$parent_section_id = null;
    326 			$new_parent        = true;
    327 
    328 			foreach ( $this->parent->sections as $key => $section ) {
    329 				// Not a type that should go on the customizer.
    330 				if ( isset( $section['type'] ) && ( 'divide' === $section['type'] ) ) {
    331 					continue;
    332 				}
    333 
    334 				if ( isset( $section['id'] ) && 'import/export' === $section['id'] ) {
    335 					continue;
    336 				}
    337 
    338 				// If section customizer is set to false.
    339 				if ( isset( $section['customizer'] ) && false === $section['customizer'] ) {
    340 					continue;
    341 				}
    342 				// if we are in a subsection and parent is set to customizer false !!!
    343 				if ( ( isset( $section['subsection'] ) && $section['subsection'] ) ) {
    344 					if ( $new_parent ) {
    345 						$new_parent        = false;
    346 						$parent_section_id = ( $key - 1 );
    347 					}
    348 				} else { // not a subsection reset.
    349 					$parent_section_id = null;
    350 					$new_parent        = true;
    351 				}
    352 				if ( isset( $parent_section_id ) && ( isset( $this->parent->sections[ $parent_section_id ]['customizer'] ) && false === $this->parent->sections[ $parent_section_id ]['customizer'] ) ) {
    353 					continue;
    354 				}
    355 
    356 				$section['permissions'] = $section['permissions'] ?? 'edit_theme_options';
    357 
    358 				// No errors please.
    359 				if ( ! isset( $section['desc'] ) ) {
    360 					$section['desc'] = '';
    361 				}
    362 
    363 				// Fill the description if there is a subtitle.
    364 				if ( empty( $section['desc'] ) && ! empty( $section['subtitle'] ) ) {
    365 					$section['desc'] = $section['subtitle'];
    366 				}
    367 
    368 				// Let's make a section ID from the title.
    369 				if ( empty( $section['id'] ) ) {
    370 					$section['id'] = Redux_Core::strtolower( str_replace( ' ', '', $section['title'] ) );
    371 				}
    372 
    373 				// No title is present, let's show what section is missing a title.
    374 				if ( ! isset( $section['title'] ) ) {
    375 					$section['title'] = '';
    376 				}
    377 
    378 				// Let's set a default priority.
    379 				if ( empty( $section['priority'] ) ) {
    380 					$section['priority'] = $order['heading'];
    381 					$order['heading'] ++;
    382 				}
    383 				$section['id'] = $this->parent->args['opt_name'] . '-' . $section['id'];
    384 
    385 				if ( method_exists( $wp_customize, 'add_panel' ) && ( ! isset( $section['subsection'] ) || ( isset( $section['subsection'] ) && true !== $section['subsection'] ) ) && isset( $this->parent->sections[ ( $key + 1 ) ]['subsection'] ) && $this->parent->sections[ ( $key + 1 ) ]['subsection'] ) {
    386 					$this->add_panel(
    387 						$this->parent->args['opt_name'] . '-' . $section['id'],
    388 						array(
    389 							'priority'    => $section['priority'],
    390 							'capability'  => $section['permissions'],
    391 							'title'       => $section['title'],
    392 							'section'     => $section,
    393 							'opt_name'    => $this->parent->args['opt_name'],
    394 							'description' => '',
    395 						),
    396 						$wp_customize
    397 					);
    398 
    399 					$panel = $this->parent->args['opt_name'] . '-' . $section['id'];
    400 
    401 					$this->add_section(
    402 						$section['id'],
    403 						array(
    404 							'title'       => $section['title'],
    405 							'priority'    => $section['priority'],
    406 							'description' => $section['desc'],
    407 							'section'     => $section,
    408 							'opt_name'    => $this->parent->args['opt_name'],
    409 							'capability'  => $section['permissions'],
    410 							'panel'       => $panel,
    411 						),
    412 						$wp_customize
    413 					);
    414 				} else {
    415 					if ( ! isset( $section['subsection'] ) || ( isset( $section['subsection'] ) && true !== $section['subsection'] ) ) {
    416 						$panel = '';
    417 					}
    418 
    419 					$this->add_section(
    420 						$section['id'],
    421 						array(
    422 							'title'       => $section['title'],
    423 							'priority'    => $section['priority'],
    424 							'description' => $section['desc'],
    425 							'opt_name'    => $this->parent->args['opt_name'],
    426 							'section'     => $section,
    427 							'capability'  => $section['permissions'],
    428 							'panel'       => $panel,
    429 						),
    430 						$wp_customize
    431 					);
    432 				}
    433 
    434 				if ( ! isset( $section['fields'] ) || ( isset( $section['fields'] ) && empty( $section['fields'] ) ) ) {
    435 					continue;
    436 				}
    437 
    438 				foreach ( $section['fields'] as $skey => $option ) {
    439 
    440 					if ( isset( $option['customizer'] ) && false === $option['customizer'] ) {
    441 						continue;
    442 					}
    443 
    444 					if ( false === $this->parent->args['customizer'] && ( ! isset( $option['customizer'] ) || true !== $option['customizer'] ) ) {
    445 						continue;
    446 					}
    447 
    448 					$this->options[ $option['id'] ] = $option;
    449 					add_action(
    450 						'redux/advanced_customizer/control/render/' . $this->parent->args['opt_name'] . '-' . $option['id'],
    451 						array(
    452 							$this,
    453 							'render',
    454 						)
    455 					);
    456 
    457 					$option['permissions'] = $option['permissions'] ?? 'edit_theme_options';
    458 
    459 					// Change the item priority if not set.
    460 					if ( 'heading' !== $option['type'] && ! isset( $option['priority'] ) ) {
    461 						$option['priority'] = $order['option'];
    462 						$order['option'] ++;
    463 					}
    464 
    465 					if ( ! empty( $this->options_defaults[ $option['id'] ] ) ) {
    466 						$option['default'] = $this->options_defaults['option']['id'];
    467 					}
    468 
    469 					if ( ! isset( $option['default'] ) ) {
    470 						$option['default'] = '';
    471 					}
    472 					if ( ! isset( $option['title'] ) ) {
    473 						$option['title'] = '';
    474 					}
    475 
    476 					$option['id'] = $this->parent->args['opt_name'] . '[' . $option['id'] . ']';
    477 
    478 					if ( 'heading' !== $option['type'] && 'import_export' !== $option['type'] && ! empty( $option['type'] ) ) {
    479 
    480 						$wp_customize->add_setting(
    481 							$option['id'],
    482 							array(
    483 								'default'           => $option['default'],
    484 								'transport'         => 'refresh',
    485 								'opt_name'          => $this->parent->args['opt_name'],
    486 								'sanitize_callback' => array( $this, 'field_validation' ),
    487 
    488 								// phpcs:ignore Squiz.PHP.CommentedOutCode
    489 								// 'type'              => 'option',
    490 								// 'capabilities'     => $option['permissions'],
    491 								// 'capabilities'      => 'edit_theme_options',
    492 								// 'capabilities'   => $this->parent->args['page_permissions'],
    493 								// 'theme_supports'    => '',
    494 								// 'sanitize_callback' => '__return_false',
    495 								// 'sanitize_js_callback' =>array( &$parent, '_field_input' ),
    496 							)
    497 						);
    498 					}
    499 
    500 					if ( ! empty( $option['data'] ) && empty( $option['options'] ) ) {
    501 						if ( empty( $option['args'] ) ) {
    502 							$option['args'] = array();
    503 						}
    504 
    505 						if ( 'elusive-icons' === $option['data'] || 'elusive-icon' === $option['data'] || 'elusive' === $option['data'] ) {
    506 							$icons_file = Redux_Core::$dir . 'inc/fields/select/elusive-icons.php';
    507 
    508 							// phpcs:ignore WordPress.NamingConventions.ValidHookName
    509 							$icons_file = apply_filters( 'redux-font-icons-file', $icons_file );
    510 
    511 							if ( file_exists( $icons_file ) ) {
    512 								require_once $icons_file;
    513 							}
    514 						}
    515 
    516 						$option['options'] = $this->parent->wordpress_data->get( $option['data'], $option['args'], $this->parent->args['opt_name'] );
    517 					}
    518 
    519 					$class_name = 'Redux_Customizer_Control_' . $option['type'];
    520 
    521 					// phpcs:ignore WordPress.NamingConventions.ValidHookName
    522 					do_action( 'redux/extension/customizer/control_init', $option );
    523 
    524 					if ( ! class_exists( $class_name ) ) {
    525 						continue;
    526 					}
    527 
    528 					$wp_customize->add_control(
    529 						new $class_name(
    530 							$wp_customize,
    531 							$option['id'],
    532 							array(
    533 								'label'           => $option['title'],
    534 								'section'         => $section['id'],
    535 								'settings'        => $option['id'],
    536 								'type'            => 'redux-' . $option['type'],
    537 								'field'           => $option,
    538 								'ReduxFramework'  => $this->parent,
    539 								'active_callback' => ( isset( $option['required'] ) && class_exists( 'Redux_Customizer_Active_Callback' ) ) ? array(
    540 									'Redux_Customizer_Active_Callback',
    541 									'evaluate',
    542 								) : '__return_true',
    543 								'priority'        => $option['priority'],
    544 							)
    545 						)
    546 					);
    547 
    548 					$section['fields'][ $skey ]['name'] = $option['id'];
    549 					if ( ! isset( $section['fields'][ $skey ]['class'] ) ) { // No errors please.
    550 						$section['fields'][ $skey ]['class'] = '';
    551 					}
    552 
    553 					$this->controls[ $section['fields'][ $skey ]['id'] ] = $section['fields'][ $skey ];
    554 
    555 					add_action(
    556 						'redux/advanced_customizer/render/' . $option['id'],
    557 						array(
    558 							$this,
    559 							'field_render',
    560 						),
    561 						$option['priority']
    562 					);
    563 				}
    564 			}
    565 		}
    566 
    567 		/**
    568 		 * Add customizer section.
    569 		 *
    570 		 * @param string               $id           ID.
    571 		 * @param array                $args         Args.
    572 		 * @param WP_Customize_Manager $wp_customize .
    573 		 */
    574 		public function add_section( string $id, array $args, WP_Customize_Manager $wp_customize ) {
    575 
    576 			if ( is_a( $id, 'WP_Customize_Section' ) ) {
    577 				$section = $id;
    578 			} else {
    579 				// phpcs:ignore WordPress.NamingConventions.ValidHookName
    580 				$section_class = apply_filters( 'redux/customizer/section/class_name', 'Redux_Customizer_Section' );
    581 				$section       = new $section_class( $wp_customize, $id, $args );
    582 			}
    583 
    584 			$wp_customize->add_section( $section, $args );
    585 		}
    586 
    587 		/**
    588 		 * Add a customize panel.
    589 		 *
    590 		 * @param WP_Customize_Panel|string $id           Customize Panel object, or Panel ID.
    591 		 * @param array                     $args         Optional. Panel arguments. Default empty array.
    592 		 * @param WP_Customize_Manager      $wp_customize .
    593 		 *
    594 		 * @since  4.0.0
    595 		 * @access public
    596 		 */
    597 		public function add_panel( $id, array $args, WP_Customize_Manager $wp_customize ) {
    598 			if ( is_a( $id, 'WP_Customize_Panel' ) ) {
    599 				$panel = $id;
    600 			} else {
    601 				// phpcs:ignore WordPress.NamingConventions.ValidHookName
    602 				$panel_class = apply_filters( 'redux/customizer/panel/class_name', 'Redux_Customizer_Panel' );
    603 				$panel       = new $panel_class( $wp_customize, $id, $args );
    604 			}
    605 
    606 			$wp_customize->add_panel( $panel, $args );
    607 		}
    608 
    609 		/**
    610 		 * Render Redux fields.
    611 		 *
    612 		 * @param array $option Option.
    613 		 */
    614 		public function field_render( array $option ) {
    615 			echo '1';
    616 			preg_match_all( '/\[([^\]]*)\]/', $option->id, $matches );
    617 			$id = $matches[1][0];
    618 			echo esc_url( $option->link() );
    619 
    620 			$this->parent->render_class->field_input( $this->controls[ $id ] );
    621 			echo '2';
    622 		}
    623 
    624 		/**
    625 		 * Actions to take before customizer save.
    626 		 *
    627 		 * @param array $plugin_options .
    628 		 */
    629 		public function customizer_save_before( array $plugin_options ) {
    630 			$this->before_save = $this->parent->options;
    631 		}
    632 
    633 		/**
    634 		 * Actions to take after customizer save.
    635 		 *
    636 		 * @param WP_Customize_Manager $wp_customize .
    637 		 */
    638 		public function customizer_save_after( WP_Customize_Manager $wp_customize ) {
    639 			if ( empty( $this->parent->options ) ) {
    640 				$this->parent->get_options();
    641 			}
    642 			if ( empty( $this->orig_options ) && ! empty( $this->parent->options ) ) {
    643 				$this->orig_options = $this->parent->options;
    644 			}
    645 
    646 			if ( isset( $_POST['customized'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
    647 				$options = json_decode( sanitize_text_field( wp_unslash( $_POST['customized'] ) ), true ); // phpcs:ignore WordPress.Security.NonceVerification
    648 
    649 				$compiler = false;
    650 				$changed  = false;
    651 
    652 				foreach ( $options as $key => $value ) {
    653 					if ( strpos( $key, $this->parent->args['opt_name'] ) !== false ) {
    654 						$key = str_replace( $this->parent->args['opt_name'] . '[', '', rtrim( $key, ']' ) );
    655 
    656 						if ( ! isset( $this->orig_options[ $key ] ) || $value !== $this->orig_options[ $key ] || ( isset( $this->orig_options[ $key ] ) && ! empty( $this->orig_options[ $key ] ) && empty( $value ) ) ) {
    657 							$this->parent->options[ $key ] = $value;
    658 							$changed                       = true;
    659 							if ( isset( $this->parent->compiler_fields[ $key ] ) ) {
    660 								$compiler = true;
    661 							}
    662 						}
    663 					}
    664 				}
    665 
    666 				if ( $changed ) {
    667 					$this->parent->set_options( $this->parent->options );
    668 					if ( $compiler ) {
    669 						// Have to set this to stop the output of the CSS and typography stuff.
    670 						$this->parent->no_output = true;
    671 						$this->parent->output_class->enqueue();
    672 
    673 						// phpcs:ignore WordPress.NamingConventions.ValidHookName
    674 						do_action( "redux/options/{$this->parent->args['opt_name']}/compiler", $this->parent->options, $this->parent->compilerCSS );
    675 
    676 						// phpcs:ignore WordPress.NamingConventions.ValidHookName
    677 						do_action( "redux/options/{$this->args['opt_name']}/compiler/advanced", $this->parent );
    678 					}
    679 				}
    680 			}
    681 		}
    682 
    683 		/**
    684 		 * Enqueue CSS/JS for preview pane
    685 		 *
    686 		 * @since       1.0.0
    687 		 * @access      public
    688 		 * @global      $wp_styles
    689 		 * @return      void
    690 		 */
    691 		public function enqueue_previewer() {
    692 			wp_enqueue_script( 'redux-extension-previewer-js', $this->extension_url . 'assets/js/preview.js', array(), self::$version, true );
    693 
    694 			$localize = array(
    695 				'save_pending'   => esc_html__( 'You have changes that are not saved. Would you like to save them now?', 'redux-framework' ),
    696 				'reset_confirm'  => esc_html__( 'Are you sure? Resetting will lose all custom values.', 'redux-framework' ),
    697 				'preset_confirm' => esc_html__( 'Your current options will be replaced with the values of this preset. Would you like to proceed?', 'redux-framework' ),
    698 				'opt_name'       => $this->args['opt_name'],
    699 				'options'        => $this->parent->options,
    700 				'defaults'       => $this->parent->options_defaults,
    701 
    702 				// phpcs:ignore Squiz.PHP.CommentedOutCode
    703 				// 'folds'             => $this->folds,
    704 			);
    705 
    706 			wp_localize_script( 'redux-extension-previewer-js', 'reduxPost', $localize );
    707 		}
    708 
    709 		/**
    710 		 * Enqueue CSS/JS for the customizer controls
    711 		 *
    712 		 * @since       1.0.0
    713 		 * @access      public
    714 		 * @global      $wp_styles
    715 		 * @return      void
    716 		 */
    717 		public function enqueue() {
    718 			global $wp_styles;
    719 
    720 			$localize = array(
    721 				'save_pending'   => esc_html__( 'You have changes that are not saved.  Would you like to save them now?', 'redux-framework' ),
    722 				'reset_confirm'  => esc_html__( 'Are you sure?  Resetting will lose all custom values.', 'redux-framework' ),
    723 				'preset_confirm' => esc_html__( 'Your current options will be replaced with the values of this preset.  Would you like to proceed?', 'redux-framework' ),
    724 				'opt_name'       => $this->args['opt_name'],
    725 				'field'          => $this->parent->options,
    726 				'defaults'       => $this->parent->options_defaults,
    727 
    728 				// phpcs:ignore Squiz.PHP.CommentedOutCode
    729 				// 'folds'             => $this->folds,
    730 			);
    731 
    732 			// Values used by the javascript.
    733 			wp_localize_script( 'redux-js', 'redux_opts', $localize );
    734 
    735 			// phpcs:ignore WordPress.NamingConventions.ValidHookName
    736 			do_action( 'redux-enqueue-' . $this->args['opt_name'] );
    737 
    738 			foreach ( $this->sections as $section ) {
    739 				if ( isset( $section['fields'] ) ) {
    740 					foreach ( $section['fields'] as $field ) {
    741 						if ( isset( $field['type'] ) ) {
    742 							$field_classes = array( 'Redux_' . $field['type'], 'ReduxFramework_' . $field['type'] );
    743 
    744 							$field_class = Redux_Functions::class_exists_ex( $field_classes );
    745 
    746 							if ( false === $field_class ) {
    747 
    748 								// phpcs:ignore WordPress.NamingConventions.ValidHookName
    749 								$class_file = apply_filters( 'redux-typeclass-load', $this->path . 'inc/fields/' . $field['type'] . '/field_' . $field['type'] . '.php', $field_class );
    750 
    751 								if ( $class_file ) {
    752 									require_once $class_file;
    753 
    754 									$field_class = Redux_Functions::class_exists_ex( $field_classes );
    755 
    756 								}
    757 							}
    758 
    759 							if ( class_exists( $field_class ) && method_exists( $field_class, 'enqueue' ) ) {
    760 								$enqueue = new $field_class( '', '', $this );
    761 								$enqueue->enqueue();
    762 							}
    763 						}
    764 					}
    765 				}
    766 			}
    767 		}
    768 
    769 		/**
    770 		 * Register Option for use
    771 		 *
    772 		 * @since       1.0.0
    773 		 * @access      public
    774 		 * @return      void
    775 		 */
    776 		public function register_setting() {
    777 
    778 		}
    779 
    780 		/**
    781 		 * Validate the options before insertion
    782 		 *
    783 		 * @param       array|string $value The options array.
    784 		 *
    785 		 * @return      string|array
    786 		 * @since       3.0.0
    787 		 * @access      public
    788 		 */
    789 		public function field_validation( $value ) {
    790 
    791 			return $value;
    792 		}
    793 
    794 		/**
    795 		 * HTML OUTPUT.
    796 		 *
    797 		 * @since       1.0.0
    798 		 * @access      public
    799 		 * @return      void
    800 		 */
    801 		public function customizer_html_output() {
    802 
    803 		}
    804 	}
    805 
    806 	if ( ! function_exists( 'redux_customizer_custom_validation' ) ) {
    807 		/**
    808 		 * Custom validation.
    809 		 *
    810 		 * @param mixed $field Field.
    811 		 *
    812 		 * @return mixed
    813 		 */
    814 		function redux_customizer_custom_validation( $field ) {
    815 			return $field;
    816 		}
    817 	}
    818 
    819 	if ( ! class_exists( 'ReduxFramework_extension_customizer' ) ) {
    820 		class_alias( 'Redux_Extension_Customizer', 'ReduxFramework_extension_customizer' );
    821 	}
    822 }