🏨 Hotel Booking Enhancements: - Implemented Eagle Booking Advanced Pricing add-on - Added Booking.com-style rate management system - Created professional calendar interface for pricing - Integrated deals and discounts functionality 💰 Advanced Pricing Features: - Dynamic pricing models (per room, per person, per adult) - Base rates, adult rates, and child rates management - Length of stay discounts and early bird deals - Mobile rates and secret deals implementation - Seasonal promotions and flash sales 📅 Availability Management: - Real-time availability tracking - Stop sell and restriction controls - Closed to arrival/departure functionality - Minimum/maximum stay requirements - Automatic sold-out management 💳 Payment Integration: - Maintained Redsys payment gateway integration - Seamless integration with existing Eagle Booking - No modifications to core Eagle Booking plugin 🛠️ Technical Implementation: - Custom database tables for advanced pricing - WordPress hooks and filters integration - AJAX-powered admin interface - Data migration from existing Eagle Booking - Professional calendar view for revenue management 📊 Admin Interface: - Booking.com-style management dashboard - Visual rate and availability calendar - Bulk operations for date ranges - Statistics and analytics dashboard - Modal dialogs for quick editing 🔧 Code Quality: - WordPress coding standards compliance - Secure database operations with prepared statements - Proper input validation and sanitization - Error handling and logging - Responsive admin interface 🤖 Generated with Claude Code (https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
818 lines
24 KiB
PHP
818 lines
24 KiB
PHP
<?php
|
|
/**
|
|
* Redux Customizer Extension Class
|
|
* Short description.
|
|
*
|
|
* @package ReduxFramework/Extentions
|
|
* @class Redux_Extension_Customizer
|
|
* @version 4.4.11
|
|
* @noinspection PhpIgnoredClassAliasDeclaration
|
|
*/
|
|
|
|
defined( 'ABSPATH' ) || exit;
|
|
|
|
// Don't duplicate me!
|
|
if ( ! class_exists( 'Redux_Extension_Customizer', false ) ) {
|
|
|
|
/**
|
|
* Main ReduxFramework customizer extension class
|
|
*
|
|
* @since 1.0.0
|
|
*/
|
|
class Redux_Extension_Customizer extends Redux_Extension_Abstract {
|
|
|
|
/**
|
|
* Set extension version.
|
|
*
|
|
* @var string
|
|
*/
|
|
public static $version = '4.4.11';
|
|
|
|
/**
|
|
* Set the name of the field. Ideally, this will also be your extension's name.
|
|
* Please use underscores and NOT dashes.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $field_name = 'customizer';
|
|
|
|
/**
|
|
* Set the friendly name of the extension. This is for display purposes. No underscores or dashes are required.
|
|
*
|
|
* @var string
|
|
*/
|
|
public $extension_name = 'Customizer';
|
|
|
|
/**
|
|
* Original options.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $orig_options = array();
|
|
|
|
/**
|
|
* Post values.
|
|
*
|
|
* @var array
|
|
*/
|
|
private static $post_values = array();
|
|
|
|
/**
|
|
* Options array.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $options = array();
|
|
|
|
/**
|
|
* Controls array.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $controls = array();
|
|
|
|
/**
|
|
* Before save array.
|
|
*
|
|
* @var array
|
|
*/
|
|
public $before_save = array();
|
|
|
|
/**
|
|
* Redux object.
|
|
*
|
|
* @var object
|
|
*/
|
|
protected $redux;
|
|
|
|
/**
|
|
* Field array.
|
|
*
|
|
* @var array
|
|
*/
|
|
private $redux_fields = array();
|
|
|
|
/**
|
|
* Redux_Extension_my_extension constructor.
|
|
*
|
|
* @param ReduxFramework $redux ReduxFramework pointer.
|
|
*/
|
|
public function __construct( $redux ) {
|
|
global $pagenow;
|
|
global $wp_customize;
|
|
|
|
parent::__construct( $redux, __FILE__ );
|
|
|
|
if ( is_admin() && ! isset( $wp_customize ) && 'customize.php' !== $pagenow && 'admin-ajax.php' !== $pagenow ) {
|
|
return;
|
|
}
|
|
|
|
$this->add_field( 'customizer' );
|
|
|
|
$this->load();
|
|
}
|
|
|
|
/**
|
|
* The customizer load code
|
|
*/
|
|
private function load() {
|
|
global $pagenow, $wp_customize;
|
|
|
|
if ( false === $this->parent->args['customizer'] ) {
|
|
return;
|
|
}
|
|
|
|
// Override the Redux_Core class.
|
|
add_filter( "redux/extension/{$this->parent->args['opt_name']}/customizer", array( $this, 'remove_core_customizer_class' ) );
|
|
|
|
if ( ! isset( $wp_customize ) && 'customize.php' !== $pagenow && 'admin-ajax.php' !== $pagenow ) {
|
|
return;
|
|
}
|
|
|
|
self::get_post_values();
|
|
|
|
if ( isset( $_POST['wp_customize'] ) && 'on' === $_POST['wp_customize'] ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
$this->parent->args['customizer_only'] = true;
|
|
}
|
|
|
|
if ( isset( $_POST['wp_customize'] ) && 'on' === $_POST['wp_customize'] && ! empty( $_POST['customized'] ) && ! isset( $_POST['action'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
add_action( "redux/options/{$this->parent->args['opt_name']}/options", array( $this, 'override_values' ), 100 );
|
|
}
|
|
|
|
add_action( 'customize_register', array( $this, 'register_customizer_controls' ) ); // Create controls.
|
|
add_action( 'wp_head', array( $this, 'customize_preview_init' ) );
|
|
|
|
add_action( 'customize_save_after', array( &$this, 'customizer_save_after' ) ); // After save.
|
|
|
|
// Add global controls CSS file.
|
|
add_action( 'customize_controls_print_scripts', array( $this, 'enqueue_controls_css' ) );
|
|
add_action( 'customize_controls_init', array( $this, 'enqueue_panel_css' ) );
|
|
add_action( 'wp_enqueue_styles', array( $this, 'custom_css' ), 11 );
|
|
|
|
add_action( 'redux/extension/customizer/control_init', array( $this, 'create_field_classes' ), 1, 2 );
|
|
|
|
add_action( 'wp_ajax_' . $this->parent->args['opt_name'] . '_customizer_save', array( $this, 'customizer' ) );
|
|
add_action( 'customize_controls_print_styles', array( $this, 'add_nonce_html' ) );
|
|
}
|
|
|
|
/**
|
|
* Add nonce HTML for AJAX.
|
|
*/
|
|
public function add_nonce_html() {
|
|
$nonce = wp_create_nonce( 'redux_customer_nonce' );
|
|
|
|
?>
|
|
<div class="redux-customizer-nonce" data-nonce="<?php echo esc_attr( $nonce ); ?>"></div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* AJAX callback for customizer save...to make sanitize/validate work.
|
|
*/
|
|
public function customizer() {
|
|
try {
|
|
$return_array = array();
|
|
|
|
if ( isset( $_POST['nonce'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_customer_nonce' ) && isset( $_POST['opt_name'] ) && '' !== $_POST['opt_name'] ) {
|
|
$redux = Redux::instance( sanitize_text_field( wp_unslash( $_POST['opt_name'] ) ) );
|
|
|
|
$post_data = wp_unslash( $_POST['data'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
|
|
|
|
// New method to avoid input_var nonsense. Thanks @harunbasic.
|
|
$values = Redux_Functions_Ex::parse_str( $post_data );
|
|
|
|
$all_options = get_option( sanitize_text_field( wp_unslash( $_POST['opt_name'] ) ) );
|
|
|
|
$values = wp_parse_args( $values, $all_options );
|
|
|
|
$redux->options_class->set( $redux->options_class->validate_options( $values ) );
|
|
|
|
$redux->enqueue_class->get_warnings_and_errors_array();
|
|
|
|
$return_array = array(
|
|
'status' => 'success',
|
|
'options' => $redux->options,
|
|
'errors' => $redux->enqueue_class->localize_data['errors'] ?? null,
|
|
'warnings' => $redux->enqueue_class->localize_data['warnings'] ?? null,
|
|
'sanitize' => $redux->enqueue_class->localize_data['sanitize'] ?? null,
|
|
);
|
|
}
|
|
} catch ( Exception $e ) {
|
|
$return_array = array( 'status' => $e->getMessage() );
|
|
}
|
|
|
|
echo wp_json_encode( $return_array );
|
|
|
|
die;
|
|
}
|
|
|
|
/**
|
|
* Field classes.
|
|
*
|
|
* @param array $option Option.
|
|
*/
|
|
public function create_field_classes( array $option ) {
|
|
if ( empty( $this->redux_fields ) ) {
|
|
$file_paths = glob( Redux_Core::$dir . 'inc/fields/*' );
|
|
|
|
foreach ( $file_paths as $file ) {
|
|
if ( 'section' !== $file && 'divide' !== $file && 'editor' !== $file ) {
|
|
$this->redux_fields[] = str_replace( Redux_Core::$dir . 'inc/fields/', '', $file );
|
|
}
|
|
}
|
|
|
|
$file_paths = glob( Redux_Core::$dir . 'inc/extensions/*' );
|
|
|
|
foreach ( $file_paths as $file ) {
|
|
if ( 'section' !== $file && 'divide' !== $file && 'editor' !== $file ) {
|
|
$this->redux_fields[] = str_replace( Redux_Core::$dir . 'inc/extensions/', '', $file );
|
|
}
|
|
}
|
|
}
|
|
|
|
$class_name = 'Redux_Customizer_Control_' . $option['type'];
|
|
|
|
if ( ! class_exists( $class_name ) && ( in_array( $option['type'], $this->redux_fields, true ) || ( isset( $option['customizer_enabled'] ) && $option['customizer_enabled'] ) ) ) {
|
|
$upload_dir = Redux_Core::$upload_dir;
|
|
|
|
if ( ! file_exists( $upload_dir . $option['type'] . '.php' ) ) {
|
|
if ( ! is_dir( $upload_dir ) ) {
|
|
$this->parent->filesystem->execute( 'mkdir', $upload_dir );
|
|
}
|
|
|
|
$template = str_replace( '{{type}}', $option['type'], '<?php' . PHP_EOL . ' class Redux_Customizer_Control_{{type}} extends Redux_Customizer_Control {' . PHP_EOL . ' public $type = "redux-{{type}}";' . PHP_EOL . ' }' );
|
|
|
|
$this->parent->filesystem->execute( 'put_contents', $upload_dir . $option['type'] . '.php', array( 'content' => $template ) );
|
|
}
|
|
|
|
if ( file_exists( $upload_dir . $option['type'] . '.php' ) ) {
|
|
include_once $upload_dir . $option['type'] . '.php';
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enqueue extension scripts/styles.
|
|
*/
|
|
public function enqueue_controls_css() {
|
|
$this->parent->enqueue_class->get_warnings_and_errors_array();
|
|
$this->parent->enqueue_class->init();
|
|
|
|
if ( $this->parent->args['dev_mode'] ) {
|
|
wp_enqueue_style(
|
|
'redux-extension-customizer',
|
|
$this->extension_url . 'redux-extension-customizer.css',
|
|
array(),
|
|
self::$version
|
|
);
|
|
}
|
|
|
|
wp_enqueue_script(
|
|
'redux-extension-customizer',
|
|
$this->extension_url . 'redux-extension-customizer' . Redux_Functions::is_min() . '.js',
|
|
array( 'jquery', 'redux-js' ),
|
|
self::$version,
|
|
true
|
|
);
|
|
|
|
wp_localize_script(
|
|
'redux-extension-customizer',
|
|
'redux_customizer',
|
|
array(
|
|
'body_class' => sanitize_html_class( 'admin-color-' . get_user_option( 'admin_color' ), 'fresh' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Enqueue panel CSS>
|
|
*/
|
|
public function enqueue_panel_css() {}
|
|
|
|
/**
|
|
* Remove core customizer class.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function remove_core_customizer_class(): string {
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Customize preview init.
|
|
*/
|
|
public function customize_preview_init() {
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( 'redux/customizer/live_preview' );
|
|
}
|
|
|
|
/**
|
|
* Get post values.
|
|
*/
|
|
protected static function get_post_values() {
|
|
if ( empty( self::$post_values ) && ! empty( $_POST['customized'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
self::$post_values = json_decode( stripslashes_deep( sanitize_text_field( wp_unslash( $_POST['customized'] ) ) ), true ); // phpcs:ignore WordPress.Security.NonceVerification
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Override customizer values.
|
|
*
|
|
* @param array $data Values.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function override_values( array $data ): array {
|
|
self::get_post_values();
|
|
|
|
if ( isset( $_POST['customized'] ) && ! empty( self::$post_values ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
if ( is_array( self::$post_values ) ) {
|
|
foreach ( self::$post_values as $key => $value ) {
|
|
if ( strpos( $key, $this->parent->args['opt_name'] ) !== false ) {
|
|
$key = str_replace( $this->parent->args['opt_name'] . '[', '', rtrim( $key, ']' ) );
|
|
$data[ $key ] = $value;
|
|
|
|
$GLOBALS[ $this->parent->args['global_variable'] ][ $key ] = $value;
|
|
$this->parent->options[ $key ] = $value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Render Redux fields.
|
|
*
|
|
* @param object $control .
|
|
*/
|
|
public function render( $control ) {
|
|
$field_id = str_replace( $this->parent->args['opt_name'] . '-', '', $control->redux_id );
|
|
$field = $this->options[ $field_id ];
|
|
|
|
if ( ! empty( $field['compiler'] ) ) {
|
|
echo '<tr class="compiler">';
|
|
} else {
|
|
echo '<tr>';
|
|
}
|
|
|
|
echo '<th scope="row">' . wp_kses_post( $this->parent->field_head[ $field['id'] ] ) . '</th>';
|
|
echo '<td>';
|
|
|
|
$field['name'] = $field['id'];
|
|
$this->parent->render_class->field_input( $field );
|
|
|
|
echo '</td>';
|
|
echo '</tr>';
|
|
}
|
|
|
|
// All sections, settings, and controls will be added here.
|
|
|
|
/**
|
|
* Register customizer controls.
|
|
*
|
|
* @param WP_Customize_Manager $wp_customize .
|
|
*
|
|
* @throws ReflectionException Exception.
|
|
*/
|
|
public function register_customizer_controls( WP_Customize_Manager $wp_customize ) {
|
|
if ( ! class_exists( 'Redux_Customizer_Section' ) ) {
|
|
require_once __DIR__ . '/inc/class-redux-customizer-section.php';
|
|
|
|
if ( method_exists( $wp_customize, 'register_section_type' ) ) {
|
|
$wp_customize->register_section_type( 'Redux_Customizer_Section' );
|
|
}
|
|
}
|
|
|
|
if ( ! class_exists( 'Redux_Customizer_Panel' ) ) {
|
|
require_once __DIR__ . '/inc/class-redux-customizer-panel.php';
|
|
|
|
if ( method_exists( $wp_customize, 'register_panel_type' ) ) {
|
|
$wp_customize->register_panel_type( 'Redux_Customizer_Panel' );
|
|
}
|
|
}
|
|
|
|
if ( ! class_exists( 'Redux_Customizer_Control' ) ) {
|
|
require_once __DIR__ . '/inc/class-redux-customizer-control.php';
|
|
}
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( 'redux/extension/customizer/control/includes' );
|
|
|
|
$order = array(
|
|
'heading' => - 500,
|
|
'option' => - 500,
|
|
);
|
|
|
|
$panel = '';
|
|
|
|
$this->parent->args['options_api'] = false;
|
|
$this->parent->options_class->register();
|
|
|
|
$parent_section_id = null;
|
|
$new_parent = true;
|
|
|
|
foreach ( $this->parent->sections as $key => $section ) {
|
|
// Not a type that should go on the customizer.
|
|
if ( isset( $section['type'] ) && ( 'divide' === $section['type'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
if ( isset( $section['id'] ) && 'import/export' === $section['id'] ) {
|
|
continue;
|
|
}
|
|
|
|
// If section customizer is set to false.
|
|
if ( isset( $section['customizer'] ) && false === $section['customizer'] ) {
|
|
continue;
|
|
}
|
|
// if we are in a subsection and parent is set to customizer false !!!
|
|
if ( ( isset( $section['subsection'] ) && $section['subsection'] ) ) {
|
|
if ( $new_parent ) {
|
|
$new_parent = false;
|
|
$parent_section_id = ( $key - 1 );
|
|
}
|
|
} else { // not a subsection reset.
|
|
$parent_section_id = null;
|
|
$new_parent = true;
|
|
}
|
|
if ( isset( $parent_section_id ) && ( isset( $this->parent->sections[ $parent_section_id ]['customizer'] ) && false === $this->parent->sections[ $parent_section_id ]['customizer'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$section['permissions'] = $section['permissions'] ?? 'edit_theme_options';
|
|
|
|
// No errors please.
|
|
if ( ! isset( $section['desc'] ) ) {
|
|
$section['desc'] = '';
|
|
}
|
|
|
|
// Fill the description if there is a subtitle.
|
|
if ( empty( $section['desc'] ) && ! empty( $section['subtitle'] ) ) {
|
|
$section['desc'] = $section['subtitle'];
|
|
}
|
|
|
|
// No title is present, let's show what section is missing a title.
|
|
if ( ! isset( $section['title'] ) ) {
|
|
$section['title'] = '';
|
|
}
|
|
|
|
// Let's make a section ID from the title.
|
|
if ( empty( $section['id'] ) ) {
|
|
$section['id'] = Redux_Core::strtolower( str_replace( ' ', '', $section['title'] ) );
|
|
}
|
|
|
|
// Let's set a default priority.
|
|
if ( empty( $section['priority'] ) ) {
|
|
$section['priority'] = $order['heading'];
|
|
++$order['heading'];
|
|
}
|
|
$section['id'] = $this->parent->args['opt_name'] . '-' . $section['id'];
|
|
|
|
if ( method_exists( $wp_customize, 'add_panel' ) && ( ! isset( $section['subsection'] ) || ( true !== $section['subsection'] ) ) && isset( $this->parent->sections[ ( $key + 1 ) ]['subsection'] ) && $this->parent->sections[ ( $key + 1 ) ]['subsection'] ) {
|
|
$this->add_panel(
|
|
$this->parent->args['opt_name'] . '-' . $section['id'],
|
|
array(
|
|
'priority' => $section['priority'],
|
|
'capability' => $section['permissions'],
|
|
'title' => $section['title'],
|
|
'section' => $section,
|
|
'opt_name' => $this->parent->args['opt_name'],
|
|
'description' => '',
|
|
),
|
|
$wp_customize
|
|
);
|
|
|
|
$panel = $this->parent->args['opt_name'] . '-' . $section['id'];
|
|
|
|
$this->add_section(
|
|
$section['id'],
|
|
array(
|
|
'title' => $section['title'],
|
|
'priority' => $section['priority'],
|
|
'description' => $section['desc'],
|
|
'section' => $section,
|
|
'opt_name' => $this->parent->args['opt_name'],
|
|
'capability' => $section['permissions'],
|
|
'panel' => $panel,
|
|
),
|
|
$wp_customize
|
|
);
|
|
} else {
|
|
if ( ! isset( $section['subsection'] ) || ( true !== $section['subsection'] ) ) {
|
|
$panel = '';
|
|
}
|
|
|
|
$this->add_section(
|
|
$section['id'],
|
|
array(
|
|
'title' => $section['title'],
|
|
'priority' => $section['priority'],
|
|
'description' => $section['desc'],
|
|
'opt_name' => $this->parent->args['opt_name'],
|
|
'section' => $section,
|
|
'capability' => $section['permissions'],
|
|
'panel' => $panel,
|
|
),
|
|
$wp_customize
|
|
);
|
|
}
|
|
|
|
if ( ( empty( $section['fields'] ) ) ) {
|
|
continue;
|
|
}
|
|
|
|
foreach ( $section['fields'] as $skey => $option ) {
|
|
|
|
if ( isset( $option['customizer'] ) && false === $option['customizer'] ) {
|
|
continue;
|
|
}
|
|
|
|
if ( false === $this->parent->args['customizer'] && ( ! isset( $option['customizer'] ) || true !== $option['customizer'] ) ) {
|
|
continue;
|
|
}
|
|
|
|
$this->options[ $option['id'] ] = $option;
|
|
add_action( 'redux/customizer/control/render/' . $this->parent->args['opt_name'] . '-' . $option['id'], array( $this, 'render' ) );
|
|
|
|
$option['permissions'] = $option['permissions'] ?? 'edit_theme_options';
|
|
|
|
// Change the item priority if not set.
|
|
if ( 'heading' !== $option['type'] && ! isset( $option['priority'] ) ) {
|
|
$option['priority'] = $order['option'];
|
|
++$order['option'];
|
|
}
|
|
|
|
if ( ! empty( $this->options_defaults[ $option['id'] ] ) ) {
|
|
$option['default'] = $this->options_defaults['option']['id'];
|
|
}
|
|
|
|
if ( ! isset( $option['default'] ) ) {
|
|
$option['default'] = '';
|
|
}
|
|
if ( ! isset( $option['title'] ) ) {
|
|
$option['title'] = '';
|
|
}
|
|
|
|
$option['id'] = $this->parent->args['opt_name'] . '[' . $option['id'] . ']';
|
|
|
|
if ( 'heading' !== $option['type'] && 'import_export' !== $option['type'] && ! empty( $option['type'] ) ) {
|
|
|
|
$wp_customize->add_setting(
|
|
$option['id'],
|
|
array(
|
|
'default' => $option['default'],
|
|
'transport' => 'refresh',
|
|
'opt_name' => $this->parent->args['opt_name'],
|
|
'sanitize_callback' => array( $this, 'field_validation' ),
|
|
)
|
|
);
|
|
}
|
|
|
|
if ( ! empty( $option['data'] ) && empty( $option['options'] ) ) {
|
|
if ( empty( $option['args'] ) ) {
|
|
$option['args'] = array();
|
|
}
|
|
|
|
if ( 'elusive-icons' === $option['data'] || 'elusive-icon' === $option['data'] || 'elusive' === $option['data'] ) {
|
|
$icons_file = Redux_Core::$dir . 'inc/fields/select/elusive-icons.php';
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
$icons_file = apply_filters( 'redux-font-icons-file', $icons_file );
|
|
|
|
if ( file_exists( $icons_file ) ) {
|
|
require_once $icons_file;
|
|
}
|
|
}
|
|
$option['options'] = $this->parent->wordpress_data->get( $option['data'], $option['args'] );
|
|
}
|
|
|
|
$class_name = 'Redux_Customizer_Control_' . $option['type'];
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( 'redux/extension/customizer/control_init', $option );
|
|
|
|
if ( ! class_exists( $class_name ) ) {
|
|
continue;
|
|
}
|
|
|
|
$wp_customize->add_control(
|
|
new $class_name(
|
|
$wp_customize,
|
|
$option['id'],
|
|
array(
|
|
'label' => $option['title'],
|
|
'section' => $section['id'],
|
|
'settings' => $option['id'],
|
|
'type' => 'redux-' . $option['type'],
|
|
'field' => $option,
|
|
'ReduxFramework' => $this->parent,
|
|
'active_callback' => ( isset( $option['required'] ) && class_exists( 'Redux_Customizer_Active_Callback' ) ) ? array(
|
|
'Redux_Customizer_Active_Callback',
|
|
'evaluate',
|
|
) : '__return_true',
|
|
'priority' => $option['priority'],
|
|
)
|
|
)
|
|
);
|
|
|
|
$section['fields'][ $skey ]['name'] = $option['id'];
|
|
if ( ! isset( $section['fields'][ $skey ]['class'] ) ) { // No errors please.
|
|
$section['fields'][ $skey ]['class'] = '';
|
|
}
|
|
|
|
$this->controls[ $section['fields'][ $skey ]['id'] ] = $section['fields'][ $skey ];
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add customizer section.
|
|
*
|
|
* @param string $id ID.
|
|
* @param array $args Args.
|
|
* @param WP_Customize_Manager $wp_customize .
|
|
*/
|
|
public function add_section( string $id, array $args, WP_Customize_Manager $wp_customize ) {
|
|
|
|
if ( is_a( $id, 'WP_Customize_Section' ) ) {
|
|
$section = $id;
|
|
} else {
|
|
$section = new Redux_Customizer_Section( $wp_customize, $id, $args );
|
|
}
|
|
|
|
$wp_customize->add_section( $section, $args );
|
|
}
|
|
|
|
/**
|
|
* Add a customize panel.
|
|
*
|
|
* @param WP_Customize_Panel|string $id Customize Panel object, or Panel ID.
|
|
* @param array $args Optional. Panel arguments. Default empty array.
|
|
* @param WP_Customize_Manager $wp_customize .
|
|
*
|
|
* @since 4.0.0
|
|
* @access public
|
|
*/
|
|
public function add_panel( $id, array $args, WP_Customize_Manager $wp_customize ) {
|
|
if ( is_a( $id, 'WP_Customize_Panel' ) ) {
|
|
$panel = $id;
|
|
} else {
|
|
$panel = new Redux_Customizer_Panel( $wp_customize, $id, $args );
|
|
}
|
|
|
|
$wp_customize->add_panel( $panel, $args );
|
|
}
|
|
|
|
/**
|
|
* Actions to take after customizer save.
|
|
*
|
|
* @throws ReflectionException Exception.
|
|
*/
|
|
public function customizer_save_after() {
|
|
if ( empty( $this->parent->options ) ) {
|
|
$this->parent->get_options();
|
|
}
|
|
|
|
if ( empty( $this->orig_options ) && ! empty( $this->parent->options ) ) {
|
|
$this->orig_options = $this->parent->options;
|
|
}
|
|
|
|
if ( isset( $_POST['customized'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
|
|
$options = json_decode( sanitize_text_field( wp_unslash( $_POST['customized'] ) ), true ); // phpcs:ignore WordPress.Security.NonceVerification
|
|
|
|
$compiler = false;
|
|
$changed = false;
|
|
|
|
foreach ( $options as $key => $value ) {
|
|
if ( strpos( $key, $this->parent->args['opt_name'] ) !== false ) {
|
|
$key = str_replace( $this->parent->args['opt_name'] . '[', '', rtrim( $key, ']' ) );
|
|
|
|
if ( ! isset( $this->orig_options[ $key ] ) || $value !== $this->orig_options[ $key ] || ( isset( $this->orig_options[ $key ] ) && ! empty( $this->orig_options[ $key ] ) && empty( $value ) ) ) {
|
|
$this->parent->options[ $key ] = $value;
|
|
$changed = true;
|
|
|
|
if ( isset( $this->parent->compiler_fields[ $key ] ) ) {
|
|
$compiler = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( $changed ) {
|
|
$this->parent->options_class->set( $this->parent->options );
|
|
if ( $compiler ) {
|
|
// Have to set this to stop the output of the CSS and typography stuff.
|
|
$this->parent->no_output = true;
|
|
$this->parent->output_class->enqueue();
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( "redux/options/{$this->parent->args['opt_name']}/compiler", $this->parent->options, $this->parent->compilerCSS );
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( "redux/options/{$this->parent->args['opt_name']}/compiler/advanced", $this->parent );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enqueue CSS/JS for the customizer controls
|
|
*
|
|
* @since 1.0.0
|
|
* @access public
|
|
* @global $wp_styles
|
|
* @return void
|
|
*/
|
|
public function enqueue() {
|
|
$localize = array(
|
|
'save_pending' => esc_html__( 'You have changes that are not saved. Would you like to save them now?', 'redux-framework' ),
|
|
'reset_confirm' => esc_html__( 'Are you sure? Resetting will lose all custom values.', 'redux-framework' ),
|
|
'preset_confirm' => esc_html__( 'Your current options will be replaced with the values of this preset. Would you like to proceed?', 'redux-framework' ),
|
|
'opt_name' => $this->parent->args['opt_name'],
|
|
'field' => $this->parent->options,
|
|
'defaults' => $this->parent->options_defaults,
|
|
'folds' => $this->parent->folds,
|
|
);
|
|
|
|
// Values used by the javascript.
|
|
wp_localize_script( 'redux-js', 'redux_opts', $localize );
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
do_action( 'redux-enqueue-' . $this->parent->args['opt_name'] );
|
|
|
|
foreach ( $this->parent->sections as $section ) {
|
|
if ( isset( $section['fields'] ) ) {
|
|
foreach ( $section['fields'] as $field ) {
|
|
if ( isset( $field['type'] ) ) {
|
|
$field_classes = array( 'Redux_' . $field['type'], 'ReduxFramework_' . $field['type'] );
|
|
|
|
$field_class = Redux_Functions::class_exists_ex( $field_classes );
|
|
|
|
if ( false === $field_class ) {
|
|
|
|
// phpcs:ignore WordPress.NamingConventions.ValidHookName
|
|
$class_file = apply_filters( 'redux-typeclass-load', $this->path . 'inc/fields/' . $field['type'] . '/field_' . $field['type'] . '.php', $field_class );
|
|
|
|
if ( $class_file ) {
|
|
require_once $class_file;
|
|
|
|
$field_class = Redux_Functions::class_exists_ex( $field_classes );
|
|
|
|
}
|
|
}
|
|
|
|
if ( class_exists( $field_class ) && method_exists( $field_class, 'enqueue' ) ) {
|
|
$enqueue = new $field_class( '', '', $this );
|
|
$enqueue->enqueue();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Register Option for use
|
|
*
|
|
* @since 1.0.0
|
|
* @access public
|
|
* @return void
|
|
*/
|
|
public function register_setting() {
|
|
}
|
|
|
|
/**
|
|
* Validate the options before insertion
|
|
*
|
|
* @param array|string $value The options array.
|
|
*
|
|
* @return array|string $value
|
|
* @since 3.0.0
|
|
* @access public
|
|
*/
|
|
public function field_validation( $value ) {
|
|
|
|
return $value;
|
|
}
|
|
}
|
|
|
|
if ( ! function_exists( 'redux_customizer_custom_validation' ) ) {
|
|
/**
|
|
* Custom validation.
|
|
*
|
|
* @param mixed $field Field.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
function redux_customizer_custom_validation( $field ) {
|
|
return $field;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( ! class_exists( 'ReduxFramework_extension_customizer' ) ) {
|
|
class_alias( 'Redux_Extension_Customizer', 'ReduxFramework_extension_customizer' );
|
|
}
|