Hotel Raxa - Advanced Booking System Implementation

🏨 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>
This commit is contained in:
Hotel Raxa Dev
2025-07-11 07:43:22 +02:00
commit 5b1e2453c7
9816 changed files with 2784509 additions and 0 deletions

View File

@@ -0,0 +1,123 @@
<?php
/**
* Redux Accordion Field Class
*
* @package Redux Extentions
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Accordion
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Accordion' ) ) {
/**
* Main ReduxFramework_Accordion class
*
* @since 1.0.0
*/
class Redux_Accordion extends Redux_Field {
/**
* Set field defaults.
*/
public function set_defaults() {
$defaults = array(
'position' => 'end',
'style' => '',
'class' => '',
'title' => '',
'subtitle' => '',
'open' => '',
'open-icon' => 'el-plus',
'close-icon' => 'el-minus',
);
$this->field = wp_parse_args( $this->field, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @since 1.0.0
* @access public
* @return void
*/
public function render() {
$guid = uniqid();
$field_pos = '';
$add_class = '';
// primary container.
if ( 'start' === $this->field['position'] ) {
$add_class = ' form-table-accordion';
$field_pos = 'start';
} elseif ( 'end' === $this->field['position'] ) {
$add_class = ' hide';
$field_pos = 'end';
}
echo '<input type="hidden" id="accordion-' . esc_attr( $this->field['id'] ) . '-marker" data-open-icon="' . esc_attr( $this->field['open-icon'] ) . '" data-close-icon="' . esc_attr( $this->field['close-icon'] ) . '"></td></tr></table>';
$is_open = false;
if ( isset( $this->field['open'] ) && true === $this->field['open'] ) {
$is_open = true;
}
echo '<div data-state="' . esc_attr( $is_open ) . '" data-position="' . esc_attr( $field_pos ) . '" id="' . esc_attr( $this->field['id'] ) . '" class="redux-accordion-field redux-field ' . esc_attr( $this->field['style'] ) . esc_attr( $this->field['class'] ) . '">';
echo '<div class="control">';
echo '<div class="redux-accordion-info' . esc_attr( $add_class ) . '">';
if ( ! empty( $this->field['title'] ) ) {
echo '<h3>' . esc_html( $this->field['title'] ) . '</h3>';
}
$icon_class = '';
if ( ! empty( $this->field['subtitle'] ) ) {
echo '<div class="redux-accordion-desc">' . esc_html( $this->field['subtitle'] ) . '</div>';
$icon_class = ' subtitled';
}
echo '<span class="el el-plus' . esc_attr( $icon_class ) . '"></span>';
echo '</div>';
echo '</div>';
echo '</div>';
echo '<table id="accordion-table-' . esc_attr( $this->field['id'] ) . '" data-id="' . esc_attr( $this->field['id'] ) . '" class="form-table form-table-accordion no-border' . esc_attr( $add_class ) . '"><tbody><tr class="hide"><th></th><td id="' . esc_attr( $guid ) . '">';
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access public
* @return void
*/
public function enqueue() {
// Set up min files for dev_mode = false.
$min = Redux_Functions::isMin();
// Field dependent JS.
wp_enqueue_script(
'redux-field-accordion',
$this->url . 'redux-accordion' . $min . '.js',
array( 'jquery', 'redux-js' ),
Redux_Extension_Accordion::$version,
true
);
// Field CSS.
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-accordion',
$this->url . 'redux-accordion.css',
array(),
Redux_Extension_Accordion::$version
);
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,21 @@
.redux-main .redux-accordion-field { overflow: hidden; cursor: pointer; margin-top: 10px; }
.redux-main .redux-accordion-field:first-child { margin-top: 0; }
.redux-main .redux-accordion-field .redux-accordion-info { border: 1px solid #dfdfdf; padding: 10px 15px; height: auto; min-height: 20px; overflow: hidden; word-wrap: break-word; background: #FAFAFA; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); }
.redux-main .redux-accordion-field .redux-accordion-info:hover { border-color: #999; }
.redux-main .redux-accordion-field .redux-accordion-info .el { color: #000; float: right; margin-top: -23px; margin-right: 10px; -webkit-transition: all 0.5s; transition: all 0.5s; }
.redux-main .redux-accordion-field .redux-accordion-info .el.subtitled { margin-top: -33px; }
.redux-main .redux-accordion-field h3 { margin: 0; border-bottom: 0; }
.redux-main .redux-accordion-field .redux-accordion-desc { margin: -5px 0 10px; }
.redux-accordion-wrap { border: 1px solid #e5e5e5; -webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); box-shadow: 0 1px 1px rgba(0, 0, 0, 0.04); border-top: none; padding: 0 15px; background: #fff; }
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtYWNjb3JkaW9uLmNzcyIsInNvdXJjZXMiOlsicmVkdXgtYWNjb3JkaW9uLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsQUFDSSxXQURPLENBQ1Asc0JBQXNCLENBQUMsRUFDbkIsUUFBUSxFQUFFLE1BQU0sRUFDaEIsTUFBTSxFQUFFLE9BQU8sRUFDZixVQUFVLEVBQUUsSUFBSSxHQXlDbkI7O0FBN0NMLEFBTVEsV0FORyxDQUNQLHNCQUFzQixBQUtqQixZQUFZLENBQUMsRUFDVixVQUFVLEVBQUUsQ0FBQyxHQUNoQjs7QUFSVCxBQVVRLFdBVkcsQ0FDUCxzQkFBc0IsQ0FTbEIscUJBQXFCLENBQUMsRUFDbEIsTUFBTSxFQUFFLGlCQUFpQixFQUN6QixPQUFPLEVBQUUsU0FBUyxFQUNsQixNQUFNLEVBQUUsSUFBSSxFQUNaLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLFFBQVEsRUFBRSxNQUFNLEVBQ2hCLFNBQVMsRUFBRSxVQUFVLEVBQ3JCLFVBQVUsRUFBRSxPQUFPLEVBQ25CLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLG1CQUFrQixFQUNoRCxVQUFVLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsbUJBQWtCLEdBZ0IzQzs7QUFuQ1QsQUFxQlksV0FyQkQsQ0FDUCxzQkFBc0IsQ0FTbEIscUJBQXFCLEFBV2hCLE1BQU0sQ0FBQyxFQUNKLFlBQVksRUFBRSxJQUFJLEdBQ3JCOztBQXZCYixBQXlCWSxXQXpCRCxDQUNQLHNCQUFzQixDQVNsQixxQkFBcUIsQ0FlakIsR0FBRyxDQUFDLEVBQ0EsS0FBSyxFQUFFLElBQUksRUFDWCxLQUFLLEVBQUUsS0FBSyxFQUNaLFVBQVUsRUFBRSxLQUFLLEVBQ2pCLFlBQVksRUFBRSxJQUFJLEVBQ2xCLFVBQVUsRUFBRSxRQUFRLEdBSXZCOztBQWxDYixBQStCZ0IsV0EvQkwsQ0FDUCxzQkFBc0IsQ0FTbEIscUJBQXFCLENBZWpCLEdBQUcsQUFNRSxVQUFVLENBQUMsRUFDUixVQUFVLEVBQUUsS0FBSyxHQUNwQjs7QUFqQ2pCLEFBcUNRLFdBckNHLENBQ1Asc0JBQXNCLENBb0NsQixFQUFFLENBQUMsRUFDQyxNQUFNLEVBQUUsQ0FBQyxFQUNULGFBQWEsRUFBRSxDQUFDLEdBQ25COztBQXhDVCxBQTBDUSxXQTFDRyxDQUNQLHNCQUFzQixDQXlDbEIscUJBQXFCLENBQUMsRUFDbEIsTUFBTSxFQUFFLFdBQVcsR0FDdEI7O0FBSVQsQUFBQSxxQkFBcUIsQ0FBQyxFQUNsQixNQUFNLEVBQUUsaUJBQWlCLEVBQ3pCLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLG1CQUFrQixFQUNoRCxVQUFVLEVBQUUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsbUJBQWtCLEVBQ3hDLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLE9BQU8sRUFBRSxNQUFNLEVBQ2YsVUFBVSxFQUFFLElBQUksR0FDbkIifQ== */
/*# sourceMappingURL=redux-accordion.css.map */

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,109 @@
/* global jQuery, document, redux */
( function ( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.accordion = redux.field_objects.accordion || {};
redux.field_objects.accordion.init = function ( selector ) {
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-accordion:visible' );
}
$( selector ).each(
function () {
var $id;
var group;
var test;
var accordionMarker;
var openIcon;
var closeIcon;
var table;
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
$id = el.attr( 'data-id' );
table = $( '#accordion-' + $id + '-marker' );
table.parents( 'tr:first' ).css( { display: 'none' } ).prev( 'tr' ).css( 'border-bottom', 'none' );
group = table.parents( '.redux-group-tab:first' );
if ( ! group.hasClass( 'accordionsChecked' ) ) {
group.addClass( 'accordionsChecked' );
test = group.find( '.redux-accordion-indent-start h3' );
$.each(
test,
function ( key, value ) {
key = null;
$( value ).css( 'margin-top', '20px' );
}
);
if ( '20px' === group.find( 'h3:first' ).css( 'margin-top' ) ) {
group.find( 'h3:first' ).css( 'margin-top', '0' );
}
accordionMarker = table;
openIcon = accordionMarker.data( 'open-icon' );
closeIcon = accordionMarker.data( 'close-icon' );
group.find( '.redux-accordion-field' ).on(
'click',
function ( e ) {
var id = $( this ).attr( 'id' );
var table = $( '#accordion-table-' + id );
e.preventDefault();
if ( table.closest( 'div' ).is( ':visible' ) ) {
$( this ).find( '.el' ).removeClass( closeIcon ).addClass( openIcon );
table.closest( 'div' ).slideUp();
} else {
table.closest( 'div' ).slideDown();
$.redux.initFields();
$( this ).find( '.el' ).removeClass( openIcon ).addClass( closeIcon );
}
}
);
group.find( '.redux-accordion-field' ).each(
function () {
var id;
var state;
var table;
var position = $( this ).data( 'position' );
if ( 'start' === position ) {
id = $( this ).attr( 'id' );
state = Boolean( $( this ).data( 'state' ) );
table = $( '#accordion-table-' + id );
table.wrapAll( '<div class="redux-accordion-wrap"/>' );
if ( false === state ) {
table.closest( 'div' ).hide();
} else {
$( this ).find( '.el' ).removeClass( openIcon ).addClass( closeIcon );
}
}
}
);
}
}
);
};
} )( jQuery );

View File

@@ -0,0 +1 @@
.redux-main .redux-accordion-field{overflow:hidden;cursor:pointer;margin-top:10px}.redux-main .redux-accordion-field:first-child{margin-top:0}.redux-main .redux-accordion-field .redux-accordion-info{border:1px solid #dfdfdf;padding:10px 15px;height:auto;min-height:20px;overflow:hidden;word-wrap:break-word;background:#fafafa;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.04);box-shadow:0 1px 1px rgba(0,0,0,0.04)}.redux-main .redux-accordion-field .redux-accordion-info:hover{border-color:#999}.redux-main .redux-accordion-field .redux-accordion-info .el{color:#000;float:right;margin-top:-23px;margin-right:10px;-webkit-transition:all .5s;transition:all .5s}.redux-main .redux-accordion-field .redux-accordion-info .el.subtitled{margin-top:-33px}.redux-main .redux-accordion-field h3{margin:0;border-bottom:0}.redux-main .redux-accordion-field .redux-accordion-desc{margin:0;margin-bottom:10px;margin-top:-5px}.redux-accordian-wrap{border:1px solid #e5e5e5;-webkit-box-shadow:0 1px 1px rgba(0,0,0,0.04);box-shadow:0 1px 1px rgba(0,0,0,0.04);border-top:0;padding:0 15px;background:#fff}

View File

@@ -0,0 +1 @@
!function(t){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.accordion=redux.field_objects.accordion||{},redux.field_objects.accordion.init=function(i){i=i||t(document).find(".redux-group-tab:visible").find(".redux-container-accordion:visible"),t(i).each(function(){var i,s,d,e=t(this),a=e;(a=e.hasClass("redux-field-container")?a:e.parents(".redux-field-container:first")).hasClass("redux-field-init")&&(a.removeClass("redux-field-init"),a=e.attr("data-id"),(e=t("#accordion-"+a+"-marker")).parents("tr:first").css({display:"none"}).prev("tr").css("border-bottom","none"),(a=e.parents(".redux-group-tab:first")).hasClass("accordionsChecked")||(a.addClass("accordionsChecked"),i=a.find(".redux-accordion-indent-start h3"),t.each(i,function(i,e){t(e).css("margin-top","20px")}),"20px"===a.find("h3:first").css("margin-top")&&a.find("h3:first").css("margin-top","0"),s=(i=e).data("open-icon"),d=i.data("close-icon"),a.find(".redux-accordion-field").on("click",function(i){var e=t(this).attr("id"),e=t("#accordion-table-"+e);i.preventDefault(),e.closest("div").is(":visible")?(t(this).find(".el").removeClass(d).addClass(s),e.closest("div").slideUp()):(e.closest("div").slideDown(),t.redux.initFields(),t(this).find(".el").removeClass(s).addClass(d))}),a.find(".redux-accordion-field").each(function(){var i,e;"start"===t(this).data("position")&&(e=t(this).attr("id"),i=Boolean(t(this).data("state")),(e=t("#accordion-table-"+e)).wrapAll('<div class="redux-accordion-wrap"/>'),!1===i?e.closest("div").hide():t(this).find(".el").removeClass(s).addClass(d))})))})}}(jQuery);

View File

@@ -0,0 +1,56 @@
.redux-main {
.redux-accordion-field {
overflow: hidden;
cursor: pointer;
margin-top: 10px;
&:first-child {
margin-top: 0;
}
.redux-accordion-info {
border: 1px solid #dfdfdf;
padding: 10px 15px;
height: auto;
min-height: 20px;
overflow: hidden;
word-wrap: break-word;
background: #FAFAFA;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
&:hover {
border-color: #999;
}
.el {
color: #000;
float: right;
margin-top: -23px;
margin-right: 10px;
transition: all 0.5s;
&.subtitled {
margin-top: -33px;
}
}
}
h3 {
margin: 0;
border-bottom: 0;
}
.redux-accordion-desc {
margin: -5px 0 10px;
}
}
}
.redux-accordion-wrap {
border: 1px solid #e5e5e5;
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
box-shadow: 0 1px 1px rgba(0, 0, 0, .04);
border-top: none;
padding: 0 15px;
background: #fff;
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* Redux Accordion Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Accordion
* @version 4.3.16
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Extension_Accordion' ) ) {
/**
* Main ReduxFramework_Extension_Accordion extension class
*
* @since 1.0.0
*/
class Redux_Extension_Accordion extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.3.16';
/**
* Extension friendly name.
*
* @var string
*/
public $extension_name = 'Accordion';
/**
* Class Constructor. Defines the args for the extension class
*
* @since 1.0.0
* @access public
*
* @param ReduxFramework $redux Parent settings.
*
* @return void
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'accordion' );
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,707 @@
<?php
/**
* Redux Color Scheme Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Color_Scheme
*
* @version 4.4.10
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Extension_Color_Scheme' ) ) {
/**
* Class Redux_Extension_Color_Scheme
*/
class Redux_Extension_Color_Scheme extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.4.10';
/**
* Extension friendly name.
*
* @var string
*/
public $extension_name = 'Color Schemes';
/**
* Field ID.
*
* @var string
*/
public $field_id = '';
/**
* Transparent output bit.
*
* @var bool
*/
public $output_transparent = false;
/**
* Extension field name.
*
* @var string
*/
public $field_name = '';
/**
* Class Constructor. Defines the args for the extensions class
*
* @since 1.0.0
* @access public
*
* @param object $redux Parent settings.
*
* @return void
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'color_scheme' );
$this->field_name = 'color_scheme';
add_filter( "redux/options/{$this->parent->args['opt_name']}/defaults", array( $this, 'set_defaults' ) );
// Ajax hooks.
add_action( 'wp_ajax_redux_color_schemes', array( $this, 'parse_ajax' ) );
add_action( 'wp_ajax_nopriv_redux_color_schemes', array( $this, 'parse_ajax' ) );
// Reset hooks.
add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults', array( $this, 'reset_defaults' ), 0, 3 );
add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/defaults_section', array( $this, 'reset_defaults_section' ), 0, 3 );
// Save filter.
add_action( 'redux/validate/' . $this->parent->args['opt_name'] . '/before_validation', array( $this, 'save_hook' ), 0, 3 );
// Register hook - to get field id and prep helper.
add_action( 'redux/options/' . $this->parent->args['opt_name'] . '/field/' . $this->field_name . '/register', array( $this, 'register_field' ) );
include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
Redux_Color_Scheme_Functions::init( $redux );
$field = Redux_Color_Scheme_Functions::get_field( $redux );
if ( ! is_array( $field ) ) {
return;
}
$this->field_id = $field['id'];
// Prep storage.
$upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
// Create uploads/redux_scheme_colors/ folder.
if ( ! is_dir( $upload_dir ) ) {
$redux->filesystem->execute( 'mkdir', $upload_dir );
}
}
/**
* Set default values after reset.
*
* @param array $defaults Default values.
*
* @return array
*/
public function set_defaults( array $defaults = array() ): array {
if ( ! Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
return $defaults;
}
if ( empty( $this->field_id ) ) {
return $defaults;
}
$x = get_option( $this->parent->args['opt_name'] );
$color_opts = $x[ $this->field_id ] ?? array();
$wrong_format = false;
if ( ! isset( $color_opts['color_scheme_name'] ) ) {
$wrong_format = true;
$data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
if ( ! empty( $data ) && isset( $x[ $this->field_id ] ) ) {
$x[ $this->field_id ] = $data;
update_option( $this->parent->args['opt_name'], $x );
}
}
Redux_Color_Scheme_Functions::$parent = $this->parent;
$ot_val = Redux_Color_Scheme_Functions::get_output_transparent_val();
$this->output_transparent = $ot_val;
Redux_Color_Scheme_Functions::convert_to_db();
$scheme_key = Redux_Color_Scheme_Functions::get_scheme_key();
$scheme_data = get_option( $scheme_key );
$scheme_data_exists = ! empty( $scheme_data );
$default_exists = in_array( 'default', array_map( 'strtolower', Redux_Color_Scheme_Functions::get_scheme_names() ), true );
if ( ! $scheme_data_exists || ! $default_exists || $wrong_format ) {
$data = $this->get_default_data();
// Add to (and/or create) JSON scheme file.
Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
// Set default scheme.
Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
$data = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
$this->parent->options[ $this->field_id ] = $data;
$defaults[ $this->field_id ] = $data;
}
return $defaults;
}
/**
* Field Register. Sets the whole smash up.
*
* @param array $data Field data.
*
* @return void
* @since 1.0.0
* @access public
*/
public function register_field( array $data ) {
// Include color_scheme helper.
include_once $this->extension_dir . 'color_scheme/inc/class-redux-color-scheme-functions.php';
if ( isset( $data['output_transparent'] ) ) {
$this->output_transparent = $data['output_transparent'];
}
$this->field_id = $data['id'];
Redux_Color_Scheme_Functions::$field_id = $data['id'];
// Set helper parent object.
Redux_Color_Scheme_Functions::$parent = $this->parent;
// Prep storage.
$upload_dir = Redux_Color_Scheme_Functions::$upload_dir;
// Set upload_dir cookie.
setcookie( 'redux_color_scheme_upload_dir', $upload_dir, 0, '/' );
}
/**
* Reset defaults.
*
* @param array $defaults Default values.
*
* @return array
*/
public function reset_defaults( array $defaults = array() ): array {
if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
// Check if reset_all was fired.
$this->reset_all();
$defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
}
return $defaults;
}
/**
* Reset section defaults.
*
* @param array $defaults Default values.
*
* @return array
*/
public function reset_defaults_section( array $defaults = array() ): array {
if ( Redux_Helpers::is_field_in_use( $this->parent, 'color_scheme' ) ) {
// Get the current tab/section number.
if ( isset( $_COOKIE['redux_current_tab'] ) ) {
$cur_tab = sanitize_text_field( wp_unslash( $_COOKIE['redux_current_tab'] ) );
// Get the tab/section number field is used on.
$tab_num = $this->parent->field_sections['color_scheme'][ $this->field_id ];
// Match...
if ( $cur_tab === $tab_num ) {
// Reset data.
$this->reset_all();
}
$defaults[ $this->field_id ] = Redux_Color_Scheme_Functions::data_array_from_scheme( 'Default' );
}
}
return $defaults;
}
/**
* Save Changes Hook. What to do when changes are saved
*
* @param array $saved_options Saved data.
* @param array $old_options Previous data.
*
* @return array
* @since 1.0.0
* @access public
*/
public function save_hook( array $saved_options = array(), array $old_options = array() ): array {
if ( ! isset( $saved_options[ $this->field_id ] ) || empty( $saved_options[ $this->field_id ] ) || ( is_array( $saved_options[ $this->field_id ] ) && $old_options === $saved_options ) || ! array_key_exists( $this->field_id, $saved_options ) ) {
return $saved_options;
}
// We'll use the reset hook instead.
if ( ! empty( $saved_options['defaults'] ) || ! empty( $saved_options['defaults-section'] ) ) {
return $saved_options;
}
$first_value = reset( $saved_options[ $this->field_id ] ); // First Element's Value.
// Parse the JSON to an array.
if ( isset( $first_value['data'] ) ) {
Redux_Color_Scheme_Functions::$parent = $this->parent;
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
Redux_Color_Scheme_Functions::set_current_scheme_id( $saved_options['redux-scheme-select'] );
// Get the current field ID.
$raw_data = $saved_options[ $this->field_id ];
// Create a new array.
$save_data = array();
// Enum through saved data.
foreach ( $raw_data as $id => $val ) {
if ( 'color_scheme_name' !== $id ) {
if ( is_array( $val ) ) {
if ( ! isset( $val['data'] ) ) {
continue;
}
$data = json_decode( rawurldecode( $val['data'] ), true );
// Sanitize everything.
$color = $data['color'] ?? '';
$alpha = $data['alpha'] ?? 1;
$id = $data['id'] ?? $id;
$title = $data['title'] ?? $id;
$grp = $data['group'] ?? '';
if ( '' === $color || 'transparent' === $color ) {
$rgba = $this->output_transparent ? 'transparent' : '';
} else {
$rgba = Redux_Helpers::hex2rgba( $color, $alpha );
}
// Create an array of saved data.
$save_data[] = array(
'id' => $id,
'title' => $title,
'color' => $color,
'alpha' => $alpha,
'group' => $grp,
'rgba' => $rgba,
);
} else {
$save_data[] = array(
'id' => $id,
'value' => $val,
'type' => 'select',
);
}
}
}
$new_scheme = array();
$new_scheme['color_scheme_name'] = Redux_Color_Scheme_Functions::get_current_scheme_id();
// Enum through values and assign them to a new array.
foreach ( $save_data as $val ) {
if ( isset( $val['id'] ) ) {
$new_scheme[ $val['id'] ] = $val;
}
}
// Filter for DB save
// Doesn't need to save select arrays to a database,
// just the id => value.
$database_data = $new_scheme;
foreach ( $database_data as $k => $v ) {
if ( isset( $v['type'] ) ) {
$val = $v['value'];
unset( $database_data[ $k ] );
$database_data[ $k ] = $val;
}
}
$saved_options[ $this->field_id ] = $database_data;
// Check if we should save this compared to the old data.
$save_scheme = false;
// Doesn't exist or is empty.
if ( ! isset( $old_options[ $this->field_id ] ) || ( isset( $old_options[ $this->field_id ] ) && ! empty( $old_options[ $this->field_id ] ) ) ) {
$save_scheme = true;
}
// Isn't empty and isn't the same as the new array.
if ( ! empty( $old_options[ $this->field_id ] ) && $saved_options[ $this->field_id ] !== $old_options[ $this->field_id ] ) {
$save_scheme = true;
}
if ( $save_scheme ) {
$scheme = Redux_Color_Scheme_Functions::get_current_scheme_id();
Redux_Color_Scheme_Functions::set_scheme_data( $scheme, $save_data );
}
}
return $saved_options;
}
/**
* Reset data. Restores colour picker to default values
*
* @since 1.0.0
* @access private
* @return void
*/
private function reset_data() {
Redux_Color_Scheme_Functions::$parent = $this->parent;
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
// Get default data.
$data = $this->get_default_data();
// Add to (and/or create) JSON scheme file.
Redux_Color_Scheme_Functions::set_scheme_data( 'Default', $data );
// Set default scheme.
Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
}
/**
* Reset All Hook. Todo list when all data is reset
*
* @return void
* @since 1.0.0
* @access public
*/
public function reset_all() {
if ( ! empty( $this->field_id ) && isset( $this->parent->options_defaults[ $this->field_id ] ) && ! empty( $this->parent->options_defaults[ $this->field_id ] ) ) {
Redux_Color_Scheme_Functions::$parent = $this->parent;
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
$this->reset_data();
}
}
/**
* AJAX evaluator. Determine course of action based on AJAX callback
*
* @since 1.0.0
* @access public
* @return void
*/
public function parse_ajax() {
if ( isset( $_REQUEST['nonce'] ) && isset( $_REQUEST['opt_name'] ) && wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['nonce'] ) ), 'redux_' . sanitize_text_field( wp_unslash( $_REQUEST['opt_name'] ) ) . '_color_schemes' ) ) {
$parent = $this->parent;
// Do action.
if ( isset( $_REQUEST['type'] ) ) {
// Save scheme.
if ( 'save' === $_REQUEST['type'] ) {
$this->save_scheme( $parent );
// Delete scheme.
} elseif ( 'delete' === $_REQUEST['type'] ) {
$this->delete_scheme( $parent );
// Scheme change.
} elseif ( 'update' === $_REQUEST['type'] ) {
$this->get_scheme_html( $parent );
// Export scheme file.
} elseif ( 'export' === $_REQUEST['type'] ) {
$this->download_schemes();
}
}
} else {
wp_die( esc_html__( 'Invalid Security Credentials. Please reload the page and try again.', 'redux-framework' ) );
}
}
/**
* Download Scheme File.
*
* @since 1.0.0
* @access private
* @return void
*/
private function download_schemes() {
Redux_Color_Scheme_Functions::$parent = $this->parent;
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
// Read contents of scheme file.
$content = Redux_Color_Scheme_Functions::read_scheme_file();
$content = wp_json_encode( $content );
// Set header info.
header( 'Content-Description: File Transfer' );
header( 'Content-type: application/txt' );
header( 'Content-Disposition: attachment; filename="redux_schemes_' . $this->parent->args['opt_name'] . '_' . $this->field_id . '_' . gmdate( 'm-d-Y' ) . '.json"' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate' );
header( 'Pragma: public' );
// File download.
echo $content; // phpcs:ignore WordPress.Security.EscapeOutput
// 2B ~! 2B
die;
}
/**
* Save Scheme. Saved an individual scheme to JSON scheme file.
*
* @param object $redux ReduxFramework object.
*
* @since 1.0.0
* @access private
* @return void
*/
private function save_scheme( $redux ) {
Redux_Color_Scheme_Functions::$parent = $redux;
Redux_Color_Scheme_Functions::$field_id = $this->field_id;
// Get the scheme name.
if ( isset( $_REQUEST['scheme_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$scheme_name = sanitize_text_field( wp_unslash( $_REQUEST['scheme_name'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
// Check for duplicates.
$names = Redux_Color_Scheme_Functions::get_scheme_names();
foreach ( $names as $name ) {
$name = strtolower( $name );
$tmp_name = strtolower( $scheme_name );
if ( $name === $tmp_name ) {
echo 'fail';
die();
}
}
// Get scheme data.
if ( isset( $_REQUEST['scheme_data'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$scheme_data = wp_unslash( $_REQUEST['scheme_data'] ); // phpcs:ignore WordPress.Security
// Get field ID.
if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$scheme_data = rawurldecode( $scheme_data );
$scheme_data = json_decode( $scheme_data, true );
// Save scheme to file. If successful...
if ( true === Redux_Color_Scheme_Functions::set_scheme_data( $scheme_name, $scheme_data ) ) {
// Update scheme selector.
echo Redux_Color_Scheme_Functions::get_scheme_select_html( $scheme_name ); // phpcs:ignore WordPress.Security.EscapeOutput
}
}
}
}
die(); // a horrible death!
}
/**
* Delete Scheme. Delete individual scheme from JSON scheme file.
*
* @param object $redux ReduxFramework object.
*
* @since 1.0.0
* @access private
* @return void
*/
private function delete_scheme( $redux ) {
// Get deleted scheme ID.
if ( isset( $_REQUEST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$scheme_id = sanitize_text_field( wp_unslash( $_REQUEST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
// Get field ID.
if ( isset( $_REQUEST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
$field_id = sanitize_text_field( wp_unslash( $_REQUEST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
// If scheme ID was passed (and why wouldn't it be?? Hmm??).
if ( $scheme_id ) {
Redux_Color_Scheme_Functions::$field_id = $field_id;
Redux_Color_Scheme_Functions::$parent = $redux;
// Get the entire scheme file.
$schemes = Redux_Color_Scheme_Functions::read_scheme_file();
// If we got a good read...
if ( false !== $schemes ) {
// If scheme name exists...
if ( isset( $schemes[ $scheme_id ] ) ) {
// Unset it.
unset( $schemes[ $scheme_id ] );
// Save the scheme data, minus the deleted scheme. Upon success...
if ( true === Redux_Color_Scheme_Functions::write_scheme_file( $schemes ) ) {
// Set default scheme.
Redux_Color_Scheme_Functions::set_current_scheme_id( 'Default' );
// Update field ID.
Redux_Color_Scheme_Functions::$field_id = $field_id;
// Meh TODO.
Redux_Color_Scheme_Functions::set_database_data();
echo 'success';
} else {
echo 'Failed to write JSON file to server.';
}
} else {
echo 'Scheme name does not exist in JSON string. Aborting.';
}
} else {
echo 'Failed to read JSON scheme file, or file is empty.';
}
} else {
echo 'No scheme ID passed. Aborting.';
}
}
}
die(); // rolled a two.
}
/**
* Gets the new scheme based on selection.
*
* @param object $redux ReduxFramework object.
*
* @since 1.0.0
* @access private
* @return void
*/
private function get_scheme_html( $redux ) {
if ( isset( $_POST['scheme_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Get the selected scheme name.
$scheme_id = sanitize_text_field( wp_unslash( $_POST['scheme_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
if ( isset( $_POST['field_id'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
// Get the field ID.
$field_id = sanitize_text_field( wp_unslash( $_POST['field_id'] ) ); // phpcs:ignore WordPress.Security.NonceVerification
// Get the field class.
$field_class = isset( $_POST['field_class'] ) ? sanitize_text_field( wp_unslash( $_POST['field_class'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
Redux_Color_Scheme_Functions::$parent = $redux;
// Set the updated field ID.
Redux_Color_Scheme_Functions::$field_id = $field_id;
// Set the updated field class.
Redux_Color_Scheme_Functions::$field_class = $field_class;
// Get the color picket layout HTML.
$html = Redux_Color_Scheme_Functions::get_current_color_scheme_html( $scheme_id );
// Print!
echo $html; // phpcs:ignore WordPress.Security.EscapeOutput
}
}
die(); // another day.
}
/**
* Retrieves an array of default data for color picker.
*
* @since 1.0.0
* @access private
* @return array Default values from config.
*/
private function get_default_data(): array {
$def_opts = $this->parent->options_defaults[ $this->field_id ];
$sections = $this->parent->sections;
$data = array();
foreach ( $sections as $arr ) {
if ( isset( $arr['fields'] ) ) {
foreach ( $arr['fields'] as $arr2 ) {
if ( $arr2['id'] === $this->field_id ) {
// Select fields.
if ( isset( $arr2['select'] ) ) {
foreach ( $arr2['select'] as $v ) {
$data[] = array(
'id' => $v['id'],
'value' => $v['default'],
'type' => 'select',
);
}
}
}
}
}
}
foreach ( $def_opts as $v ) {
$title = $v['title'] ?? $v['id'];
$color = $v['color'] ?? '';
$alpha = $v['alpha'] ?? 1;
$grp = $v['group'] ?? '';
if ( '' === $color || 'transparent' === $color ) {
$rgba = $this->output_transparent ? 'transparent' : '';
} else {
$rgba = Redux_Helpers::hex2rgba( $color, $alpha );
}
$data[] = array(
'id' => $v['id'],
'title' => $title,
'color' => $color,
'alpha' => $alpha,
'group' => $grp,
'rgba' => $rgba,
);
}
return $data;
}
}
}
class_alias( 'Redux_Extension_Color_Scheme', 'ReduxFramework_Extension_Color_Scheme' );

View File

@@ -0,0 +1,381 @@
<?php
/**
* Redux Color Scheme Attach Class
*
* WordPress' functions are lot loaded in this file due to a post-callback in javascript. We therefore must
* compensate for WPCS by creating our own validate/sanitize/nonce functions, which are comments throughout.
*
* @package Redux Extentions
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Color_Scheme_Import
*/
if ( ! class_exists( 'Redux_Color_Scheme_Import' ) ) {
/**
* Class Redux_Color_Scheme_Import
*/
class Redux_Color_Scheme_Import {
/**
* Errors.
*
* @var string
*/
private $err = '';
/**
* Upload directory.
*
* @var string
*/
private $upload_dir = '';
/**
* Field ID.
*
* @var string
*/
private $field_id = '';
/**
* Option panel opt_name.
*
* @var string
*/
private $opt_name = '';
/**
* Text result.
*
* @var string
*/
private $result;
/**
* Data.
*
* @var string
*/
private $data;
/**
* Redux_Color_Scheme_Import constructor.
*/
public function __construct() {
// Set result to false.
$this->result = false;
// String used more than once.
$abort = ' Aborting import.';
// This is our nonce check using MD5.
// $this->sanitize_input replaces sanitize_title() and wp_unslash().
// phpcs:disable WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification
if ( isset( $_REQUEST['nonce'] ) && $this->sanitize_input( $_REQUEST['nonce'] ) === md5( 'color_scheme_import' ) ) { // WPCS: CSRF ok, sanitization ok.
// Is request type set?
if ( isset( $_REQUEST['type'] ) ) { // WPCS: CSRF ok.
// Is request type import?
if ( 'import' === $this->sanitize_input( $_REQUEST['type'] ) ) { // WPCS: CSRF ok, sanitization ok.
// Get upload dir from cookie.
if ( true === $this->get_upload_dir() ) {
// Check for field id.
if ( isset( $_REQUEST['field_id'] ) && isset( $_REQUEST['opt_name'] ) ) { // WPCS: CSRF ok.
// Get field id.
$this->field_id = $this->sanitize_input( $_REQUEST['field_id'] );
$this->opt_name = $this->sanitize_input( $_REQUEST['opt_name'] );
// Process import file.
if ( true === $this->process_file() ) {
$this->result = true;
$this->data = 'Import successful! Click <strong>OK</strong> to refresh.';
// process_file failed, return error message.
} else {
$this->data = $this->err . $abort;
}
} else {
$this->data = 'Invalid field ID.' . $abort;
}
// Cookie read failed.
} else {
$this->data = $this->err . $abort;
}
// No request types. Somebody tryin' to do something they shouldn't.
} else {
$this->data = 'Invalid request type.' . $abort;
}
// No request type? Just in case.
} else {
$this->data = 'No request type specified.' . $abort;
}
} else {
$this->data = 'Security check failed.' . $abort;
}
// phpcs:enable WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification
// data array to return.
$arr = array(
'result' => $this->result,
'data' => $this->data,
);
// json encode.
$arr = json_encode( $arr ); // phpcs:ignore WordPress.WP.AlternativeFunctions
echo $arr; // phpcs:ignore WordPress.Security.EscapeOutput
}
/**
* Replaces proprietary WordPress functions sanitize_title() and wp_unslash().
*
* @param string|array $input Value to sanitize.
*/
private function sanitize_input( $input ): string {
$input = is_array( $input ) ? array_map( 'stripslashes_deep', $input ) : stripslashes( $input );
return htmlspecialchars( $input, ENT_QUOTES );
}
/**
* Get wp upload dir from cookie.
*
* @return bool
*/
private function get_upload_dir(): bool {
// cookie name.
$val = 'redux_color_scheme_upload_dir';
// Is the cookie there?
if ( isset( $_COOKIE[ $val ] ) ) {
// Get value from cookie.
$upload_dir = $this->sanitize_input( $_COOKIE[ $val ] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
// Is it blank?
if ( '' === $upload_dir ) {
$this->err = 'Required cookie is empty.';
// Nope, grab the data.
} else {
$this->upload_dir = $upload_dir;
return true;
}
// No cookie for you!
} else {
$this->err = 'Unable to read required cookie.';
}
return false;
}
/**
* Process import file
*
* @return bool
*/
private function process_file(): bool {
// Undefined | Multiple Files | $_FILES Corruption Attacks
// If this request falls under any of them, treat it invalid.
if ( ! isset( $_FILES['file']['error'] ) || is_array( $_FILES['file']['error'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
$this->err = 'Invalid upload parameters.';
return false;
} else {
switch ( $_FILES['file']['error'] ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
// All is good.
case UPLOAD_ERR_OK:
break;
// Missing file.
case UPLOAD_ERR_NO_FILE:
$this->err = 'No file chosen.';
return false;
// File too big.
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
$this->err = 'Exceeds filesize limit.';
return false;
// Unknown err.
default:
$this->err = 'Unknown error.';
return false;
}
// get file name.
$filename = htmlspecialchars( trim( $_FILES['file']['name'] ), ENT_QUOTES ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification.Missing
// get a temp file path.
$filepath = htmlspecialchars( trim( $_FILES['file']['tmp_name'] ), ENT_QUOTES ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput, WordPress.Security.NonceVerification.Missing
// remove illegal chars.
$filename = preg_replace( '#[^a-z (),-_]#i', '', $filename );
// Is accepted type?
if ( true === $this->is_proper_mime( $filepath ) ) {
// Check for JSON extension.
if ( $this->is_ext_json( $filename ) ) {
// Is the actual scheme file?
if ( $this->is_scheme_file( $filepath ) ) {
// Try moving it from temp to wp upload.
if ( ! move_uploaded_file( $filepath, $this->upload_dir . '/' . $this->opt_name . '_' . $this->field_id . '.json' ) ) {
$this->err = 'Cannot move Redux color scheme file to the upload folder.';
} else {
return true;
}
}
}
}
}
return false;
}
/**
* Check for a proper MIME type.
*
* @param string $filepath File path.
*
* @return bool
*/
private function is_proper_mime( string $filepath ): bool {
// Get MIME type.
$finfo = new finfo( FILEINFO_MIME_TYPE );
// Check a type against accepted list.
$ext = in_array(
$finfo->file( $filepath ),
array(
'json' => 'application/json',
'tmp' => 'application/json',
),
true
);
// Bad type.
if ( false === $ext ) {
$this->err = 'Invalid file format.';
return false;
}
return true;
}
/**
* Is file a valid scheme file.
*
* @param string $filepath File path.
*
* @return bool
*/
private function is_scheme_file( string $filepath ): bool {
// Check for valid color scheme backup tag.
$content = $this->read_tmp( $filepath );
// If empty, set the error.
if ( '' === $content ) {
$this->err = 'The selected file is empty.';
// check for valid scheme entry.
} else {
// scheme tag.
$tag = '"color_scheme_name"';
// Locate its position in the string.
$pos = strpos( $content, $tag );
// Is There? Return true.
if ( $pos > 0 ) {
return true;
// Otherwise, set the error.
} else {
$this->err = 'The selected file is not a valid color scheme file.';
}
}
return false;
}
/**
* Check for valid extension.
*
* @param string $filename File name.
*
* @return bool
*/
private function is_ext_json( string $filename ): bool {
// Get last period position.
$pos = strrpos( $filename, '.' );
// One found.
if ( $pos > 0 ) {
// Extract file extension.
$ext = substr( $filename, $pos + 1 );
// Is JSON, then continue.
if ( 'json' === $ext ) {
return true;
// If not, set err.
} else {
$this->err = 'The selected file is a ' . strtoupper( $ext ) . ' file, not a JSON file.';
}
// No file ext found, set error.
} else {
$this->err = 'The selected file has no JSON extension.';
}
return false;
}
/**
* Reads data from file.
*
* @param string $file File path.
*
* @return bool|string
*/
private function read_tmp( string $file ) {
if ( file_exists( $file ) ) {
$fp = fopen( $file, 'r' ); // phpcs:ignore WordPress.WP.AlternativeFunctions
$data = fread( $fp, filesize( $file ) ); // phpcs:ignore WordPress.WP.AlternativeFunctions
fclose( $fp ); // phpcs:ignore WordPress.WP.AlternativeFunctions
return $data;
} else {
return '';
}
}
}
new Redux_Color_Scheme_Import();
}

View File

@@ -0,0 +1,422 @@
<?php
/**
* Redux Color Scheme Field Class
*
* @package Redux Extentions
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Color_Scheme
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Color_Scheme' ) ) {
/**
* Main ReduxFramework_color_scheme class
*
* @since 1.0.0
*/
class Redux_Color_Scheme extends Redux_Field {
/**
* Set Defaults.
*/
public function set_defaults() {
// Validate.
$this->field['options']['picker_font_size'] = $this->field['options']['picker_font_size'] ?? '11px';
$this->field['options']['picker_gap'] = $this->field['options']['picker_gap'] ?? '60px';
$this->field['options']['show_input'] = $this->field['options']['show_input'] ?? true;
$this->field['options']['show_initial'] = $this->field['options']['show_initial'] ?? true;
$this->field['options']['show_alpha'] = $this->field['options']['show_alpha'] ?? true;
$this->field['options']['show_palette'] = $this->field['options']['show_palette'] ?? true;
$this->field['options']['show_palette_only'] = $this->field['options']['show_palette_only'] ?? false;
$this->field['options']['max_palette_size'] = $this->field['options']['max_palette_size'] ?? 10;
$this->field['options']['show_selection_palette'] = $this->field['options']['show_selection_palette'] ?? true;
$this->field['options']['allow_empty'] = $this->field['options']['allow_empty'] ?? true;
$this->field['options']['clickout_fires_change'] = $this->field['options']['clickout_fires_change'] ?? false;
$this->field['options']['choose_text'] = $this->field['options']['choose_text'] ?? 'Choose';
$this->field['options']['cancel_text'] = $this->field['options']['cancel_text'] ?? 'Cancel';
$this->field['options']['show_buttons'] = $this->field['options']['show_buttons'] ?? true;
$this->field['options']['container_class'] = $this->field['options']['container_class'] ?? 'redux-colorpicker-container';
$this->field['options']['replacer_class'] = $this->field['options']['replacer_class'] ?? 'redux-colorpicker-replacer';
$this->field['options']['use_extended_classes'] = $this->field['options']['use_extended_classes'] ?? false;
$this->field['options']['palette'] = $this->field['options']['palette'] ?? null;
$this->field['simple'] = $this->field['simple'] ?? false;
// Convert an empty array to null, if there.
$this->field['options']['palette'] = empty( $this->field['options']['palette'] ) ? null : $this->field['options']['palette'];
$this->field['no_compiler_output'] = $this->field['no_compiler_output'] ?? false;
$this->field['output_transparent'] = $this->field['output_transparent'] ?? false;
$this->field['accordion'] = $this->field['accordion'] ?? true;
// tooltips.
$this->field['tooltip_toggle'] = $this->field['tooltip_toggle'] ?? true;
$this->field['tooltips']['style']['color'] = $this->field['tooltips']['style']['color'] ?? 'light';
$this->field['tooltips']['style']['shadow'] = $this->field['tooltips']['style']['shadow'] ?? true;
$this->field['tooltips']['style']['rounded'] = $this->field['tooltips']['style']['rounded'] ?? false;
$this->field['tooltips']['style']['style'] = $this->field['tooltips']['style']['style'] ?? '';
$this->field['tooltips']['position']['my'] = $this->field['tooltips']['position']['my'] ?? 'top center';
$this->field['tooltips']['position']['at'] = $this->field['tooltips']['position']['at'] ?? 'bottom center';
$this->field['tooltips']['effect']['show_effect'] = $this->field['tooltips']['effect']['show_effect'] ?? 'slide';
$this->field['tooltips']['effect']['show_duration'] = $this->field['tooltips']['effect']['show_duration'] ?? 500;
$this->field['tooltips']['effect']['show_event'] = $this->field['tooltips']['effect']['show_event'] ?? 'mouseover';
$this->field['tooltips']['effect']['hide_effect'] = $this->field['tooltips']['effect']['hide_effect'] ?? 'slide';
$this->field['tooltips']['effect']['hide_duration'] = $this->field['tooltips']['effect']['hide_duration'] ?? 500;
$this->field['tooltips']['effect']['hide_effect'] = $this->field['tooltips']['effect']['hide_effect'] ?? 'mouseleave';
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @since 1.0.0
* @access public
* @return void
*/
public function render() {
$field_id = esc_attr( $this->field['id'] );
// Set field ID, just in case.
Redux_Color_Scheme_Functions::$field_id = $field_id;
Redux_Color_Scheme_Functions::$field = $this->field;
Redux_Color_Scheme_Functions::$parent = $this->parent;
if ( isset( $this->field['select'] ) ) {
if ( is_array( $this->field['select'] ) && ! empty( $this->field['select'] ) ) {
Redux_Color_Scheme_Functions::$select = $this->field['select'];
}
}
// Nonce.
$nonce = wp_create_nonce( "redux_{$this->parent->args['opt_name']}_color_schemes" );
// Modal message.
echo '<div id="redux-' . esc_attr( $field_id ) . '-scheme-message-notice" style="display:none; cursor: default">';
echo ' <h2>message</h2>';
echo ' <input type="button" id="redux-' . esc_attr( $field_id ) . '-scheme-ok" value="OK" />';
echo '</div>';
// Waiting message.
echo '<div id="redux-' . esc_attr( $field_id ) . '-scheme-wait-message" style="display:none;">';
echo ' <h1><img alt="Please wait..." src="' . esc_url( $this->url ) . 'img/busy.gif" /> Please wait...</h1>';
echo '</div>';
// Delete dialog.
echo '<div id="redux-' . esc_attr( $field_id ) . '-delete-scheme-question" style="display:none; cursor: default">';
echo ' <h2>Are you sure you want to delete this scheme?</h2>';
echo ' <input type="button" id="redux-' . esc_attr( $field_id ) . '-delete-scheme-yes" value="Yes" />';
echo ' <input type="button" id="redux-' . esc_attr( $field_id ) . '-delete-scheme-no" value="No" />';
echo '</div>';
// Select2 params.
if ( isset( $this->field['select2'] ) ) { // if there are any, let's pass them to js.
$select2_params = wp_json_encode( $this->field['select2'] );
$select2_params = htmlspecialchars( $select2_params, ENT_QUOTES );
echo '<input type="hidden" class="select2_params" value="' . $select2_params . '">'; // phpcs:ignore WordPress.Security.EscapeOutput
}
$tt_in_use = Redux_Color_Scheme_Functions::tooltips_in_use( $this->field );
$tooltips = '';
if ( $tt_in_use ) {
$tooltips = rawurlencode( wp_json_encode( $this->field['tooltips'] ) );
}
$tt_toggle_state = Redux_Color_Scheme_Functions::get_tooltip_toggle_state();
// Color picker container.
// phpcs:disable WordPress.Security.EscapeOutput
echo '<div
class="redux-color-scheme-container ' . esc_attr( $this->field['class'] ) . '"
data-id="' . esc_attr( $field_id ) . '"
data-opt-name="' . esc_attr( $this->parent->args['opt_name'] ) . '"
data-nonce="' . esc_attr( $nonce ) . '"
data-picker-gap="' . esc_attr( $this->field['options']['picker_gap'] ) . '"
data-picker-font-size="' . esc_attr( $this->field['options']['picker_font_size'] ) . '"
data-accordion="' . esc_attr( $this->field['accordion'] ) . '"
data-tooltips="' . $tooltips . '"
data-show-tooltips="' . esc_attr( $tt_toggle_state ) . '"
data-show-input="' . esc_attr( $this->field['options']['show_input'] ) . '"
data-show-initial="' . esc_attr( $this->field['options']['show_initial'] ) . '"
data-show-alpha="' . esc_attr( $this->field['options']['show_alpha'] ) . '"
data-show-palette="' . esc_attr( $this->field['options']['show_palette'] ) . '"
data-show-palette-only="' . esc_attr( $this->field['options']['show_palette_only'] ) . '"
data-show-selection-palette="' . esc_attr( $this->field['options']['show_selection_palette'] ) . '"
data-max-palette-size="' . esc_attr( $this->field['options']['max_palette_size'] ) . '"
data-allow-empty="' . esc_attr( $this->field['options']['allow_empty'] ) . '"
data-clickout-fires-change="' . esc_attr( $this->field['options']['clickout_fires_change'] ) . '"
data-choose-text="' . esc_attr( $this->field['options']['choose_text'] ) . '"
data-cancel-text="' . esc_attr( $this->field['options']['cancel_text'] ) . '"
data-palette="' . rawurlencode( wp_json_encode( $this->field['options']['palette'] ) ) . '"
>';
// phpcs:enable WordPress.Security.EscapeOutput
// Hide scheme save stuff on simple mode.
if ( false === $this->field['simple'] ) {
echo '<div>';
// Select container.
echo '<div class="redux-scheme-select-container input_wrapper">';
echo ' <span class="redux-label redux-select-scheme-label">Scheme:</span>';
// Output scheme selector.
echo Redux_Color_Scheme_Functions::get_scheme_select_html( '' ); // phpcs:ignore WordPress.Security.EscapeOutput
echo '</div>';
// Text input.
echo '<div class="redux-scheme-name input_wrapper">';
echo ' <span class="redux-label redux-text-scheme-label">Name:</span>';
echo ' <input
type="text"
class="noUpdate redux-scheme-input-' . esc_attr( $field_id ) . '"
id="redux-scheme-input"
/>';
echo '</div>';
// Action buttons/links.
echo ' <div class="redux-action-links">';
echo ' <span class="redux-label redux-action-scheme-label">Actions:</span>';
// Save button.
echo ' <a
href="javascript:void(0);"
id="redux-' . esc_attr( $field_id ) . '-save-scheme-button"
class="redux-save-scheme-button button-secondary">' . esc_html__( 'Add', 'redux-framework' ) . '
</a>';
// Delete button.
echo ' <a
href="javascript:void(0);"
id="redux-' . esc_attr( $field_id ) . '-delete-scheme-button"
class="redux-delete-scheme-button button-secondary">' . esc_html__( 'Delete', 'redux-framework' ) . '
</a>';
$link = admin_url( 'admin-ajax.php?action=redux_color_schemes&type=export&nonce=' . esc_attr( $nonce ) ) . '&opt_name=' . esc_attr( $this->parent->args['opt_name'] );
// Export button.
echo ' <a
href="' . esc_url( $link ) . '"
id="redux-' . esc_attr( $field_id ) . '-export-scheme-button"
data-opt-name="' . esc_attr( $this->parent->args['opt_name'] ) . '"
data-submit="' . esc_url( $this->url ) . '"
class="redux-export-scheme-button button-primary">' . esc_html__( 'Export', 'redux-framework' ) . '
</a>';
// Import button.
echo ' <a
href="javascript:void(0);"
id="redux-' . esc_attr( $field_id ) . '-import-scheme-button"
data-submit="' . esc_url( $this->url ) . '"
data-nonce="' . esc_attr( md5( 'color_scheme_import' ) ) . '"
class="noUpdate redux-import-scheme-button button-secondary">' . esc_html__( 'Import', 'redux-framework' ) . '
</a>';
if ( $this->field['tooltip_toggle'] && $tt_in_use ) {
$checked = '';
if ( $tt_toggle_state ) {
$checked = 'checked';
}
echo '<div class="redux-color-scheme-tooltip-checkbox">';
echo '<input class="" name="' . esc_attr( $this->parent->args['opt_name'] ) . '[redux-color-scheme-tooltip-toggle]" id="redux-' . esc_attr( $field_id ) . '-tooltip-checkbox" type="checkbox" value="' . esc_attr( $tt_toggle_state ) . '" ' . esc_html( $checked ) . '>Show Tooltips';
echo '</div>';
}
echo ' </div>';
echo '</div>';
echo '<div>';
echo '<hr/>';
}
// Set field class. Gotta do it this way so custom class makes
// it through AJAX.
Redux_Color_Scheme_Functions::$field_class = 'redux-color-scheme ';
// Color picker layout.
echo Redux_Color_Scheme_Functions::get_current_color_scheme_html(); // phpcs:ignore WordPress.Security.EscapeOutput
echo '</div>';
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access public
* @return void
*/
public function enqueue() {
// Set up min files for dev_mode = false.
$min = Redux_Functions::is_min();
// One-Click Upload.
wp_enqueue_script(
'redux-ocupload',
$this->url . 'vendor/jquery.ocupload' . $min . '.js',
array( 'jquery' ),
'1.1.2',
true
);
// Field dependent JS.
wp_enqueue_script(
'redux-field-color-scheme',
$this->url . 'redux-color-scheme' . $min . '.js',
array( 'jquery', 'redux-spectrum-js', 'select2-js', 'redux-block-ui' ),
Redux_Extension_Color_Scheme::$version,
true
);
// Field CSS.
if ( true === $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-color-scheme',
$this->url . 'redux-color-scheme.css',
array( 'redux-spectrum-css', 'select2-css' ),
Redux_Extension_Color_Scheme::$version
);
}
// AJAX.
wp_localize_script(
'redux-field-color-scheme',
'redux_ajax_script',
array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) )
);
}
/**
* Get default data.
*
* @param string $id Field ID.
*
* @return array
*/
private function data_from_default( string $id ): array {
$x = $this->field;
$data = array();
foreach ( $x['default'] as $arr ) {
if ( $arr['id'] === $id ) {
$data['selector'] = $arr['selector'] ?? '';
$data['mode'] = $arr['mode'] ?? '';
$data['important'] = $arr['important'] ?? '';
break;
}
}
return $data;
}
/**
* If this field requires any scripts or css, define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access private
* @return string
*/
private function get_css(): string {
// No notices.
$css = '';
// Must be an array.
if ( is_array( $this->value ) ) {
// Enum array to parse values.
foreach ( $this->value as $id => $val ) {
// Default selector data, so we always have current info.
$def_data = $this->data_from_default( $id );
// Sanitize alpha.
$alpha = $val['alpha'] ?? 1;
// Sanitize color.
$color = $val['color'] ?? '';
// Only build rgba output if alpha ia less than 1.
if ( $alpha < 1 && '' !== $alpha ) {
$color = Redux_Helpers::hex2rgba( $color, $alpha );
}
$important = $def_data['important'] ?? false;
if ( true === $important ) {
$important = ' !important';
} else {
$important = '';
}
// Sanitize selector.
$selector = $def_data['selector'] ?? '';
if ( is_array( $selector ) ) {
foreach ( $selector as $mode => $element ) {
if ( '' !== $element && '' !== $color ) {
$css .= $element . '{' . $mode . ': ' . $color . $important . ';}';
}
}
} else {
// Sanitize mode, default to 'color'.
$mode = $def_data['mode'] ?? 'color';
// Only build value if selector is indicated.
if ( '' !== $selector && '' !== $color ) {
$css .= $selector . '{' . $mode . ': ' . $color . $important . ';} ';
}
}
}
}
return $css;
}
/**
* Generate CSS style.
*
* @param string $data Field data.
*
* @return string
*/
public function css_style( $data ): string {
return '';
}
/**
* Output Function.
* Used to enqueue to the front-end
*
* @param string|null|array $style Style.
* @since 1.0.0
* @access public
* @return void
*/
public function output( $style = '' ) {
if ( ! empty( $this->value ) ) {
if ( ! empty( $this->field['output'] ) && ( true === $this->field['output'] ) ) {
$css = $this->get_css();
$this->parent->outputCSS .= $css;
}
if ( ! $this->field['no_compiler_output'] ) {
if ( ! empty( $this->field['compiler'] ) && ( true === $this->field['compiler'] ) ) {
$css = $this->get_css();
$this->parent->compilerCSS .= $css;
}
}
}
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -0,0 +1,991 @@
/* global redux, redux_ajax_script,redux_change, reduxColorSchemeAfterUpdateHTML */
( function ( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.color_scheme = redux.field_objects.color_scheme || {};
redux.field_objects.color_scheme.nonce = '';
redux.field_objects.color_scheme.fieldID = '';
redux.field_objects.color_scheme.optName = '';
redux.field_objects.color_scheme.el = '';
redux.field_objects.color_scheme.showTooltips = '';
redux.field_objects.color_scheme.default_params = {};
redux.field_objects.color_scheme.hexToRGBA = function ( hex, alpha ) {
var result;
var r;
var b;
var g;
if ( null === hex ) {
result = '';
} else {
hex = hex.replace( '#', '' );
r = parseInt( hex.substring( 0, 2 ), 16 );
g = parseInt( hex.substring( 2, 4 ), 16 );
b = parseInt( hex.substring( 4, 6 ), 16 );
result = 'rgba(' + r + ',' + g + ',' + b + ',' + alpha + ')';
}
return result;
};
redux.field_objects.color_scheme.init = function ( selector ) {
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-color_scheme:visible' );
}
$( selector ).each(
function () {
var el = $( this );
var parent = el;
redux.field_objects.color_scheme.el = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
redux.field_objects.color_scheme.modInit( el );
redux.field_objects.color_scheme.setAccordions( el );
redux.field_objects.color_scheme.import( el );
redux.field_objects.color_scheme.delete( el );
redux.field_objects.color_scheme.save( el );
redux.field_objects.color_scheme.qtip( el );
}
);
};
redux.field_objects.color_scheme.qtip = function ( el ) {
var tooltips;
var shadow;
var rounded;
var color;
var style;
var myPos;
var atPos;
var classes;
var destroy = false;
if ( false === redux.field_objects.color_scheme.showTooltips ) {
destroy = true;
}
tooltips = el.find( '.redux-color-scheme-container' ).data( 'tooltips' );
if ( '' === tooltips ) {
return;
}
tooltips = decodeURIComponent( tooltips );
tooltips = JSON.parse( tooltips );
shadow = '';
if ( true === tooltips.style.shadow ) {
shadow = 'qtip-shadow';
}
rounded = '';
if ( true === tooltips.style.rounded ) {
rounded = 'qtip-rounded';
}
color = '';
if ( '' !== tooltips.style.color ) {
color = 'qtip-' + tooltips.style.color;
}
style = '';
if ( '' !== tooltips.style.style ) {
style = 'qtip-' + tooltips.style.style;
}
classes = shadow + ',' + color + ',' + rounded + ',' + style;
classes = classes.replace( /,/g, ' ' );
myPos = tooltips.position.my;
atPos = tooltips.position.at;
myPos = $.redux.verifyPos( myPos.toLowerCase(), true );
atPos = $.redux.verifyPos( atPos.toLowerCase(), false );
$( 'li.redux-cs-qtip' ).each(
function () {
var content = $( this ).attr( 'qtip-content' );
var title = $( this ).attr( 'qtip-title' );
if ( '' === content && '' === title ) {
return;
}
if ( true === destroy ) {
$( this ).qtip( 'destroy', true );
} else {
$( this ).qtip(
{
content: {
text: content, title: title
},
show: {
effect: function () {
if ( 'slide' === tooltips.effect.show_effect ) {
$( this ).slideDown( tooltips.effect.show_duration );
} else if ( 'fade' === tooltips.effect.show_effect ) {
$( this ).fadeIn( tooltips.effect.show_duration );
} else {
$( this ).show();
}
}, event: tooltips.effect.show_event
},
hide: {
effect: function () {
if ( 'slide' === tooltips.effect.hide_effect ) {
$( this ).slideUp( tooltips.effect.hide_duration );
} else if ( 'fade' === tooltips.effect.hide_effect ) {
$( this ).fadeOut( tooltips.effect.hide_duration );
} else {
$( this ).hide();
}
}, event: tooltips.effect.hide_event
},
style: {
classes: classes
},
position: {
my: myPos, at: atPos
}
}
);
}
}
);
};
redux.field_objects.color_scheme.setAccordions = function ( el ) {
var accordionSection;
var isOpen;
var ulContainer = el.find( 'ul.redux-scheme-layout' );
var openIcon = ulContainer.data( 'open-icon' );
var closeIcon = ulContainer.data( 'close-icon' );
var isAccordion = Boolean( el.find( '.redux-color-scheme-container' ).data( 'accordion' ) );
if ( true === isAccordion ) {
accordionSection = el.find( '.redux-color-scheme-accordion-section' );
accordionSection.each(
function () {
isOpen = Boolean( $( this ).data( 'state' ) );
if ( false === isOpen ) {
$( this ).hide();
} else {
$( this ).prev( '.redux-color-scheme-accordion' ).find( '.el' ).removeClass( openIcon ).addClass( closeIcon );
redux.field_objects.color_scheme.initColorPicker( $( this ) );
}
}
);
el.find( '.redux-color-scheme-accordion' ).on(
'click',
function ( e ) {
var nextAccordion;
e.preventDefault();
nextAccordion = $( this ).next( '.redux-color-scheme-accordion-section' );
if ( nextAccordion.is( ':visible' ) ) {
$( this ).find( '.el' ).removeClass( closeIcon ).addClass( openIcon );
nextAccordion.slideUp();
} else {
$( this ).find( '.el' ).removeClass( openIcon ).addClass( closeIcon );
redux.field_objects.color_scheme.initColorPicker( nextAccordion );
nextAccordion.slideDown();
}
}
);
} else {
redux.field_objects.color_scheme.initColorPicker( el );
}
};
redux.field_objects.color_scheme.modInit = function ( el ) {
var select2_handle;
var select2_params;
redux.field_objects.color_scheme.nonce = el.find( '.redux-color-scheme-container' ).data( 'nonce' );
redux.field_objects.color_scheme.fieldID = el.find( '.redux-color-scheme-container' ).data( 'id' );
redux.field_objects.color_scheme.optName = el.find( '.redux-color-scheme-container' ).data( 'opt-name' );
redux.field_objects.color_scheme.showTooltips = el.find( '.redux-color-scheme-container' ).data( 'show-tooltips' );
redux.field_objects.color_scheme.default_params = {
triggerChange: true, allowClear: false
};
select2_handle = el.find( '.redux-container-color_scheme' ).find( '.select2_params' );
if ( select2_handle.length > 0 ) {
select2_params = select2_handle.val();
select2_params = JSON.parse( select2_params );
redux.field_objects.color_scheme.default_params = $.extend( {}, redux.field_objects.color_scheme.default_params, select2_params );
}
// Init select2 for scheme select.
el.find( '.redux-scheme-select' ).select2( redux.field_objects.color_scheme.default_params );
// Init select2 for select boxes.
el.find( 'select.redux-color-scheme-opt-select' ).select2( redux.field_objects.color_scheme.default_params );
// Auto select text in input box.
el.find( 'input.redux-scheme-input-' + redux.field_objects.color_scheme.fieldID ).on(
'click',
function ( e ) {
this.focus();
this.select();
e.preventDefault();
}
);
// Set scheme input box to selected value.
el.find( 'input.redux-scheme-input-' + redux.field_objects.color_scheme.fieldID ).val( el.find( '#redux-scheme-select-' + redux.field_objects.color_scheme.fieldID ).val() );
// Select change.
el.find( '#redux-scheme-select-' + redux.field_objects.color_scheme.fieldID ).on(
'change',
function () {
redux.field_objects.color_scheme.selectChange( el );
}
);
el.find( '#redux-' + redux.field_objects.color_scheme.fieldID + '-tooltip-checkbox' ).on(
'change',
function () {
var checked = $( this ).is( ':checked' );
$( this ).val( checked );
redux.field_objects.color_scheme.showTooltips = checked;
redux.field_objects.color_scheme.qtip( el );
}
);
};
redux.field_objects.color_scheme.import = function ( el ) {
var fieldID = redux.field_objects.color_scheme.fieldID;
var optName = redux.field_objects.color_scheme.optName;
var myUpload = el.find( '#redux-' + fieldID + '-import-scheme-button' );
var submit = myUpload.data( 'submit' );
var nonce = myUpload.data( 'nonce' );
myUpload.upload(
{
name: 'file',
method: 'post',
action: submit + 'class-redux-color-scheme-import.php',
nonce: nonce,
enctype: 'multipart/form-data',
fileType: '.json',
params: {
type: 'import',
field_id: fieldID,
opt_name: optName,
nonce: nonce
},
autoSubmit: true,
onSubmit: function () {},
onComplete: function ( data ) {
// Parse JSON.
data = JSON.parse( data );
// Set success/fail message.
el.find( '#redux-' + fieldID + '-scheme-message-notice h2' ).html( data.data );
// Show message.
$.blockUI(
{
message: el.find( '#redux-' + fieldID + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px', padding: '5px'
}
}
);
// Click OK.
$( '#redux-' + fieldID + '-scheme-ok' ).on(
'click',
function () {
// Unload modal.
$.unblockUI();
// Reload window on success.
if ( true === data.result ) {
window.onbeforeunload = '';
location.reload();
}
// Bail out!
return false;
}
);
},
// Unused.
onSelect: function () {
}
}
);
};
redux.field_objects.color_scheme.delete = function ( el ) {
var field_id = redux.field_objects.color_scheme.fieldID;
el.find( '#redux-' + field_id + '-delete-scheme-button' ).on(
'click',
function ( event ) {
var select_name;
// Prevent default action.
event.preventDefault();
// Retrieve selected scheme name.
select_name = el.find( '#redux-scheme-select-' + field_id ).val();
// Check for 'default', as we don't want to delete it.
if ( 'default' === select_name.toLowerCase() ) {
// Set on screen message.
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'Cannot delete the <strong>Default</strong> scheme, as it is reserved.' );
// Show message.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Clicked OK.
$( '#redux-' + field_id + '-scheme-ok' ).on(
'click',
function () {
$.unblockUI();
return false;
}
);
return false;
}
// Load delete question modal.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-delete-scheme-question' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Clicked yes.
$( '#redux-' + field_id + '-delete-scheme-yes' ).on(
'click',
function () {
var data;
var wait_msg;
// If selected scheme name is valid...
if ( select_name ) {
// Set ajax parameters.
data = {
action: 'redux_color_schemes',
nonce: redux.field_objects.color_scheme.nonce,
opt_name: redux.field_objects.color_scheme.optName,
type: 'delete',
scheme_id: select_name,
field_id: field_id
};
// Load Please wait message.
wait_msg = el.find( '#redux-' + field_id + '-scheme-wait-message h1' ).html();
$.blockUI(
{
message: '<h1>' + wait_msg + 'deleting scheme.<h1/>',
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Post ajax.
$.post(
redux_ajax_script.ajaxurl,
data,
function ( response ) {
// Successful delete.
if ( 'success' === response ) {
// Remove deleted scheme from selector.
el.find( '#redux-scheme-select-' + field_id + ' option[value=\'' + select_name + '\']' ).remove();
// Clear selector (default).
el.find( '.redux-scheme-select' ).select2();
el.find( '.redux-scheme-select' ).val( 'Default' ).trigger( 'change' );
// Clear input box.
el.find( 'input.redux-scheme-input-' + field_id ).val( '' );
// Update modal message text.
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'The <strong>' + select_name + '</strong> scheme has been removed.<br/><br/>The color table has been reset to default values.' );
// Display the notice.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Click OK, unload msg, bail out.
$( '#redux-' + field_id + '-scheme-ok' ).on(
'click',
function () {
$.unblockUI();
// Update the HTML preview.
redux.field_objects.color_scheme.updateSchemeHTML( 0, el );
return false;
}
);
} else {
// Update modal message with fail response.
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'Delete failed: ' + response );
// Display the notice.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Click OK, unload msg, bail out.
$( '#redux-' + field_id + '-scheme-ok' ).on(
'click',
function () {
$.unblockUI();
return false;
}
);
}
}
);
}
}
);
// Clicked no.
$( '#redux-' + field_id + '-delete-scheme-no' ).on(
'click',
function () {
$.unblockUI();
return false;
}
);
}
);
};
redux.field_objects.color_scheme.save = function ( el ) {
var field_id = redux.field_objects.color_scheme.fieldID;
el.find( '#redux-' + field_id + '-save-scheme-button' ).on(
'click',
function ( event ) {
var input_text;
var scheme_name;
var data;
var wait_msg;
var arrData = [];
event.preventDefault();
// Prevent blank input.
input_text = el.find( 'input.redux-scheme-input-' + field_id ).val();
// Trim.
input_text = input_text.replace( /^\s+|\s+$/gm, '' );
// Allow only alphanumeric, space, dash, and underscore.
input_text = input_text.replace( /[^a-z0-9\s\-]/gi, '' );
// Do nothing if input_text is empty.
if ( '' === input_text ) {
return false;
}
// Check for default scheme.
if ( 'default' === input_text.toLowerCase() ) {
// Update notice message.
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'The name <strong>Default</strong> cannot be used as it is reserved.' );
// Display msg.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Clicked OK. Close message and exit.
$( '#redux-' + field_id + '-scheme-ok' ).on(
'click',
function () {
$.unblockUI();
return false;
}
);
// Bail out.
return false;
}
// Enum through them all and collect data.
el.find( '.redux-scheme-layout-container' ).each(
function () {
var obj = $( this ).children( '.redux-color-scheme' );
var title = obj.data( 'title' );
var id = obj.data( 'id' );
var color = obj.data( 'hex-color' );
var alpha = obj.data( 'alpha' );
var rgba = obj.data( 'rgba' );
var group = obj.data( 'group' );
// Push data into the array.
arrData.push(
{
id: id,
title: title,
color: color,
alpha: alpha,
rgba: rgba,
group: group
}
);
}
);
arrData = JSON.stringify( arrData );
arrData = encodeURIComponent( arrData );
// Get scheme name from text box.
scheme_name = el.find( '.redux-scheme-input-' + field_id ).val();
// If one exists, proceed.
if ( scheme_name ) {
// Set ajax parameters.
data = {
action: 'redux_color_schemes',
nonce: redux.field_objects.color_scheme.nonce,
opt_name: redux.field_objects.color_scheme.optName,
type: 'save',
scheme_name: scheme_name,
scheme_data: arrData,
field_id: field_id
};
// Get default wait message.
wait_msg = el.find( '#redux-' + field_id + '-scheme-wait-message h1' ).html();
// Load wait message.
$.blockUI(
{
message: '<h1>' + wait_msg + 'saving scheme.</h1>',
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
el.find( '.redux-scheme-select' ).select2( 'destroy' );
// Post ajax.
$.post(
redux_ajax_script.ajaxurl,
data,
function ( response ) {
// New selector change hook.
el.find( '#redux-scheme-select-' + field_id ).on(
'change',
function () {
redux.field_objects.color_scheme.selectChange( el );
}
);
if ( 'fail' === response ) {
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'The scheme <strong>' + scheme_name + '</strong> already exists and cannot be added again.' );
} else {
// Replace selector with updated values.
el.find( '#redux-scheme-select-' + field_id ).replaceWith( response );
// Update notice message.
el.find( '#redux-' + field_id + '-scheme-message-notice h2' ).html( 'The scheme <strong>' + scheme_name + '</strong> has been added to your scheme list.' );
}
// Display notice message.
$.blockUI(
{
message: el.find( '#redux-' + field_id + '-scheme-message-notice' ),
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Clicked OK. Unload and exit.
$( '#redux-' + field_id + '-scheme-ok' ).on(
'click',
function () {
$.unblockUI();
return false;
}
);
//redux.field_objects.color_scheme.init( el );
el.find( '#redux-scheme-select-' + redux.field_objects.color_scheme.fieldID ).on(
'change',
function () {
redux.field_objects.color_scheme.selectChange( el );
}
);
el.find( '.redux-scheme-select' ).select2( redux.field_objects.color_scheme.default_params );
el.find( 'select.redux-color-scheme-opt-select' ).select2( redux.field_objects.color_scheme.default_params );
}
);
}
}
);
};
redux.field_objects.color_scheme.selectChange = function ( el ) {
var selected;
var field_id = redux.field_objects.color_scheme.fieldID;
// Fade out the colour pickers.
el.find( 'ul.redux-scheme-layout' ).fadeOut();
// Get selected value.
selected = el.find( '#redux-scheme-select-' + field_id ).val();
// Remove default blank value, if any.
el.find( '#redux-scheme-select-' + field_id + ' option[value=\'\']' ).remove();
// Get scheme name from input box.
el.find( 'input.redux-scheme-input-' + field_id ).val( selected );
// Update colour pickers.
redux.field_objects.color_scheme.updateSchemeHTML( selected, el );
};
redux.field_objects.color_scheme.updateSchemeHTML = function ( selected, el ) {
var field_class;
var data;
var field_id = redux.field_objects.color_scheme.fieldID;
// Get default wait msg.
var wait_msg = el.find( '#redux-' + field_id + '-scheme-wait-message h1' ).html();
// Display appended msg.
$.blockUI(
{
message: '<h1>' + wait_msg + 'updating scheme.</h1>',
theme: false,
css: {
width: '500px',
padding: '5px'
}
}
);
// Get field class. Needed for custom classes from field array.
field_class = el.find( '.redux-color-scheme' ).attr( 'class' );
// Set ajax parameters.
data = {
action: 'redux_color_schemes',
nonce: redux.field_objects.color_scheme.nonce,
opt_name: redux.field_objects.color_scheme.optName,
type: 'update',
scheme_id: selected,
field_id: field_id,
field_class: field_class
};
// Post ajax.
$.post(
redux_ajax_script.ajaxurl,
data,
function ( response ) {
// Replace colour picker layout.
el.find( 'ul.redux-scheme-layout' ).replaceWith( response );
// Re-init colour pickers.
redux.field_objects.color_scheme.setAccordions( el );
// Fade colour pickers back in.
el.find( 'ul.redux-scheme-layout' ).fadeIn();
// Remove waiting msg.
$.unblockUI();
// Set flags for compiler.
redux_change( el.find( '.redux-color-scheme-container' ) );
el.find( 'select.redux-color-scheme-opt-select' ).select2( redux.field_objects.color_scheme.default_params );
if ( 'function' === typeof reduxColorSchemeAfterUpdateHTML ) {
reduxColorSchemeAfterUpdateHTML( $( this ), el );
}
}
);
};
// Initialize colour picker.
redux.field_objects.color_scheme.initColorPicker = function ( el ) {
// Get field ID.
var field_id = redux.field_objects.color_scheme.fieldID;
// Get the color scheme container.
var colorpickerInput = el.find( '.redux-color-scheme' );
// Get alpha value and sanitize it.
var currentAlpha = colorpickerInput.data( 'current-alpha' );
// Get colour value and sanitize it.
var currentColor = colorpickerInput.data( 'current-color' );
var outputTransparent = colorpickerInput.data( 'output-transparent' );
// Color picker arguments.
var container = redux.field_objects.color_scheme.el.find( '.redux-color-scheme-container' );
// Get, decode and parse palette.
var palette = container.data( 'palette' );
var pickerGap = container.data( 'picker-gap' );
var pickerFontSize = container.data( 'picker-font-size' );
// Get and sanitize show input argument.
var showInput = container.data( 'show-input' );
// Get and sanitize show initial argument.
var showInitial = container.data( 'show-initial' );
// Get and sanitize show alpha argument.
var showAlpha = container.data( 'show-alpha' );
// Get and sanitize allow empty argument.
var allowEmpty = container.data( 'allow-empty' );
// Get and sanitize show palette argument.
var showPalette = container.data( 'show-palette' );
// Get and sanitize show palette only argument.
var showPaletteOnly = container.data( 'show-palette-only' );
// Get and sanitize show selection palette argument.
var showSelectionPalette = container.data( 'show-selection-palette' );
// Get max palette size.
var maxPaletteSize = Number( container.data( 'max-palette-size' ) );
// Get and sanitize clickout fires change argument.
var clickoutFiresChange = container.data( 'clickout-fires-change' );
// Get choose button text.
var chooseText = String( container.data( 'choose-text' ) );
// Get cancel button text.
var cancelText = String( container.data( 'cancel-text' ) );
// Get and sanitize show buttons argument.
var showButtons = container.data( 'show-buttons' );
// Get container class.
var containerClass = String( container.data( 'container-class' ) );
// Get replacer class.
var replacerClass = String( container.data( 'replacer-class' ) );
// Picker gap css.
el.find( 'li.redux-scheme-layout' ).css( 'width', pickerGap );
// Picker font size.
el.find( '.redux-layout-label' ).attr( 'style', 'font-size: ' + pickerFontSize + '!important' );
currentAlpha = Number( ( null === currentAlpha || undefined === currentAlpha ) ? 1 : currentAlpha );
currentColor = ( '' === currentColor || 'transparent' === currentColor ) ? '' : currentColor;
outputTransparent = Boolean( ( '' === outputTransparent ) ? false : outputTransparent );
palette = decodeURIComponent( palette );
palette = JSON.parse( palette );
// Default palette.
if ( null === palette ) {
palette = [
['#000000', '#434343', '#666666', '#999999', '#b7b7b7', '#cccccc', '#d9d9d9', '#efefef', '#f3f3f3', '#ffffff'],
['#980000', '#ff0000', '#ff9900', '#ffff00', '#00ff00', '#00ffff', '#4a86e8', '#0000ff', '#9900ff', '#ff00ff'],
['#e6b8af', '#f4cccc', '#fce5cd', '#fff2cc', '#d9ead3', '#d9ead3', '#c9daf8', '#cfe2f3', '#d9d2e9', '#ead1dc'],
['#dd7e6b', '#ea9999', '#f9cb9c', '#ffe599', '#b6d7a8', '#a2c4c9', '#a4c2f4', '#9fc5e8', '#b4a7d6', '#d5a6bd'],
['#cc4125', '#e06666', '#f6b26b', '#ffd966', '#93c47d', '#76a5af', '#6d9eeb', '#6fa8dc', '#8e7cc3', '#c27ba0'],
['#a61c00', '#cc0000', '#e69138', '#f1c232', '#6aa84f', '#45818e', '#3c78d8', '#3d85c6', '#674ea7', '#a64d79'],
['#85200c', '#990000', '#b45f06', '#bf9000', '#38761d', '#134f5c', '#1155cc', '#0b5394', '#351c75', '#741b47'],
['#5b0f00', '#660000', '#783f04', '#7f6000', '#274e13', '#0c343d', '#1c4587', '#073763', '#20124d', '#4c1130']
];
}
pickerGap = String( ( '' === pickerGap ) ? '60px' : pickerGap );
pickerFontSize = String( ( '' === pickerFontSize ) ? '11px' : pickerFontSize );
showInput = Boolean( ( '' === showInput ) ? false : showInput );
showInitial = Boolean( ( '' === showInitial ) ? false : showInitial );
showAlpha = Boolean( ( '' === showAlpha ) ? false : showAlpha );
allowEmpty = Boolean( ( '' === allowEmpty ) ? false : allowEmpty );
showPalette = Boolean( ( '' === showPalette ) ? false : showPalette );
showPaletteOnly = Boolean( ( '' === showPaletteOnly ) ? false : showPaletteOnly );
showSelectionPalette = Boolean( ( '' === showSelectionPalette ) ? false : showSelectionPalette );
clickoutFiresChange = Boolean( ( '' === clickoutFiresChange ) ? false : clickoutFiresChange );
showButtons = Boolean( ( '' === showButtons ) ? false : showButtons );
// Color picker options.
colorpickerInput.spectrum(
{
color: currentColor,
showAlpha: showAlpha,
showInput: showInput,
allowEmpty: allowEmpty,
className: 'redux-full-spectrum',
showInitial: showInitial,
showPalette: showPalette,
showSelectionPalette: showSelectionPalette,
maxPaletteSize: maxPaletteSize,
showPaletteOnly: showPaletteOnly,
clickoutFiresChange: clickoutFiresChange,
chooseText: chooseText,
cancelText: cancelText,
showButtons: showButtons,
containerClassName: containerClass,
replacerClassName: replacerClass,
preferredFormat: 'hex6',
localStorageKey: 'redux.spectrum.' + field_id,
palette: palette,
// On change.
change: function ( color ) {
var colorVal;
var alphaVal;
var rgbaVal;
var blockID;
var dataBlock;
var rawData;
if ( null === color ) {
if ( true === outputTransparent ) {
colorVal = 'transparent';
} else {
colorVal = null;
}
alphaVal = null;
} else {
colorVal = color.toHexString();
alphaVal = color.getAlpha();
}
if ( 'transparent' !== colorVal ) {
rgbaVal = redux.field_objects.color_scheme.hexToRGBA( colorVal, alphaVal );
} else {
rgbaVal = 'transparent';
}
blockID = $( this ).data( 'block-id' );
dataBlock = el.find( 'input#' + blockID + '-data' );
rawData = dataBlock.val();
rawData = decodeURIComponent( rawData );
rawData = JSON.parse( rawData );
rawData.color = colorVal;
rawData.alpha = alphaVal;
rawData.rgba = rgbaVal;
rawData = JSON.stringify( rawData );
rawData = encodeURIComponent( rawData );
dataBlock.val( rawData );
redux_change( redux.field_objects.color_scheme.el.find( '.redux-color-scheme-container' ) );
}
}
);
};
} )( jQuery );

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,311 @@
.sp-container {
color: #555;
border-color: #cccccc;
background: #f7f7f7;
-webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
vertical-align: top;
}
.sp-replacer {
color: #555;
border-color: #cccccc;
background: #f7f7f7;
-webkit-box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
box-shadow: inset 0 1px 0 #fff, 0 1px 0 rgba( 0, 0, 0, 0.08 );
vertical-align: top;
}
.sp-replacer:focus,
.sp-replacer:hover,
.sp-replacer.focus,
.sp-replacer.hover {
background: #fafafa;
border-color: #999;
color: #222;
}
.sp-replacer:focus,
.sp-replacer.focus {
-webkit-box-shadow:
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
box-shadow:
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
}
.sp-replacer.active:focus {
-webkit-box-shadow:
inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ),
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
box-shadow:
inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 ),
0 0 0 1px #5b9dd9,
0 0 2px 1px rgba(30, 140, 190, .8);
}
.sp-replacer.active,
.sp-replacer.active:hover,
.sp-replacer:active{
background: #eee;
border-color: #999;
color: #333;
-webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
}
.redux-container-spectrum {
}
.redux-container-color_scheme {
.redux-color-scheme-select-close-hr {
margin-left: 15px;
}
.redux-color-scheme-opt-select {
margin-left: 15px;
}
.redux-color-scheme-blank-hr {
clear: both;
border-top: 0 solid;
border-bottom: 0 solid;
}
ul.redux-scheme-layout {
margin: 0;
padding: 0;
list-style-type: none;
.redux-color-scheme-group {
&.accordion {
padding-bottom: 10px;
}
.redux-color-scheme-accordion {
border: 1px solid #dfdfdf;
background: #FAFAFA;
cursor: pointer;
&:hover {
border-color: #999;
}
span {
&.dashicons {
float: right;
margin-right: 3px;
&.not-titled.subtitled {
margin-top: -2px;
}
&.titled {
margin-top: -25px;
}
&.titled.subtitled {
margin-top: -10px;
}
}
}
.redux-label {
cursor: pointer;
&.redux-layout-group-label {
margin-left: 8px!important;
margin-top: -10px!important;
padding-bottom: 5px;
color: #222;
}
&.redux-layout-group-desc-label {
margin-left: 8px!important;
margin-top: -3px!important;
color: #444;
&.not-titled {
padding-top: 10px;
padding-bottom: 5px;
}
&.titled {
margin-top: -7px!important;
padding-bottom: 5px;
}
}
}
}
.redux-color-scheme-accordion-section {
display: block;
border: 1px solid rgb(223, 223, 223);
border-top: 0;
background: #fff;
.redux-color-scheme-group-desc {
font-size: 12px !important;
text-align: left;
cursor: default;
margin-left: 13px;
margin-right: 13px;
margin-bottom: 2px;
padding-top: 10px;
font-weight: 400;
}
}
}
li.redux-scheme-layout {
width: 60px;
line-height: 11px;
text-align: center;
float: left;
margin: 8px;
height: 95px;
.redux-full-spectrum.sp-palette {
max-width: 200px;
}
.redux-layout-label {
font-size: 11px;
text-align: center;
}
}
}
.redux-color-scheme-container{
hr {
margin-bottom: 10px;
}
.input_wrapper {
display: block;
position: relative;
padding: 0;
width: 44%;
max-width: 44%;
min-width: 70px;
float: left;
clear: none;
height: 57px;
box-sizing: border-box;
vertical-align: baseline;
}
.redux-label {
display: block;
position: relative;
font-size: 12px !important;
text-align: left;
color: #999999;
margin: 4px 0 2px 0 !important;
cursor: default;
&.redux-layout-group-label {
clear: both;
font-weight: 600;
}
&.redux-layout-group-desc-label {
font-style: italic;
}
&.redux-color-scheme-opt-select-title {
font-weight: 600;
margin-left: 15px!important;
}
&.redux-color-scheme-opt-select-desc {
font-style: italic;
margin-left: 15px!important;
}
}
.redux-scheme-name{
.redux-text-scheme-label {
font-size: 13px;
}
input#redux-scheme-input {
width: 100%;
}
}
.redux-action-links {
clear: left;
height: 60px;
.redux-delete-scheme-button,
.redux-import-scheme-button,
.redux-export-scheme-button,
.redux-save-scheme-button {
margin-top: 4px !important;
width: 64px !important;
text-align: center !important;
margin-right: 3px !important;
}
span.redux-action-scheme-label {
font-size: 13px;
clear: left;
}
.hidden-input-div {
height: 40px !important;
left: 213px !important;
top: -34px !important;
cursor: pointer !important;
}
.redux-color-scheme-tooltip-checkbox {
position: relative;
width: 204px;
margin: 0;
padding: 0;
height: 33px !important;
left: 293px !important;
top: -55px !important;
cursor: pointer !important;
font-weight: 400;
}
}
.redux-scheme-select-container {
.redux-select-scheme-label {
font-size: 13px;
}
.redux-scheme-select {
width: 95%;
}
}
.redux-scheme-layout-container {
width: 60px;
height: 36px;
margin: 0 auto 10px auto;
padding-top: 3px;
}
}
}
@media screen and (max-width: 782px) {
.redux-color-scheme-container{
.redux-scheme-name {
clear: left !important;
}
.redux-action-links {
padding-top: 10px;
}
}
}

View File

@@ -0,0 +1,909 @@
<?php
/**
* Redux Custom Font Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com> & Dovy Paukstys <dovy@reduxframework.com>
* @class Redux_Extension_Custom_Fonts
* @version 4.4.2
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Extension_Custom_Fonts' ) ) {
/**
* Class Redux_Extension_Custom_Fonts
*/
class Redux_Extension_Custom_Fonts extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.4.2';
/**
* Extension friendly name.
*
* @var string
*/
public $ext_name = 'Custom Fonts';
/**
* Custom fonts array.
*
* @var array
*/
public $custom_fonts = array();
/**
* WordPress upload directory.
*
* @var string
*/
public $upload_dir = '';
/**
* WordPress upload URI.
*
* @var string
*/
public $upload_url = '';
/**
* Extension instance.
*
* @var null
*/
public static $instance = null;
/**
* Is font conversation service available?
*
* @var bool
*/
private $can_convert;
/**
* Class Constructor. Defines the args for the extensions class
*
* @param object $redux ReduxFramework pointer.
*
* @return void
* @since 1.0.0
* @access public
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
self::$instance = parent::get_instance();
$this->add_field( 'custom_fonts' );
$this->upload_dir = Redux_Core::$upload_dir . 'custom-fonts/';
$this->upload_url = Redux_Core::$upload_url . 'custom-fonts/';
if ( ! is_dir( $this->upload_dir ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir );
}
if ( ! is_dir( $this->upload_dir . '/custom' ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . '/custom' );
}
$this->get_fonts();
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
if ( filemtime( $this->upload_dir . 'custom' ) > ( filemtime( $this->upload_dir . 'fonts.css' ) + 10 ) ) {
$this->generate_css();
}
} else {
$this->generate_css();
}
add_action( 'wp_ajax_redux_custom_fonts', array( $this, 'ajax' ) );
add_action( 'wp_ajax_redux_custom_font_timer', array( $this, 'timer' ) );
add_filter( "redux/{$this->parent->args['opt_name']}/field/typography/custom_fonts", array( $this, 'add_custom_fonts' ) );
// phpcs:disable
// $this->is_field = Redux_Helpers::is_field_in_use( $parent, 'custom_fonts' );
// if ( ! $this->is_field ) {
// $this->add_section();
// }
add_filter( "redux/options/{$this->parent->args['opt_name']}/section/redux_dynamic_font_control", array( $this, 'remove_dynamic_section' ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
add_action( 'wp_head', array( $this, 'enqueue_output' ), 150 );
add_filter( 'tiny_mce_before_init', array( $this, 'extend_tinymce_dropdown' ) );
$this->can_convert = true; // has_filter( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url' );
// phpcs:enable
}
/**
* Timer.
*/
public function timer() {
$name = get_option( 'redux_custom_font_current' );
if ( ! empty( $name ) ) {
echo esc_html( $name );
}
die();
}
/**
* Remove the dynamically added section if the field was used elsewhere
*
* @param array $section Section array.
*
* @return array
* @since Redux_Framework 3.1.1
*/
public function remove_dynamic_section( array $section ): array {
if ( isset( $this->parent->field_types['custom_fonts'] ) ) {
$section = array();
}
return $section;
}
/**
* Adds FontMeister fonts to the TinyMCE drop-down.
* Typekit's fonts don't render properly in the drop-down and in the editor,
* because Typekit needs JS and TinyMCE doesn't support that.
*
* @param array $opt Option array.
*
* @return array
*/
public function extend_tinymce_dropdown( array $opt ): array {
if ( ! is_admin() ) {
return $opt;
}
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
$theme_advanced_fonts = $opt['font_formats'] ?? 'Andale Mono=andale mono,times;Arial=arial,helvetica,sans-serif;Arial Black=arial black,avant garde;Book Antiqua=book antiqua,palatino;Comic Sans MS=comic sans ms,sans-serif;Courier New=courier new,courier;Georgia=georgia,palatino;Helvetica=helvetica;Impact=impact,chicago;Symbol=symbol;Tahoma=tahoma,arial,helvetica,sans-serif;Terminal=terminal,monaco;Times New Roman=times new roman,times;Trebuchet MS=trebuchet ms,geneva;Verdana=verdana,geneva;Webdings=webdings;Wingdings=wingdings,zapf dingbats';
$custom_fonts = '';
$stylesheet = $this->upload_url . 'fonts.css';
if ( empty( $opt['content_css'] ) ) {
$opt['content_css'] = $stylesheet;
} else {
$opt['content_css'] = $opt['content_css'] . ',' . $stylesheet;
}
foreach ( $this->custom_fonts as $arr ) {
foreach ( $arr as $font => $pieces ) {
$custom_fonts .= ';' . $font . '=' . $font;
}
}
$opt['font_formats'] = $theme_advanced_fonts . $custom_fonts;
}
return $opt;
}
/**
* Function to enqueue the custom fonts css
*/
public function enqueue_output() {
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
wp_enqueue_style(
'redux-custom-fonts',
$this->upload_url . 'fonts.css',
array(),
time()
);
}
}
/**
* Adds the appropriate mime types to WordPress
*
* @param array $existing_mimes Mine array.
*
* @return array
*/
public function custom_upload_mimes( array $existing_mimes = array() ): array {
$existing_mimes['ttf'] = 'font/ttf';
$existing_mimes['otf'] = 'font/otf';
$existing_mimes['eot'] = 'application/vnd.ms-fontobject';
$existing_mimes['woff'] = 'application/font-woff';
$existing_mimes['woff2'] = 'application/font-woff2';
$existing_mimes['svg'] = 'image/svg+xml';
$existing_mimes['zip'] = 'application/zip';
return $existing_mimes;
}
/**
* Gets all the fonts in the custom_fonts directory
*/
public function get_fonts() {
if ( empty( $this->custom_fonts ) ) {
$params = array(
'include_hidden' => false,
'recursive' => true,
);
$fonts = $this->parent->filesystem->execute( 'dirlist', $this->upload_dir, $params );
if ( ! empty( $fonts ) ) {
foreach ( $fonts as $section ) {
if ( 'd' === $section['type'] && ! empty( $section['name'] ) ) {
if ( 'custom' === $section['name'] ) {
$section['name'] = esc_html__( 'Custom Fonts', 'redux-framework' );
}
if ( empty( $section['files'] ) ) {
continue;
}
$this->custom_fonts[ $section['name'] ] = $this->custom_fonts[ $section['name'] ] ?? array();
foreach ( $section['files'] as $font ) {
if ( ! empty( $font['name'] ) ) {
if ( empty( $font['files'] ) ) {
continue;
}
$kinds = array();
foreach ( $font['files'] as $f ) {
$valid = $this->check_font_name( $f );
if ( $valid ) {
$kinds[] = $valid;
}
}
$this->custom_fonts[ $section['name'] ][ $font['name'] ] = $kinds;
}
}
}
}
}
}
}
/**
* Add custom fonts.
*
* @param mixed $custom_fonts Custom fonts.
*
* @return array
*/
public function add_custom_fonts( $custom_fonts ): array {
if ( empty( $custom_fonts ) ) {
$custom_fonts = array();
}
return wp_parse_args( $custom_fonts, $this->custom_fonts );
}
/**
* Ajax used within the panel to add and process the fonts
*/
public function ajax() {
if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST['nonce'] ) ), 'redux_custom_fonts' ) ) {
die( 0 );
}
if ( isset( $_POST['type'] ) && 'delete' === $_POST['type'] ) {
if ( isset( $_POST['section'] ) ) {
if ( esc_html__( 'Custom Fonts', 'redux-framework' ) === $_POST['section'] ) {
$_POST['section'] = 'custom';
}
}
try {
if ( isset( $_POST['section'] ) || isset( $_POST['name'] ) ) {
$this->parent->filesystem->execute( 'rmdir', $this->upload_dir . sanitize_title( wp_unslash( $_POST['section'] ) ) . '/' . sanitize_title( wp_unslash( $_POST['name'] ) ) . '/', array( 'recursive' => true ) );
$result = array( 'type' => 'success' );
echo wp_json_encode( $result );
}
} catch ( Exception $e ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'Unable to delete font file(s).', 'redux-framework' ),
)
);
}
die();
}
if ( ! isset( $_POST['title'] ) ) {
$_POST['title'] = '';
}
if ( ! isset( $_POST['filename'] ) ) {
$_POST['filename'] = '';
}
if ( ! empty( $_POST['attachment_id'] ) ) {
if ( isset( $_POST['title'] ) || isset( $_POST['mime'] ) ) {
$msg = $this->process_web_font( sanitize_key( wp_unslash( $_POST['attachment_id'] ) ), sanitize_text_field( wp_unslash( $_POST['title'] ) ), sanitize_text_field( wp_unslash( $_POST['filename'] ) ), sanitize_text_field( wp_unslash( $_POST['mime'] ) ) );
if ( empty( $msg ) ) {
$msg = '';
}
$result = array(
'type' => 'success',
'msg' => $msg,
);
echo wp_json_encode( $result );
}
}
die();
}
/**
* Get only valid files. Ensure everything is proper for processing.
*
* @param string $path Path.
*
* @return array
*/
public function get_valid_files( string $path ): array {
$output = array();
$path = trailingslashit( $path );
$params = array(
'include_hidden' => false,
'recursive' => true,
);
$files = $this->parent->filesystem->execute( 'dirlist', $path, $params );
foreach ( $files as $file ) {
if ( 'd' === $file['type'] ) {
$output = array_merge( $output, $this->get_valid_files( $path . $file['name'] ) );
} elseif ( 'f' === $file['type'] ) {
$valid = $this->check_font_name( $file );
if ( $valid ) {
$output[ $valid ] = trailingslashit( $path ) . $file['name'];
}
}
}
return $output;
}
/**
* Take a valid web font and process the missing pieces.
*
* @param string $attachment_id ID.
* @param string $name Name.
* @param string $true_filename Filename.
* @param string $mime_type Mine type.
*/
public function process_web_font( string $attachment_id, string $name, string $true_filename, string $mime_type ) {
// phpcs:ignore WordPress.Security.NonceVerification
if ( ! isset( $_POST['conversion'] ) ) {
$_POST['conversion'] = 'false';
}
// phpcs:ignore WordPress.Security.NonceVerification
$conversion = sanitize_text_field( wp_unslash( $_POST['conversion'] ) );
$missing = array();
$complete = array(
'ttf',
'woff',
'woff2',
'eot',
'svg',
'otf',
);
$subfolder = 'custom/';
$subtype = explode( '/', $mime_type );
$subtype = trim( max( $subtype ) );
if ( ! is_dir( $this->upload_dir ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir );
}
if ( ! is_dir( $this->upload_dir . $subfolder ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder );
}
$temp = $this->upload_dir . 'temp';
$path = get_attached_file( $attachment_id );
if ( empty( $path ) ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'Attachment does not exist.', 'redux-framework' ),
)
);
die();
}
$filename = explode( '/', $path );
$filename = $filename[ ( count( $filename ) - 1 ) ];
$fontname = ucfirst(
str_replace(
array(
'.zip',
'.ttf',
'.woff',
'.woff2',
'.eot',
'.svg',
'.otf',
),
'',
strtolower( $filename )
)
);
if ( empty( $name ) ) {
$name = $fontname;
}
$ret = array();
if ( ! is_dir( $temp ) ) {
$this->parent->filesystem->execute( 'mkdir', $temp );
}
if ( 'zip' === $subtype ) {
$unzipfile = unzip_file( $path, $temp );
if ( is_wp_error( $unzipfile ) ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => $unzipfile->get_error_message() . '<br><br>' . esc_html__( 'Unzipping failed.', 'redux-framework' ),
)
);
die();
}
$output = $this->get_valid_files( $temp );
if ( ! empty( $output ) ) {
foreach ( $complete as $test ) {
if ( ! isset( $output[ $test ] ) ) {
$missing[] = $test;
}
}
if ( ! is_dir( $this->upload_dir . $subfolder . $name . '/' ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder . $name . '/' );
}
foreach ( $output as $key => $value ) {
$param_array = array(
'destination' => $this->upload_dir . $subfolder . $name . '/' . $fontname . '.' . $key,
'overwrite' => true,
'chmod' => 755,
);
$this->parent->filesystem->execute( 'copy', $value, $param_array );
}
if ( true === $this->can_convert && 'true' === $conversion ) {
$ret = $this->get_missing_files( $name, $fontname, $missing, $output, $subfolder, $true_filename );
}
}
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
$this->generate_css();
wp_delete_attachment( $attachment_id, true );
} elseif ( 'svg+xml' === $subtype || 'vnd.ms-fontobject' === $subtype || 'x-font-ttf' === $subtype || 'ttf' === $subtype || 'otf' === $subtype || 'font-woff' === $subtype || 'font-woff2' === $subtype || 'application-octet-stream' === $subtype || 'octet-stream' === $subtype ) {
foreach ( $complete as $test ) {
if ( $subtype !== $test ) {
if ( ! isset( $output[ $test ] ) ) {
$missing[] = $test;
}
}
}
if ( ! is_dir( $this->upload_dir . $subfolder . $name . '/' ) ) {
$this->parent->filesystem->execute( 'mkdir', $this->upload_dir . $subfolder . $name . '/' );
}
$output = array( $subtype => $path );
// TODO: COnversion error not moving single file.
if ( true === $this->can_convert && 'true' === $conversion ) {
$ret = $this->get_missing_files( $name, $fontname, $missing, $output, $subfolder, $true_filename );
} else {
$param_array = array(
'destination' => $this->upload_dir . $subfolder . '/' . $name . '/' . $true_filename, // $fontname . '.' . $subtype,
'overwrite' => true,
'chmod' => 755,
);
$this->parent->filesystem->execute( 'copy', $path, $param_array );
}
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
$this->generate_css();
wp_delete_attachment( $attachment_id, true );
} else {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'File type not recognized.', 'redux-framework' ) . ' ' . $subtype,
)
);
die();
}
if ( is_array( $ret ) && ! empty( $ret ) ) {
$msg = esc_html__( 'Unidentified error.', 'redux-framework' );
if ( isset( $ret['msg'] ) ) {
$msg = $ret['msg'];
}
return $msg;
}
return '';
}
/**
* Ping the WebFontOMatic API to get the missing files.
*
* @param string $name Name.
* @param string $fontname Font name.
* @param array $missing Missing.
* @param array $output Output.
* @param string $subfolder Folder.
* @param string $true_filename Font name with extension.
*/
private function get_missing_files( string $name, string $fontname, array $missing, array $output, string $subfolder, string $true_filename ) {
if ( ! empty( $name ) && ! empty( $missing ) ) {
$temp = $this->upload_dir . 'temp';
$font_ext = pathinfo( $true_filename, PATHINFO_EXTENSION );
$unsupported = array( 'eot', 'woff', 'woff2' );
// Find a file to convert from.
foreach ( $output as $key => $value ) {
if ( 'eot' === $key ) {
continue;
} else {
$main = $key;
break;
}
}
if ( ! isset( $main ) ) {
echo wp_json_encode(
array(
'type' => 'error',
'msg' => esc_html__( 'No valid font file was found.', 'redux-framework' ),
)
);
$this->parent->filesystem->execute( 'rmdir', $temp, array( 'recursive' => true ) );
$this->parent->filesystem->execute( 'rmdir', $this->upload_dir . $subfolder . $name . '/', array( 'recursive' => true ) );
die();
}
update_option( 'redux_custom_font_current', $name . '.zip' );
$boundary = wp_generate_password( 24 );
$headers = array(
'content-type' => 'multipart/form-data; boundary=' . $boundary,
'user-agent' => 'redux-custom-fonts-' . self::$version . ' using ' . wp_get_theme(),
);
$payload = '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="md5"' . "\r\n\r\n";
$payload .= md5( 'redux_custom_font' );
$payload .= "\r\n";
if ( $output[ $main ] ) {
$payload .= '--' . $boundary;
$payload .= "\r\n";
$payload .= 'Content-Disposition: form-data; name="convert"; filename="' . basename( $output[ $main ] ) . '"' . "\r\n";
$payload .= "\r\n";
$payload .= $this->parent->filesystem->execute( 'get_contents', $output[ $main ] );
$payload .= "\r\n";
}
$payload .= '--' . $boundary . '--';
$args = array(
'headers' => $headers,
'body' => $payload,
'user-agent' => $headers['user-agent'],
'timeout' => 300,
'sslverify' => true,
);
// phpcs:disable WordPress.NamingConventions.ValidHookName
$api_url = apply_filters( 'redux/' . $this->parent->args['opt_name'] . '/extensions/custom_fonts/api_url', 'https://redux.io/fonts' );
$response = wp_remote_post( $api_url, $args );
if ( is_wp_error( $response ) ) {
return array(
'type' => 'error',
'msg' => $response->get_error_message() . '<br><br>' . esc_html__( 'Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
);
} elseif ( null !== json_decode( $response['body'] ) ) {
return json_decode( $response['body'], true );
}
$param_array = array(
'content' => $response['body'],
'overwrite' => true,
'chmod' => FS_CHMOD_FILE,
);
$zip_file = $temp . DIRECTORY_SEPARATOR . $fontname . '.zip';
$ret = $this->parent->filesystem->execute( 'put_contents', $zip_file, $param_array );
$zip = unzip_file( $zip_file, $temp );
if ( ! is_wp_error( $zip ) ) {
$params = array(
'include_hidden' => false,
'recursive' => false,
);
$files = $this->parent->filesystem->execute( 'dirlist', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR, $params );
foreach ( $files as $file ) {
$param_array = array(
'destination' => $this->upload_dir . $subfolder . $name . DIRECTORY_SEPARATOR . $file['name'],
'overwrite' => true,
'chmod' => 755,
);
$this->parent->filesystem->execute( 'move', $temp . DIRECTORY_SEPARATOR . 'fonts' . DIRECTORY_SEPARATOR . $file['name'], $param_array );
}
} else {
$path_parts = pathinfo( $output[ $main ] );
$param_array = array(
'destination' => $this->upload_dir . $subfolder . $name . DIRECTORY_SEPARATOR . $path_parts['basename'],
'overwrite' => true,
'chmod' => 755,
);
$this->parent->filesystem->execute( 'move', $output[ $main ], $param_array );
if ( in_array( $font_ext, $unsupported, true ) ) {
return array(
'type' => 'error',
// translators: %s = font extension.
'msg' => $zip->get_error_message() . '<br><br>' . sprintf( esc_html__( 'The font converter does not support %s fonts.', 'redux-framework' ), $font_ext ),
);
} else {
return array(
'type' => 'error',
'msg' => $zip->get_error_message() . '<br><br>' . esc_html__( 'ZIP error. Your font could not be converted at this time. Please try again later.', 'redux-framework' ),
);
}
}
delete_option( 'redux_custom_font_current' );
}
return '';
}
/**
* Check if the file name is a valid font file.
*
* @param array $file File.
*
* @return bool|string
*/
private function check_font_name( array $file ) {
if ( '.woff' === strtolower( substr( $file['name'], - 5 ) ) ) {
return 'woff';
}
if ( '.woff2' === strtolower( substr( $file['name'], - 6 ) ) ) {
return 'woff2';
}
$sub = strtolower( substr( $file['name'], - 4 ) );
if ( '.ttf' === $sub ) {
return 'ttf';
}
if ( '.eot' === $sub ) {
return 'eot';
}
if ( '.svg' === $sub ) {
return 'svg';
}
if ( '.otf' === $sub ) {
return 'otf';
}
return false;
}
/**
* Generate a new custom CSS file for enqueuing on the frontend and backend.
*/
private function generate_css() {
$params = array(
'include_hidden' => false,
'recursive' => true,
);
$fonts = $this->parent->filesystem->execute( 'dirlist', $this->upload_dir . 'custom/', $params );
if ( empty( $fonts ) || ! is_array( $fonts ) ) {
return;
}
foreach ( $fonts as $font ) {
if ( 'd' === $font['type'] ) {
break;
}
if ( file_exists( $this->upload_dir . 'fonts.css' ) ) {
$this->parent->filesystem->execute( 'delete', $this->upload_dir . 'fonts.css' );
}
return;
}
$css = '';
foreach ( $fonts as $font ) {
if ( 'd' === $font['type'] ) {
$css .= $this->generate_font_css( $font['name'], $this->upload_dir . 'custom/' );
}
}
if ( '' !== $css ) {
$param_array = array(
'content' => $css,
'chmod' => FS_CHMOD_FILE,
);
$this->parent->filesystem->execute( 'put_contents', $this->upload_dir . 'fonts.css', $param_array );
}
}
/**
* Process to actually construct the custom font css file.
*
* @param string $name Name.
* @param string $dir Directory.
*
* @return string
*/
private function generate_font_css( string $name, string $dir ): ?string {
$path = $dir . $name;
$params = array(
'include_hidden' => false,
'recursive' => true,
);
$files = $this->parent->filesystem->execute( 'dirlist', $path, $params );
if ( empty( $files ) ) {
return null;
}
$output = array();
foreach ( $files as $file ) {
$output[ $this->check_font_name( $file ) ] = $file['name'];
}
$css = '@font-face {';
$css .= 'font-family:"' . $name . '";';
$src = array();
if ( isset( $output['eot'] ) ) {
$src[] = "url('{$this->upload_url}custom/$name/{$output['eot']}?#iefix') format('embedded-opentype')";
}
if ( isset( $output['woff'] ) ) {
$src[] = "url('{$this->upload_url}custom/$name/{$output['woff']}') format('woff')";
}
if ( isset( $output['woff2'] ) ) {
$src[] = "url('{$this->upload_url}custom/$name/{$output['woff2']}') format('woff2')";
}
if ( isset( $output['ttf'] ) ) {
$src[] = "url('{$this->upload_url}custom/$name/{$output['ttf']}') format('truetype')";
}
if ( isset( $output['svg'] ) ) {
$src[] = "url('{$this->upload_url}custom/$name/{$output['svg']}#svg$name') format('svg')";
}
if ( ! empty( $src ) ) {
$css .= 'src:' . implode( ', ', $src ) . ';';
}
// Replace font weight and style with sub-sets.
$css .= 'font-weight: normal;';
$css .= 'font-style: normal;';
$css .= '}';
return $css;
}
/**
* Custom function for filtering the section array.
* Good for child themes to override or add to the sections.
* Simply include this function in the child themes functions.php file.
* NOTE: the defined constants for URLs and directories will NOT be available at this point in a child theme,
* so you must use get_template_directory_uri() if you want to use any of the built-in icons
*/
public function add_section() {
if ( ! isset( $this->parent->fontControl ) ) {
$this->parent->sections[] = array(
'title' => esc_html__( 'Font Control', 'redux-framework' ),
'desc' => '<p class="description"></p>',
'icon' => 'el-icon-font',
'id' => 'redux_dynamic_font_control',
// Leave this as a blank section, no options just some intro text set above.
'fields' => array(),
);
for ( $i = count( $this->parent->sections ); $i >= 1; $i-- ) {
if ( isset( $this->parent->sections[ $i ] ) && isset( $this->parent->sections[ $i ]['title'] ) && esc_html__( 'Font Control', 'redux-framework' ) === $this->parent->sections[ $i ]['title'] ) {
$this->parent->fontControl = $i;
$this->parent->sections[ $this->parent->fontControl ]['fields'][] = array(
'id' => 'redux_font_control',
'type' => 'custom_fonts',
);
break;
}
}
}
}
}
}
class_alias( 'Redux_Extension_Custom_Fonts', 'ReduxFramework_Extension_custom_fonts' );

View File

@@ -0,0 +1,204 @@
<?php
/**
* Redux Custom Font Field Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com> & Dovy Paukstys <dovy@reduxframework.com>
* @class Redux_Custom_Fonts
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Custom_Fonts' ) ) {
/**
* Main ReduxFramework_custom_fonts class
*
* @since 1.0.0
*/
class Redux_Custom_Fonts extends Redux_Field {
/**
* Set field defaults.
*/
public function set_defaults() {
$defaults = array(
'convert' => false,
'eot' => false,
'svg' => false,
'ttf' => false,
'woff' => true,
'woff2' => true,
);
$this->value = wp_parse_args( $this->value, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @return void
* @since 1.0.0
* @access public
*/
public function render() {
echo '</fieldset></td></tr>';
echo '<tr>';
echo '<td colspan="2">';
echo '<fieldset
class="redux-field-container redux-field redux-field-init redux-container-custom_font"
data-type="' . esc_attr( $this->field['type'] ) . '"
data-id="' . esc_attr( $this->field['id'] ) . '"
>';
$can_convert = true;
$nonce = wp_create_nonce( 'redux_custom_fonts' );
$this->field['custom_fonts'] = apply_filters( "redux/{$this->parent->args[ 'opt_name' ]}/field/typography/custom_fonts", array() ); // phpcs:ignore WordPress.NamingConventions.ValidHookName
if ( $can_convert ) {
echo '<div class="">';
echo '<label for="custom-font-convert">';
echo '<input type="hidden" class="checkbox-check" data-val="1" name="' . esc_attr( $this->field['name'] ) . '[convert]" value="' . esc_attr( $this->value['convert'] ) . '"/>';
echo '<input type="checkbox" class="checkbox" id="custom-font-convert" value="1"' . checked( $this->value['convert'], '1', false ) . '">';
echo 'Enable font conversion';
echo '</label>';
echo '</div>';
echo '</div>';
}
if ( ! empty( $this->field['custom_fonts'] ) ) {
foreach ( $this->field['custom_fonts'] as $section => $fonts ) {
if ( empty( $fonts ) ) {
continue;
}
echo '<h3>' . esc_html( $section ) . '</h3>';
echo '<div class="font-error" style="display: none;"><p><strong>' . esc_html__( 'Error', 'redux-framework' ) . '</strong>: <span></span></p></div>';
echo '<table class="wp-list-table widefat plugins" style="border-spacing:0;"><tbody>';
foreach ( $fonts as $font => $pieces ) {
echo '<tr class="active">';
echo '<td class="plugin-title" style="min-width: 40%"><strong>' . esc_html( $font ) . '</strong></td>';
echo '<td class="column-description desc">';
echo '<div class="plugin-description">';
if ( is_array( $pieces ) && ! empty( $pieces ) ) {
foreach ( $pieces as $piece ) {
echo '<span class="button button-primary button-small font-pieces">' . esc_html( $piece ) . '</span>';
}
}
echo '</div>';
echo '</td>';
echo '<td style="width: 140px;"><div class="action-row visible">';
echo '<span style="display:none;"><a href="#" class="rename">Rename</a> | </span>';
echo '<a href="#" class="fontDelete delete" data-section="' . esc_attr( $section ) . '" data-name="' . esc_attr( $font ) . '" data-type="delete">' . esc_html__( 'Delete', 'redux-framework' ) . '</a>';
echo '<span class="spinner" style="display:none; visibility: visible;"></span>';
echo '</div>';
echo '</td>';
echo '</tr>';
}
echo '</tbody></table>';
}
echo '<div class="upload_button_div"><span class="button media_add_font" data-nonce="' . esc_attr( $nonce ) . '" id="' . esc_attr( $this->field['id'] ) . '-custom_fonts">' . esc_html__( 'Add Font', 'redux-framework' ) . '</span></div><br />';
} else {
echo '<h3>' . esc_html__( 'No Custom Fonts Found', 'redux-framework' ) . '</h3>';
echo '<div class="upload_button_div"><span class="button media_add_font" data-nonce="' . esc_attr( $nonce ) . '" id="' . esc_attr( $this->field['id'] ) . '-custom_fonts">' . esc_html__( 'Add Font', 'redux-framework' ) . '</span></div>';
}
echo '</fieldset></td></tr>';
}
/**
* Functions to pass data from the PHP to the JS at render time.
*
* @param array $field Field.
* @param string $value Value.
*
* @return array
*/
public function localize( $field, $value = '' ): array {
$params = array();
if ( ! isset( $field['mode'] ) ) {
$field['mode'] = 'image';
}
$params['mode'] = $field['mode'];
if ( empty( $value ) && isset( $this->value ) ) {
$value = $this->value;
}
$params['val'] = $value;
return $params;
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @return void
* @since 1.0.0
* @access public
*/
public function enqueue() {
$min = Redux_Functions::isMin();
wp_enqueue_script(
'redux-field-custom-fonts',
$this->url . '/redux-custom-fonts' . $min . '.js',
array( 'jquery', 'redux-block-ui' ),
Redux_Extension_Custom_Fonts::$version,
true
);
wp_localize_script(
'redux-field-custom-fonts',
'redux_custom_fonts_l10',
apply_filters(
'redux_custom_fonts_localized_data',
array(
'delete_error' => esc_html__( 'There was an error deleting your font:', 'redux-framework' ),
'unzip' => esc_html__( 'Unzipping archive and generating any missing font files.', 'redux-framework' ),
'convert' => esc_html__( 'Converting font file(s)...', 'redux-framework' ),
'partial' => esc_html__( 'The only file(s) imported were those uploaded. Please refresh the page to continue (making note of any errors before doing so, please).', 'redux-framework' ),
'unknown' => esc_html__( 'An unknown error occurred. Please try again.', 'redux-framework' ),
'complete' => esc_html__( 'Conversion complete. Refreshing page...', 'redux-framework' ),
'media_title' => esc_html__( 'Choose Font file or ZIP of font files.', 'redux-framework' ),
'media_button' => esc_html__( 'Update', 'redux-framework' ),
)
)
);
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-custom-fonts',
$this->url . 'redux-custom-fonts.css',
array(),
Redux_Extension_Custom_Fonts::$version
);
}
$class = Redux_Extension_Custom_Fonts::$instance;
if ( ! empty( $class->custom_fonts ) ) {
if ( file_exists( $class->upload_dir . 'fonts.css' ) ) {
wp_enqueue_style(
'redux-custom_fonts',
$class->upload_url . 'fonts.css',
array(),
Redux_Core::$version
);
}
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,33 @@
.redux-container-custom_font table tr td { padding: 10px 9px !important; }
.redux-container-custom_font table.widefat { border-left: 1px solid #dfdfdf; border-right: 1px solid #dfdfdf; border-top: 1px solid #dfdfdf; }
.redux-container-custom_font .upload_button_div { margin: 10px 0; float: right; }
.redux-container-custom_font .spinner { margin-top: 0; }
.redux-container-custom_font .fontDelete { float: right; }
.redux-container-custom_font .action-row { text-align: right; padding-right: 5px; line-height: 20px; }
.redux-container-custom_font .plugins .active td, .redux-container-custom_font .plugins .active th { background-color: #FAFAFA; }
.redux-container-custom_font .font-error { margin: 5px 0 15px; border-left: 4px solid #dd3d36; background: #fff; -webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.1); padding: 1px 12px; outline: 0; }
.redux-container-custom_font .font-error p { margin: 0.5em 0; padding: 2px; }
.redux-container-custom_font .conversion-types { border: solid #e7e7e7 1px; padding-top: 5px; padding-bottom: 5px; padding-left: 10px; margin-bottom: 10px; opacity: 1; }
.redux-container-custom_font .conversion-types .checkbox { margin-left: 20px !important; }
.redux-container-custom_font .conversion-types.is-disabled { cursor: not-allowed; opacity: 0.7; }
.redux-container-custom_font .conversion-types.is-disabled .checkbox, .redux-container-custom_font .conversion-types.is-disabled label { cursor: not-allowed; }
.redux-container-custom_font .font-pieces { margin-right: 1px; }
.fontActionWorking { background: green !important; }
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtY3VzdG9tLWZvbnRzLmNzcyIsInNvdXJjZXMiOlsicmVkdXgtY3VzdG9tLWZvbnRzLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsQUFFUSw0QkFGb0IsQ0FDeEIsS0FBSyxDQUNELEVBQUUsQ0FBQyxFQUFFLENBQUMsRUFDRixPQUFPLEVBQUUsbUJBQW1CLEdBQy9COztBQUpULEFBTVEsNEJBTm9CLENBQ3hCLEtBQUssQUFLQSxRQUFRLENBQUMsRUFDTixXQUFXLEVBQUUsaUJBQWlCLEVBQzlCLFlBQVksRUFBRSxpQkFBaUIsRUFDL0IsVUFBVSxFQUFFLGlCQUFpQixHQUNoQzs7QUFWVCxBQWFJLDRCQWJ3QixDQWF4QixrQkFBa0IsQ0FBQyxFQUNmLE1BQU0sRUFBRSxNQUFNLEVBQ2QsS0FBSyxFQUFFLEtBQUssR0FDZjs7QUFoQkwsQUFrQkksNEJBbEJ3QixDQWtCeEIsUUFBUSxDQUFDLEVBQ0wsVUFBVSxFQUFDLENBQUMsR0FDZjs7QUFwQkwsQUFzQkksNEJBdEJ3QixDQXNCeEIsV0FBVyxDQUFDLEVBQ1IsS0FBSyxFQUFFLEtBQUssR0FDZjs7QUF4QkwsQUEwQkksNEJBMUJ3QixDQTBCeEIsV0FBVyxDQUFDLEVBQ1IsVUFBVSxFQUFFLEtBQUssRUFDakIsYUFBYSxFQUFFLEdBQUcsRUFDbEIsV0FBVyxFQUFFLElBQUksR0FDcEI7O0FBOUJMLEFBa0NZLDRCQWxDZ0IsQ0FnQ3hCLFFBQVEsQ0FDSixPQUFPLENBQ0gsRUFBRSxFQWxDZCw0QkFBNEIsQ0FnQ3hCLFFBQVEsQ0FDSixPQUFPLENBRUgsRUFBRSxDQUFDLEVBQ0MsZ0JBQWdCLEVBQUUsT0FBTyxHQUM1Qjs7QUFyQ2IsQUF5Q0ksNEJBekN3QixDQXlDeEIsV0FBVyxDQUFDLEVBQ1IsTUFBTSxFQUFFLFVBQVUsRUFDbEIsV0FBVyxFQUFFLGlCQUFpQixFQUM5QixVQUFVLEVBQUUsSUFBSSxFQUNoQixrQkFBa0IsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsa0JBQW9CLEVBQ3BELFVBQVUsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsa0JBQW9CLEVBQzVDLE9BQU8sRUFBRSxRQUFRLEVBQ2pCLE9BQU8sRUFBRSxDQUFDLEdBS2I7O0FBckRMLEFBaURRLDRCQWpEb0IsQ0F5Q3hCLFdBQVcsQ0FRUCxDQUFDLENBQUMsRUFDRSxNQUFNLEVBQUUsT0FBTyxFQUNmLE9BQU8sRUFBRSxHQUFHLEdBQ2Y7O0FBcERULEFBdURJLDRCQXZEd0IsQ0F1RHhCLGlCQUFpQixDQUFDLEVBQ2QsTUFBTSxFQUFFLGlCQUFpQixFQUN6QixXQUFXLEVBQUUsR0FBRyxFQUNoQixjQUFjLEVBQUUsR0FBRyxFQUNuQixZQUFZLEVBQUUsSUFBSSxFQUNsQixhQUFhLEVBQUUsSUFBSSxFQUNuQixPQUFPLEVBQUMsQ0FBQyxHQWVaOztBQTVFTCxBQStEUSw0QkEvRG9CLENBdUR4QixpQkFBaUIsQ0FRYixTQUFTLENBQUMsRUFDTixXQUFXLEVBQUUsSUFBSSxDQUFBLFVBQVUsR0FDOUI7O0FBakVULEFBbUVRLDRCQW5Fb0IsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FBQyxFQUNWLE1BQU0sRUFBQyxXQUFXLEVBQ2xCLE9BQU8sRUFBRSxHQUFHLEdBTWY7O0FBM0VULEFBdUVZLDRCQXZFZ0IsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FJVCxTQUFTLEVBdkVyQiw0QkFBNEIsQ0F1RHhCLGlCQUFpQixBQVlaLFlBQVksQ0FLVCxLQUFLLENBQUMsRUFDRixNQUFNLEVBQUMsV0FBVyxHQUNyQjs7QUExRWIsQUE4RUksNEJBOUV3QixDQThFeEIsWUFBWSxDQUFDLEVBQ1QsWUFBWSxFQUFFLEdBQUcsR0FDcEI7O0FBR0wsQUFBQSxrQkFBa0IsQ0FBQyxFQUNmLFVBQVUsRUFBRSxnQkFBZ0IsR0FDL0IifQ== */
/*# sourceMappingURL=redux-custom-fonts.css.map */

View File

@@ -0,0 +1,329 @@
/* global redux, wp, redux_custom_fonts_l10, ajaxurl */
(function ( $ ) {
'use strict';
var l10n;
var reduxObject;
var ajaxDone = false;
redux.field_objects = redux.field_objects || {};
redux.field_objects.custom_fonts = redux.field_objects.custom_fonts || {};
redux.field_objects.custom_fonts.init = function ( selector ) {
// If no selector is passed, grab one from the HTML.
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-custom_font:visible' );
}
// Enum instances of our object.
$( selector ).each(
function () {
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
// Init module level code.
redux.field_objects.custom_fonts.modInit( el );
}
);
};
redux.field_objects.custom_fonts.modInit = function ( el ) {
var optName = $( '.redux-ajax-security' ).data( 'opt-name' );
l10n = redux_custom_fonts_l10;
if ( undefined === optName ) {
reduxObject = redux;
} else {
reduxObject = redux.optName;
}
el.find( '.checkbox' ).on(
'click',
function () {
var val = 0;
var checkName;
var checkVal;
var opVal;
checkName = $( this ).attr( 'id' );
if ( 'custom-font-convert' === checkName ) {
if ( $( this ).is( ':checked' ) ) {
checkVal = '';
opVal = 1;
el.find( '.conversion-types' ).removeClass( 'is-disabled' );
} else {
checkVal = 'disabled';
opVal = 0.7;
el.find( '.conversion-types' ).addClass( 'is-disabled' );
}
el.find( '#custom-font-eot,#custom-font-svg,#custom-font-ttf,#custom-font-woff,#custom-font-woff2' ).prop( 'disabled', checkVal );
el.find( '.conversion-types' ).css( 'opacity', opVal );
}
if ( $( this ).is( ':checked' ) ) {
val = $( this ).parent().find( '.checkbox-check' ).attr( 'data-val' );
}
$( this ).parent().find( '.checkbox-check' ).val( val );
redux_change( $( this ) );
}
);
// Remove the image button.
el.find( '.remove-font' ).off( 'click' ).on(
'click',
function () {
redux.field_objects.custom_fonts.remove_font( el, $( this ).parents( 'fieldset.redux-field:first' ) );
}
);
// Upload media button.
el.find( '.media_add_font' ).off().on(
'click',
function ( event ) {
redux.field_objects.custom_fonts.add_font( el, event, $( this ).parents( 'fieldset.redux-field:first' ) );
}
);
el.find( '.fontDelete' ).on(
'click',
function ( e ) {
var data;
var parent = $( this ).parents( 'td:first' );
e.preventDefault();
parent.find( '.spinner' ).show();
data = $( this ).data();
data.action = 'redux_custom_fonts';
data.nonce = $( this ).parents( '.redux-container-custom_font:first' ).find( '.media_add_font' ).attr( 'data-nonce' );
$.post(
ajaxurl,
data,
function ( response ) {
var rowCount;
response = JSON.parse( response );
if ( response.type && 'success' === response.type ) {
rowCount = parent.parents( 'table:first' ).find( 'tr' ).length;
if ( 1 === rowCount ) {
parent.parents( 'table:first' ).fadeOut().remove();
} else {
parent.parents( 'tr:first' ).fadeOut().remove();
}
} else {
alert( l10n.delete_error + ' ' + response.msg );
parent.find( '.spinner' ).hide();
}
}
);
return false;
}
);
};
redux.field_objects.custom_fonts.startTimer = function ( el, status ) {
var cur_data;
$.ajax(
{
url: ajaxurl,
type: 'POST',
data: {
action: 'redux_custom_font_timer'
},
beforeSend: function () {
},
success: function ( data ) {
var msg;
if ( false === ajaxDone ) {
setTimeout( redux.field_objects.custom_fonts.startTimer( el, status ), 500 );
msg = reduxObject.args.please_wait + ': ' + status + '<br><br>' + data;
} else {
msg = l10n.complete;
data = 'finished';
}
if ( '' !== data ) {
if ( cur_data !== data ) {
$( '.blockUI.blockMsg h2' ).html( msg );
cur_data = data;
}
}
}
}
);
};
redux.field_objects.custom_fonts.add_font = function ( el, event, selector ) {
var frame;
event.preventDefault();
// If the media frame already exists, reopen it.
if ( frame ) {
frame.open();
return;
}
// Create the media frame.
frame = wp.media(
{
multiple: false,
library: {
type: ['application', 'font'] // Only allow zip files.
}, // Set the title of the modal.
title: 'Redux Custom Fonts: ' + l10n.media_title, // Customize the submit button.
button: {
// Set the text of the button.
text: l10n.media_button
// Tell the button not to close the modal, since we're
// going to refresh the page when the image is selected.
}
}
);
// When an image is selected, run a callback.
frame.on(
'select',
function () {
var nonce;
var data;
var status;
var conversion;
// Grab the selected attachment.
var attachment = frame.state().get( 'selection' ).first();
var error = selector.find( '.font-error' );
error.slideUp();
error.find( 'span' ).text( '' );
frame.close();
if ( 'application' !== attachment.attributes.type && 'font' !== attachment.attributes.type ) {
return;
}
nonce = $( selector ).find( '.media_add_font' ).attr( 'data-nonce' );
conversion = $( '#custom-font-convert' ).is( ':checked' );
data = {
action: 'redux_custom_fonts',
nonce: nonce,
attachment_id: attachment.id,
title: attachment.attributes.title,
mime: attachment.attributes.mime,
filename: attachment.attributes.filename,
conversion: Boolean( conversion )
};
if ( 'application/zip ' === data.mime ) {
status = l10n.unzip;
} else {
status = l10n.convert;
}
redux.field_objects.custom_fonts.startTimer( el, status );
$.blockUI( { message: '<h2>' + reduxObject.args.please_wait + ': ' + status + '</h2>' } );
$.post(
ajaxurl,
data,
function ( response ) {
console.log( 'Redux Custom Fonts API Response (For support purposes)' );
console.log( response );
response = JSON.parse( response );
if ( 'success' === response.type ) {
if ( '' !== response.msg ) {
$.unblockUI();
error.find( 'span' ).html( response.msg + ' ' + l10n.partial );
error.slideDown();
ajaxDone = true;
return;
}
window.onbeforeunload = '';
location.reload();
} else if ( 'error' === response.type ) {
$.unblockUI();
error.find( 'span' ).html( response.msg );
error.slideDown();
} else {
$.unblockUI();
error.find( 'span' ).text( l10n.unknown );
error.slideDown();
}
ajaxDone = true;
}
);
}
);
// Finally, open the modal.
frame.open();
};
redux.field_objects.custom_fonts.remove_font = function ( el, selector ) {
el = null;
// This shouldn't have been run...
if ( ! selector.find( '.remove-image' ).addClass( 'hide' ) ) {
return;
}
};
redux.field_objects.custom_fonts.sleep = function ( milliseconds ) {
var start = new Date().getTime();
var i;
for ( i = 0; i < 1e7; i += 1 ) {
if ( ( new Date().getTime() - start ) > milliseconds ) {
break;
}
}
};
})( jQuery );

View File

@@ -0,0 +1 @@
.redux-container-custom_font table tr td{padding:10px 9px !important}.redux-container-custom_font table.widefat{border-left:1px solid #dfdfdf;border-right:1px solid #dfdfdf;border-top:1px solid #dfdfdf}.redux-container-custom_font .upload_button_div{margin:10px 0;float:right}.redux-container-custom_font .spinner{margin-top:0}.redux-container-custom_font .fontDelete{float:right}.redux-container-custom_font .action-row{text-align:right;padding-right:5px;line-height:20px}.redux-container-custom_font .plugins .active td,.redux-container-custom_font .plugins .active th{background-color:#fafafa}.redux-container-custom_font .font-error{margin:5px 0 15px;border-left:4px solid #dd3d36;background:#fff;-webkit-box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);box-shadow:0 1px 1px 0 rgba(0,0,0,0.1);padding:1px 12px;outline:0}.redux-container-custom_font .font-error p{margin:.5em 0;padding:2px}.fontActionWorking{background:green !important}

View File

@@ -0,0 +1 @@
!function(r){"use strict";var a,c,f=!1;redux.field_objects=redux.field_objects||{},redux.field_objects.custom_fonts=redux.field_objects.custom_fonts||{},redux.field_objects.custom_fonts.init=function(t){t=t||r(document).find(".redux-group-tab:visible").find(".redux-container-custom_font:visible"),r(t).each(function(){var t=r(this),e=t;(e=t.hasClass("redux-field-container")?e:t.parents(".redux-field-container:first")).is(":hidden")||e.hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),redux.field_objects.custom_fonts.modInit(t))})},redux.field_objects.custom_fonts.modInit=function(n){var t=r(".redux-ajax-security").data("opt-name");a=redux_custom_fonts_l10,c=void 0===t?redux:redux.optName,n.find(".checkbox").on("click",function(){var t,e,o=0;"custom-font-convert"===r(this).attr("id")&&(r(this).is(":checked")?(t="",e=1,n.find(".conversion-types").removeClass("is-disabled")):(t="disabled",e=.7,n.find(".conversion-types").addClass("is-disabled")),n.find("#custom-font-eot,#custom-font-svg,#custom-font-ttf,#custom-font-woff,#custom-font-woff2").prop("disabled",t),n.find(".conversion-types").css("opacity",e)),r(this).is(":checked")&&(o=r(this).parent().find(".checkbox-check").attr("data-val")),r(this).parent().find(".checkbox-check").val(o),redux_change(r(this))}),n.find(".remove-font").off("click").on("click",function(){redux.field_objects.custom_fonts.remove_font(n,r(this).parents("fieldset.redux-field:first"))}),n.find(".media_add_font").off().on("click",function(t){redux.field_objects.custom_fonts.add_font(n,t,r(this).parents("fieldset.redux-field:first"))}),n.find(".fontDelete").on("click",function(t){var e=r(this).parents("td:first");return t.preventDefault(),e.find(".spinner").show(),(t=r(this).data()).action="redux_custom_fonts",t.nonce=r(this).parents(".redux-container-custom_font:first").find(".media_add_font").attr("data-nonce"),r.post(ajaxurl,t,function(t){(t=JSON.parse(t)).type&&"success"===t.type?(1===e.parents("table:first").find("tr").length?e.parents("table:first"):e.parents("tr:first")).fadeOut().remove():(alert(a.delete_error+" "+t.msg),e.find(".spinner").hide())}),!1})},redux.field_objects.custom_fonts.startTimer=function(o,n){var s;r.ajax({url:ajaxurl,type:"POST",data:{action:"redux_custom_font_timer"},beforeSend:function(){},success:function(t){var e;!1===f?(setTimeout(redux.field_objects.custom_fonts.startTimer(o,n),500),e=c.args.please_wait+": "+n+"<br><br>"+t):(e=a.complete,t="finished"),""!==t&&s!==t&&(r(".blockUI.blockMsg h2").html(e),s=t)}})},redux.field_objects.custom_fonts.add_font=function(s,t,i){var d;t.preventDefault(),(d=wp.media({multiple:!1,library:{type:["application","font"]},title:"Redux Custom Fonts: "+a.media_title,button:{text:a.media_button}})).on("select",function(){var t,e,o=d.state().get("selection").first(),n=i.find(".font-error");n.slideUp(),n.find("span").text(""),d.close(),"application"!==o.attributes.type&&"font"!==o.attributes.type||(t=r(i).find(".media_add_font").attr("data-nonce"),e=r("#custom-font-convert").is(":checked"),o="application/zip "===(t={action:"redux_custom_fonts",nonce:t,attachment_id:o.id,title:o.attributes.title,mime:o.attributes.mime,filename:o.attributes.filename,conversion:Boolean(e)}).mime?a.unzip:a.convert,redux.field_objects.custom_fonts.startTimer(s,o),r.blockUI({message:"<h2>"+c.args.please_wait+": "+o+"</h2>"}),r.post(ajaxurl,t,function(t){if(console.log("Redux Custom Fonts API Response (For support purposes)"),console.log(t),"success"===(t=JSON.parse(t)).type){if(""!==t.msg)return r.unblockUI(),n.find("span").html(t.msg+" "+a.partial),n.slideDown(),void(f=!0);window.onbeforeunload="",location.reload()}else"error"===t.type?(r.unblockUI(),n.find("span").html(t.msg)):(r.unblockUI(),n.find("span").text(a.unknown)),n.slideDown();f=!0}))}),d.open()},redux.field_objects.custom_fonts.remove_font=function(t,e){e.find(".remove-image").addClass("hide")},redux.field_objects.custom_fonts.sleep=function(t){for(var e=(new Date).getTime(),o=0;o<1e7&&!((new Date).getTime()-e>t);o+=1);}}(jQuery);

View File

@@ -0,0 +1,86 @@
.redux-container-custom_font {
table {
tr td {
padding: 10px 9px !important;
}
&.widefat {
border-left: 1px solid #dfdfdf;
border-right: 1px solid #dfdfdf;
border-top: 1px solid #dfdfdf;
}
}
.upload_button_div {
margin: 10px 0;
float: right;
}
.spinner {
margin-top:0;
}
.fontDelete {
float: right;
}
.action-row {
text-align: right;
padding-right: 5px;
line-height: 20px;
}
.plugins {
.active {
td,
th {
background-color: #FAFAFA;
}
}
}
.font-error {
margin: 5px 0 15px;
border-left: 4px solid #dd3d36;
background: #fff;
-webkit-box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
box-shadow: 0 1px 1px 0 rgba( 0, 0, 0, 0.1 );
padding: 1px 12px;
outline: 0;
p {
margin: 0.5em 0;
padding: 2px;
}
}
.conversion-types {
border: solid #e7e7e7 1px;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 10px;
margin-bottom: 10px;
opacity:1;
.checkbox {
margin-left: 20px!important;
}
&.is-disabled {
cursor:not-allowed;
opacity: 0.7;
.checkbox,
label {
cursor:not-allowed;
}
}
}
.font-pieces {
margin-right: 1px;
}
}
.fontActionWorking {
background: green !important;
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,817 @@
<?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' );
}

View File

@@ -0,0 +1,98 @@
<?php
/**
* Customizer Control.
*
* @package Redux Framework/Extensions
* @version 3.5
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Customizer_Control', false ) ) {
/**
* Class Redux_Customizer_Control
*/
class Redux_Customizer_Control extends WP_Customize_Control {
/**
* Redux ID.
*
* @var string
*/
public $redux_id = '';
/**
* Field render.
*/
public function render() {
$this->redux_id = str_replace( 'customize-control-', '', 'customize-control-' . str_replace( '[', '-', str_replace( ']', '', $this->id ) ) );
$class = 'customize-control redux-group-tab redux-field customize-control-' . $this->type;
$opt_name_arr = explode( '[', $this->id );
$opt_name = $opt_name_arr[0];
$field_id = str_replace( ']', '', $opt_name_arr[1] );
$section = Redux_Helpers::section_from_field_id( $opt_name, $field_id );
if ( isset( $section['disabled'] ) && true === $section['disabled'] ) {
$class .= ' disabled';
}
if ( isset( $section['hidden'] ) && true === $section['hidden'] ) {
$class .= ' hidden';
}
?>
<li id="<?php echo esc_attr( $this->redux_id ); ?>-li" class="<?php echo esc_attr( $class ); ?>">
<?php if ( 'repeater' !== $this->type ) { ?>
<input
type="hidden"
data-id="<?php echo esc_attr( $this->id ); ?>"
data-key="<?php echo esc_attr( str_replace( $opt_name . '-', '', $this->redux_id ) ); ?>"
class="redux-customizer-input"
id="customizer_control_id_<?php echo esc_attr( $this->redux_id ); ?>" <?php echo esc_url( $this->get_link() ); ?>
value=""/>
<?php } ?>
<?php $this->render_content(); ?>
</li>
<?php
}
/**
* Render content hook.
*/
public function render_content() {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/customizer/control/render/' . $this->redux_id, $this );
}
/**
* Label output.
*/
public function label() {
// The label has already been sanitized in the Fields class, no need to re-sanitize it.
echo( $this->label ); // phpcs:ignore WordPress.Security.EscapeOutput
}
/**
* Description output.
*/
public function description() {
if ( ! empty( $this->description ) ) {
// The description has already been sanitized in the Fields class, no need to re-sanitize it.
echo '<span class="description customize-control-description">' . esc_html( $this->description ) . '</span>';
}
}
/**
* Title output.
*/
public function title() {
echo '<span class="customize-control-title">';
$this->label();
$this->description();
echo '</span>';
}
}
}

View File

@@ -0,0 +1,237 @@
<?php
/**
* Redux Customizer Panel Class
*
* @class Redux_Customizer_Panel
* @version 4.0.0
* @package Redux Framework/Extentions
*/
defined( 'ABSPATH' ) || exit;
/**
* Customizer section representing widget area (sidebar).
*
* @package WordPress
* @subpackage Customize
* @since 4.1.0
* @see WP_Customize_Section
*/
class Redux_Customizer_Panel extends WP_Customize_Panel {
/**
* Type of this panel.
*
* @since 4.0.0
* @access public
* @var string
*/
public $type = 'redux';
/**
* Panel opt_name.
*
* @since 4.0.0
* @access public
* @var string
*/
public $opt_name = '';
/**
* Section array.
*
* @var array|mixed
*/
public $section = array();
/**
* Constructor.
* Any supplied $args override class property defaults.
*
* @since 4.0.0
*
* @param WP_Customize_Manager $manager Customizer bootstrap instance.
* @param string $id A specific ID for the panel.
* @param array $args Panel arguments.
*/
public function __construct( $manager, $id, $args = array() ) {
parent::__construct( $manager, $id, $args );
// Redux addition.
if ( isset( $args['section'] ) ) {
$this->section = $args['section'];
$this->description = $this->section['desc'] ?? '';
$this->opt_name = $args['opt_name'] ?? '';
}
}
/**
* WP < 4.3 Render
*
* @since
* @access protected
*/
protected function render() {
global $wp_version;
$version = explode( '-', $wp_version );
if ( version_compare( $version[0], '4.3', '<' ) ) {
$this->render_fallback();
}
}
/**
* Render.
*/
protected function render_fallback() {
$classes = 'accordion-section redux-main redux-panel control-section control-panel control-panel-' . esc_attr( $this->type );
?>
<li id="accordion-panel-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>"
data-width="<?php echo isset( $this->section['customizer_width'] ) ? esc_attr( $this->section['customizer_width'] ) : ''; ?>">
<h3 class="accordion-section-title" tabindex="0">
<?php if ( isset( $this->section['icon'] ) && ! empty( $this->section['icon'] ) ) : ?>
<i class="<?php echo esc_attr( $this->section['icon'] ); ?>"></i>
<?php endif; ?>
<?php
echo wp_kses(
$this->title,
array(
'em' => array(),
'i' => array(),
'strong' => array(),
'span' => array(
'class' => array(),
'style' => array(),
),
)
);
?>
<span class="screen-reader-text"><?php esc_html_e( 'Press return or enter to open this panel', 'redux-framework' ); ?></span>
</h3>
<ul class="accordion-sub-container control-panel-content">
<table class="form-table">
<tbody><?php $this->render_content(); ?></tbody>
</table>
</ul>
</li>
<?php
}
/**
* Render the sections that have been added to the panel.
*
* @since 4.1.0
* @access protected
*/
protected function render_content() {
?>
<li class="panel-meta accordion-section redux-panel redux-panel-meta control-section
<?php
if ( empty( $this->description ) ) {
echo ' cannot-expand';
}
?>
">
<div class="accordion-section-title" tabindex="0">
<span class="preview-notice">
<?php /* translators: %s is the site/panel title in the Customizer */ ?>
<?php printf( esc_html__( 'You are customizing', 'redux-framework' ) . ' %s', '<strong class="panel-title">' . esc_html( $this->title ) . '</strong>' ); ?>
</span>
</div>
<?php if ( ! empty( $this->description ) ) { ?>
<div class="accordion-section-content description legacy">
<?php echo wp_kses_post( $this->description ); ?>
</div>
<?php } ?>
</li>
<?php
}
/**
* JSON.
*
* @return array
*/
public function json(): array {
$array = wp_array_slice_assoc(
parent::json(),
array(
'id',
'title',
'description',
'priority',
'type',
)
);
$array['content'] = $this->get_content();
$array['active'] = $this->active();
$array['instanceNumber'] = $this->instance_number;
// BEGIN Redux Additions.
$array['width'] = $this->section['customizer_width'] ?? '';
$array['icon'] = ( isset( $this->section['icon'] ) && ! empty( $this->section['icon'] ) ) ? $this->section['icon'] : 'hide';
$array['opt_name'] = $this->opt_name;
return $array;
}
/**
* An Underscore (JS) template for this panel's content (but not its container).
* Class variables for this panel class are available in the `data` JS object;
* export custom variables by overriding {@see WP_Customize_Panel::json()}.
*
* @see WP_Customize_Panel::print_template()
* @since 4.3.0
*/
protected function content_template() {
?>
<li
class="panel-meta customize-info redux-customizer-opt-name redux-panel accordion-section <# if ( ! data.description ) { #> cannot-expand<# } #>"
data-opt-name="{{{ data.opt_name }}}">
<button class="customize-panel-back" tabindex="-1">
<span class="screen-reader-text"><?php esc_attr_e( 'Back', 'redux-framework' ); ?></span></button>
<div class="accordion-section-title">
<span class="preview-notice">
<?php /* translators: %s is the site/panel title in the Customizer */ ?>
<?php printf( esc_html__( 'You are customizing', 'redux-framework' ) . ' %s', '<strong class="panel-title">{{ data.title }}</strong>' ); ?>
</span>
<# if ( data.description ) { #>
<button
class="customize-help-toggle dashicons dashicons-editor-help"
tabindex="0"
aria-expanded="false">
<span class="screen-reader-text"><?php esc_attr_e( 'Help', 'redux-framework' ); ?></span></button>
<# } #>
</div>
<# if ( data.description ) { #>
<div class="description customize-panel-description">
{{{ data.description }}}
</div>
<# } #>
</li>
<?php
}
/**
* An Underscore (JS) template for rendering this panel's container.
* Class variables for this panel class are available in the `data` JS object;
* export custom variables by overriding {@see WP_Customize_Panel::json()}.
*
* @see WP_Customize_Panel::print_template()
* @since 4.3.0
*/
protected function render_template() {
?>
<li id="accordion-panel-{{ data.id }}"
class="accordion-section redux-panel control-section control-panel control-panel-{{ data.type }}"
data-width="{{ data.width }}">
<h3 class="accordion-section-title" tabindex="0">
<# if ( data.icon ) { #><i class="{{ data.icon }}"></i> <# } #>{{ data.title }}
<span class="screen-reader-text"><?php echo esc_html__( 'Press return or enter to open this panel', 'redux-framework' ); ?></span>
</h3>
<ul class="accordion-sub-container control-panel-content"></ul>
</li>
<?php
}
}

View File

@@ -0,0 +1,203 @@
<?php
/**
* Customizer section representing widget area (sidebar).
*
* @package WordPress
* @subpackage Customize
* @since 4.0.0
* @see WP_Customize_Section
*/
defined( 'ABSPATH' ) || exit;
/**
* Class Redux_Customizer_Section
*/
class Redux_Customizer_Section extends WP_Customize_Section {
/**
* Type of this section.
*
* @since 4.1.0
* @access public
* @var string
*/
public $type = 'redux';
/**
* Panel opt_name.
*
* @since 4.0.0
* @access public
* @var string
*/
public $opt_name = '';
/**
* Section array.
*
* @var array|mixed
*/
public $section = array();
/**
* Constructor.
* Any supplied $args override class property defaults.
*
* @since 3.4.0
*
* @param WP_Customize_Manager $manager Customizer bootstrap instance.
* @param string $id A specific ID of the section.
* @param array $args Section arguments.
*/
public function __construct( $manager, $id, $args = array() ) {
parent::__construct( $manager, $id, $args );
// Redux addition.
if ( isset( $args['section'] ) ) {
$this->section = $args['section'];
$this->description = $this->section['desc'] ?? '';
$this->opt_name = $args['opt_name'] ?? '';
}
}
/**
* WP < 4.3 Render
*/
protected function render() {
global $wp_version;
$version = explode( '-', $wp_version );
if ( version_compare( $version[0], '4.3', '<' ) ) {
$this->render_fallback();
}
}
/**
* Render the section, and the controls that have been added to it.
*
* @since 3.4.0
*/
protected function render_fallback() {
$classes = 'accordion-section redux-section control-section control-section-' . $this->type;
?>
<li id="accordion-section-<?php echo esc_attr( $this->id ); ?>" class="<?php echo esc_attr( $classes ); ?>">
<h3 class="accordion-section-title" tabindex="0">
<?php
echo wp_kses(
$this->title,
array(
'em' => array(),
'i' => array(),
'strong' => array(),
'span' => array(
'class' => array(),
'style' => array(),
),
)
);
?>
<span class="screen-reader-text"><?php esc_attr_e( 'Press return or enter to expand', 'redux-framework' ); ?></span>
</h3>
<ul class="accordion-section-content redux-main">
<?php
if ( isset( $this->opt_name ) && isset( $this->section ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/page/$this->opt_name/section/before", $this->section );
}
?>
<?php if ( ! empty( $this->description ) ) { ?>
<li class="customize-section-description-container">
<p class="description customize-section-description legacy"><?php echo wp_kses_post( $this->description ); ?></p>
</li>
<?php } ?>
</ul>
</li>
<?php
}
/**
* Gather the parameters passed to client JavaScript via JSON.
*
* @since 4.1.0
*
* @return array The array to be exported to the client as JSON.
*/
public function json(): array {
$array = wp_array_slice_assoc(
parent::json(),
array(
'id',
'title',
'description',
'priority',
'panel',
'type',
)
);
$array['content'] = $this->get_content();
$array['active'] = $this->active();
$array['instanceNumber'] = $this->instance_number;
if ( $this->panel ) {
/* translators: &#9656; is the unicode right-pointing triangle, and %s is the section title in the Customizer */
$array['customizeAction'] = sprintf( __( 'Customizing &#9656; %s', 'redux-framework' ), esc_html( $this->manager->get_panel( $this->panel )->title ) );
} else {
$array['customizeAction'] = __( 'Customizing', 'redux-framework' );
}
// BEGIN Redux Additions.
$array['width'] = $this->section['customizer_width'] ?? '';
$array['icon'] = ( isset( $this->section['icon'] ) && ! empty( $this->section['icon'] ) ) ? $this->section['icon'] : 'hide';
$array['opt_name'] = $this->opt_name;
return $array;
}
/**
* An Underscore (JS) template for rendering this section.
* Class variables for this section class are available in the `data` JS object;
* export custom variables by overriding {@see WP_Customize_Section::json()}.
*
* @see WP_Customize_Section::print_template()
* @since 4.3.0
*/
protected function render_template() {
?>
<li id="accordion-section-{{ data.id }}"
class="redux-standalone-section redux-customizer-opt-name redux-section accordion-section control-section control-section-{{ data.type }}"
data-opt-name="{{ data.opt_name }}"
data-width="{{ data.width }}">
<h3 class="accordion-section-title" tabindex="0">
<# if ( data.icon ) { #><i class="{{ data.icon }}"></i> <# } #>{{ data.title }}
<span class="screen-reader-text"><?php esc_html_e( 'Press return or enter to open', 'redux-framework' ); ?></span>
</h3>
<ul class="accordion-section-content redux-main">
<li class="customize-section-description-container">
<div class="customize-section-title">
<button class="customize-section-back" tabindex="-1">
<span class="screen-reader-text"><?php esc_html_e( 'Back', 'redux-framework' ); ?></span>
</button>
<h3>
<span class="customize-action">
{{{ data.customizeAction }}}
</span> {{ data.title }}
</h3>
</div>
<# if ( data.description ) { #>
<p class="description customize-section-description">{{{ data.description }}}</p>
<# } #>
<?php
if ( isset( $this->opt_name ) && isset( $this->section ) ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( "redux/page/$this->opt_name/section/before", $this->section );
}
?>
</li>
</ul>
</li>
<?php
}
}

View File

@@ -0,0 +1,12 @@
<?php
/**
* Redux Customizer Shim.
*
* Shim for the old way of calling the customizer.
*
* @package Redux
*/
defined( 'ABSPATH' ) || exit;
require_once __DIR__ . '/class-redux-customizer-panel.php';

View File

@@ -0,0 +1,12 @@
<?php
/**
* Redux Customizer Shim.
*
* Shim for the old way of calling the customizer.
*
* @package Redux
*/
defined( 'ABSPATH' ) || exit;
require_once __DIR__ . '/class-redux-customizer-section.php';

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,59 @@
.wp-customizer .redux-container { overflow: visible; }
.wp-customizer .redux-container .redux-main input { margin: 0 !important; }
.wp-customizer .redux-container .redux-main input.spinner-input { margin-right: 30px !important; margin-left: 30px !important; margin-top: 0 !important; }
.wp-customizer .redux-container .redux-main .redux-container-editor .wp-editor-area { color: #000000; }
.wp-customizer .redux-section.open .redux-group-tab { display: block !important; }
.wp-customizer .redux-section.open .redux-group-tab.hide { display: none !important; }
.wp-customizer .redux-section p.customize-section-description { margin-top: 22px; word-break: break-word; }
.wp-customizer .redux-section p.customize-section-description.legacy { margin-top: 7px; }
.wp-customizer .control-section-themes .accordion-section-title { margin: 0; }
.wp-customizer #customize-controls .description { display: block; }
.wp-customizer #customize-controls .customize-info { margin-bottom: 0; }
.wp-customizer #customize-controls .redux-section .accordion-section-content { background: #fcfcfc; }
.wp-customizer .redux-section .accordion-section-title i, .wp-customizer .redux-field .accordion-field-title i, .wp-customizer .redux-panel .accordion-section-title i { margin-right: 5px; }
.wp-customizer .accordion-section.redux-main { background: inherit; margin-left: inherit; border-left: inherit; -moz-box-shadow: inherit; -webkit-box-shadow: inherit; padding: inherit; box-shadow: inherit; }
.wp-customizer .redux_field_th { padding: 13px 0 0 0; }
.wp-customizer .redux-main .redux-field-container { padding: 10px 0; }
.wp-customizer .redux-main .select_wrapper { float: none; width: 100%; display: inline-block; }
.wp-customizer .redux-main .select2-container { margin-right: 0 !important; margin-bottom: 5px !important; width: 100% !important; }
.wp-customizer .redux-main .select_wrapper:nth-child(odd) { margin-right: 0; }
.wp-customizer .redux-main .redux-option-image { max-width: 42% !important; margin-right: 3%; }
.wp-customizer .redux-main .customize-control { border-bottom: 1px solid #ddd; padding-bottom: 4px; }
.wp-customizer .redux-main .customize-control:last-child { border-bottom: 0; padding-bottom: 0; }
.wp-customizer .redux-main .upload { width: 100% !important; }
.wp-customizer .redux-main h3 { margin-top: inherit; }
.wp-customizer .redux-main .redux-container-raw { margin-top: 22px; word-break: break-word; padding: 0 !important; }
.wp-customizer .redux-main .redux-container-password input { width: 100%; }
.wp-customizer .select2-drop, .wp-customizer .select2-container { z-index: 999999; }
.wp-customizer .customize-control-redux-raw { list-style: none; }
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtZXh0ZW5zaW9uLWN1c3RvbWl6ZXIuY3NzIiwic291cmNlcyI6WyJyZWR1eC1leHRlbnNpb24tY3VzdG9taXplci5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLEFBQ0ksY0FEVSxDQUNWLGdCQUFnQixDQUFDLEVBQ2IsUUFBUSxFQUFFLE9BQU8sR0FrQnBCOztBQXBCTCxBQUlZLGNBSkUsQ0FDVixnQkFBZ0IsQ0FFWixXQUFXLENBQ1AsS0FBSyxDQUFDLEVBQ0YsTUFBTSxFQUFFLFlBQVksR0FDdkI7O0FBTmIsQUFRWSxjQVJFLENBQ1YsZ0JBQWdCLENBRVosV0FBVyxDQUtQLEtBQUssQUFBQSxjQUFjLENBQUMsRUFDaEIsWUFBWSxFQUFFLGVBQWUsRUFDN0IsV0FBVyxFQUFFLGVBQWUsRUFDNUIsVUFBVSxFQUFFLFlBQVksR0FDM0I7O0FBWmIsQUFlZ0IsY0FmRixDQUNWLGdCQUFnQixDQUVaLFdBQVcsQ0FXUCx1QkFBdUIsQ0FDbkIsZUFBZSxDQUFDLEVBQ1osS0FBSyxFQUFDLE9BQU8sR0FDaEI7O0FBakJqQixBQXNCSSxjQXRCVSxDQXNCVixjQUFjLEFBQUEsS0FBSyxDQUFDLGdCQUFnQixDQUFDLEVBQ2pDLE9BQU8sRUFBRSxnQkFBZ0IsR0FLNUI7O0FBNUJMLEFBeUJRLGNBekJNLENBc0JWLGNBQWMsQUFBQSxLQUFLLENBQUMsZ0JBQWdCLEFBRy9CLEtBQUssQ0FBQyxFQUNILE9BQU8sRUFBQyxJQUFJLENBQUEsVUFBVSxHQUN6Qjs7QUEzQlQsQUErQlEsY0EvQk0sQ0E4QlYsY0FBYyxDQUNWLENBQUMsQUFBQSw4QkFBOEIsQ0FBQyxFQUM1QixVQUFVLEVBQUUsSUFBSSxFQUNoQixVQUFVLEVBQUUsVUFBVSxHQUl6Qjs7QUFyQ1QsQUFrQ1ksY0FsQ0UsQ0E4QlYsY0FBYyxDQUNWLENBQUMsQUFBQSw4QkFBOEIsQUFHMUIsT0FBTyxDQUFDLEVBQ0wsVUFBVSxFQUFFLEdBQUcsR0FDbEI7O0FBcENiLEFBd0NJLGNBeENVLENBd0NWLHVCQUF1QixDQUFDLHdCQUF3QixDQUFDLEVBQzdDLE1BQU0sRUFBRSxDQUFDLEdBQ1o7O0FBMUNMLEFBNkNRLGNBN0NNLENBNENWLG1CQUFtQixDQUNmLFlBQVksQ0FBQyxFQUNULE9BQU8sRUFBRSxLQUFLLEdBQ2pCOztBQS9DVCxBQWdEUSxjQWhETSxDQTRDVixtQkFBbUIsQ0FJZixlQUFlLENBQUMsRUFDWixhQUFhLEVBQUUsQ0FBQyxHQUNuQjs7QUFsRFQsQUFtRFEsY0FuRE0sQ0E0Q1YsbUJBQW1CLENBT2YsY0FBYyxDQUFDLDBCQUEwQixDQUFDLEVBQ3RDLFVBQVUsRUFBRSxPQUFPLEdBQ3RCOztBQXJEVCxBQXdESSxjQXhEVSxDQXdEVixjQUFjLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxFQXhEN0MsY0FBYyxDQXlEVixZQUFZLENBQUMsc0JBQXNCLENBQUMsQ0FBQyxFQXpEekMsY0FBYyxDQTBEVixZQUFZLENBQUMsd0JBQXdCLENBQUMsQ0FBQyxDQUFDLEVBQ3BDLFlBQVksRUFBRSxHQUFHLEdBQ3BCOztBQTVETCxBQThESSxjQTlEVSxDQThEVixrQkFBa0IsQUFBQSxXQUFXLENBQUMsRUFDMUIsVUFBVSxFQUFFLE9BQU8sRUFDbkIsV0FBVyxFQUFFLE9BQU8sRUFDcEIsV0FBVyxFQUFFLE9BQU8sRUFDcEIsZUFBZSxFQUFFLE9BQU8sRUFDeEIsa0JBQWtCLEVBQUUsT0FBTyxFQUMzQixPQUFPLEVBQUUsT0FBTyxFQUNoQixVQUFVLEVBQUUsT0FBTyxHQUN0Qjs7QUF0RUwsQUF3RUksY0F4RVUsQ0F3RVYsZUFBZSxDQUFDLEVBQ1osT0FBTyxFQUFFLFVBQVUsR0FDdEI7O0FBMUVMLEFBNkVRLGNBN0VNLENBNEVWLFdBQVcsQ0FDUCxzQkFBc0IsQ0FBQyxFQUNuQixPQUFPLEVBQUUsTUFBTSxHQUNsQjs7QUEvRVQsQUFnRlEsY0FoRk0sQ0E0RVYsV0FBVyxDQUlQLGVBQWUsQ0FBQyxFQUNaLEtBQUssRUFBRSxJQUFJLEVBQ1gsS0FBSyxFQUFFLElBQUksRUFDWCxPQUFPLEVBQUUsWUFBWSxHQUN4Qjs7QUFwRlQsQUFxRlEsY0FyRk0sQ0E0RVYsV0FBVyxDQVNQLGtCQUFrQixDQUFDLEVBQ2YsWUFBWSxFQUFFLFlBQVksRUFDMUIsYUFBYSxFQUFFLGNBQWMsRUFDN0IsS0FBSyxFQUFFLGVBQWUsR0FDekI7O0FBekZULEFBMEZRLGNBMUZNLENBNEVWLFdBQVcsQ0FjUCxlQUFlLEFBQUEsVUFBVyxDQUFBLEdBQUcsRUFBRSxFQUMzQixZQUFZLEVBQUUsQ0FBQyxHQUNsQjs7QUE1RlQsQUE2RlEsY0E3Rk0sQ0E0RVYsV0FBVyxDQWlCUCxtQkFBbUIsQ0FBQyxFQUNoQixTQUFTLEVBQUUsY0FBYyxFQUN6QixZQUFZLEVBQUUsRUFBRSxHQUNuQjs7QUFoR1QsQUFpR1EsY0FqR00sQ0E0RVYsV0FBVyxDQXFCUCxrQkFBa0IsQ0FBQyxFQUNmLGFBQWEsRUFBRSxjQUFjLEVBQzdCLGNBQWMsRUFBRSxHQUFHLEdBQ3RCOztBQXBHVCxBQXFHUSxjQXJHTSxDQTRFVixXQUFXLENBeUJQLGtCQUFrQixBQUFBLFdBQVcsQ0FBQyxFQUMxQixhQUFhLEVBQUUsQ0FBQyxFQUNoQixjQUFjLEVBQUUsQ0FBQyxHQUNwQjs7QUF4R1QsQUF5R1EsY0F6R00sQ0E0RVYsV0FBVyxDQTZCUCxPQUFPLENBQUMsRUFDSixLQUFLLEVBQUUsZUFBZSxHQUN6Qjs7QUEzR1QsQUE0R1EsY0E1R00sQ0E0RVYsV0FBVyxDQWdDUCxFQUFFLENBQUMsRUFDQyxVQUFVLEVBQUUsT0FBTyxHQUN0Qjs7QUE5R1QsQUErR1EsY0EvR00sQ0E0RVYsV0FBVyxDQW1DUCxvQkFBb0IsQ0FBQyxFQUNqQixVQUFVLEVBQUUsSUFBSSxFQUNoQixVQUFVLEVBQUUsVUFBVSxFQUN0QixPQUFPLEVBQUUsWUFBWSxHQUN4Qjs7QUFuSFQsQUFvSFEsY0FwSE0sQ0E0RVYsV0FBVyxDQXdDUCx5QkFBeUIsQ0FBQyxLQUFLLENBQUMsRUFDNUIsS0FBSyxFQUFFLElBQUksR0FDZDs7QUF0SFQsQUF5SEksY0F6SFUsQ0F5SFYsYUFBYSxFQXpIakIsY0FBYyxDQTBIVixrQkFBa0IsQ0FBQyxFQUNmLE9BQU8sRUFBRSxNQUFNLEdBQ2xCOztBQTVITCxBQThISSxjQTlIVSxDQThIViw0QkFBNEIsQ0FBQyxFQUN6QixVQUFVLEVBQUUsSUFBSSxHQUNuQiJ9 */
/*# sourceMappingURL=redux-extension-customizer.css.map */

View File

@@ -0,0 +1,233 @@
/* global jQuery, document, redux, redux_change:true, wp, ajaxurl */
(function ( $ ) {
'use strict';
redux.customizer = redux.customizer || {};
$( document ).ready(
function () {
redux.customizer.init();
}
);
redux.customizer.init = function () {
var reduxChange;
var redux_initFields;
$( 'body' ).addClass( redux.customizer.body_class );
$( '.accordion-section.redux-section, .accordion-section.redux-panel, .accordion-section-title' ).on(
'click',
function () {
$.redux.initFields();
}
);
$( '.accordion-section.redux-section h3, .accordion-section.redux-panel h3' ).on(
'click',
function () {
redux.customizer.resize( $( this ).parent() );
}
);
if ( undefined === redux.optName ) {
console.log( 'Redux customizer extension failure' );
return;
}
$( '.control-panel-back, .customize-panel-back' ).on(
'click',
function () {
$( document ).find( 'form#customize-controls' ).removeAttr( 'style' );
$( document ).find( '.wp-full-overlay' ).removeAttr( 'style' );
redux.customizer.width = 0;
}
);
$( '.control-section-back, .customize-section-back' ).on(
'click',
function () {
redux.customizer.resize( $( this ).parent().parent().parent() );
}
);
if ( redux.customizer ) {
// Customizer save hook.
$( '#customize-save-button-wrapper #save' ).on(
'click',
function () {
setTimeout(
function () {
var $parent = $( document.getElementById( 'customize-controls' ) );
var $data = $parent.serialize();
var nonce = $( '.redux-customizer-nonce' ).data( 'nonce' );
$.ajax(
{
type: 'post',
dataType: 'json',
url: ajaxurl,
data: {
action: redux.optName.args.opt_name + '_customizer_save',
nonce: nonce,
opt_name: redux.optName.args.opt_name,
data: $data
},
error: function ( response ) {
if ( true === redux.optName.args.dev_mode ) {
console.log( response.responseText );
}
},
success: function ( response ) {
if ( 'success' === response.status ) {
console.log( response );
$( '.redux-action_bar .spinner' ).removeClass( 'is-active' );
redux.optName.options = response.options;
redux.optName.errors = response.errors;
redux.optName.warnings = response.warnings;
redux.optName.sanitize = response.sanitize;
if ( null !== response.errors || null !== response.warnings ) {
$.redux.notices();
}
if ( null !== response.sanitize ) {
$.redux.sanitize();
}
} else {
console.log( response.responseText );
}
}
}
);
},
1000
);
}
);
}
redux.optName.args.disable_save_warn = true;
reduxChange = redux_change;
redux_change = function ( variable ) {
variable = $( variable );
reduxChange.apply( this, arguments );
redux.customizer.save( variable );
};
redux_initFields = $.redux.initFields;
$.redux.initFiles = function () {
redux_initFields();
};
};
redux.customizer.resize = function ( el ) {
var width;
var test;
var id;
var parentId;
if ( el.attr( 'data-width' ) ) {
redux.customizer.width = el.attr( 'data-width' );
width = redux.customizer.width;
} else {
width = redux.customizer.width;
}
if ( $( 'body' ).width() < 640 ) {
width = '';
}
if ( '' !== width ) {
test = $( '#' + el.attr( 'aria-owns' ) );
if ( test.length > 0 ) {
el = test;
}
}
if ( el.hasClass( 'open' ) || el.hasClass( 'current-panel' ) || el.hasClass( 'current-section' ) ) {
if ( '' !== width ) {
$( document ).find( 'form#customize-controls' ).attr(
'style',
'width:' + width + ';'
);
$( document ).find( '.wp-full-overlay' ).attr(
'style',
'margin-left:' + width + ';'
);
}
} else {
id = el.attr( 'id' );
parentId = $( '*[aria-owns="' + id + '"]' ).parents( '.redux-panel:first' ).attr( 'id' );
width = $( '*[aria-owns="' + parentId + '"]' ).attr( 'data-width' );
if ( ! width ) {
$( document ).find( 'form#customize-controls' ).removeAttr( 'style' );
$( document ).find( '.wp-full-overlay' ).removeAttr( 'style' );
} else {
$( document ).find( 'form#customize-controls' ).attr(
'style',
'width:' + width + ';'
);
$( document ).find( '.wp-full-overlay' ).attr(
'style',
'margin-left:' + width + ';'
);
}
}
};
redux.customizer.save = function ( $obj ) {
var $parent = $obj.hasClass( 'redux-field' ) ? $obj : $obj.parents( '.redux-field-container:first' );
redux.customizer.inputSave( $parent );
};
redux.customizer.inputSave = function ( $parent ) {
var $id;
var $nData;
var $key;
var $control;
if ( ! $parent.hasClass( 'redux-field-container' ) ) {
$parent = $parent.parents( '[class^="redux-field-container"]' );
}
$id = $parent.parent().find( '.redux-customizer-input' ).data( 'id' );
if ( ! $id ) {
$parent = $parent.parents( '.redux-container-repeater:first' );
$id = $parent.parent().find( '.redux-customizer-input' ).data( 'id' );
}
$nData = $parent.find( ':input' ).serializeJSON();
$.each(
$nData,
function ( $k, $v ) {
$k = null;
$nData = $v;
}
);
$key = $parent.parent().find( '.redux-customizer-input' ).data( 'key' );
if ( $nData[$key] ) {
$nData = $nData[$key];
}
$control = wp.customize.control( $id );
// Customizer hack since they didn't code it to save order...
if ( JSON.stringify( $control.setting._value ) !== JSON.stringify( $nData ) ) {
$control.setting._value = null;
}
$control.setting.set( $nData );
};
})( jQuery );

View File

@@ -0,0 +1 @@
!function(n){"use strict";redux.customizer=redux.customizer||{},n(document).ready(function(){redux.customizer.init()}),redux.customizer.init=function(){var t,e;n("body").addClass(redux.customizer.body_class),n(".accordion-section.redux-section, .accordion-section.redux-panel, .accordion-section-title").on("click",function(){n.redux.initFields()}),n(".accordion-section.redux-section h3, .accordion-section.redux-panel h3").on("click",function(){redux.customizer.resize(n(this).parent())}),void 0===redux.optName?console.log("Redux customizer extension failure"):(n(".control-panel-back, .customize-panel-back").on("click",function(){n(document).find("form#customize-controls").removeAttr("style"),n(document).find(".wp-full-overlay").removeAttr("style"),redux.customizer.width=0}),n(".control-section-back, .customize-section-back").on("click",function(){redux.customizer.resize(n(this).parent().parent().parent())}),redux.customizer&&n("#customize-save-button-wrapper #save").on("click",function(){setTimeout(function(){var e=n(document.getElementById("customize-controls")).serialize(),t=n(".redux-customizer-nonce").data("nonce");n.ajax({type:"post",dataType:"json",url:ajaxurl,data:{action:redux.optName.args.opt_name+"_customizer_save",nonce:t,opt_name:redux.optName.args.opt_name,data:e},error:function(e){!0===redux.optName.args.dev_mode&&console.log(e.responseText)},success:function(e){"success"===e.status?(console.log(e),n(".redux-action_bar .spinner").removeClass("is-active"),redux.optName.options=e.options,redux.optName.errors=e.errors,redux.optName.warnings=e.warnings,redux.optName.sanitize=e.sanitize,null===e.errors&&null===e.warnings||n.redux.notices(),null!==e.sanitize&&n.redux.sanitize()):console.log(e.responseText)}})},1e3)}),redux.optName.args.disable_save_warn=!0,t=redux_change,redux_change=function(e){e=n(e),t.apply(this,arguments),redux.customizer.save(e)},e=n.redux.initFields,n.redux.initFiles=function(){e()})},redux.customizer.resize=function(e){e.attr("data-width")&&(redux.customizer.width=e.attr("data-width"));var t,r=redux.customizer.width;(e=""!==(r=n("body").width()<640?"":r)&&0<(t=n("#"+e.attr("aria-owns"))).length?t:e).hasClass("open")||e.hasClass("current-panel")||e.hasClass("current-section")?""!==r&&(n(document).find("form#customize-controls").attr("style","width:"+r+";"),n(document).find(".wp-full-overlay").attr("style","margin-left:"+r+";")):(t=e.attr("id"),e=n('*[aria-owns="'+t+'"]').parents(".redux-panel:first").attr("id"),(r=n('*[aria-owns="'+e+'"]').attr("data-width"))?(n(document).find("form#customize-controls").attr("style","width:"+r+";"),n(document).find(".wp-full-overlay").attr("style","margin-left:"+r+";")):(n(document).find("form#customize-controls").removeAttr("style"),n(document).find(".wp-full-overlay").removeAttr("style")))},redux.customizer.save=function(e){e=e.hasClass("redux-field")?e:e.parents(".redux-field-container:first");redux.customizer.inputSave(e)},redux.customizer.inputSave=function(e){var t=(t=(e=e.hasClass("redux-field-container")?e:e.parents('[class^="redux-field-container"]')).parent().find(".redux-customizer-input").data("id"))||(e=e.parents(".redux-container-repeater:first")).parent().find(".redux-customizer-input").data("id"),r=e.find(":input").serializeJSON();n.each(r,function(e,t){r=t}),e=e.parent().find(".redux-customizer-input").data("key"),r[e]&&(r=r[e]),e=wp.customize.control(t),JSON.stringify(e.setting._value)!==JSON.stringify(r)&&(e.setting._value=null),e.setting.set(r)}}(jQuery);

View File

@@ -0,0 +1,130 @@
.wp-customizer {
.redux-container {
overflow: visible;
.redux-main {
input {
margin: 0 !important;
}
input.spinner-input {
margin-right: 30px !important;
margin-left: 30px !important;
margin-top: 0 !important;
}
.redux-container-editor {
.wp-editor-area {
color:#000000;
}
}
}
}
.redux-section.open .redux-group-tab {
display: block !important;
&.hide {
display:none!important;
}
}
.redux-section {
p.customize-section-description {
margin-top: 22px;
word-break: break-word;
&.legacy {
margin-top: 7px;
}
}
}
.control-section-themes .accordion-section-title {
margin: 0;
}
#customize-controls {
.description {
display: block;
}
.customize-info {
margin-bottom: 0;
}
.redux-section .accordion-section-content {
background: #fcfcfc;
}
}
.redux-section .accordion-section-title i,
.redux-field .accordion-field-title i,
.redux-panel .accordion-section-title i {
margin-right: 5px;
}
.accordion-section.redux-main {
background: inherit;
margin-left: inherit;
border-left: inherit;
-moz-box-shadow: inherit;
-webkit-box-shadow: inherit;
padding: inherit;
box-shadow: inherit;
}
.redux_field_th {
padding: 13px 0 0 0;
}
.redux-main {
.redux-field-container {
padding: 10px 0;
}
.select_wrapper {
float: none;
width: 100%;
display: inline-block;
}
.select2-container {
margin-right: 0 !important;
margin-bottom: 5px !important;
width: 100% !important;
}
.select_wrapper:nth-child(odd) {
margin-right: 0;
}
.redux-option-image {
max-width: 42% !important;
margin-right: 3%;
}
.customize-control {
border-bottom: 1px solid #ddd;
padding-bottom: 4px;
}
.customize-control:last-child {
border-bottom: 0;
padding-bottom: 0;
}
.upload {
width: 100% !important;
}
h3 {
margin-top: inherit;
}
.redux-container-raw {
margin-top: 22px;
word-break: break-word;
padding: 0 !important;
}
.redux-container-password input {
width: 100%;
}
}
.select2-drop,
.select2-container {
z-index: 999999;
}
.customize-control-redux-raw {
list-style: none;
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* Redux Date/Time Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Datetime
*
* @version 4.3.15
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Extension_Datetime', false ) ) {
/**
* Class Redux_Extension_Datetime
*/
class Redux_Extension_Datetime extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.3.15';
/**
* Extension friendly name.
*
* @var string
*/
public $extension_name = 'Date/Time';
/**
* Redux_Extension_Datetime constructor.
*
* @param object $redux ReduxFramework pointer.
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'datetime' );
}
}
}

View File

@@ -0,0 +1,275 @@
<?php
/**
* Redux Date/Time Field Class
*
* @package Redux Extentions
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Datetime
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Datetime', false ) ) {
/**
* Class Redux_Datetime
*/
class Redux_Datetime extends Redux_Field {
/**
* Set field defaults.
*/
public function set_defaults() {
$defaults = array(
'date-format' => 'mm-dd-yy',
'time-format' => 'hh:mm TT z',
'split' => false,
'separator' => ' ',
'date-picker' => true,
'time-picker' => true,
'control-type' => 'slider',
'num-of-months' => 1,
// DO NOT CHANGE THESE!!!!
// It will make this file's javascript sister
// cry like a deflowered virgin on prom night.
'timezone-list' => null,
'timezone' => '0',
'hour-min' => 0,
'hour-max' => 23,
'minute-min' => 0,
'minute-max' => 59,
'date-min' => - 1,
'date-max' => - 1,
);
$this->field = wp_parse_args( $this->field, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @since 1.0.0
* @access public
* @return void
*/
public function render() {
$num_of_months = $this->field['num-of-months'];
if ( 0 === $num_of_months ) {
$num_of_months = 1;
}
// Validate min/max values.
$hour_min = $this->field['hour-min'];
$hour_max = $this->field['hour-max'];
$min_min = $this->field['minute-min'];
$min_max = $this->field['minute-max'];
if ( $hour_min < 0 || $hour_min > 23 ) {
$hour_min = 0;
}
if ( $hour_max < 0 || $hour_max > 23 ) {
$hour_max = 23;
}
if ( $min_min < 0 || $min_min > 59 ) {
$min_min = 0;
}
if ( $min_max < 0 || $min_max > 59 ) {
$min_max = 59;
}
// Validate min date month.
if ( is_array( $this->field['date-min'] ) ) {
if ( isset( $this->field['date-min']['month'] ) ) {
if ( $this->field['date-min']['month'] < 1 || $this->field['date-min']['month'] > 12 ) {
$this->field['date-min']['month'] = 1;
}
}
if ( isset( $this->field['date-min']['day'] ) ) {
if ( $this->field['date-min']['day'] < 1 || $this->field['date-min']['day'] > 31 ) {
$this->field['date-min']['day'] = 1;
}
}
}
// Validate max date month.
if ( is_array( $this->field['date-max'] ) ) {
if ( isset( $this->field['date-max']['month'] ) ) {
if ( $this->field['date-max']['month'] < 1 || $this->field['date-max']['month'] > 12 ) {
$this->field['date-max']['month'] = 1;
}
}
// Validate max date day (imperfect, so we'll just use 31).
if ( isset( $this->field['date-max']['day'] ) ) {
if ( $this->field['date-max']['day'] < 1 || $this->field['date-max']['day'] > 31 ) {
$this->field['date-max']['day'] = 1;
}
}
}
// Assignment, make it easier to read.
$field_id = $this->field['id'];
$field_name = $this->field['name'];
$split = $this->field['split'];
$control_type = $this->field['control-type'];
// Sanitize width
// Sanitize default value.
if ( true === $split ) {
if ( ! is_array( $this->value ) ) {
$this->value = array();
$this->value['time'] = '';
$this->value['date'] = '';
}
} elseif ( is_array( $this->value ) ) {
$this->value = '';
}
// Dummy check, in case something other than select or slider
// is entered.
switch ( $control_type ) {
case 'select':
case 'slider':
break;
default:
$control_type = 'slider';
}
// Set placeholder based on mode.
if ( true === $split ) {
$date_placeholder = $this->field['placeholder']['date'] ?? __( 'Date', 'your-domain-here' );
$time_placeholder = $this->field['placeholder']['time'] ?? __( 'Time', 'your-domain-here' );
} else {
$date_placeholder = $this->field['placeholder'] ?? __( 'Date / Time', 'your-domain-here' );
}
// Output defaults to div, so JS can read it.
// Broken up for readability; coz I'm the one who has to debug it!
echo '<div id="' . esc_attr( $field_id ) . '" class="redux-datetime-container"
data-dev-mode="' . esc_attr( $this->parent->args['dev_mode'] ) . '"
data-version="' . esc_attr( Redux_Extension_Datetime::$version ) . '"
data-id="' . esc_attr( $field_id ) . '"
data-mode="' . esc_attr( $split ) . '"
data-separator="' . esc_attr( $this->field['separator'] ) . '"
data-control-type="' . esc_attr( $control_type ) . '"
data-rtl="' . esc_attr( is_rtl() ) . '"
data-num-of-months="' . esc_attr( $num_of_months ) . '"
data-hour-min="' . esc_attr( $hour_min ) . '"
data-hour-max="' . esc_attr( $hour_max ) . '"
data-minute-min="' . esc_attr( $min_min ) . '"
data-minute-max="' . esc_attr( $min_max ) . '"
data-date-min="' . rawurlencode( wp_json_encode( $this->field['date-min'] ) ) . '"
data-date-max="' . rawurlencode( wp_json_encode( $this->field['date-max'] ) ) . '"
data-timezone="' . esc_attr( $this->field['timezone'] ) . '"
data-timezone-list="' . rawurlencode( wp_json_encode( $this->field['timezone-list'] ) ) . '"
data-date-picker="' . esc_attr( $this->field['date-picker'] ) . '"
data-time-picker="' . esc_attr( $this->field['time-picker'] ) . '"
data-time-format="' . esc_attr( $this->field['time-format'] ) . '"
data-date-format="' . esc_attr( $this->field['date-format'] ) . '">';
// If split mode is on, output two text boxes.
if ( true === $split ) {
echo '<div class="redux-date-input input_wrapper">';
echo '<label for="' . esc_attr( $field_id ) . '-date" class="redux-date-input-label">' . esc_html( $date_placeholder ) . '</label>';
echo ' <input
data-id="' . esc_attr( $field_id ) . '"
type="text"
id="' . esc_attr( $field_id ) . '-date"
name="' . esc_attr( $field_name ) . '[date]"
placeholder="' . esc_attr( $date_placeholder ) . '"
value="' . esc_attr( $this->value['date'] ) . '"
class="redux-date-picker ' . esc_attr( $this->field['class'] ) . '" />&nbsp;&nbsp;';
echo '</div>';
echo '<div class="redux-time-input input_wrapper">';
echo '<label for="' . esc_attr( $field_id ) . '-time" class="redux-time-input-label">' . esc_html( $time_placeholder ) . '</label>';
echo ' <input
data-id="' . esc_attr( $field_id ) . '"
type="text"
id="' . esc_attr( $field_id ) . '-time"
name="' . esc_attr( $field_name ) . '[time]"
placeholder="' . esc_attr( $time_placeholder ) . '"
value="' . esc_attr( $this->value['time'] ) . '"
class="redux-time-picker ' . esc_attr( $this->field['class'] ) . '" />';
// Otherwise, just one.
} else {
echo '<div class="redux-datetime-input single_wrapper">';
echo '<label for="' . esc_attr( $field_id ) . '-date" class="redux-datetime-input-label">' . esc_attr( $date_placeholder ) . '</label>';
echo ' <input
data-id="' . esc_attr( $field_id ) . '"
type="text"
id="' . esc_attr( $field_id ) . '-date"
name="' . esc_attr( $field_name ) . '"
placeholder="' . esc_attr( $date_placeholder ) . '"
value="' . esc_attr( $this->value ) . '"
class="redux-date-picker ' . esc_attr( $this->field['class'] ) . '" />';
}
echo '</div>';
// Close da div, main!
echo '</div>';
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access public
* @return void
*/
public function enqueue() {
$min = Redux_Functions::is_min();
wp_enqueue_script(
'redux-datetime-slider',
$this->url . 'vendor/jquery-ui-sliderAccess' . $min . '.js',
array( 'jquery' ),
'0.3',
true
);
wp_enqueue_script(
'redux-datetime',
$this->url . 'vendor/jquery-ui-timepicker-addon' . $min . '.js',
array(
'jquery',
'jquery-ui-datepicker',
'jquery-ui-widget',
'jquery-ui-slider',
'redux-datetime-slider',
),
'1.6.3',
true
);
wp_enqueue_script(
'redux-field-datetime',
$this->url . 'redux-datetime' . $min . '.js',
array( 'jquery', 'redux-datetime', 'redux-js' ),
Redux_Extension_Datetime::$version,
true
);
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-datetime',
$this->url . 'redux-datetime.css',
array(),
Redux_Extension_Datetime::$version,
);
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,177 @@
/* global redux, jQuery */
( function( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.datetime = redux.field_objects.datetime || {};
redux.field_objects.datetime.init = function( selector ) {
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-datetime:visible' );
}
$( selector ).each(
function() {
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
el.find( '.redux-date-picker' ).each(
function() {
var dateFormat;
var timeFormat;
var separator;
var rtl;
var numOfMonths;
var hourMin;
var hourMax;
var minuteMin;
var minuteMax;
var controlType;
var datePicker;
var timePicker;
var timeOnly = false;
var timezoneList;
var dateMin;
var minDate;
var dateMax;
var maxDate;
var timezone;
var split;
var altField = '';
var timePickerID;
var mainID = $( this ).parents( '.redux-datetime-container:first' ).attr( 'id' );
var id = $( '#' + mainID );
dateFormat = id.data( 'date-format' );
dateFormat = String( ( '' === dateFormat ) ? 'mm-dd-yy' : dateFormat );
timeFormat = id.data( 'time-format' );
timeFormat = String( ( '' === timeFormat ) ? 'h:mm TT' : timeFormat );
separator = id.data( 'separator' );
separator = String( ( '' === separator ) ? ' ' : separator );
rtl = id.data( 'rtl' );
rtl = Boolean( ( '' === rtl ) ? false : rtl );
numOfMonths = id.data( 'num-of-months' );
hourMin = id.data( 'hour-min' );
hourMax = id.data( 'hour-max' );
minuteMin = id.data( 'minute-min' );
minuteMax = id.data( 'minute-max' );
controlType = id.data( 'control-type' );
controlType = String( ( '' === controlType ) ? 'slider' : controlType );
datePicker = id.data( 'date-picker' );
datePicker = Boolean( ( '' === datePicker ) ? false : datePicker );
timePicker = id.data( 'time-picker' );
timePicker = Boolean( ( '' === timePicker ) ? false : timePicker );
if ( false === datePicker ) {
timeOnly = true;
}
timezoneList = id.data( 'timezone-list' );
timezoneList = decodeURIComponent( timezoneList );
timezoneList = JSON.parse( timezoneList );
dateMin = id.data( 'date-min' );
dateMin = decodeURIComponent( dateMin );
dateMin = JSON.parse( dateMin );
if ( dateMin === - 1 ) {
minDate = null;
} else if ( 'object' === typeof dateMin ) {
minDate = new Date( dateMin.year, dateMin.month, dateMin.day );
} else {
minDate = dateMin;
}
dateMax = id.data( 'date-max' );
dateMax = decodeURIComponent( dateMax );
dateMax = JSON.parse( dateMax );
if ( dateMax === - 1 ) {
maxDate = null;
} else if ( 'object' === typeof dateMax ) {
maxDate = new Date( dateMax.year, dateMax.month, dateMax.day );
} else {
maxDate = dateMax;
}
timezone = id.data( 'timezone' );
split = id.data( 'mode' );
split = Boolean( ( '' === split ) ? false : split );
if ( true === split ) {
timePickerID = el.find( 'input.redux-time-picker' ).data( 'id' );
altField = '#' + timePickerID + '-time'; // '.redux-time-picker';
}
$( this ).datetimepicker(
{
beforeShow: function( input, instance ) {
var el = $( '#ui-datepicker-div' );
var popover = instance.dpDiv;
$( '.redux-container:first' ).append( el );
el.hide();
setTimeout(
function() {
popover.position(
{
my: 'left top',
at: 'left bottom',
collision: 'none',
of: input
}
);
},
1
);
},
altField: altField,
dateFormat: dateFormat,
timeFormat: timeFormat,
separator: separator,
showTimepicker: timePicker,
timeOnly: timeOnly,
controlType: controlType,
isRTL: rtl,
timezoneList: timezoneList,
timezone: timezone,
hourMin: hourMin,
hourMax: hourMax,
minuteMin: minuteMin,
minuteMax: minuteMax,
minDate: minDate,
maxDate: maxDate,
numberOfMonths: numOfMonths
}
);
}
);
}
);
};
} )( jQuery );

View File

@@ -0,0 +1 @@
.redux-container-datetime .redux-datetime-container .input_wrapper,.redux-container-datetime .redux-datetime-container single_wrapper{display:block;position:relative;margin:0 4px 0 5px;padding:0;width:25%;max-width:25%;min-width:70px;float:left;clear:none;height:57px;-webkit-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box;vertical-align:baseline}.redux-container-datetime .redux-datetime-container .single_wrapper{width:50% !important;max-width:50% !important}.redux-container-datetime .redux-datetime-container label{display:block;position:relative;font-size:12px !important;text-align:left;color:#999;margin:4px 0 2px 0 !important;cursor:default}.redux-container-datetime .redux-datetime-container .redux-date-picker{width:100%}.redux-container-datetime .redux-datetime-container .redux-time-picker{width:100%}.ui-tpicker-grid-label{background:0;border:0;margin:0;padding:0}.ui-timepicker-div .ui-widget-header{margin-bottom:8px}.ui-timepicker-div dl{text-align:left}.ui-timepicker-div dl dt{float:left;clear:left;padding:0 0 0 5px}.ui-timepicker-div dl dd{margin:0 10px 10px 40%}.ui-timepicker-div td{font-size:90%}.ui-timepicker-div .ui_tpicker_unit_hide{display:none}.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input{background:0;color:inherit;border:0;outline:0;border-bottom:solid 1px #555;width:95%}.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input:focus{border-bottom-color:#aaa}.ui-timepicker-div.ui-timepicker-oneLine{padding-right:2px}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,.ui-timepicker-div.ui-timepicker-oneLine dt{display:none}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label{display:block;padding-top:2px}.ui-timepicker-div.ui-timepicker-oneLine dl{text-align:right}.ui-timepicker-div.ui-timepicker-oneLine dl dd,.ui-timepicker-div.ui-timepicker-oneLine dl dd>div{display:inline-block;margin:0}.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before,.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before{content:'.';display:inline-block}.ui-timepicker-div.ui-timepicker-oneLine dd.ui_tpicker_minute:before,.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before{content:':';display:inline-block}.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide,.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{display:none}.ui-timepicker-div .ui-widget-header{margin-bottom:8px}.ui-timepicker-div .ui-slider{position:relative;text-align:left}.ui-timepicker-div .ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-timepicker-div .ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-timepicker-div .ui-slider.ui-state-disabled .ui-slider-handle,.ui-timepicker-div .ui-slider.ui-state-disabled .ui-slider-range{-webkit-filter:inherit;filter:inherit}.ui-timepicker-div .ui-slider-horizontal{height:.8em}.ui-timepicker-div .ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-timepicker-div .ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-timepicker-div .ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-timepicker-div .ui-slider-horizontal .ui-slider-range-min{left:0}.ui-timepicker-div .ui-slider-horizontal .ui-slider-range-max{right:0}.ui-timepicker-div .ui-slider-vertical{width:.8em;height:100px}.ui-timepicker-div .ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-timepicker-div .ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-timepicker-div .ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-timepicker-div .ui-slider-vertical .ui-slider-range-max{top:0}.ui-timepicker-rtl{direction:rtl}.ui-timepicker-rtl dl{text-align:right;padding:0 5px 0 0}.ui-timepicker-rtl dl dt{float:right;clear:right}.ui-timepicker-rtl dl dd{margin:0 40% 10px 10px}

View File

@@ -0,0 +1 @@
!function(j){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.datetime=redux.field_objects.datetime||{},redux.field_objects.datetime.init=function(e){e=e||j(document).find(".redux-group-tab:visible").find(".redux-container-datetime:visible"),j(e).each(function(){var y=j(this),e=y;(e=y.hasClass("redux-field-container")?e:y.parents(".redux-field-container:first")).is(":hidden")||e.hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),y.find(".redux-date-picker").each(function(){var e,t,a,i,d,n,o,r,m,s,u,c,l,f,p=!1,x="",h=j(this).parents(".redux-datetime-container:first").attr("id"),h=j("#"+h),b=h.data("date-format");b=String(""===b?"mm-dd-yy":b),e=h.data("time-format"),e=String(""===e?"h:mm TT":e),t=h.data("separator"),t=String(""===t?" ":t),a=h.data("rtl"),a=Boolean(""!==a&&a),i=h.data("num-of-months"),d=h.data("hour-min"),n=h.data("hour-max"),o=h.data("minute-min"),r=h.data("minute-max"),m=h.data("control-type"),m=String(""===m?"slider":m),u=h.data("date-picker"),u=Boolean(""!==u&&u),s=h.data("time-picker"),s=Boolean(""!==s&&s),!1===u&&(p=!0),u=h.data("timezone-list"),u=decodeURIComponent(u),u=JSON.parse(u),c=h.data("date-min"),c=decodeURIComponent(c),c=-1===(c=JSON.parse(c))?null:"object"==typeof c?new Date(c.year,c.month,c.day):c,l=h.data("date-max"),l=decodeURIComponent(l),l=-1===(l=JSON.parse(l))?null:"object"==typeof l?new Date(l.year,l.month,l.day):l,f=h.data("timezone"),h=h.data("mode"),!0===Boolean(""!==h&&h)&&(x="#"+y.find("input.redux-time-picker").data("id")+"-time"),j(this).datetimepicker({beforeShow:function(e,t){var a=j("#ui-datepicker-div"),i=t.dpDiv;j(".redux-container:first").append(a),a.hide(),setTimeout(function(){i.position({my:"left top",at:"left bottom",collision:"none",of:e})},1)},altField:x,dateFormat:b,timeFormat:e,separator:t,showTimepicker:s,timeOnly:p,controlType:m,isRTL:a,timezoneList:u,timezone:f,hourMin:d,hourMax:n,minuteMin:o,minuteMax:r,minDate:c,maxDate:l,numberOfMonths:i})}))})}}(jQuery);

View File

@@ -0,0 +1,234 @@
.redux-container-datetime {
.redux-datetime-container {
.input_wrapper,
.single_wrapper {
display: block;
position: relative;
margin: 0 4px 0 5px;
padding: 0;
width: 25%;
max-width: 25%;
min-width: 70px;
float: left;
clear: none;
height: 57px;
box-sizing: border-box;
vertical-align: baseline;
}
.single_wrapper {
width: 50%!important;
max-width: 50%!important;
}
label {
display: block;
position: relative;
font-size: 12px !important;
text-align: left;
color: #999999;
margin: 4px 0 2px 0 !important;
cursor: default;
}
.redux-date-picker {
width: 100%
}
.redux-time-picker {
width: 100%
}
}
}
.ui-tpicker-grid-label {
background: none;
border: none;
margin: 0;
padding: 0;
}
.ui-timepicker-div {
.ui-widget-header {
margin-bottom: 8px;
}
dl {
text-align: left;
dt {
float: left;
clear:left;
padding: 0 0 0 5px;
}
dd {
margin: 0 10px 10px 40%;
}
}
td {
font-size: 90%;
}
.ui_tpicker_unit_hide{
display: none;
}
.ui_tpicker_time .ui_tpicker_time_input {
background: none;
color: inherit;
border: none;
outline: none;
border-bottom: solid 1px #555;
width: 95%;
&:focus {
border-bottom-color: #aaa;
}
}
&.ui-timepicker-oneLine {
padding-right: 2px;
.ui_tpicker_time,
dt {
display: none;
}
.ui_tpicker_time_label {
display: block; padding-top: 2px;
}
dl {
text-align: right;
dd,
dd > div {
display:inline-block;
margin:0;
}
dd.ui_tpicker_millisec:before,
dd.ui_tpicker_microsec:before {
content:'.';
display:inline-block;
}
}
dd.ui_tpicker_minute:before,
dl dd.ui_tpicker_second:before {
content:':';
display:inline-block;
}
.ui_tpicker_unit_hide,
.ui_tpicker_unit_hide:before{
display: none;
}
}
.ui-widget-header {
margin-bottom: 8px;
}
.ui-slider {
position: relative;
text-align: left;
.ui-slider-handle {
position: absolute;
z-index: 2;
width: 1.2em;
height: 1.2em;
cursor: default;
-ms-touch-action: none;
touch-action: none;
}
.ui-slider-range {
position: absolute;
z-index: 1;
font-size: .7em;
display: block;
border: 0;
background-position: 0 0;
}
&.ui-state-disabled .ui-slider-handle,
&.ui-state-disabled .ui-slider-range {
filter: inherit;
}
}
.ui-slider-horizontal {
height: .8em;
.ui-slider-handle {
top: -.3em;
margin-left: -.6em;
}
.ui-slider-handle {
top: -.3em;
margin-left: -.6em;
}
.ui-slider-range {
top: 0;
height: 100%;
}
.ui-slider-range-min {
left: 0;
}
.ui-slider-range-max {
right: 0;
}
}
.ui-slider-vertical {
width: .8em;
height: 100px;
.ui-slider-handle {
left: -.3em;
margin-left: 0;
margin-bottom: -.6em;
}
.ui-slider-range {
left: 0;
width: 100%;
}
.ui-slider-range-min {
bottom: 0;
}
.ui-slider-range-max {
top: 0;
}
}
}
.ui-timepicker-rtl{
direction: rtl;
dl {
text-align: right;
padding: 0 5px 0 0;
dt{
float: right;
clear: right;
}
dd {
margin: 0 40% 10px 10px;
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,45 @@
<?php
/**
* Redux Google Maps Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Google_Maps
* @version 4.4.0
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Extension_Google_Maps' ) ) {
/**
* Class ReduxFramework_extension_google_maps
*/
class Redux_Extension_Google_Maps extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.4.0';
/**
* Extension friendly name.
*
* @var string
*/
public $extension_name = 'Google Maps';
/**
* ReduxFramework_extension_google_maps constructor.
*
* @param ReduxFramework $redux ReduxFramework object.
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'google_maps' );
}
}
}

View File

@@ -0,0 +1,404 @@
<?php
/**
* Redux Google Maps Field Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Google_Maps
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Google_Maps' ) ) {
/**
* Main ReduxFramework_google_maps class
*
* @since 1.0.0
*/
class Redux_Google_Maps extends Redux_Field {
/**
* API Key.
*
* @var string
*/
private $api_key = '';
/**
* Get field defaults.
*/
public function set_defaults() {
$field = array(
'api_key' => '',
'map_version' => 'weekly',
);
$this->field = wp_parse_args( $this->field, $field );
$this->api_key = null;
$this->field['api_key'] = $this->field['api_key'] ?? '';
if ( empty( $this->field['api_key'] ) ) {
$redux = get_option( $this->parent->args['opt_name'] );
$this->api_key = $redux['google_map_api_key'] ?? '';
} else {
$this->api_key = $this->field['api_key'];
}
// Necessary, in case the user doesn't fill out a default array.
$def_street_number = $this->field['default']['street_number'] ?? '';
$def_route = $this->field['default']['route'] ?? '';
$def_locality = $this->field['default']['locality'] ?? '';
$def_state = $this->field['default']['administrative_area_level_1'] ?? '';
$def_postal = $this->field['default']['postal_code'] ?? '';
$def_country = $this->field['default']['country'] ?? '';
$def_lat = $this->field['default']['latitude'] ?? '';
$def_long = $this->field['default']['longitude'] ?? '';
$def_marker_info = $this->field['default']['marker_info'] ?? '';
$def_zoom = $this->field['default']['zoom'] ?? '';
$defaults = array(
'latitude' => $def_lat,
'longitude' => $def_long,
'street_number' => $def_street_number,
'route' => $def_route,
'locality' => $def_locality,
'administrative_area_level_1' => $def_state, // <-dickheads at google. lol, srsly...wtf?
// level_1 huh? maybe It's for multiple planets one day.
'postal_code' => $def_postal,
'country' => $def_country,
'marker_info' => $def_marker_info,
'zoom' => $def_zoom,
);
$this->value = wp_parse_args( $this->value, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @since 1.0.0
* @access public
* @return void
*/
public function render() {
// Set default or saved zoom
// USA: 39.11676722061108,-100.47761000000003
// Zoom far: 3
// zoom close 17.
if ( empty( $this->value['zoom'] ) ) {
if ( $this->value['street_number'] ) {
$the_zoom = 17; // make it close if the street is included.
} else {
$the_zoom = 3; // make it far if it's not.
}
} else {
$the_zoom = $this->value['zoom'];
}
// Make full address.
$locality = ! empty( $this->value['locality'] ) ? $this->value['locality'] . ', ' : '';
$route = ! empty( $this->value['route'] ) ? $this->value['route'] . ', ' : '';
$country = ! empty( $this->value['country'] ) ? ', ' . $this->value['country'] : '';
$full = $this->value['street_number'] . ' ' . $route . ' ' . $locality . $this->value['administrative_area_level_1'] . ' ' . $this->value['postal_code'] . $country;
$data_full = rawurlencode( $full );
// Hide/show various input fields.
$show_address = $this->field['show_address'] ?? true;
$show_city = $this->field['show_city'] ?? true;
$show_state = $this->field['show_state'] ?? true;
$show_postal = $this->field['show_postal'] ?? true;
$show_country = $this->field['show_country'] ?? true;
$show_lat = $this->field['show_latitude'] ?? true;
$show_long = $this->field['show_longitude'] ?? true;
$show_marker_info = $this->field['show_marker_info'] ?? true;
$show_controls = $this->field['show_controls'] ?? true;
$this->field['placeholder'] = $this->field['placeholder'] ?? esc_html__( 'Enter your address', 'redux-framework' );
$this->field['marker_tooltip'] = $this->field['marker_tooltip'] ?? esc_html__( 'Left mouse down on top of me to move me!', 'redux-framework' );
$this->field['no_geometry_alert'] = $this->field['no_geometry_alert'] ?? esc_html__( 'The returned place contains no geometric data.', 'redux-framework' );
$this->field['delay_render'] = $this->field['delay_render'] ?? false;
$this->field['class'] = $this->field['class'] ?? '';
$this->field['show_api_key'] = $this->field['show_api_key'] ?? true;
$this->field['street_view_control'] = $this->field['street_view_control'] ?? true;
$this->field['map_type_control'] = $this->field['map_type_control'] ?? true;
$this->field['scroll_wheel'] = $this->field['scroll_wheel'] ?? false;
$this->field['map_height'] = $this->field['map_height'] ?? '';
$map_height = '';
if ( ! empty( $this->field['map_height'] ) ) {
$map_height = 'style="height:' . esc_attr( $this->field['map_height'] ) . ';"';
}
$geo_alert = rawurlencode( $this->field['no_geometry_alert'] );
// admin defined.
$the_lat = $this->value['latitude'];
$the_long = $this->value['longitude'];
$marker_tooltip = rawurlencode( $this->field['marker_tooltip'] );
if ( ! empty( $the_lat ) && ! empty( $the_long ) ) {
$full = '';
}
$hidden_style = ' style="display: none!important;" ';
?>
<div
class="redux_framework_google_maps <?php echo esc_attr( $this->field['class'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>"
data-idx=""
data-delay-render="<?php echo esc_attr( $this->field['delay_render'] ); ?>"
data-scroll-wheel="<?php echo esc_attr( $this->field['scroll_wheel'] ); ?>"
data-street-view="<?php echo esc_attr( $this->field['street_view_control'] ); ?>"
data-map-type="<?php echo esc_attr( $this->field['map_type_control'] ); ?>"
data-marker-tooltip="<?php echo esc_attr( $marker_tooltip ); ?>"
data-geo-alert="<?php echo $geo_alert; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>"
data-address="<?php echo $data_full; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>">
<input
type="hidden"
class="google_m_zoom_input"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[zoom]"
value="<?php echo esc_attr( $the_zoom ); ?>"
/>
<?php $is_hidden = $show_controls ? '' : 'hidden'; ?>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_autocomplete"></label>
<input
id="<?php echo esc_attr( $this->field['id'] ); ?>_autocomplete"
class="google_m_controls google_m_autocomplete <?php echo esc_attr( $is_hidden ); ?>" type="text"
value="<?php echo esc_attr( trim( $full ) ); ?>"
placeholder="<?php echo esc_attr( $this->field['placeholder'] ); ?>"/>
<div
id="<?php echo esc_attr( $this->field['id'] ); ?>_type_selector"
class="google_m_controls <?php echo esc_attr( $is_hidden ); ?>">
<input class="noUpdate" type="radio" name="type" id="changetype-all-<?php echo esc_attr( $this->field['id'] ); ?>" checked="checked"/>
<label for="changetype-all-<?php echo esc_attr( $this->field['id'] ); ?>"><?php esc_html_e( 'All', 'redux-framework' ); ?></label>
<input class="noUpdate" type="radio" name="type" id="changetype-establishment-<?php echo esc_attr( $this->field['id'] ); ?>"/>
<label for="changetype-establishment-<?php echo esc_attr( $this->field['id'] ); ?>"><?php esc_html_e( 'Place', 'redux-framework' ); ?></label>
<input class="noUpdate" type="radio" name="type" id="changetype-address-<?php echo esc_attr( $this->field['id'] ); ?>"/>
<label for="changetype-address-<?php echo esc_attr( $this->field['id'] ); ?>"><?php esc_html_e( 'Address', 'redux-framework' ); ?></label>
<input class="noUpdate" type="radio" name="type" id="changetype-geocode-<?php echo esc_attr( $this->field['id'] ); ?>"/>
<label for="changetype-geocode-<?php echo esc_attr( $this->field['id'] ); ?>"><?php esc_html_e( 'Geo', 'redux-framework' ); ?></label>
</div>
<div
id="<?php echo esc_attr( $this->field['id'] ); ?>_map_canvas"
class="google_m_canvas"
data-default-long="<?php echo esc_attr( $the_long ); ?>"
data-default-lat="<?php echo esc_attr( $the_lat ); ?>"
data-default-zoom="<?php echo esc_attr( $the_zoom ); ?>"
<?php echo $map_height; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
</div>
<div class="google_maps_address_results">
<?php $is_hidden = $show_address ? '' : $hidden_style; ?>
<div class="input_wrapper street-address" <?php echo $is_hidden; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_street_number"><?php esc_html_e( 'Address', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_street_number"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[street_number]"
value="<?php echo esc_attr( $this->value['street_number'] ); ?>"
class="slimField field"
data-default-value="<?php echo esc_attr( $this->value['street_number'] ); ?>"
type="text"
/>
</div>
<div class="input_wrapper route" <?php echo $is_hidden; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_route"><?php esc_html_e( 'Street', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_route"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[route]"
value="<?php echo esc_attr( $this->value['route'] ); ?>"
class="wideField field"
data-default-value="<?php echo esc_attr( $this->value['route'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_city ? '' : $hidden_style; ?>
<div class="input_wrapper city" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_locality"><?php esc_html_e( 'City', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_locality"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[locality]"
value="<?php echo esc_attr( $this->value['locality'] ); ?>"
class="wideField field"
data-default-value="<?php echo esc_attr( $this->value['locality'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_state ? '' : $hidden_style; ?>
<div class="input_wrapper state" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_administrative_area_level_1"><?php esc_html_e( 'State', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_administrative_area_level_1"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[administrative_area_level_1]"
value="<?php echo esc_attr( $this->value['administrative_area_level_1'] ); ?>"
class="slimField field"
data-default-value="<?php echo esc_attr( $this->value['administrative_area_level_1'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_postal ? '' : $hidden_style; ?>
<div class="input_wrapper zip-code" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_postal_code"><?php esc_html_e( 'ZIP Code', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_postal_code"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[postal_code]"
value="<?php echo esc_attr( $this->value['postal_code'] ); ?>"
class="slimField field"
data-default-value="<?php echo esc_attr( $this->value['postal_code'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_country ? '' : $hidden_style; ?>
<div class="input_wrapper country" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_country"><?php esc_html_e( 'Country', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_country"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[country]"
value="<?php echo esc_attr( $this->value['country'] ); ?>"
class="wideField field"
data-default-value="<?php echo esc_attr( $this->value['country'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_lat ? '' : $hidden_style; ?>
<div class="input_wrapper latitude" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_latitude"><?php esc_html_e( 'Latitude', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_latitude"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[latitude]"
value="<?php echo esc_attr( $this->value['latitude'] ); ?>"
class="wideField field"
data-default-value="<?php echo esc_attr( $this->value['latitude'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_long ? '' : $hidden_style; ?>
<div class="input_wrapper longitude" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_longitude"><?php esc_html_e( 'Longitude', 'redux-framework' ); ?></label>
<input
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_longitude"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[longitude]"
value="<?php echo esc_attr( $this->value['longitude'] ); ?>"
class="wideField field"
data-default-value="<?php echo esc_attr( $this->value['longitude'] ); ?>"
type="text"
/>
</div>
<?php $is_hidden = $show_marker_info ? '' : $hidden_style; ?>
<div class="input_wrapper marker-info" <?php echo( $is_hidden ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>>
<label for="<?php echo esc_attr( $this->field['id'] ); ?>_marker_info"><?php esc_html_e( 'Marker Info', 'redux-framework' ); ?></label>
<textarea
data-id="<?php echo esc_attr( $this->field['id'] ); ?>"
id="<?php echo esc_attr( $this->field['id'] ); ?>_marker_info"
name="<?php echo esc_attr( $this->field['name'] . $this->field['name_suffix'] ); ?>[marker_info]"
class="field"
data-default-value="<?php echo esc_attr( $this->value['marker_info'] ); ?>"
rows="3"
type="text"><?php echo esc_textarea( $this->value['marker_info'] ); ?></textarea>
</div>
</div>
<?php if ( $this->field['show_api_key'] ) { ?>
<div class="input google_m_api_key">
<a href="javascript:void(0);" class="button button-secondary google_m_api_key_button"><?php esc_html_e( 'Google Map API Key', 'redux-framework' ); ?></a>
<div class="google_m_api_key_wrapper">
<p class="description" id="google_m_api_key_description">
<?php
$api_key_site = ' ' . sprintf( '<a href="https://console.developers.google.com/flows/enableapi?apiid=maps_backend&keyType=CLIENT_SIDE&reusekey=true" target="_blank">%s</a>', esc_html__( 'Get an API Key', 'redux-framework' ) ) . ' ';
$usage_limit_site = ' ' . sprintf( '<a href="https://developers.google.com/maps/documentation/javascript/usage" target="_blank">%s</a>', esc_html__( 'Google Map Usage Limits', 'redux-framework' ) ) . ' ';
// translators: %1$s: Google Maps API Key url. %2$s: Google Maps Usage URL.
echo sprintf( esc_html__( 'Google Maps supports 25,000 free map loads per 24 hours for 90 consecutive days. In the events you run a high volume site, you may need to obtain an API Key to continue using Google Map output beyond the free quota. To sign up for an API Key, please visit the %1$s site. For more information about Google Map usage limits, please visit the %2$s guide.', 'redux-framework' ), $api_key_site, $usage_limit_site ) . '<br><br>' . esc_html__( 'Once you have obtained an API Key, please enter it in the text box below and save the options panel.', 'redux-framework' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
?>
</p>
<label for="google_m_api_key_input"><?php esc_html_e( 'API Key', 'redux-framework' ); ?></label>
<input
type="text"
value="<?php echo esc_attr( $this->api_key ); ?>"
name="<?php echo esc_attr( $this->parent->args['opt_name'] ); ?>[google_map_api_key]"
id="google_m_api_key_input" class="large-text"/>
</div>
</div>
<?php } ?>
</div>
<?php
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access public
* @return void
*/
public function enqueue() {
$min = Redux_Functions::isMin();
$api_key = '';
if ( ! empty( $this->api_key ) ) {
$api_key = $this->api_key;
}
wp_register_script(
'redux-field-google-maps',
$this->url . 'redux-google-maps' . $min . '.js',
array( 'jquery', 'redux-js' ),
Redux_Extension_Google_Maps::$version,
true
);
if ( ! wp_script_is( 'redux-field-google-maps' ) ) {
$script = '(g=>{var h,a,k,p="The Google Maps JavaScript API",c="google",l="importLibrary",q="__ib__",m=document,b=window;b=b[c]||(b[c]={});var d=b.maps||(b.maps={}),r=new Set,e=new URLSearchParams,u=()=>h||(h=new Promise(async(f,n)=>{await (a=m.createElement("script"));e.set("libraries",[...r]+"");for(k in g)e.set(k.replace(/[A-Z]/g,t=>"_"+t[0].toLowerCase()),g[k]);e.set("callback",c+".maps."+q);a.src=`https://maps.${c}apis.com/maps/api/js?`+e;d[q]=f;a.onerror=()=>h=n(Error(p+" could not load."));a.nonce=m.querySelector("script[nonce]")?.nonce||"";m.head.append(a)}));d[l]?console.warn(p+" only loads once. Ignoring:",g):d[l]=(f,...n)=>r.add(f)&&u().then(()=>d[l](f,...n))})({
key:"' . $api_key . '",
v:"' . $this->field['map_version'] . '",
libraries:"places",
callback:"initMap"
});';
wp_add_inline_script( 'redux-field-google-maps', $script );
}
wp_enqueue_script( 'redux-field-google-maps' );
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-google-maps',
$this->url . 'redux-google-maps.css',
array(),
Redux_Extension_Google_Maps::$version
);
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,45 @@
.redux-main .redux-container-google_maps .google_m_api_key { padding-bottom: 10px; clear: left; padding-top: 20px; }
.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper { display: none; }
.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper label { display: block !important; position: relative; font-size: 12px !important; text-align: left; color: #999999; margin: 4px 0 2px 0 !important; cursor: default; }
.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper .description { margin-bottom: 7px; }
.redux-main .redux-container-google_maps .google_maps_address_results { padding-top: 20px; }
.redux-main .redux-container-google_maps .google_maps_address_results .latitude { clear: left; }
.redux-main .redux-container-google_maps .google_maps_address_results .marker-info { clear: left !important; height: 75px !important; width: 100% !important; margin-bottom: 10px !important; }
.redux-main .redux-container-google_maps .google_maps_address_results label { display: block !important; position: relative; font-size: 12px !important; text-align: left; color: #999999; margin: 4px 0 2px 0 !important; cursor: default; }
.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper { display: block; position: relative; float: left; clear: none; margin: 0 10px 0 0; height: 57px; -webkit-box-sizing: border-box; box-sizing: border-box; }
.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper:nth-child(odd) { margin-right: 10px !important; }
.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper:nth-child(even) { margin-right: 10px !important; }
.redux-main .redux-container-google_maps .google_m_canvas { margin: 0; padding: 0; height: 250px; width: 100%; }
.redux-main .redux-container-google_maps .google_m_canvas img { max-width: initial !important; }
.redux-main .redux-container-google_maps .google_m_autocomplete { background-color: #fff; color: #B5B5B5; font-family: Roboto, system-ui; font-size: 15px; font-weight: 300; margin-left: 12px; padding: 0 11px 0 13px; text-overflow: ellipsis; width: 50%; }
.redux-main .redux-container-google_maps .google_m_autocomplete:focus { border-color: #4d90fe; }
.redux-main .redux-container-google_maps .google_map_address_results { border: 1px solid #CBCBCB; background-color: #EDEDED; width: 100%; padding: 5px; }
.redux-main .redux-container-google_maps .field { width: 99%; }
.redux-main .redux-container-google_maps .slimField { width: 80px; }
.redux-main .redux-container-google_maps .wideField { width: 150px !important; }
.redux-main .google_m_controls { color: #fff; background-color: #4d90fe; padding: 5px 11px 0 11px; width: 50%; margin-top: 7px; border: 1px solid transparent; border-radius: 2px 0 0 2px; -webkit-box-sizing: border-box; box-sizing: border-box; height: 32px; outline: none; -webkit-box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3); }
.redux-main .google_m_controls label { margin-left: -5px !important; margin-right: 7px !important; font-size: 12px; }
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtZ29vZ2xlLW1hcHMuY3NzIiwic291cmNlcyI6WyJyZWR1eC1nb29nbGUtbWFwcy5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLEFBRVEsV0FGRyxDQUNQLDRCQUE0QixDQUN4QixpQkFBaUIsQ0FBQyxFQUNkLGNBQWMsRUFBRSxJQUFJLEVBQ3BCLEtBQUssRUFBRSxJQUFJLEVBQ1gsV0FBVyxFQUFFLElBQUksR0FtQnBCOztBQXhCVCxBQU9ZLFdBUEQsQ0FDUCw0QkFBNEIsQ0FDeEIsaUJBQWlCLENBS2IseUJBQXlCLENBQUMsRUFDdEIsT0FBTyxFQUFFLElBQUksR0FlaEI7O0FBdkJiLEFBVWdCLFdBVkwsQ0FDUCw0QkFBNEIsQ0FDeEIsaUJBQWlCLENBS2IseUJBQXlCLENBR3JCLEtBQUssQ0FBQyxFQUNGLE9BQU8sRUFBRSxnQkFBZ0IsRUFDekIsUUFBUSxFQUFFLFFBQVEsRUFDbEIsU0FBUyxFQUFFLGVBQWUsRUFDMUIsVUFBVSxFQUFFLElBQUksRUFDaEIsS0FBSyxFQUFFLE9BQU8sRUFDZCxNQUFNLEVBQUUsc0JBQXNCLEVBQzlCLE1BQU0sRUFBRSxPQUFPLEdBQ2xCOztBQWxCakIsQUFvQmdCLFdBcEJMLENBQ1AsNEJBQTRCLENBQ3hCLGlCQUFpQixDQUtiLHlCQUF5QixDQWFyQixZQUFZLENBQUMsRUFDVCxhQUFhLEVBQUUsR0FBRyxHQUNyQjs7QUF0QmpCLEFBMEJRLFdBMUJHLENBQ1AsNEJBQTRCLENBeUJ4Qiw0QkFBNEIsQ0FBQyxFQUN6QixXQUFXLEVBQUUsSUFBSSxHQXdDcEI7O0FBbkVULEFBNkJZLFdBN0JELENBQ1AsNEJBQTRCLENBeUJ4Qiw0QkFBNEIsQ0FHeEIsU0FBUyxDQUFDLEVBQ04sS0FBSyxFQUFFLElBQUksR0FDZDs7QUEvQmIsQUFpQ1ksV0FqQ0QsQ0FDUCw0QkFBNEIsQ0F5QnhCLDRCQUE0QixDQU94QixZQUFZLENBQUMsRUFDVCxLQUFLLEVBQUUsSUFBSSxDQUFBLFVBQVUsRUFDckIsTUFBTSxFQUFFLElBQUksQ0FBQSxVQUFVLEVBQ3RCLEtBQUssRUFBRSxJQUFJLENBQUEsVUFBVSxFQUNyQixhQUFhLEVBQUUsSUFBSSxDQUFBLFVBQVUsR0FDaEM7O0FBdENiLEFBd0NZLFdBeENELENBQ1AsNEJBQTRCLENBeUJ4Qiw0QkFBNEIsQ0FjeEIsS0FBSyxDQUFDLEVBQ0YsT0FBTyxFQUFFLEtBQUssQ0FBQSxVQUFVLEVBQ3hCLFFBQVEsRUFBRSxRQUFRLEVBQ2xCLFNBQVMsRUFBRSxlQUFlLEVBQzFCLFVBQVUsRUFBRSxJQUFJLEVBQ2hCLEtBQUssRUFBRSxPQUFPLEVBQ2QsTUFBTSxFQUFFLHNCQUFzQixFQUM5QixNQUFNLEVBQUUsT0FBTyxHQUNsQjs7QUFoRGIsQUFrRFksV0FsREQsQ0FDUCw0QkFBNEIsQ0F5QnhCLDRCQUE0QixDQXdCeEIsY0FBYyxDQUFDLEVBQ1gsT0FBTyxFQUFFLEtBQUssRUFDZCxRQUFRLEVBQUUsUUFBUSxFQUNsQixLQUFLLEVBQUUsSUFBSSxFQUNYLEtBQUssRUFBRSxJQUFJLEVBQ1gsTUFBTSxFQUFFLFVBQVUsRUFDbEIsTUFBTSxFQUFFLElBQUksRUFDWixVQUFVLEVBQUUsVUFBVSxHQVN6Qjs7QUFsRWIsQUEyRGdCLFdBM0RMLENBQ1AsNEJBQTRCLENBeUJ4Qiw0QkFBNEIsQ0F3QnhCLGNBQWMsQUFTVCxVQUFXLENBQUEsR0FBRyxFQUFFLEVBQ2IsWUFBWSxFQUFFLGVBQWUsR0FDaEM7O0FBN0RqQixBQStEZ0IsV0EvREwsQ0FDUCw0QkFBNEIsQ0F5QnhCLDRCQUE0QixDQXdCeEIsY0FBYyxBQWFULFVBQVcsQ0FBQSxJQUFJLEVBQUUsRUFDZCxZQUFZLEVBQUUsZUFBZSxHQUNoQzs7QUFqRWpCLEFBcUVRLFdBckVHLENBQ1AsNEJBQTRCLENBb0V4QixnQkFBZ0IsQ0FBQyxFQUNiLE1BQU0sRUFBRSxDQUFDLEVBQ1QsT0FBTyxFQUFFLENBQUMsRUFDVixNQUFNLEVBQUUsS0FBSyxFQUNiLEtBQUssRUFBRSxJQUFJLEdBS2Q7O0FBOUVULEFBMkVZLFdBM0VELENBQ1AsNEJBQTRCLENBb0V4QixnQkFBZ0IsQ0FNWixHQUFHLENBQUMsRUFDQSxTQUFTLEVBQUUsa0JBQWtCLEdBQ2hDOztBQTdFYixBQWdGUSxXQWhGRyxDQUNQLDRCQUE0QixDQStFeEIsc0JBQXNCLENBQUMsRUFDbkIsZ0JBQWdCLEVBQUUsSUFBSSxFQUN0QixLQUFLLEVBQUUsT0FBTyxFQUNkLFdBQVcsRUFBRSxpQkFBaUIsRUFDOUIsU0FBUyxFQUFFLElBQUksRUFDZixXQUFXLEVBQUUsR0FBRyxFQUNoQixXQUFXLEVBQUUsSUFBSSxFQUNqQixPQUFPLEVBQUUsYUFBYSxFQUN0QixhQUFhLEVBQUUsUUFBUSxFQUN2QixLQUFLLEVBQUUsR0FBRyxHQUtiOztBQTlGVCxBQTJGWSxXQTNGRCxDQUNQLDRCQUE0QixDQStFeEIsc0JBQXNCLEFBV2pCLE1BQU0sQ0FBQyxFQUNKLFlBQVksRUFBRSxPQUFPLEdBQ3hCOztBQTdGYixBQWdHUSxXQWhHRyxDQUNQLDRCQUE0QixDQStGeEIsMkJBQTJCLENBQUMsRUFDeEIsTUFBTSxFQUFFLGlCQUFpQixFQUN6QixnQkFBZ0IsRUFBRSxPQUFPLEVBQ3pCLEtBQUssRUFBRSxJQUFJLEVBQ1gsT0FBTyxFQUFFLEdBQUcsR0FDZjs7QUFyR1QsQUF1R1EsV0F2R0csQ0FDUCw0QkFBNEIsQ0FzR3hCLE1BQU0sQ0FBQyxFQUNILEtBQUssRUFBRSxHQUFHLEdBQ2I7O0FBekdULEFBMkdRLFdBM0dHLENBQ1AsNEJBQTRCLENBMEd4QixVQUFVLENBQUMsRUFDUCxLQUFLLEVBQUUsSUFBSSxHQUNkOztBQTdHVCxBQStHUSxXQS9HRyxDQUNQLDRCQUE0QixDQThHeEIsVUFBVSxDQUFDLEVBQ1AsS0FBSyxFQUFFLEtBQUssQ0FBQSxVQUFVLEdBQ3pCOztBQWpIVCxBQW9ISSxXQXBITyxDQW9IUCxrQkFBa0IsQ0FBQyxFQUNmLEtBQUssRUFBRSxJQUFJLEVBQ1gsZ0JBQWdCLEVBQUUsT0FBTyxFQUN6QixPQUFPLEVBQUUsZUFBZSxFQUN4QixLQUFLLEVBQUUsR0FBRyxFQUNWLFVBQVUsRUFBRSxHQUFHLEVBQ2YsTUFBTSxFQUFFLHFCQUFxQixFQUM3QixhQUFhLEVBQUUsV0FBVyxFQUMxQixVQUFVLEVBQUUsVUFBVSxFQUN0QixNQUFNLEVBQUUsSUFBSSxFQUNaLE9BQU8sRUFBRSxJQUFJLEVBQ2IsVUFBVSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLGtCQUFrQixHQU8zQzs7QUF0SUwsQUFpSVEsV0FqSUcsQ0FvSFAsa0JBQWtCLENBYWQsS0FBSyxDQUFDLEVBQ0YsV0FBVyxFQUFHLElBQUcsQ0FBQSxVQUFVLEVBQzNCLFlBQVksRUFBRSxHQUFHLENBQUEsVUFBVSxFQUMzQixTQUFTLEVBQUUsSUFBSSxHQUNsQiJ9 */
/*# sourceMappingURL=redux-google-maps.css.map */

View File

@@ -0,0 +1,550 @@
/**
* Field Google Map
*/
/* global jQuery, document, redux_change, redux, google */
(function( $ ) {
'use strict';
var g_map;
var g_marker;
var g_autoComplete;
var g_LatLng;
redux.field_objects = redux.field_objects || {};
redux.field_objects.google_maps = redux.field_objects.google_maps || {};
/* LIBRARY INIT */
redux.field_objects.google_maps.init = function( selector ) {
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-google_maps:visible' );
}
$( selector ).each(
function( i ) {
var containerID;
var delayRender;
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
// Get container ID.
containerID = el.find( '.redux_framework_google_maps' ).attr( 'id' );
// Check for delay render, which is useful for calling a map
// render after javascript load.
delayRender = Boolean( el.find( '.redux_framework_google_maps' ).data( 'delay-render' ) );
// API Key button.
redux.field_objects.google_maps.clickHandler( el );
// Init our maps.
redux.field_objects.google_maps.initMap( el, i, containerID, delayRender );
// Fucking radio button won't check on its own, for some reason.
setTimeout(
function() {
$( '#changetype-all' ).prop( 'checked', true );
},
1
);
}
);
};
/* API BUTTON CLICK HANDLER */
redux.field_objects.google_maps.clickHandler = function( el ) {
// Find the API Key button and react on click.
el.find( '.google_m_api_key_button' ).on(
'click',
function() {
// Find message wrapper.
var wrapper = el.find( '.google_m_api_key_wrapper' );
if ( wrapper.is( ':visible' ) ) {
// If wrapper is visible, close it.
wrapper.slideUp(
'fast',
function() {
el.find( '#google_m_api_key_input' ).trigger( 'focus' );
}
);
} else {
// If wrapper is visible, open it.
wrapper.slideDown(
'medium',
function() {
el.find( '#google_m_api_key_input' ).trigger( 'focus' );
}
);
}
}
);
// Auto select autocomplete contents,
// since Google doesn't do this inherently.
el.find( '.google_m_autocomplete' ).on(
'click',
function( e ) {
this.trigger( 'focus' );
this.trigger( 'select' );
e.preventDefault();
}
);
};
/* MAP RENDER FUNCTION */
redux.field_objects.google_maps.renderMap = async function( el, mapClass ) {
var scrollWheel;
var streetView;
var mapType;
var address;
var defLat;
var defLong;
var defaultZoom;
var mapOptions;
var geocoder;
var noLatLng = false;
var containerID = el.find( '.redux_framework_google_maps' ).attr( 'id' );
// Set IDs to variables.
var autocomplete = containerID + '_autocomplete';
var canvas = containerID + '_map_canvas';
var canvasId = $( '#' + canvas );
var ac;
// Create the autocomplete object, restricting the search
// to geographical location types.
g_autoComplete = await google.maps.importLibrary( 'places' );
ac = new g_autoComplete.Autocomplete(
( document.getElementById( autocomplete ) ),
{
types: ['geocode']
}
);
// Data bindings.
scrollWheel = Boolean( mapClass.data( 'scroll-wheel' ) );
streetView = Boolean( mapClass.data( 'street-view' ) );
mapType = Boolean( mapClass.data( 'map-type' ) );
address = mapClass.data( 'address' );
address = decodeURIComponent( address );
address = address.trim();
// Set default Lat/lng.
defLat = canvasId.data( 'default-lat' );
defLong = canvasId.data( 'default-long' );
defaultZoom = canvasId.data( 'default-zoom' );
// Eval whether to set maps based on lat/lng or address.
if ( '' !== address ) {
if ( '' === defLat || '' === defLong ) {
noLatLng = true;
}
} else {
noLatLng = false;
}
// Can't have empty values, or the map API will complain.
// Set default for middle of the United States.
defLat = defLat ? defLat : 39.11676722061108;
defLong = defLong ? defLong : - 100.47761000000003;
if ( noLatLng ) {
// If displaying map based on an address.
geocoder = new google.maps.Geocoder();
// Set up Geocode and pass address.
geocoder.geocode(
{ 'address': address },
function( results, status ) {
var latitude;
var longitude;
// Function results.
if ( status === google.maps.GeocoderStatus.OK ) {
// A good address was passed.
g_LatLng = results[0].geometry.location;
// Set map options.
mapOptions = {
center: g_LatLng,
zoom: defaultZoom,
streetViewControl: streetView,
mapTypeControl: mapType,
scrollwheel: scrollWheel,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.LEFT_BOTTOM
}
};
// Create map.
g_map = new google.maps.Map( document.getElementById( canvas ), mapOptions );
// Render map controls.
redux.field_objects.google_maps.renderControls( el, autocomplete, mapClass );
// Get and set lat/long data.
latitude = el.find( '#' + containerID + '_latitude' );
latitude.val( results[0].geometry.location.lat() );
longitude = el.find( '#' + containerID + '_longitude' );
longitude.val( results[0].geometry.location.lng() );
} else {
// No data found, alert the user.
alert( 'Geocode was not successful for the following reason: ' + status );
}
}
);
} else {
// If displaying map based on an lat/lng.
g_LatLng = new google.maps.LatLng( defLat, defLong );
// Set map options.
mapOptions = {
center: g_LatLng,
zoom: defaultZoom, // Start off far unless an item is selected, set by php.
streetViewControl: streetView,
mapTypeControl: mapType,
scrollwheel: scrollWheel,
mapTypeControlOptions: {
style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR,
position: google.maps.ControlPosition.LEFT_BOTTOM
}
};
// Create the map.
g_map = new google.maps.Map( document.getElementById( canvas ), mapOptions );
// Render map controls.
redux.field_objects.google_maps.renderControls( el, autocomplete, mapClass );
}
};
/* INIT MAP FUNCTION */
redux.field_objects.google_maps.initMap = function( el, idx, containerID, delayRender ) {
var delayed;
// Pull the map class.
var mapClass = el.find( '.redux_framework_google_maps' );
// Add map index to data attr. Why, say we want to use delay_render,
// and want to init the map later on. You'd need the index number in the
// event of multiple map instances. This allows one to retrieve it
// later.
$( mapClass ).attr( 'data-idx', idx );
if ( true === delayRender ) {
return;
}
// Map has been rendered, no need to process again.
if ( $( '#' + containerID ).hasClass( 'rendered' ) ) {
return;
}
// If map is set to delay render and has been initiated
// from another scrip, add the 'render' class so rendering
// does not occur. it messes things up.
delayed = Boolean( mapClass.data( 'delay-render' ) );
if ( true === delayed ) {
mapClass.addClass( 'rendered' );
}
// Render the map.
redux.field_objects.google_maps.renderMap( el, mapClass );
};
/* RENDER CONTROLS FUNCTION */
redux.field_objects.google_maps.renderControls = function( el, autoComplete, mapClass ) {
var markerTooltip;
var infoWindow;
// Set variables.
var containerID = el.find( '.redux_framework_google_maps' ).attr( 'id' );
var controls = containerID + '_type_selector';
// Get HTML.
var input = document.getElementById( autoComplete );
var types = document.getElementById( controls );
// Set objects into the map.
g_map.controls[google.maps.ControlPosition.TOP_LEFT].push( input );
g_map.controls[google.maps.ControlPosition.TOP_LEFT].push( types );
// Bind objects to the map.
g_autoComplete = new google.maps.places.Autocomplete( input );
g_autoComplete.bindTo( 'bounds', g_map );
// Get the marker tooltip data.
markerTooltip = mapClass.data( 'marker-tooltip' );
markerTooltip = decodeURIComponent( markerTooltip );
// Create infoWindow.
infoWindow = new google.maps.InfoWindow();
// Create marker.
g_marker = new google.maps.Marker(
{
position: g_LatLng,
map: g_map,
anchorPoint: new google.maps.Point( 0, - 29 ),
draggable: true,
title: markerTooltip,
animation: google.maps.Animation.DROP
}
);
// Add Event Listeners.
redux.field_objects.google_maps.addListeners( el, mapClass, g_marker, infoWindow );
};
/* ADD LISTENERS FUNCTION */
redux.field_objects.google_maps.addListeners = function( el, mapClass, marker ) {
var infoWindow;
// Set variables.
var containerID = el.find( '.redux_framework_google_maps' ).attr( 'id' );
var latitude = containerID + '_latitude';
var longitude = containerID + '_longitude';
var marker_info = containerID + '_marker_info';
var geoAlert = mapClass.data( 'geo-alert' );
geoAlert = decodeURIComponent( geoAlert );
// Place change.
google.maps.event.addListener(
g_autoComplete,
'place_changed',
function() {
var place;
var address;
infoWindow.close();
marker.setVisible( false );
// Get place data.
place = g_autoComplete.getPlace();
// Display alert if something went wrong.
if ( ! place.geometry ) {
window.alert( geoAlert );
return;
}
// If the place has a geometry, then present it on a map.
if ( place.geometry.viewport ) {
g_map.fitBounds( place.geometry.viewport );
} else {
g_map.setCenter( place.geometry.location );
g_map.setZoom( 17 ); // Why 17? Because it looks good.
}
// Set the marker icon.
marker.setIcon(
({
url: place.icon,
size: new google.maps.Size( 71, 71 ),
origin: new google.maps.Point( 0, 0 ),
anchor: new google.maps.Point( 17, 34 ),
scaledSize: new google.maps.Size( 35, 35 )
})
);
// Set marker position and display.
marker.setPosition( place.geometry.location );
marker.setVisible( true );
// Form array of address components.
address = '';
if ( place.address_components ) {
address = [( place.address_components[0] && place.address_components[0].short_name || '' ),
( place.address_components[1] && place.address_components[1].short_name || '' ),
( place.address_components[2] && place.address_components[2].short_name || '' )].join( ' ' );
}
// Set the default marker info window with address data.
infoWindow.setContent( '<div><strong>' + place.name + '</strong><br>' + address );
infoWindow.open( g_map, marker );
// Run Geolocation.
redux.field_objects.google_maps.geoLocate();
// Fill in address inputs.
redux.field_objects.google_maps.fillInAddress( el, latitude, longitude );
}
);
// Search radio buttons.
redux.field_objects.google_maps.setupClickListener( 'changetype-all-' + containerID, [] );
redux.field_objects.google_maps.setupClickListener( 'changetype-address-' + containerID, ['address'] );
redux.field_objects.google_maps.setupClickListener( 'changetype-establishment-' + containerID, ['establishment'] );
redux.field_objects.google_maps.setupClickListener( 'changetype-geocode-' + containerID, ['geocode'] );
// Marker drag.
google.maps.event.addListener(
marker,
'drag',
function( event ) {
document.getElementById( latitude ).value = event.latLng.lat();
document.getElementById( longitude ).value = event.latLng.lng();
}
);
// End marker drag.
google.maps.event.addListener(
marker,
'dragend',
function() {
redux_change( el.find( '.redux_framework_google_maps' ) );
}
);
// Zoom Changed.
g_map.addListener(
'zoom_changed',
function() {
el.find( '.google_m_zoom_input' ).val( g_map.getZoom() );
}
);
// Marker Info Window.
infoWindow = new google.maps.InfoWindow();
google.maps.event.addListener(
marker,
'click',
function() {
var infoValue = document.getElementById( marker_info ).value;
if ( '' !== infoValue ) {
infoWindow.setContent( infoValue );
infoWindow.open( g_map, g_marker );
}
}
);
};
/* FILL IN ADDRESS FUNCTION */
redux.field_objects.google_maps.fillInAddress = function( el, latitude, longitude ) {
// Set variables.
var containerID = el.find( '.redux_framework_google_maps' ).attr( 'id' );
// What if someone only wants city, or state, ect...
// gotta do it this way to check for the address!
// need to check each of the returned components to see what is returned.
var componentForm = {
street_number: 'short_name',
route: 'long_name',
locality: 'long_name',
administrative_area_level_1: 'short_name',
country: 'long_name',
postal_code: 'short_name'
};
// Get the place details from the autocomplete object.
var place = g_autoComplete.getPlace();
var component;
var i;
var addressType;
var _d_addressType;
var val;
var len;
document.getElementById( latitude ).value = place.geometry.location.lat();
document.getElementById( longitude ).value = place.geometry.location.lng();
for ( component in componentForm ) {
if ( componentForm.hasOwnProperty( component ) ) {
// Push in the dynamic form element ID again.
component = containerID + '_' + component;
// Assign to proper place.
document.getElementById( component ).value = '';
document.getElementById( component ).disabled = false;
}
}
// Get each component of the address from the place details
// and fill the corresponding field on the form.
len = place.address_components.length;
for ( i = 0; i < len; i += 1 ) {
addressType = place.address_components[i].types[0];
if ( componentForm[addressType] ) {
// Push in the dynamic form element ID again.
_d_addressType = containerID + '_' + addressType;
// Get the original.
val = place.address_components[i][componentForm[addressType]];
// Assign to proper place.
document.getElementById( _d_addressType ).value = val;
}
}
};
redux.field_objects.google_maps.setupClickListener = function( id, types ) {
var radioButton = document.getElementById( id );
google.maps.event.addListener(
radioButton,
'click',
function() {
g_autoComplete.setTypes( types );
}
);
};
redux.field_objects.google_maps.geoLocate = function() {
if ( navigator.geolocation ) {
navigator.geolocation.getCurrentPosition(
function( position ) {
var geolocation = new google.maps.LatLng( position.coords.latitude, position.coords.longitude );
var circle = new google.maps.Circle(
{
center: geolocation,
radius: position.coords.accuracy
}
);
g_autoComplete.setBounds( circle.getBounds() );
}
);
}
};
} )( jQuery );

View File

@@ -0,0 +1 @@
.redux-main .redux-container-google_maps .google_m_api_key{padding-bottom:10px;clear:left;padding-top:20px}.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper{display:none}.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper label{display:block !important;position:relative;font-size:12px !important;text-align:left;color:#999;margin:4px 0 2px 0 !important;cursor:default}.redux-main .redux-container-google_maps .google_m_api_key .google_m_api_key_wrapper .description{margin-bottom:7px}.redux-main .redux-container-google_maps .google_maps_address_results{padding-top:20px}.redux-main .redux-container-google_maps .google_maps_address_results .latitude{clear:left}.redux-main .redux-container-google_maps .google_maps_address_results .marker-info{clear:left !important;height:75px !important;width:100% !important;margin-bottom:10px !important}.redux-main .redux-container-google_maps .google_maps_address_results label{display:block !important;position:relative;font-size:12px !important;text-align:left;color:#999;margin:4px 0 2px 0 !important;cursor:default}.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper{display:block;position:relative;float:left;clear:none;margin:0 10px 0 0;height:57px;-webkit-box-sizing:border-box;-o-box-sizing:border-box;box-sizing:border-box}.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper:nth-child(odd){margin-right:10px !important}.redux-main .redux-container-google_maps .google_maps_address_results .input_wrapper:nth-child(even){margin-right:10px !important}.redux-main .redux-container-google_maps .google_m_canvas{margin:0;padding:0;height:250px;width:100%}.redux-main .redux-container-google_maps .google_m_canvas img{max-width:initial !important}.redux-main .redux-container-google_maps .google_m_autocomplete{background-color:#fff;color:#b5b5b5;font-family:Roboto;font-size:15px;font-weight:300;margin-left:12px;padding:0 11px 0 13px;text-overflow:ellipsis;width:50%}.redux-main .redux-container-google_maps .google_m_autocomplete:focus{border-color:#4d90fe}.redux-main .redux-container-google_maps .google_map_address_results{border:1px solid #cbcbcb;background-color:#ededed;width:100%;padding:5px}.redux-main .redux-container-google_maps .field{width:99%}.redux-main .redux-container-google_maps .slimField{width:80px}.redux-main .redux-container-google_maps .wideField{width:150px !important}.redux-main .google_m_controls{color:#fff;background-color:#4d90fe;padding:5px 11px 0 11px;width:50%;margin-top:7px;border:1px solid transparent;border-radius:2px 0 0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;-moz-box-sizing:border-box;height:32px;outline:0;-webkit-box-shadow:0 2px 6px rgba(0,0,0,0.3);box-shadow:0 2px 6px rgba(0,0,0,0.3)}.redux-main .google_m_controls label{margin-left:-5px !important;margin-right:7px !important;font-size:12px}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,136 @@
.redux-main {
.redux-container-google_maps {
.google_m_api_key {
padding-bottom: 10px;
clear: left;
padding-top: 20px;
.google_m_api_key_wrapper {
display: none;
label {
display: block !important;
position: relative;
font-size: 12px !important;
text-align: left;
color: #999999;
margin: 4px 0 2px 0 !important;
cursor: default;
}
.description {
margin-bottom: 7px;
}
}
}
.google_maps_address_results {
padding-top: 20px;
.latitude {
clear: left;
}
.marker-info {
clear: left!important;
height: 75px!important;
width: 100%!important;
margin-bottom: 10px!important;
}
label {
display: block!important;
position: relative;
font-size: 12px !important;
text-align: left;
color: #999999;
margin: 4px 0 2px 0 !important;
cursor: default;
}
.input_wrapper {
display: block;
position: relative;
float: left;
clear: none;
margin: 0 10px 0 0;
height: 57px;
box-sizing: border-box;
&:nth-child(odd) {
margin-right: 10px !important;
}
&:nth-child(even) {
margin-right: 10px !important;
}
}
}
.google_m_canvas {
margin: 0;
padding: 0;
height: 250px;
width: 100%;
img {
max-width: initial !important;
}
}
.google_m_autocomplete {
background-color: #fff;
color: #B5B5B5;
font-family: Roboto, system-ui;
font-size: 15px;
font-weight: 300;
margin-left: 12px;
padding: 0 11px 0 13px;
text-overflow: ellipsis;
width: 50%;
&:focus {
border-color: #4d90fe;
}
}
.google_map_address_results {
border: 1px solid #CBCBCB;
background-color: #EDEDED;
width: 100%;
padding: 5px;
}
.field {
width: 99%;
}
.slimField {
width: 80px;
}
.wideField {
width: 150px!important;
}
}
.google_m_controls {
color: #fff;
background-color: #4d90fe;
padding: 5px 11px 0 11px;
width: 50%;
margin-top: 7px;
border: 1px solid transparent;
border-radius: 2px 0 0 2px;
box-sizing: border-box;
height: 32px;
outline: none;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
label {
margin-left: -5px!important;
margin-right: 7px!important;
font-size: 12px;
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,128 @@
<?php
/**
* Redux Icon Select Extension Class
*
* @package Redux Extentions
* @author Dovy Paukstys <dovy@reduxframework.com> & Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Icon_Select
* @version 4.4.2
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Extension_Icon_Select' ) ) {
/**
* Main ReduxFramework icon_select extension class
*
* @since 3.1.6
*/
class Redux_Extension_Icon_Select extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.4.2';
/**
* Extension friendly name.
*
* @var string
*/
public $ext_name = 'Icon Select';
/**
* ReduxFramework_Extension_Icon_Select constructor.
*
* @param ReduxFramework $redux ReduxFramework object.
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'icon_select' );
add_action( 'wp_ajax_redux_get_icons', array( $this, 'get_icons' ) );
}
/**
* Add icons to modal.
*
* @return void
*/
public function get_icons() {
$nonce = ( ! empty( $_POST['nonce'] ) ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : '';
$icon_set = ( ! empty( $_POST['icon_set'] ) ) ? sanitize_text_field( wp_unslash( $_POST['icon_set'] ) ) : '';
$select_text = ( ! empty( $_POST['select_text'] ) ) ? sanitize_text_field( wp_unslash( $_POST['select_text'] ) ) : '';
if ( ! wp_verify_nonce( $nonce, 'redux_icon_nonce' ) ) {
wp_send_json_error( array( 'error' => esc_html__( 'Error: Invalid nonce verification.', 'redux-framework' ) ) );
}
ob_start();
$class = '';
if ( 'font-awesome' === $icon_set ) {
require_once Redux_Core::$dir . 'inc/lib/font-awesome-6-free.php';
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$icon_lists = apply_filters( 'redux/extensions/icon_select/fontawesome/icons', redux_icon_select_fa_6_free() );
} elseif ( 'dashicons' === $icon_set ) {
require_once Redux_Core::$dir . 'inc/lib/dashicons.php';
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$icon_lists = apply_filters( 'redux/extensions/icon_select/dashicons/icons', redux_get_dashicons() );
} elseif ( 'elusive' === $icon_set ) {
require_once Redux_Core::$dir . 'inc/lib/elusive-icons.php';
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$icon_lists = apply_filters( 'redux/extensions/icon_select/elusive/icons', redux_get_font_icons() );
} else {
$data = ( ! empty( $_POST['data'] ) ) ? ( wp_unslash( $_POST['data'] ) ) : ''; // phpcs:ignore WordPress.Security
$data = json_decode( rawurldecode( $data ), true );
$icons = '';
foreach ( $data as $arr_data ) {
if ( $arr_data['title'] === $select_text ) {
$icons = $arr_data['icons'];
$class = ( ! empty( $arr_data['class'] ) ? $arr_data['class'] . ' ' : '' );
}
}
// phpcs:ignore WordPress.NamingConventions.ValidHookName
$icon_lists = apply_filters( 'redux/extensions/icon_select/custom/icons', $icons );
}
if ( ! empty( $icon_lists ) ) {
foreach ( $icon_lists as $list ) {
/**
* Icon output.
* Custom output for icon libraries that support different standards.
*
* @param string $default Original output.
* @param string $title Title of the icon.
* @param string $class Class of the icon.
* @param string $icon_Set Selected Icon set.
*
* @since 4.4.2
*/
echo apply_filters( 'redux/extension/icon_select/' . $this->parent->args['opt_name'] . '/output', '<i title="' . esc_attr( $list ) . '" class="' . esc_attr( $class . ' ' . $list ) . '" /></i>', $list, $class, $select_text ); // phpcs:ignore WordPress.NamingConventions.ValidHookName, WordPress.Security.EscapeOutput
}
} else {
echo '<div class="redux-error-text">' . esc_html__( 'No data available.', 'redux-framework' ) . '</div>';
}
$content = ob_get_clean();
wp_send_json_success( array( 'content' => $content ) );
}
}
}
class_alias( 'Redux_Extension_Icon_Select', 'ReduxFramework_extension_icon_select' );

View File

@@ -0,0 +1,459 @@
<?php
/**
* Redux Icon Select Field Class
*
* @package Redux Extentions
* @author Dovy Paukstys <dovy@reduxframework.com> & Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Icon_Select
* @version 4.4.2
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Icon_Select' ) ) {
/**
* Main ReduxFramework_icon_select class
*
* @since 1.0.0
*/
class Redux_Icon_Select extends Redux_Field {
/**
* Stylesheet URL array, for enqueue.
*
* @var array
*/
private $stylesheet_url = array();
/**
* Stylesheet data array.
*
* @var array
*/
private $stylesheet_data = array();
/**
* Error flag to prevent render and enqueue.
*
* @var bool
*/
private $is_error = false;
/**
* ReduxFramework_Icon_Select constructor.
*
* @param array $field Field array.
* @param string $value Value.
* @param ReduxFramework $redux ReduxFramework object.
*
* @throws ReflectionException Exception.
*/
public function __construct( $field = array(), $value = '', $redux = object ) {
parent::__construct( $field, $value, $redux );
if ( empty( $field ) ) {
return;
}
if ( ! is_array( $this->field['stylesheet'] ) ) {
if ( '' !== $this->field['stylesheet'] ) {
$this->stylesheet_data[] = array(
'url' => $this->field['stylesheet'],
'class' => $this->field['prefix'],
'title' => basename( $this->field['stylesheet'] ),
'icons' => $this->field['options'],
'exclude' => $this->field['exclude_icons'],
);
unset( $this->field['exclude_icons'] );
unset( $this->field['options'] );
unset( $this->field['stylesheet'] );
unset( $this->field['prefix'] );
}
} else {
$arr = $this->field['stylesheet'];
if ( isset( $arr['url'] ) || isset( $arr['title'] ) ) {
$arr = array( $arr );
}
foreach ( $arr as $idx => $val ) {
$val['url'] = ! empty( $val['url'] ) ? $val['url'] : '';
$val['title'] = ! empty( $val['title'] ) ? $val['title'] : basename( $val['url'] );
$val['class'] = ! empty( $val['prefix'] ) ? $val['prefix'] : '';
$val['icons'] = ! empty( $val['icons'] ) ? $val['icons'] : array();
$val['exclude'] = ! empty( $val['exclude'] ) ? $val['exclude'] : '';
$val['regex'] = ! empty( $val['regex'] ) ? $val['regex'] : '';
$arr[ $idx ] = $val;
}
$this->stylesheet_data = $arr;
}
if ( ! empty( $this->stylesheet_data ) ) {
foreach ( $this->stylesheet_data as $idx => $sub_arr ) {
if ( false === stripos( $sub_arr['url'], '//' ) ) {
$this->stylesheet_url[] = '';
} else {
$this->stylesheet_url[] = $sub_arr['url'];
}
if ( empty( $sub_arr['icons'] ) && ! empty( $sub_arr ) ) {
if ( false === stripos( $sub_arr['url'], '//' ) ) {
$to_parse = '';
} else {
$to_parse = wp_remote_get( $sub_arr['url'] );
if ( is_wp_error( $to_parse ) ) {
$data = array(
'parent' => $this->parent,
'type' => 'error',
'msg' => 'Icon Select: ' . esc_html__( 'Error retrieving stylesheet ', 'redux-framework' ) . ' "' . $sub_arr['url'] . '". (' . esc_html( $to_parse->get_error_code() ) . ' - ' . esc_html( $to_parse->get_error_message() ) . ')',
'id' => 'Icon_Select_notice_',
'dismiss' => false,
);
Redux_Admin_Notices::set_notice( $data );
$this->is_error = true;
return;
} elseif ( 200 !== wp_remote_retrieve_response_code( $to_parse ) ) {
$data = array(
'parent' => $this->parent,
'type' => 'error',
'msg' => 'Icon Select: ' . esc_html__( 'Error retrieving stylesheet ', 'redux-framework' ) . ' "' . $sub_arr['url'] . '". (' . wp_remote_retrieve_response_code( $to_parse ) . ' - ' . esc_html( wp_remote_retrieve_response_message( $to_parse ) ) . ')',
'id' => 'Icon_Select_notice_',
'dismiss' => false,
);
Redux_Admin_Notices::set_notice( $data );
$this->is_error = true;
return;
}
$to_parse = $to_parse['body'];
}
// Remove whitespace.
$to_parse = preg_replace( '/\s+/', ' ', $to_parse );
$regex_arr = array( '/.([\w-]+):{2}before{content/mi', '/.([\w-]+):{2}before { content/mi', '/.([\w-]+):{1}before{content:/mi', '/.([\w-]+):{1}before { content:/mi' );
if ( ! is_array( $sub_arr['exclude'] ) ) {
if ( empty( $sub_arr['exclude'] ) ) {
$sub_arr['exclude'] = array();
} else {
$sub_arr['exclude'] = array( $sub_arr['exclude'] );
}
}
$regex_arr = $this->array_merge( $sub_arr['exclude'], $regex_arr );
$str = array();
foreach ( $regex_arr as $regex ) {
preg_match_all( $regex, $to_parse, $output_array );
$str = $this->array_merge( $str, $output_array[1] );
}
if ( ! empty( $sub_arr['exclude'] ) && is_array( $sub_arr['exclude'] ) ) {
$str = $this->array_delete( $str, $sub_arr['exclude'] );
}
if ( ! empty( $str ) ) {
$sub_arr['icons'] = $str;
$this->stylesheet_data[ $idx ]['icons'] = $str;
}
}
if ( ! $this->is_multi_array( $sub_arr['icons'] ) ) {
$new_array = array();
if ( ! isset( $sub_arr['icons'][0] ) ) {
foreach ( $sub_arr['icons'] as $class_name => $class ) {
$new_array[] = $class . ' ' . $class_name;
}
$this->stylesheet_data[ $idx ]['icons'] = $new_array;
} else {
$this->stylesheet_data[ $idx ]['icons'] = $sub_arr['icons'];
}
}
}
}
}
/**
* Combine the array with null check.
*
* @param mixed $array1 First array.
* @param mixed $array2 Second array.
*
* @return array
*/
private function array_merge( $array1, $array2 ): array {
if ( ! is_array( $array1 ) ) {
$array1 = array();
}
if ( ! is_array( $array2 ) ) {
$array2 = array();
}
return array_merge( $array1, $array2 );
}
/**
* Check if the array is multidimensional.
*
* @param array $my_array Array to evaluate.
*
* @return bool
*/
private function is_multi_array( array $my_array ): bool {
if ( count( $my_array ) === count( $my_array, COUNT_RECURSIVE ) ) {
return false;
}
return true;
}
/**
* Set field defaults.
*/
public function set_defaults() {
$defaults = array(
'options' => array(),
'stylesheet' => '',
'output' => true,
'prefix' => '',
'selector' => '',
'height' => '',
'enqueue' => true,
'enqueue_frontend' => true,
'class' => '',
'button_title' => esc_html__( 'Add Icon', 'redux-framework' ),
'remove_title' => esc_html__( 'Remove Icon', 'redux-framework' ),
'elusive' => true,
'fontawesome' => true,
'dashicons' => true,
'exclude_icons' => '',
);
$this->field = wp_parse_args( $this->field, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @return void
* @since 1.0.0
* @access public
*/
public function render() {
if ( $this->is_error ) {
return;
}
$icon_sets = array();
if ( true === $this->field['fontawesome'] ) {
$icon_sets['font-awesome'] = 'Font Awesome';
}
if ( true === $this->field['dashicons'] ) {
$icon_sets['dashicons'] = 'Dashicons';
}
if ( true === $this->field['elusive'] ) {
$icon_sets['elusive'] = 'Elusive';
}
// Custom icon sets for <select>.
foreach ( $this->stylesheet_data as $value ) {
$icon_sets[ strtolower( str_replace( array( '.', ' ' ), '-', $value['title'] ) ) ] = $value['title'];
}
$icon_sets = rawurlencode( wp_json_encode( $icon_sets ) );
// Data to send to AJAX.
$ajax_data = array();
$temp = array();
foreach ( $this->stylesheet_data as $value ) {
$temp['title'] = $value['title'];
$temp['class'] = $value['class'];
$temp['icons'] = $value['icons'];
$ajax_data[] = $temp;
}
$options_json = '';
if ( ! empty( $ajax_data ) ) {
$options_json = ' data-options=' . rawurlencode( wp_json_encode( $ajax_data ) );
}
$nonce = wp_create_nonce( 'redux_icon_nonce' );
$hidden = ( empty( $this->value ) ) ? ' hidden' : '';
echo '<div class="redux-icon-select" data-icon-sets="' . esc_attr( $icon_sets ) . '"' . esc_html( $options_json ) . '>';
echo '<span class="redux-icon-select-preview' . esc_attr( $hidden ) . '"><i class="' . esc_attr( $this->value ) . '"></i></span>';
echo '<a href="#" class="button button-primary redux-icon-add" data-nonce="' . esc_attr( $nonce ) . '">' . esc_html( $this->field['button_title'] ) . '</a>';
echo '<a href="#" class="button redux-warning-primary redux-icon-remove' . esc_attr( $hidden ) . '">' . esc_html( $this->field['remove_title'] ) . '</a>';
echo '<input type="hidden" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '" value="' . esc_attr( $this->value ) . '" class="redux-icon-value" id="' . esc_attr( $this->field['id'] ) . '" />';
echo '</div>';
}
/**
* Render modal icon popup in the footer.
*
* @return void
*/
public function add_footer_modal_icon() {
?>
<div id="redux-modal-icon" class="redux-modal redux-modal-icon hidden">
<div class="redux-modal-table">
<div class="redux-modal-table-cell">
<div class="redux-modal-overlay"></div>
<div class="redux-modal-inner">
<div class="redux-modal-title">
<?php esc_html_e( 'Add Icon', 'redux-framework' ); ?>
<div class="redux-modal-close redux-icon-close"></div>
</div>
<div class="redux-modal-header">
<label for="redux-icon-select-font">
<select class="redux-icon-select-font" id="redux-icon-select-font"></select>
</label>
<label for="redux-icon-search">
<input type="text" placeholder="<?php esc_html_e( 'Search...', 'redux-framework' ); ?>" class="redux-icon-search" id="redux-icon-search"/>
</label>
<div class="redux-modal-loading">
<div class="redux-loading"></div>
</div>
</div>
<div class="redux-modal-content">
<div class="redux-modal-load"></div>
</div>
</div>
</div>
</div>
</div>
<?php
}
/**
* Do enqueue for all instances of the field.
*
* @return void
*/
public function always_enqueue() {
if ( isset( $this->stylesheet_url ) && is_array( $this->stylesheet_url ) && isset( $this->field['enqueue'] ) && $this->field['enqueue'] ) {
foreach ( $this->stylesheet_url as $idx => $stylesheet_url ) {
wp_enqueue_style(
$this->field['id'] . '-webfont-' . $idx,
$stylesheet_url,
array(),
Redux_Core::$version
);
}
}
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @return void
* @since 1.0.0
* @access public
*/
public function enqueue() {
if ( $this->is_error || '' === $this->url ) {
return;
}
add_action( 'admin_footer', array( $this, 'add_footer_modal_icon' ) );
add_action( 'customize_controls_print_footer_scripts', array( $this, 'add_footer_modal_icon' ) );
$min = Redux_Functions::isMin();
wp_enqueue_script(
'redux-field-icon-select',
$this->url . 'redux-icon-select' . $min . '.js',
array( 'jquery', 'redux-js', 'wp-util' ),
Redux_Extension_Icon_Select::$version,
true
);
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-field-icon-select',
$this->url . 'redux-icon-select.css',
array(),
Redux_Extension_Icon_Select::$version
);
}
}
/**
* This function is unused, but necessary to trigger output.
*
* @param mixed $data CSS data.
*
* @return mixed|string|void
*/
public function css_style( $data ) {
return $data;
}
/**
* Used to enqueue to Webfont to the front-end
*
* @param string|null|array $style CSS style.
*/
public function output( $style = '' ) {
if ( $this->is_error ) {
return;
}
if ( true === $this->field['elusive'] ) {
Redux_Functions_Ex::enqueue_elusive_font();
}
if ( true === $this->field['fontawesome'] ) {
Redux_Functions_Ex::enqueue_font_awesome();
}
if ( isset( $this->stylesheet_url ) && is_array( $this->stylesheet_url ) && $this->field['enqueue_frontend'] ) {
foreach ( $this->stylesheet_url as $idx => $stylesheet_url ) {
wp_enqueue_style(
$this->field['id'] . '-webfont-' . $idx,
$stylesheet_url,
array(),
Redux_Core::$version
);
}
}
}
/**
* Remove items from an array.
*
* @param array $my_array The array to manage.
* @param mixed $element An array or a string of the item to remove.
*
* @return array The cleaned array with reset keys.
*/
private function array_delete( array $my_array, $element ): array {
return ( is_array( $element ) ) ? array_values( array_diff( $my_array, $element ) ) : array_values( array_diff( $my_array, array( $element ) ) );
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,225 @@
/* global redux, jQuery */
( function( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.icon_select = redux.field_objects.icon_select || {};
redux.field_objects.icon_select.getIconArray = function( el ) {
var iconSelect = el.find( '.redux-icon-select' );
return iconSelect.data( 'options' );
};
redux.field_objects.icon_select.reloadIcons = function( el, button, modal, value, text ) {
window.wp.ajax.post(
'redux_get_icons',
{
icon_set: value,
select_text: text,
nonce: button.data( 'nonce' ),
data: redux.field_objects.icon_select.getIconArray( el )
}
).done(
function( response ) {
modal.find( '.redux-modal-loading' ).hide();
modal.find( '.redux-modal-load' ).html( response.content );
}
).fail(
function( response, status, error ) {
modal.find( '.redux-modal-loading' ).hide();
modal.find( '.redux-modal-load' ).html( error );
modal.on(
'click',
function() {
modal.addClass( 'hidden' );
modal.off( 'click' );
$( '.redux-icon-select-font' ).empty();
modal.find( '.redux-modal-load' ).empty();
}
);
}
);
};
redux.field_objects.icon_select.init = function( selector ) {
if ( ! selector ) {
selector = $( document ).find( '.redux-group-tab:visible' ).find( '.redux-container-icon_select:visible' );
}
$( selector ).each(
function() {
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
el.find( '.redux-icon-add' ).on(
'click',
function( e ) {
var iconModalLoaded = false;
var button = $( this );
var modal = $( '#redux-modal-icon' );
var select = modal.find( '.redux-icon-select-font' );
var selectVal;
var selectText;
var iconSets;
e.preventDefault();
// Extract icon set data.
iconSets = el.find( '.redux-icon-select' ).data( 'icon-sets' );
iconSets = JSON.parse( decodeURIComponent( iconSets ) );
// Fill <select> with icon set options.
$.each(
iconSets,
function ( i, item ) {
select.append(
$( '<option>', { value: i, text : item } )
);
}
);
modal.removeClass( 'hidden' );
selectVal = select.val();
selectText = select.find( ':selected' ).text();
if ( ! iconModalLoaded ) {
modal.find( '.redux-modal-loading' ).show();
window.wp.ajax.post(
'redux_get_icons',
{
icon_set: selectVal,
select_text: selectText,
nonce: button.data( 'nonce' ),
data: redux.field_objects.icon_select.getIconArray( el )
}
).done(
function( response ) {
modal.find( '.redux-modal-loading' ).hide();
iconModalLoaded = true;
var load = modal.find( '.redux-modal-load' ).html( response.content );
load.off( 'click' );
load.on(
'click',
'i',
function( e ) {
e.preventDefault();
var icon = $( this ).attr( 'title' );
el.find( '.redux-icon-select-preview i' ).removeAttr( 'class' ).addClass( icon );
el.find( '.redux-icon-select-preview' ).removeClass( 'hidden' );
el.find( '.redux-icon-remove' ).removeClass( 'hidden' );
el.find( 'input' ).val( icon ).trigger( 'change' );
modal.addClass( 'hidden' );
select.empty();
load.empty();
}
);
modal.off( 'change' );
modal.on(
'change',
'.redux-icon-select-font',
function() {
var value = $( this ).val();
var text = $( this ).find( ':selected' ).text();
modal.find( '.redux-modal-loading' ).show();
redux.field_objects.icon_select.reloadIcons( el, button, modal, value, text );
}
);
modal.on(
'change keyup',
'.redux-icon-search',
function() {
var value = $( this ).val();
var icons = load.find( 'i' );
icons.each(
function() {
var elem = $( this );
if ( elem.attr( 'title' ).search( new RegExp( value, 'i' ) ) < 0 ) {
elem.hide();
} else {
elem.show();
}
}
);
}
);
modal.on(
'click',
'.redux-modal-close, .redux-modal-overlay',
function() {
modal.addClass( 'hidden' );
select.empty();
load.empty();
}
);
}
).fail(
function( response, status, error ) {
modal.find( '.redux-modal-loading' ).hide();
modal.find( '.redux-modal-load' ).html( error );
modal.on(
'click',
function() {
select.empty();
el.find( '.redux-modal-load' ).empty();
modal.off( 'click' );
}
);
}
);
}
}
);
el.find( '.redux-icon-remove' ).on(
'click',
function( e ) {
e.preventDefault();
el.find( '.redux-icon-select-preview' ).addClass( 'hidden' );
el.find( 'input' ).val( '' ).trigger( 'change' );
$( this ).addClass( 'hidden' );
}
);
}
);
};
} )( jQuery );

View File

@@ -0,0 +1 @@
.redux-container-icon_select .redux-icon-container{position:relative;overflow-y:auto;border:2px solid #eee;padding:5px;text-align:center}.redux-container-icon_select .redux-icon-select{margin:0 !important}.redux-container-icon_select .redux-icon-select input[type='radio']{display:none}.redux-container-icon_select .redux-icon-select i{border-color:transparent;color:#555}.redux-container-icon_select .redux-icon-select i:hover{border-color:#ddd;color:#111}.redux-container-icon_select ul.redux-icon-select li{margin:10px;display:block;float:left;padding:5px}.redux-container-icon_select .redux-icon-select i,.redux-container-icon_select .redux-icon-select-selected i{border-width:4px;border-style:solid;font-size:30px;padding:5px}.redux-container-icon_select .redux-icon-select-selected i,.redux-container-icon_select .redux-icon-select-selected i:hover{border-color:#7a7a7a;color:#269ad6}

View File

@@ -0,0 +1 @@
!function(a){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.icon_select=redux.field_objects.icon_select||{},redux.field_objects.icon_select.getIconArray=function(e){return e.find(".redux-icon-select").data("options")},redux.field_objects.icon_select.reloadIcons=function(e,d,i,n,o){window.wp.ajax.post("redux_get_icons",{icon_set:n,select_text:o,nonce:d.data("nonce"),data:redux.field_objects.icon_select.getIconArray(e)}).done(function(e){i.find(".redux-modal-loading").hide(),i.find(".redux-modal-load").html(e.content)}).fail(function(e,d,n){i.find(".redux-modal-loading").hide(),i.find(".redux-modal-load").html(n),i.on("click",function(){i.addClass("hidden"),i.off("click"),a(".redux-icon-select-font").empty(),i.find(".redux-modal-load").empty()})})},redux.field_objects.icon_select.init=function(e){e=e||a(document).find(".redux-group-tab:visible").find(".redux-container-icon_select:visible"),a(e).each(function(){var c=a(this),e=c;(e=c.hasClass("redux-field-container")?e:c.parents(".redux-field-container:first")).is(":hidden")||e.hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),c.find(".redux-icon-add").on("click",function(e){var d,i=a(this),o=a("#redux-modal-icon"),t=o.find(".redux-icon-select-font");e.preventDefault(),e=c.find(".redux-icon-select").data("icon-sets"),e=JSON.parse(decodeURIComponent(e)),a.each(e,function(e,d){t.append(a("<option>",{value:e,text:d}))}),o.removeClass("hidden"),e=t.val(),d=t.find(":selected").text(),o.find(".redux-modal-loading").show(),window.wp.ajax.post("redux_get_icons",{icon_set:e,select_text:d,nonce:i.data("nonce"),data:redux.field_objects.icon_select.getIconArray(c)}).done(function(e){o.find(".redux-modal-loading").hide();var n=o.find(".redux-modal-load").html(e.content);n.off("click"),n.on("click","i",function(e){e.preventDefault();e=a(this).attr("title");c.find(".redux-icon-select-preview i").removeAttr("class").addClass(e),c.find(".redux-icon-select-preview").removeClass("hidden"),c.find(".redux-icon-remove").removeClass("hidden"),c.find("input").val(e).trigger("change"),o.addClass("hidden"),t.empty(),n.empty()}),o.off("change"),o.on("change",".redux-icon-select-font",function(){var e=a(this).val(),d=a(this).find(":selected").text();o.find(".redux-modal-loading").show(),redux.field_objects.icon_select.reloadIcons(c,i,o,e,d)}),o.on("change keyup",".redux-icon-search",function(){var d=a(this).val();n.find("i").each(function(){var e=a(this);e.attr("title").search(new RegExp(d,"i"))<0?e.hide():e.show()})}),o.on("click",".redux-modal-close, .redux-modal-overlay",function(){o.addClass("hidden"),t.empty(),n.empty()})}).fail(function(e,d,n){o.find(".redux-modal-loading").hide(),o.find(".redux-modal-load").html(n),o.on("click",function(){t.empty(),c.find(".redux-modal-load").empty(),o.off("click")})})}),c.find(".redux-icon-remove").on("click",function(e){e.preventDefault(),c.find(".redux-icon-select-preview").addClass("hidden"),c.find("input").val("").trigger("change"),a(this).addClass("hidden")}))})}}(jQuery);

View File

@@ -0,0 +1,335 @@
.redux-container-icon_select {
.redux-icon-select {
display: flex;
grid-gap: 5px;
}
.redux-icon-select-preview {
.dashicons {
height:initial!important;
}
&:not(.hidden) {
display: flex;
}
i {
display: flex;
justify-content: center;
align-items: center;
width: 30px;
font-size: 14px;
text-align: center;
vertical-align: top;
color: #555;
border: 1px solid #ccc;
background-color: #f7f7f7;
border-radius: 3px;
box-shadow: 0 1px 0 rgba(0, 0, 0, 0.08);
}
}
.redux-icon-container {
position: relative;
overflow-y: auto;
border: 2px solid #eee;
padding: 5px;
text-align: center;
}
/* .redux-icon-select {
margin: 0 !important;
input[type='radio']{
display:none;
}
i {
border-color:transparent;
color: #555;
&:hover {
border-color:#ddd;
color: #111;
}
}
}*/
ul{
&.redux-icon-select li {
margin: 10px;
display:block;
float: left;
padding:5px;
}
}
/* .redux-icon-select i,
.redux-icon-select-selected i {
border-width:4px;
border-style: solid;
font-size: 30px;
padding: 5px;
}
.redux-icon-select-selected {
i,
i:hover {
border-color:#7a7a7a;
color:#269ad6;
}
}*/
}
.redux-modal{
position: fixed;
z-index: 100101;
top: 0;
left: 0;
width: 100%;
height: 100%;
&.hidden{
display: none;
}
}
.redux-modal-icon{
z-index: 100102;
.redux-icon-title{
padding: 15px 0;
margin: 4px;
font-size: 14px;
font-weight: bold;
text-align: center;
border: 1px solid #eee;
background-color: #f7f7f7;
}
.redux-modal-header{
text-align: center;
}
.redux-icon-select-font{
display: inline-block;
height: 40px;
top: -2px;
position: relative;
}
.redux-icon-search{
width: 50%;
height: 40px;
line-height: 40px;
}
i{
cursor: pointer;
display: inline-block;
margin: 4px;
width: 35px;
height: 35px;
line-height: 35px;
font-size: 16px;
color: #555;
text-align: center;
border: 1px solid #ccc;
background-color: #f7f7f7;
border-radius: 2px;
box-shadow: 1px 1px 0 rgba(0,0,0,0.05);
&:hover {
color: #fff;
border-color: #222;
background-color: #222;
}
}
.redux-modal-content{
padding: 10px;
height: 618px;
}
.redux-error-text{
padding: 10px;
}
}
.redux-modal-table{
display: table;
width: 100%;
height: 100%;
}
.redux-modal-table-cell{
display: table-cell;
vertical-align: middle;
margin: 100px 0;
}
.redux-modal-overlay{
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: #000;
opacity: 0.5;
}
.redux-modal-inner{
position: relative;
z-index: 10;
width: 760px;
height: 750px;
margin: 0 auto;
background-color: #fff;
}
.redux-modal-content{
position: relative;
overflow: hidden;
overflow-y: auto;
height: 595px;
.redux-field{
padding: 15px 30px 15px 15px;
}
a{
&:active,
&:focus{
outline: none;
box-shadow: none;
}
}
h4{
font-size: 13px;
small{
font-style: italic;
font-weight: 400;
color: #aaa;
}
}
}
.redux-modal-title{
position: relative;
background-color: #fcfcfc;
border-bottom: 1px solid #ddd;
height: 36px;
font-size: 16px;
font-weight: 600;
line-height: 36px;
margin: 0;
padding: 0 36px 0 16px;
}
.redux-modal-header{
width: 100%;
padding: 14px 0;
background-color: #f5f5f5;
border-bottom: 1px solid #ddd;
.redux-modal-loading{
display: none;
position: absolute;
left: 20px;
top: 59px;
}
select{
display: block;
width: 250px;
margin: 0 auto;
font-size: 13px;
line-height: 1;
height: 30px;
min-height: 30px;
background-color: #fff;
}
}
.redux-modal-close{
color: #666;
padding: 0;
position: absolute;
top: 0;
right: 0;
width: 36px;
height: 36px;
text-align: center;
background: none;
border: none;
cursor: pointer;
&:before{
font: normal 20px/36px dashicons;
content: "\f158";
vertical-align: top;
width: 36px;
height: 36px;
}
&:hover{
opacity: 0.5;
}
}
.redux-loading{
position: relative;
width: 20px;
height: 20px;
background: #ccc;
border-radius: 20px;
box-shadow: 0 2px 5px rgba(0,0,0,0.07);
&:after{
position: absolute;
top: 50%;
left: 50%;
width: 4px;
height: 4px;
content: "";
margin-top: -2px;
margin-left: -2px;
background-color: white;
animation-duration: 0.5s;
animation-iteration-count: infinite;
animation-timing-function: linear;
animation-name: reduxLoader;
border-radius: 4px;
}
}
@media only screen and (max-width: 782px) {
.redux-modal{
.redux-modal-inner{
width: 90%;
}
}
}
@media only screen and (max-height: 750px) {
.redux-modal{
.redux-modal-inner{
height: auto;
}
.redux-modal-content{
height: calc(100vh - 200px);
}
}
}
@keyframes reduxLoader {
0% {
transform: rotate(0deg) translateX(-6px) rotate(0deg);
}
100% {
transform: rotate(360deg) translateX(-6px) rotate(-360deg);
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,157 @@
<?php
/**
* Redux Import/Export Extension Class
*
* @class Redux_Extension_Import_Export
* @version 4.0.0
* @package Redux Framework
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Extension_Import_Export', false ) ) {
/**
* Main ReduxFramework import_export extension class
*
* @since 3.1.6
*/
class Redux_Extension_Import_Export extends Redux_Extension_Abstract {
/**
* Ext version.
*
* @var string
*/
public static $version = '4.0.0';
/**
* Is field bit.
*
* @var bool
*/
public $is_field = false;
/**
* Class Constructor. Defines the args for the extensions class
*
* @param object $redux ReduxFramework object.
*
* @return void
* @since 1.0.0
* @access public
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'import_export' );
add_action( 'wp_ajax_redux_download_options-' . $this->parent->args['opt_name'], array( $this, 'download_options' ) );
add_action( 'wp_ajax_nopriv_redux_download_options-' . $this->parent->args['opt_name'], array( $this, 'download_options' ) );
// phpcs:ignore WordPress.NamingConventions.ValidHookName
do_action( 'redux/options/' . $this->parent->args['opt_name'] . '/import', array( $this, 'remove_cookie' ) );
$this->is_field = Redux_Helpers::is_field_in_use( $redux, 'import_export' );
if ( ! $this->is_field && $this->parent->args['show_import_export'] ) {
$this->add_section();
}
add_filter( 'upload_mimes', array( $this, 'custom_upload_mimes' ) );
}
/**
* Adds the appropriate mime types to WordPress
*
* @param array|null $existing_mimes .
*
* @return array
*/
public function custom_upload_mimes( ?array $existing_mimes = array() ): array {
$existing_mimes['redux'] = 'application/redux';
return $existing_mimes;
}
/**
* Add section to panel.
*/
public function add_section() {
$this->parent->sections[] = array(
'id' => 'import/export',
'title' => esc_html__( 'Import / Export', 'redux-framework' ),
'heading' => '',
'icon' => 'el el-refresh',
'customizer' => false,
'fields' => array(
array(
'id' => 'redux_import_export',
'type' => 'import_export',
'full_width' => true,
),
),
);
}
/**
* Import download options.
*/
public function download_options() {
if ( ! isset( $_GET['secret'] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_GET['secret'] ) ), 'redux_io_' . $this->parent->args['opt_name'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
wp_die( 'Invalid Secret for options use.' );
}
$this->parent->options_class->get();
$backup_options = $this->parent->options;
$backup_options['redux-backup'] = 1;
if ( isset( $backup_options['REDUX_imported'] ) ) {
unset( $backup_options['REDUX_imported'] );
}
// No need to escape this, as it's been properly escaped previously and through json_encode.
$content = wp_json_encode( $backup_options );
if ( isset( $_GET['action'] ) && 'redux_download_options-' . $this->parent->args['opt_name'] === $_GET['action'] ) { // phpcs:ignore WordPress.Security.NonceVerification
header( 'Content-Description: File Transfer' );
header( 'Content-type: application/txt' );
header( 'Content-Disposition: attachment; filename="redux_options_"' . $this->parent->args['opt_name'] . '_backup_' . gmdate( 'm-d-Y' ) . '.json' );
header( 'Content-Transfer-Encoding: binary' );
header( 'Expires: 0' );
header( 'Cache-Control: must-revalidate' );
header( 'Pragma: public' );
} else {
header( 'Expires: Mon, 26 Jul 1997 05:00:00 GMT' );
header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . 'GMT' );
header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' );
header( 'Cache-Control: no-store, no-cache, must-revalidate' );
header( 'Cache-Control: post-check=0, pre-check=0', false );
header( 'Pragma: no-cache' );
// Can't include the type. Thanks old Firefox and IE. BAH.
// header('Content-type: application/json');.
}
// phpcs:ignore WordPress.Security.EscapeOutput
echo( $content );
exit;
}
/**
* Remove current tab cookie.
*/
public function remove_cookie() {
// Remove the import/export tab cookie.
if ( isset( $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) && 'import_export_default' === $_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] ) {
setcookie( 'redux_current_tab_' . $this->parent->args['opt_name'], '', 1, '/' );
$_COOKIE[ 'redux_current_tab_' . $this->parent->args['opt_name'] ] = 1;
}
}
}
}
if ( ! class_exists( 'ReduxFramework_extension_import_export' ) ) {
class_alias( 'Redux_Extension_Import_Export', 'ReduxFramework_extension_import_export' );
}

View File

@@ -0,0 +1,185 @@
<?php // phpcs:disable WordPress.WhiteSpace.PrecisionAlignment.Found
/**
* Import & Export for Option Panel
*
* @package ReduxFramework
* @author Dovy Paukstys
* @version 4.0.0
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Import_Export', false ) ) {
/**
* Main Redux_import_export class
*
* @since 1.0.0
*/
class Redux_Import_Export extends Redux_Field {
/**
* Is field.
*
* @var bool
*/
public $is_field;
/**
* Redux_Import_Export constructor.
*
* @param array $field Field array.
* @param string $value Value array.
* @param object $redux ReduxFramework object.
*
* @throws ReflectionException .
*/
public function __construct( $field, $value, $redux ) {
parent::__construct( $field, $value, $redux );
$this->is_field = $this->parent->extensions['import_export']->is_field;
}
/**
* Set field defaults.
*/
public function set_defaults() {
// Set default args for this field to avoid bad indexes. Change this to anything you use.
$defaults = array(
'options' => array(),
'stylesheet' => '',
'output' => true,
'enqueue' => true,
'enqueue_frontend' => true,
);
$this->field = wp_parse_args( $this->field, $defaults );
}
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @return void
* @since 1.0.0
* @access public
*/
public function render() {
$secret = wp_create_nonce( 'redux_io_' . $this->parent->args['opt_name'] );
// No errors, please.
$defaults = array(
'full_width' => true,
'overflow' => 'inherit',
);
$this->field = wp_parse_args( $this->field, $defaults );
?>
<h4><?php esc_html_e( 'Import Options', 'redux-framework' ); ?></h4>
<p>
<a
href="javascript:void(0);"
id="redux-import-code-button"
class="button-secondary">
<?php esc_html_e( 'Import from Clipboard', 'redux-framework' ); ?>
</a>
<a
href="#"
id="redux-import-upload"
class="button-secondary">
<?php esc_html_e( 'Upload file', 'redux-framework' ); ?><span></span>
</a>
<input type="file" id="redux-import-upload-file" size="50">
</p>
<div id="redux-import-code-wrapper">
<p class="description" id="import-code-description">
<?php // phpcs:ignore WordPress.NamingConventions.ValidHookName ?>
<?php echo esc_html( apply_filters( 'redux-import-file-description', esc_html__( 'Paste your clipboard data here.', 'redux-framework' ) ) ); ?>
</p>
<label for="import-code-value"></label><textarea
id="import-code-value"
name="<?php echo esc_attr( $this->parent->args['opt_name'] ); ?>[import_code]"
class="large-text no-update" rows="3"></textarea>
</div>
<p id="redux-import-action">
<input
type="submit"
id="redux-import"
name="import"
class="button-primary"
value="<?php esc_html_e( 'Import', 'redux-framework' ); ?>">&nbsp;&nbsp;
<span>
<?php // phpcs:ignore WordPress.NamingConventions.ValidHookName ?>
<?php echo esc_html( apply_filters( 'redux-import-warning', esc_html__( 'WARNING! This will overwrite all existing option values, please proceed with caution!', 'redux-framework' ) ) ); ?>
</span>
</p>
<div class="hr">
<div class="inner">
<span>&nbsp;</span>
</div>
</div>
<h4><?php esc_html_e( 'Export Options', 'redux-framework' ); ?></h4>
<div class="redux-section-desc">
<p class="description">
<?php // phpcs:ignore WordPress.NamingConventions.ValidHookName ?>
<?php echo esc_html( apply_filters( 'redux-backup-description', esc_html__( 'Here you can copy/download your current option settings. Keep this safe as you can use it as a backup should anything go wrong, or you can use it to restore your settings on this site (or any other site).', 'redux-framework' ) ) ); ?>
</p>
</div>
<?php $link = admin_url( 'admin-ajax.php?action=redux_download_options-' . $this->parent->args['opt_name'] . '&secret=' . $secret ); ?>
<p>
<button id="redux-export-code-copy" class="button-secondary"
data-secret="<?php echo esc_attr( $secret ); ?>"
data-copy="<?php esc_attr_e( 'Copy to Clipboard', 'redux-framework' ); ?>"
data-copied="<?php esc_attr_e( 'Copied!', 'redux-framework' ); ?>">
<?php esc_html_e( 'Copy to Clipboard', 'redux-framework' ); ?>
</button>
<a href="<?php echo esc_url( $link ); ?>" id="redux-export-code-dl" class="button-primary">
<?php esc_html_e( 'Export File', 'redux-framework' ); ?>
</a>
</p>
<p></p>
<label for="redux-export-code"></label><textarea class="large-text no-update" id="redux-export-code" rows="1"></textarea>
<?php
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @return void
* @since 1.0.0
* @access public
*/
public function enqueue() {
wp_enqueue_script(
'redux-extension-import-export',
$this->url . 'redux-import-export' . Redux_Functions::is_min() . '.js',
array(
'jquery',
'redux-js',
),
Redux_Extension_Import_Export::$version,
true
);
wp_localize_script(
'redux-extension-import-export',
'ImportExport',
array(
'unchanged_values' => esc_html__( 'Your panel has unchanged values, would you like to save them now?', 'redux-framework' ),
)
);
if ( $this->parent->args['dev_mode'] ) {
wp_enqueue_style(
'redux-import-export',
$this->url . 'redux-import-export.css',
array(),
Redux_Extension_Import_Export::$version
);
}
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,11 @@
.redux-container-import_export #redux-import-link-wrapper, .redux-container-import_export #redux-import-code-wrapper { display: none; }
.redux-container-import_export #redux-export-code, .redux-container-import_export #redux-export-link-value, .redux-container-import_export #redux-import-upload-file { display: none; }
.redux-container-import_export #redux-import-action span { color: #b94a48; }
.redux-container-import_export #redux-import-upload span { font-weight: bold; }
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtaW1wb3J0LWV4cG9ydC5jc3MiLCJzb3VyY2VzIjpbInJlZHV4LWltcG9ydC1leHBvcnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxBQUNJLDhCQUQwQixDQUMxQiwwQkFBMEIsRUFEOUIsOEJBQThCLENBRTFCLDBCQUEwQixDQUFDLEVBQ3ZCLE9BQU8sRUFBRSxJQUFJLEdBQ2hCOztBQUpMLEFBTUksOEJBTjBCLENBTTFCLGtCQUFrQixFQU50Qiw4QkFBOEIsQ0FPMUIsd0JBQXdCLEVBUDVCLDhCQUE4QixDQVExQix5QkFBeUIsQ0FBQyxFQUN0QixPQUFPLEVBQUUsSUFBSSxHQUNoQjs7QUFWTCxBQVlJLDhCQVowQixDQVkxQixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsRUFDdEIsS0FBSyxFQUFFLE9BQU8sR0FDakI7O0FBZEwsQUFlSSw4QkFmMEIsQ0FlMUIsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEVBQ3RCLFdBQVcsRUFBRSxJQUFJLEdBQ3BCIn0= */
/*# sourceMappingURL=redux-import-export.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["redux-import-export.scss","redux-import-export.css"],"names":[],"mappings":"AAAA,uHCGQ,aAAa,EAAA;;ADHrB,uKCSQ,aAAa,EAAA;;ADTrB,2DCaQ,cAAc,EAAA;;ADbtB,2DCgBQ,iBAAiB,EAAA;;AARzB,qqBAAqqB","file":"redux-import-export.css","sourcesContent":[".redux-container-import_export {\r\n #redux-import-link-wrapper,\r\n #redux-import-code-wrapper {\r\n display: none;\r\n }\r\n\r\n #redux-export-code,\r\n #redux-export-link-value,\r\n #redux-import-upload-file {\r\n display: none;\r\n }\r\n\r\n #redux-import-action span {\r\n color: #b94a48;\r\n }\r\n #redux-import-upload span {\r\n font-weight: bold;\r\n }\r\n}\r\n\r\n",".redux-container-import_export #redux-import-link-wrapper, .redux-container-import_export #redux-import-code-wrapper { display: none; }\n\n.redux-container-import_export #redux-export-code, .redux-container-import_export #redux-export-link-value, .redux-container-import_export #redux-import-upload-file { display: none; }\n\n.redux-container-import_export #redux-import-action span { color: #b94a48; }\n\n.redux-container-import_export #redux-import-upload span { font-weight: bold; }\n\n/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtaW1wb3J0LWV4cG9ydC5jc3MiLCJzb3VyY2VzIjpbInJlZHV4LWltcG9ydC1leHBvcnQuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxBQUNJLDhCQUQwQixDQUMxQiwwQkFBMEIsRUFEOUIsOEJBQThCLENBRTFCLDBCQUEwQixDQUFDLEVBQ3ZCLE9BQU8sRUFBRSxJQUFJLEdBQ2hCOztBQUpMLEFBTUksOEJBTjBCLENBTTFCLGtCQUFrQixFQU50Qiw4QkFBOEIsQ0FPMUIsd0JBQXdCLEVBUDVCLDhCQUE4QixDQVExQix5QkFBeUIsQ0FBQyxFQUN0QixPQUFPLEVBQUUsSUFBSSxHQUNoQjs7QUFWTCxBQVlJLDhCQVowQixDQVkxQixvQkFBb0IsQ0FBQyxJQUFJLENBQUMsRUFDdEIsS0FBSyxFQUFFLE9BQU8sR0FDakI7O0FBZEwsQUFlSSw4QkFmMEIsQ0FlMUIsb0JBQW9CLENBQUMsSUFBSSxDQUFDLEVBQ3RCLFdBQVcsRUFBRSxJQUFJLEdBQ3BCIn0= */\n\n/*# sourceMappingURL=redux-import-export.css.map */\n"]}

View File

@@ -0,0 +1,232 @@
/* global jQuery, document, redux, ajaxurl, ImportExport */
(function( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.import_export = redux.field_objects.import_export || {};
redux.field_objects.import_export.copy_text = function( $text ) {
var copyFrom = document.createElement( 'textarea' );
document.body.appendChild( copyFrom );
copyFrom.textContent = $text;
copyFrom.select();
document.execCommand( 'copy' );
copyFrom.remove();
};
redux.field_objects.import_export.get_options = function( $secret ) {
var $el = $( '#redux-export-code-copy' );
var url = ajaxurl + '?download=0&action=redux_download_options-' + redux.optName.args.opt_name + '&secret=' + $secret;
$el.addClass( 'disabled' ).attr( 'disabled', 'disabled' );
$el.text( $el.data( 'copy' ) );
$.get(
url,
function( data ) {
redux.field_objects.import_export.copy_text( data );
$el.removeClass( 'disabled' );
$el.text( $el.data( 'copied' ) );
setTimeout(
function() {
$el.text( $el.data( 'copy' ) ).removeClass( 'disabled' ).prop( 'disabled', false );
},
2000
);
}
);
};
redux.field_objects.import_export.init = function( selector ) {
selector = $.redux.getSelector( selector, 'import_export' );
$( selector ).each(
function() {
var textBox1;
var textBox2;
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.is( ':hidden' ) ) {
return;
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
el.each(
function() {
$( '#redux-import' ).on(
'click',
function( e ) {
if ( '' === $( '#import-code-value' ).val() && '' === $( '#import-link-value' ).val() ) {
e.preventDefault();
return false;
}
}
);
$( this ).find( '#redux-import-code-button' ).on(
'click',
function() {
var $el = $( '#redux-import-code-wrapper' );
if ( $el.is( ':visible' ) ) {
$( '#import-link-value' ).val( '' );
$( '#redux-import-link-wrapper' ).fadeOut(
'fast',
function() {
$el.fadeIn(
'fast',
function() {
$( '#import-code-value' ).trigger( 'focus' );
}
);
}
);
} else {
if ( $el.is( ':visible' ) ) {
$el.fadeOut();
} else {
$el.fadeIn(
'medium',
function() {
$( '#import-code-value' ).trigger( 'focus' );
}
);
}
}
}
);
$( this ).find( '#redux-export-code-dl' ).on(
'click',
function( e ) {
e.preventDefault();
if ( !! window.onbeforeunload ) {
if ( confirm( ImportExport.unchanged_values ) ) {
$( '#redux_top_save' ).on( 'click' );
setTimeout(
function() {
window.open( $( this ).attr( 'href' ) );
},
2000
);
}
} else {
window.open( $( this ).attr( 'href' ) );
}
}
);
$( this ).find( '#redux-import-upload' ).on(
'click',
function() {
$( '#redux-import-upload-file' ).trigger( 'click' );
}
);
document.getElementById( 'redux-import-upload-file' ).addEventListener(
'change',
function() {
var file_to_read = document.getElementById( 'redux-import-upload-file' ).files[0];
var fileread = new FileReader();
$( '#redux-import-upload span' ).text( ': ' + file_to_read.name );
fileread.onload = function() {
var content = fileread.result;
$( '#import-code-value' ).val( content );
};
fileread.readAsText( file_to_read );
}
);
$( this ).find( '#redux-export-code-copy' ).on(
'click',
function( e ) {
var $el = $( '#redux-export-code' );
var $secret = $( this ).data( 'secret' );
e.preventDefault();
if ( !! window.onbeforeunload ) {
if ( confirm( ImportExport.unchanged_values ) ) {
$( '#redux_top_save' ).trigger( 'click' );
setTimeout(
function() {
redux.field_objects.import_export.get_options( $secret, $el );
},
2000
);
}
} else {
redux.field_objects.import_export.get_options( $secret, $el );
}
}
);
$( this ).find( 'textarea' ).on(
'focusout',
function() {
var $id = $( this ).attr( 'id' );
var $el = $( this );
var $container = $el;
if ( 'import-link-value' === $id || 'import-code-value' === $id ) {
$container = $( this ).parent();
}
$container.fadeOut(
'medium',
function() {
if ( 'redux-export-link-value' !== $id ) {
$el.text( '' );
}
}
);
}
);
textBox1 = document.getElementById( 'redux-export-code' );
textBox1.onfocus = function() {
textBox1.select();
// Work around Chrome's little problem.
textBox1.onmouseup = function() {
// Prevent further mouseup intervention.
textBox1.onmouseup = null;
return false;
};
};
textBox2 = document.getElementById( 'import-code-value' );
textBox2.onfocus = function() {
textBox2.select();
// Work around Chrome's little problem.
textBox2.onmouseup = function() {
// Prevent further mouseup intervention.
textBox2.onmouseup = null;
return false;
};
};
}
);
}
);
};
})( jQuery );

View File

@@ -0,0 +1 @@
!function(n){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.import_export=redux.field_objects.import_export||{},redux.field_objects.import_export.copy_text=function(e){var t=document.createElement("textarea");document.body.appendChild(t),t.textContent=e,t.select(),document.execCommand("copy"),t.remove()},redux.field_objects.import_export.get_options=function(e){var t=n("#redux-export-code-copy"),e=ajaxurl+"?download=0&action=redux_download_options-"+redux.optName.args.opt_name+"&secret="+e;t.addClass("disabled").attr("disabled","disabled"),t.text(t.data("copy")),n.get(e,function(e){redux.field_objects.import_export.copy_text(e),t.removeClass("disabled"),t.text(t.data("copied")),setTimeout(function(){t.text(t.data("copy")).removeClass("disabled").prop("disabled",!1)},2e3)})},redux.field_objects.import_export.init=function(e){e=n.redux.getSelector(e,"import_export"),n(e).each(function(){var e,t,o=n(this),i=o;(i=o.hasClass("redux-field-container")?i:o.parents(".redux-field-container:first")).is(":hidden")||i.hasClass("redux-field-init")&&(i.removeClass("redux-field-init"),o.each(function(){n("#redux-import").on("click",function(e){if(""===n("#import-code-value").val()&&""===n("#import-link-value").val())return e.preventDefault(),!1}),n(this).find("#redux-import-code-button").on("click",function(){var e=n("#redux-import-code-wrapper");e.is(":visible")?(n("#import-link-value").val(""),n("#redux-import-link-wrapper").fadeOut("fast",function(){e.fadeIn("fast",function(){n("#import-code-value").trigger("focus")})})):e.is(":visible")?e.fadeOut():e.fadeIn("medium",function(){n("#import-code-value").trigger("focus")})}),n(this).find("#redux-export-code-dl").on("click",function(e){e.preventDefault(),window.onbeforeunload?confirm(ImportExport.unchanged_values)&&(n("#redux_top_save").on("click"),setTimeout(function(){window.open(n(this).attr("href"))},2e3)):window.open(n(this).attr("href"))}),n(this).find("#redux-import-upload").on("click",function(){n("#redux-import-upload-file").trigger("click")}),document.getElementById("redux-import-upload-file").addEventListener("change",function(){var e=document.getElementById("redux-import-upload-file").files[0],t=new FileReader;n("#redux-import-upload span").text(": "+e.name),t.onload=function(){var e=t.result;n("#import-code-value").val(e)},t.readAsText(e)}),n(this).find("#redux-export-code-copy").on("click",function(e){var t=n("#redux-export-code"),o=n(this).data("secret");e.preventDefault(),window.onbeforeunload?confirm(ImportExport.unchanged_values)&&(n("#redux_top_save").trigger("click"),setTimeout(function(){redux.field_objects.import_export.get_options(o,t)},2e3)):redux.field_objects.import_export.get_options(o,t)}),n(this).find("textarea").on("focusout",function(){var e=n(this).attr("id"),t=n(this);("import-link-value"!==e&&"import-code-value"!==e?t:n(this).parent()).fadeOut("medium",function(){"redux-export-link-value"!==e&&t.text("")})}),(e=document.getElementById("redux-export-code")).onfocus=function(){e.select(),e.onmouseup=function(){return e.onmouseup=null,!1}},(t=document.getElementById("import-code-value")).onfocus=function(){t.select(),t.onmouseup=function(){return t.onmouseup=null,!1}}}))})}}(jQuery);

View File

@@ -0,0 +1,20 @@
.redux-container-import_export {
#redux-import-link-wrapper,
#redux-import-code-wrapper {
display: none;
}
#redux-export-code,
#redux-export-link-value,
#redux-import-upload-file {
display: none;
}
#redux-import-action span {
color: #b94a48;
}
#redux-import-upload span {
font-weight: bold;
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,52 @@
<?php
/**
* Redux JS Button Extension Class
*
* @package Redux
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Extension_Js_Button
* @version 4.3.16
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Extension_Js_Button' ) ) {
/**
* Main Redux_Extension_Js_Button extension class
*
* @since 1.0.0
*/
class Redux_Extension_Js_Button extends Redux_Extension_Abstract {
/**
* Extension version.
*
* @var string
*/
public static $version = '4.3.16';
/**
* Extension friendly name.
*
* @var string
*/
public $extension_name = 'JS Button';
/**
* Class Constructor. Defines the args for the extensions class
*
* @since 1.0.0
* @access public
*
* @param ReduxFramework $redux Parent settings.
*
* @return void
*/
public function __construct( $redux ) {
parent::__construct( $redux, __FILE__ );
$this->add_field( 'js_button' );
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,136 @@
<?php
/**
* Redux JS Button Field Class
*
* @package Redux Extentions
* @author Kevin Provance <kevin.provance@gmail.com>
* @class Redux_Js_Button
*/
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( 'Redux_Js_Button' ) ) {
/**
* Main ReduxFramework_Js_Button class
*
* @since 1.0.0
*/
class Redux_Js_Button extends Redux_Field {
/**
* Field Render Function.
* Takes the vars and outputs the HTML for the field in the settings
*
* @since 1.0.0
* @access public
* @return void
*/
public function render() {
$field_id = $this->field['id'];
// primary container.
echo '<div
class="redux-js-button-container ' . esc_attr( $this->field['class'] ) . '"
id="' . esc_attr( $field_id ) . '_container"
data-id="' . esc_attr( $field_id ) . '"
style="width: 0px;"
>';
// Button render.
if ( isset( $this->field['buttons'] ) && is_array( $this->field['buttons'] ) ) {
echo '<div
class="redux-js-button-button-container"
id="redux-js-button-button-container"
style="display: inline-flex;"
>';
foreach ( $this->field['buttons'] as $idx => $arr ) {
$button_text = $arr['text'];
$button_class = $arr['class'];
$button_func = $arr['function'];
echo '<input
id="' . esc_attr( $field_id ) . '_input-' . intval( $idx ) . '"
class="hide-if-no-js button ' . esc_attr( $button_class ) . '"
type="button"
data-function="' . esc_attr( $button_func ) . '"
value="' . esc_attr( $button_text ) . '"
/>&nbsp;&nbsp;';
}
echo '</div>';
}
// Close container.
echo '</div>';
}
/**
* Do enqueue for every field instance.
*
* @return void
*/
public function always_enqueue() {
// Make sure script data exists first.
if ( isset( $this->field['script'] ) && ! empty( $this->field['script'] ) ) {
// URI location of script to enqueue.
$script_url = $this->field['script']['url'] ?? '';
// Get deps, if any.
$script_dep = $this->field['script']['dep'] ?? array();
// Get ver, if any.
$script_ver = $this->field['script']['ver'] ?? time();
// Script location in HTML.
$script_footer = $this->field['script']['in_footer'] ?? true;
// If a script exists, enqueue it.
if ( '' !== $script_url ) {
wp_enqueue_script(
'redux-js-button-' . $this->field['id'],
$script_url,
$script_dep,
$script_ver,
$script_footer
);
}
if ( isset( $this->field['enqueue_ajax'] ) && $this->field['enqueue_ajax'] ) {
wp_localize_script(
'redux-js-button-' . $this->field['id'],
'redux_ajax_script',
array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) )
);
}
}
}
/**
* Enqueue Function.
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
*
* @since 1.0.0
* @access public
* @return void
*/
public function enqueue() {
// Set up min files for dev_mode = false.
$min = Redux_Functions::isMin();
// Field dependent JS.
wp_enqueue_script(
'redux-field-js-button',
// phpcs:ignore WordPress.NamingConventions.ValidHookName
apply_filters( "redux/js_button/{$this->parent->args['opt_name']}/enqueue/redux-field-js-button-js", $this->url . 'redux-js-button' . $min . '.js' ),
array( 'jquery' ),
Redux_Extension_Js_Button::$version,
true
);
}
}
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

View File

@@ -0,0 +1,92 @@
/* global redux, jQuery */
/**
* JS Button library
*
* @author Kevin Provance (kprovance)
*/
( function( $ ) {
'use strict';
redux.field_objects = redux.field_objects || {};
redux.field_objects.js_button = redux.field_objects.js_button || {};
redux.field_objects.js_button.mainID = '';
/*******************************************************************************
* Runs when library is loaded.
******************************************************************************/
redux.field_objects.js_button.init = function( selector ) {
// If no selector is passed, grab one from the HTML.
if ( ! selector ) {
selector = $( document ).find( '.redux-container-js_button' );
}
// Enum instances of our object.
$( selector ).each(
function() {
var button;
var el = $( this );
var parent = el;
if ( ! el.hasClass( 'redux-field-container' ) ) {
parent = el.parents( '.redux-field-container:first' );
}
if ( parent.hasClass( 'redux-field-init' ) ) {
parent.removeClass( 'redux-field-init' );
} else {
return;
}
// Do module level init.
redux.field_objects.js_button.modInit( el );
// Get the button handle.
button = $( el ).find( 'input' );
$.each(
button,
function( key, value ) {
key = null;
$( this ).on(
'click',
function( e ) {
var funcName = $( value ).data( 'function' );
// Not really needed, but just in case.
e.preventDefault();
if ( '' !== funcName ) {
// Ensure custom function exists.
if ( 'function' === typeof ( window[funcName] ) ) {
// Add it to the window object and execute.
window[funcName]();
} else {
// Let the dev know he fucked up someplace.
throw( 'JS Button Error. Function ' + funcName + ' does not exist.' );
}
}
}
);
}
);
}
);
};
/*******************************************************************************
* Module level init
******************************************************************************/
redux.field_objects.js_button.modInit = function( el ) {
// ID of the fieldset.
redux.field_objects.js_button.mainID = el.attr( 'data-id' );
};
} )( jQuery );

View File

@@ -0,0 +1 @@
!function(i){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.js_button=redux.field_objects.js_button||{},redux.field_objects.js_button.mainID="",redux.field_objects.js_button.init=function(t){t=t||i(document).find(".redux-container-js_button"),i(t).each(function(){var t=i(this),e=t;(e=t.hasClass("redux-field-container")?e:t.parents(".redux-field-container:first")).hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),redux.field_objects.js_button.modInit(t),e=i(t).find("input"),i.each(e,function(t,n){i(this).on("click",function(t){var e=i(n).data("function");if(t.preventDefault(),""!==e){if("function"!=typeof window[e])throw"JS Button Error. Function "+e+" does not exist.";window[e]()}})}))})},redux.field_objects.js_button.modInit=function(t){redux.field_objects.js_button.mainID=t.attr("data-id")}}(jQuery);

View File

@@ -0,0 +1,810 @@
<?php // phpcs:ignore WordPress.NamingConventions.ValidFunctionName
/**
* Redux Framework Metaboxes API Class
* Makes instantiating a Redux Metabox object an absolute piece of cake.
*
* @package Redux_Framework
* @author Dovy Paukstys
* @subpackage Core
* @noinspection PhpUnused
*/
defined( 'ABSPATH' ) || exit;
// Don't duplicate me!
if ( ! class_exists( 'Redux_Metaboxes' ) ) {
/**
* Redux Metaboxes API Class
* Simple API for Redux Framework
*
* @since 1.0.0
*/
class Redux_Metaboxes {
/**
* Boxes array.
*
* @var array
*/
public static $boxes = array();
/**
* Sections array.
*
* @var array
*/
public static $sections = array();
/**
* Fields array.
*
* @var array
*/
public static $fields = array();
/**
* Priority array.
*
* @var array
*/
public static $priority = array();
/**
* Errors array.
*
* @var array
*/
public static $errors = array();
/**
* Init array.
*
* @var array
*/
public static $init = array();
/**
* Args array.
*
* @var array
*/
public static $args = array();
/**
* Code has run flag.
*
* @var bool
*/
public static $has_run = false;
/**
* Class load.
*/
public static function load() {
if ( version_compare( PHP_VERSION, '5.5.0', '<' ) ) {
include_once Redux_Core::$dir . 'inc/lib/array-column.php';
}
add_action( 'init', array( 'Redux_Metaboxes', 'enqueue' ), 99 );
}
/**
* Enqueue function.
*
* @throws ReflectionException Exception.
*/
public static function enqueue() {
global $pagenow;
// Check and run instances of Redux where the opt_name hasn't been run.
$pagenows = array( 'post-new.php', 'post.php' );
if ( ! empty( self::$sections ) && in_array( $pagenow, $pagenows, true ) ) {
$instances = ReduxFrameworkInstances::get_all_instances();
foreach ( self::$fields as $opt_name => $fields ) {
if ( ! isset( $instances[ $opt_name ] ) ) {
Redux::set_args(
$opt_name,
array(
'menu_type' => 'hidden',
)
);
Redux::set_sections(
$opt_name,
array(
array(
'id' => 'EXTENSION_FAKE_ID' . $opt_name,
'fields' => $fields,
'title' => 'N/A',
),
)
);
Redux::init( $opt_name );
$instances = ReduxFrameworkInstances::get_all_instances();
add_action( 'admin_enqueue_scripts', array( $instances[ $opt_name ], 'enqueue' ), 1 );
}
}
}
}
/**
* Filter Metaboxes function.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function filterMetaboxes() { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::filter_metaboxes()' );
self::filter_metaboxes();
}
/**
* Filter Metaboxes function.
*/
public static function filter_metaboxes() {
if ( true === self::$has_run ) {
return;
}
if ( ! class_exists( 'ReduxFramework' ) ) {
echo '<div id="message" class="error"><p>Redux Framework is <strong>not installed</strong>. Please install it.</p></div>';
return;
}
foreach ( self::$boxes as $opt_name => $the_boxes ) {
if ( ! self::$init[ $opt_name ] ) {
// phpcs:ignore WordPress.NamingConventions.ValidHookName
add_action( 'redux/metaboxes/' . $opt_name . '/boxes', array( 'Redux_Metaboxes', 'addMetaboxes' ), 2 );
}
}
self::$has_run = true;
}
/**
* Construct the global args array.
*
* @param string $opt_name Panel opt_name.
*
* @return mixed
* @deprecated 4.0.0 No more camelCase.
*/
public static function constructArgs( string $opt_name ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::construct_args( $opt_name )' );
return self::construct_args( $opt_name );
}
/**
* Construct the global args array.
*
* @param string $opt_name Panel opt_name.
*
* @return mixed
*/
public static function construct_args( string $opt_name ) {
Redux_Functions_Ex::record_caller( $opt_name );
$args = self::$args[ $opt_name ];
$args['opt_name'] = $opt_name;
if ( ! isset( $args['menu_title'] ) ) {
$args['menu_title'] = ucfirst( $opt_name ) . ' Options';
}
if ( ! isset( $args['page_title'] ) ) {
$args['page_title'] = ucfirst( $opt_name ) . ' Options';
}
if ( ! isset( $args['page_slug'] ) ) {
$args['page_slug'] = $opt_name . '_options';
}
return $args;
}
/**
* Construct metabox boxes array.
*
* @param string $opt_name Panel opt_name.
*
* @return array
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function constructBoxes( string $opt_name ): array { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::construct_boxes( $opt_name )' );
return self::construct_boxes( $opt_name );
}
/**
* Construct metabox boxes array.
*
* @param string $opt_name Panel opt_name.
*
* @return array
*/
public static function construct_boxes( string $opt_name ): array {
Redux_Functions_Ex::record_caller( $opt_name );
$boxes = array();
if ( ! isset( self::$boxes[ $opt_name ] ) ) {
return $boxes;
}
foreach ( self::$boxes[ $opt_name ] as $box ) {
$box['sections'] = self::construct_sections( $opt_name, $box['id'] );
$boxes[] = $box;
}
ksort( $boxes );
return $boxes;
}
/**
* Construct sections.
*
* @param string $opt_name Panel opt_name.
* @param string $box_id Metabox ID.
*
* @return array
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function constructSections( string $opt_name, string $box_id ): array { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::construct_sections( $opt_name, $box_id )' );
return self::construct_sections( $opt_name, $box_id );
}
/**
* Construct sections.
*
* @param string $opt_name Panel opt_name.
* @param string $box_id Metabox ID.
*
* @return array
*/
public static function construct_sections( string $opt_name, string $box_id ): array {
Redux_Functions_Ex::record_caller( $opt_name );
$sections = array();
if ( ! isset( self::$sections[ $opt_name ] ) ) {
return $sections;
}
foreach ( self::$sections[ $opt_name ] as $section_id => $section ) {
if ( $box_id === $section['box_id'] ) {
$p = $section['priority'];
while ( isset( $sections[ $p ] ) ) {
echo esc_html( $p++ );
}
$section['fields'] = self::construct_fields( $opt_name, $section_id );
$sections[ $p ] = $section;
}
}
ksort( $sections );
return $sections;
}
/**
* Construct fields.
*
* @param string $opt_name Panel opt_name.
* @param string|int $section_id Section ID.
*
* @return array
* @deprecated 4.0.0 No moe camelCase.
*/
public static function constructFields( string $opt_name = '', $section_id = '' ): array { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::construct_fields( $opt_name, $section_id )' );
return self::construct_fields( $opt_name, $section_id );
}
/**
* Construct fields.
*
* @param string $opt_name Panel opt_name.
* @param string|int $section_id Section ID.
*
* @return array
*/
public static function construct_fields( string $opt_name = '', $section_id = '' ): array {
Redux_Functions_Ex::record_caller( $opt_name );
$fields = array();
if ( ! isset( self::$fields[ $opt_name ] ) ) {
return $fields;
}
foreach ( self::$fields[ $opt_name ] as $field ) {
if ( $section_id === $field['section_id'] ) {
$p = $field['priority'];
while ( isset( $fields[ $p ] ) ) {
echo esc_html( $p++ );
}
$fields[ $p ] = $field;
}
}
ksort( $fields );
return $fields;
}
/**
* Retrieve the section array.
*
* @param string $opt_name Panel opt_name.
* @param string|int $id Section ID.
*
* @deprecated 4.0.0 No more camelCase.
*
* @return bool
*/
public static function getSection( string $opt_name = '', $id = '' ): bool { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::get_section( $opt_name, $id )' );
return self::get_section( $opt_name, $id );
}
/**
* Retrieve section ID.
*
* @param string $opt_name Panel opt_name.
* @param string|int $id Section ID.
*
* @return bool
*/
public static function get_section( string $opt_name = '', $id = '' ): bool {
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && ! empty( $id ) ) {
if ( ! isset( self::$sections[ $opt_name ][ $id ] ) ) {
$id = strtolower( sanitize_html_class( $id ) );
}
return self::$sections[ $opt_name ][ $id ] ?? false;
}
return false;
}
/**
* Set section array.
*
* @param string $opt_name Panel opt_name.
* @param array $section Section array.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function setSection( string $opt_name = '', array $section = array() ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::set_section( $opt_name, $section )' );
self::set_section( $opt_name, $section );
}
/**
* Set section array.
*
* @param string $opt_name Panel opt_name.
* @param array $section Section array.
*/
public static function set_section( string $opt_name = '', array $section = array() ) {
Redux_Functions_Ex::record_caller( $opt_name );
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && is_array( $section ) && ! empty( $section ) ) {
if ( ! isset( $section['id'] ) ) {
if ( isset( $section['title'] ) ) {
$section['id'] = strtolower( sanitize_html_class( $section['title'] ) );
} else {
$section['id'] = 'section';
}
if ( isset( self::$sections[ $opt_name ][ $section['id'] ] ) ) {
$orig = $section['id'];
$i = 0;
while ( isset( self::$sections[ $opt_name ][ $section['id'] ] ) ) {
$section['id'] = $orig . '_' . $i;
++$i;
}
}
}
if ( ! isset( $section['priority'] ) ) {
$section['priority'] = self::get_priority( $opt_name, 'sections' );
}
if ( isset( $section['fields'] ) ) {
if ( ! empty( $section['fields'] ) && is_array( $section['fields'] ) ) {
self::process_fields_array( $opt_name, $section['id'], $section['fields'] );
}
unset( $section['fields'] );
}
self::$sections[ $opt_name ][ $section['id'] ] = $section;
} else {
self::$errors[ $opt_name ]['section']['empty'] = esc_html__( 'Unable to create a section due an empty section array or the section variable passed was not an array.', 'redux-framework' );
}
}
/**
* Process section arrays.
*
* @param string $opt_name Panel opt_name.
* @param string|int $box_id Box ID.
* @param array $sections Sections array.
*/
public static function process_sections_array( string $opt_name = '', $box_id = '', array $sections = array() ) {
if ( ! empty( $opt_name ) && ! empty( $box_id ) && is_array( $sections ) && ! empty( $sections ) ) {
foreach ( $sections as $section ) {
if ( ! is_array( $section ) ) {
continue;
}
$section['box_id'] = $box_id;
if ( ! isset( $section['fields'] ) || ! is_array( $section['fields'] ) ) {
$section['fields'] = array();
}
self::set_section( $opt_name, $section );
}
}
}
/**
* Process Field arrays.
*
* @param string $opt_name Panel opt_name.
* @param string|int $section_id Section ID.
* @param array $fields Field arrays.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function processFieldsArray( string $opt_name = '', $section_id = '', array $fields = array() ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::process_fields_array( $opt_name, $section_id, $fields )' );
self::process_fields_array( $opt_name, $section_id, $fields );
}
/**
* Process Field arrays.
*
* @param string $opt_name Panel opt_name.
* @param string|int $section_id Section ID.
* @param array $fields Field arrays.
*/
public static function process_fields_array( string $opt_name = '', $section_id = '', array $fields = array() ) {
if ( ! empty( $opt_name ) && ! empty( $section_id ) && is_array( $fields ) && ! empty( $fields ) ) {
foreach ( $fields as $field ) {
if ( ! is_array( $field ) ) {
continue;
}
$field['section_id'] = $section_id;
self::set_field( $opt_name, $field );
}
}
}
/**
* Retrieves the field array.
*
* @param string $opt_name Panel opt_name.
* @param string|int $id Field ID.
*
* @deprecated 4.0.0 No more camelCase.
*
* @return bool
*/
public static function getField( string $opt_name = '', $id = '' ): bool { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::get_field( $opt_name, $id )' );
return self::get_field( $opt_name, $id );
}
/**
* Retrieves the field array.
*
* @param string $opt_name Panel opt_name.
* @param string|int $id Field ID.
*
* @return bool
*/
public static function get_field( string $opt_name = '', $id = '' ): bool {
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && ! empty( $id ) ) {
return self::$fields[ $opt_name ][ $id ] ?? false;
}
return false;
}
/**
* Set field array.
*
* @param string $opt_name Panel opt_name.
* @param array $field Field array.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function setField( string $opt_name = '', array $field = array() ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::set_field( $opt_name, $field )' );
self::set_field( $opt_name, $field );
}
/**
* Set field array.
*
* @param string $opt_name Panel opt_name.
* @param array $field Field array.
*/
public static function set_field( string $opt_name = '', array $field = array() ) {
Redux_Functions_Ex::record_caller( $opt_name );
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && is_array( $field ) && ! empty( $field ) ) {
if ( ! isset( $field['priority'] ) ) {
$field['priority'] = self::get_priority( $opt_name, 'fields' );
}
self::$fields[ $opt_name ][ $field['id'] ] = $field;
}
}
/**
* Set metabox box.
*
* @param string $opt_name Panel opt_name.
* @param array $box Box array.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function setBox( string $opt_name = '', array $box = array() ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::set_box( $opt_name, $box )' );
self::set_box( $opt_name, $box );
}
/**
* Set metabox box.
*
* @param string $opt_name Panel opt_name.
* @param array $box Box array.
*/
public static function set_box( string $opt_name = '', array $box = array() ) {
Redux_Functions_Ex::record_caller( $opt_name );
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && is_array( $box ) && ! empty( $box ) ) {
if ( ! isset( $box['id'] ) ) {
if ( isset( $box['title'] ) ) {
$box['id'] = strtolower( sanitize_html_class( $box['title'] ) );
} else {
$box['id'] = 'box';
}
if ( isset( self::$boxes[ $opt_name ][ $box['id'] ] ) ) {
$orig = $box['id'];
$i = 0;
while ( isset( self::$boxes[ $opt_name ][ $box['id'] ] ) ) {
$box['id'] = $orig . '_' . $i;
++$i;
}
}
}
if ( isset( $box['sections'] ) ) {
if ( ! empty( $box['sections'] ) && is_array( $box['sections'] ) ) {
self::process_sections_array( $opt_name, $box['id'], $box['sections'] );
}
unset( $box['sections'] );
}
self::$boxes[ $opt_name ][ $box['id'] ] = $box;
} else {
self::$errors[ $opt_name ]['box']['empty'] = esc_html__( 'Unable to create a box due an empty box array or the box variable passed was not an array.', 'redux-framework' );
}
}
/**
* Set Metaboxes.
*
* @param string $opt_name Panel opt_name.
* @param array $boxes Boxes array.
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function setBoxes( string $opt_name = '', array $boxes = array() ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::set_boxes( $opt_name, $boxes )' );
self::set_boxes( $opt_name, $boxes );
}
/**
* Set Metaboxes.
*
* @param string $opt_name Panel opt_name.
* @param array $boxes Boxes array.
*/
public static function set_boxes( string $opt_name = '', array $boxes = array() ) {
Redux_Functions_Ex::record_caller( $opt_name );
if ( ! empty( $boxes ) && is_array( $boxes ) ) {
foreach ( $boxes as $box ) {
self::set_box( $opt_name, $box );
}
}
}
/**
* Retrieve Metabox arrays.
*
* @param string $opt_name Panel opt_name.
*
* @deprecated 4.0.0 No more camelCase.
*
* @return mixed
*/
public static function getBoxes( string $opt_name = '' ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::get_boxes( $opt_name )' );
return self::get_boxes( $opt_name );
}
/**
* Retrieve Metabox arrays.
*
* @param string $opt_name Panel opt_name.
*
* @return mixed
*/
public static function get_boxes( string $opt_name = '' ) {
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && ! empty( self::$boxes[ $opt_name ] ) ) {
return self::$boxes[ $opt_name ];
}
return null;
}
/**
* Get Metabox box.
*
* @param string $opt_name Panel opt_name.
* @param string $key Box key.
*
* @deprecated 4.0.0 No more camelCase.
*
* @return mixed
*/
public static function getBox( string $opt_name = '', string $key = '' ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::get_box( $opt_name, $key )' );
return self::get_box( $opt_name, $key );
}
/**
* Get Metabox box.
*
* @param string $opt_name Panel opt_name.
* @param string $key Box key.
*
* @return mixed
*/
public static function get_box( string $opt_name = '', string $key = '' ) {
self::check_opt_name( $opt_name );
if ( ! empty( $opt_name ) && ! empty( $key ) && ! empty( self::$boxes[ $opt_name ] ) && isset( self::$boxes[ $opt_name ][ $key ] ) ) {
return self::$boxes[ $opt_name ][ $key ];
}
return null;
}
/**
* Get priority.
*
* @param string $opt_name Panel opt_name.
* @param string $type Type.
*
* @return mixed
*
* @deprecated 4.0.0 No more camelCase.
*/
public static function getPriority( string $opt_name, string $type ) { // phpcs:ignore: WordPress.NamingConventions.ValidFunctionName
_deprecated_function( __CLASS__ . '::' . __FUNCTION__, 'Redux 4.3', __CLASS__ . '::get_priority( $opt_name, $type )' );
return self::get_priority( $opt_name, $type );
}
/**
* Get priority.
*
* @param string $opt_name Panel opt_name.
* @param string $type Type.
*
* @return mixed
*/
public static function get_priority( string $opt_name, string $type ) {
$priority = self::$priority[ $opt_name ][ $type ];
self::$priority[ $opt_name ][ $type ] += 1;
return $priority;
}
/**
* Check opt_name.
*
* @param string $opt_name Panel opt_name.
*/
public static function check_opt_name( string $opt_name = '' ) {
if ( empty( $opt_name ) || is_array( $opt_name ) ) {
return;
}
if ( ! isset( self::$boxes[ $opt_name ] ) ) {
self::$boxes[ $opt_name ] = array();
}
if ( ! isset( self::$priority[ $opt_name ] ) ) {
self::$priority[ $opt_name ]['args'] = 1;
}
if ( ! isset( self::$sections[ $opt_name ] ) ) {
self::$sections[ $opt_name ] = array();
self::$priority[ $opt_name ]['sections'] = 1;
}
if ( ! isset( self::$fields[ $opt_name ] ) ) {
self::$fields[ $opt_name ] = array();
self::$priority[ $opt_name ]['fields'] = 1;
}
if ( ! isset( self::$errors[ $opt_name ] ) ) {
self::$errors[ $opt_name ] = array();
}
if ( ! isset( self::$init[ $opt_name ] ) ) {
self::$init[ $opt_name ] = false;
}
if ( ! isset( self::$args[ $opt_name ] ) ) {
self::$args[ $opt_name ] = false;
}
}
}
Redux_Metaboxes::load();
}

View File

@@ -0,0 +1,8 @@
<?php
/**
* Silence is golden.
*
* @package Redux Framework
*/
echo null;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,147 @@
/* global reduxMetaboxes */
jQuery(
function ( $ ) {
'use strict';
var isGutenberg = false;
$.reduxMetaBoxes = $.reduxMetaBoxes || {};
$( document ).ready(
function () {
$.reduxMetaBoxes.init();
if ( $( 'body' ).hasClass( 'block-editor-page' ) ) {
isGutenberg = true;
}
}
);
setTimeout(
function () {
if ( true === isGutenberg ) {
$( '.postbox .toggle-indicator' ).removeClass( 'toggle-indicator' ).addClass( 'el' );
}
$( '#publishing-action .button, #save-action .button, .editor-post-publish-button' ).on(
'click',
function () {
$( '.redux-save-warn' ).slideUp();
window.onbeforeunload = null;
}
);
},
1000
);
$.reduxMetaBoxes.init = function () {
$.reduxMetaBoxes.notLoaded = true;
$.redux.initFields();
if ( $( 'body' ).hasClass( 'block-editor-page' ) ) {
isGutenberg = true;
}
if ( isGutenberg ) {
setTimeout(
function () {
$.reduxMetaBoxes.checkBoxVisibility();
$( '.editor-post-format__content select, .editor-post-format select' ).on(
'change',
function () {
$.reduxMetaBoxes.checkBoxVisibility( 'post_format' );
}
);
$( '.edit-post-post-template__toggle' ).on(
'click',
function () {
setTimeout(
function () {
$( '.components-popover .components-select-control__input' ).on(
'change',
function () {
$.reduxMetaBoxes.checkBoxVisibility( 'page_template' );
}
);
},
1000
);
}
);
},
1000
);
} else {
$.reduxMetaBoxes.checkBoxVisibility();
$( '#page_template' ).on(
'change',
function () {
$.reduxMetaBoxes.checkBoxVisibility( 'page_template' );
}
);
$( 'input[name="post_format"]:radio' ).on(
'change',
function () {
$.reduxMetaBoxes.checkBoxVisibility( 'post_format' );
}
);
}
};
$.reduxMetaBoxes.checkBoxVisibility = function ( fieldID ) {
if ( 0 !== reduxMetaboxes.length ) {
$.each(
reduxMetaboxes,
function ( box, values ) {
$.each(
values,
function ( field, v ) {
var visible = false;
var testValue;
if ( field === fieldID || ! fieldID ) {
if ( 'post_format' === field ) {
if ( isGutenberg ) {
testValue = $( '.editor-post-format__content select option:selected, .editor-post-format select option:Selected' ).val();
} else {
testValue = $( 'input:radio[name="post_format"]:checked' ).val();
}
} else {
testValue = $( '#' + field ).val();
}
if ( testValue ) {
$.each(
v,
function ( key, val ) {
if ( val === testValue ) {
visible = true;
}
}
);
if ( ! visible && ! $.reduxMetaBoxes.notLoaded ) {
$( '#' + box ).hide();
} else if ( ! visible ) {
$( '#' + box ).hide();
} else {
$( '#' + box ).fadeIn( '300' );
$.redux.initFields();
}
}
}
}
);
}
);
}
};
}
);

View File

@@ -0,0 +1 @@
jQuery(function(s){"use strict";var c=!1;s.reduxMetaBoxes=s.reduxMetaBoxes||{},s(document).ready(function(){s.reduxMetaBoxes.init(),s("body").hasClass("block-editor-page")&&(c=!0)}),setTimeout(function(){!0===c&&s(".postbox .toggle-indicator").removeClass("toggle-indicator").addClass("el"),s("#publishing-action .button, #save-action .button, .editor-post-publish-button").on("click",function(){s(".redux-save-warn").slideUp(),window.onbeforeunload=null})},1e3),s.reduxMetaBoxes.init=function(){s.reduxMetaBoxes.notLoaded=!0,s.redux.initFields(),(c=s("body").hasClass("block-editor-page")?!0:c)?setTimeout(function(){s.reduxMetaBoxes.checkBoxVisibility(),s(".editor-post-format__content select, .editor-post-format select").on("change",function(){s.reduxMetaBoxes.checkBoxVisibility("post_format")}),s(".edit-post-post-template__toggle").on("click",function(){setTimeout(function(){s(".components-popover .components-select-control__input").on("change",function(){s.reduxMetaBoxes.checkBoxVisibility("page_template")})},1e3)})},1e3):(s.reduxMetaBoxes.checkBoxVisibility(),s("#page_template").on("change",function(){s.reduxMetaBoxes.checkBoxVisibility("page_template")}),s('input[name="post_format"]:radio').on("change",function(){s.reduxMetaBoxes.checkBoxVisibility("post_format")}))},s.reduxMetaBoxes.checkBoxVisibility=function(a){0!==reduxMetaboxes.length&&s.each(reduxMetaboxes,function(n,e){s.each(e,function(e,t){var o,i=!1;e!==a&&a||(o=s("post_format"===e?c?".editor-post-format__content select option:selected, .editor-post-format select option:Selected":'input:radio[name="post_format"]:checked':"#"+e).val())&&(s.each(t,function(e,t){t===o&&(i=!0)}),(i||s.reduxMetaBoxes.notLoaded)&&i?(s("#"+n).fadeIn("300"),s.redux.initFields()):s("#"+n).hide())})})}});

View File

@@ -0,0 +1,358 @@
.block-editor-page {
.postbox{
&.closed .el {
&:before {
content: ""!important;
}
}
.el{
&:before{
content: ""
}
}
}
}
.postbox {
.redux_field_th {
padding-bottom: 0 !important;
}
.redux-group-tab {
margin-bottom: 0 !important;
}
.redux-container {
filter: none;
border: none;
-moz-border-radius: 0;
/* Firefox */
-webkit-border-radius: 0;
/* Safari, Chrome */
border-radius: 0;
-moz-box-shadow: none;
-webkit-box-shadow: none;
box-shadow: none;
.redux-group-menu .active a {
background: #FFF;
}
.redux-section-title {
padding-left: 0 !important;
margin-bottom: 15px !important;
}
.redux-section-desc {
margin-bottom: 20px;
}
.redux_main {
border-left: 1px solid #D8D8D8;
-webkit-box-shadow: none;
box-shadow: none;
input[type=text] {
width: 95%;
}
}
&.redux-no-sections {
margin: 0;
background: none;
.redux-main {
background: none;
margin-left: inherit;
padding: inherit;
border-left: none !important;
min-height: 0 !important;
tr {
&:last-child {
border-bottom: none;
}
&:last-child {
th,
td {
padding-bottom: 0;
}
}
td {
//padding-top: 20px !important;
padding-top: 10px !important;
width: 100%;
}
}
.form-table:first-child tr:first-child td {
padding-top: 0 !important;
}
.redux-field {
margin-bottom: 10px !important;
}
.redux-field:last-child {
margin-bottom: 0 !important;
}
}
}
&.redux-has-sections {
.redux-main {
background: #fff;
span.description {
padding-bottom: 20px;
}
}
}
}
.redux-main h3 {
cursor: text !important;
-webkit-user-select: inherit !important;
-moz-user-select: inherit !important;
user-select: inherit !important;
padding-left: 0 !important;
}
}
.redux-box-side {
.redux-main {
.redux-field-container {
padding: 5px 0 0;
.select2-container,
select {
width: 100% !important;
}
}
}
.form-table {
tr {
td {
padding: 15px 0 !important;
}
&:last-child td {
padding-bottom: 0 !important;
}
&:first-child td {
padding-top: 5px !important;
}
}
}
}
#poststuff .redux-metabox h3.hndle,
.metabox-holder .redux-metabox h3.hndle {
cursor: pointer;
border-bottom: 0;
}
.display-group {
display: inherit !important;
}
/* Metaboxes CSS overrides */
@media (min-width: 1125px) and (max-width: 1405px) {
.postbox {
table.form-table,
.form-table > thead,
.form-table > tbody,
.form-table > tbody > tr > th,
.form-table > tbody > tr > td,
.form-table > tbody > tr {
display: block !important;
width: 100% !important;
padding: 0 !important;
&.hide {
display: none !important;
}
}
.form-table > tbody > tr {
> th,
> td {
padding: 10px !important;
}
}
.form-table > tbody > tr > th {
width: 35%;
}
}
}
.redux-metabox .form-table th,
.redux-metabox .form-table td {
margin: 0;
padding: 0;
/* width: auto;*/
}
.redux-box-side .redux-main .redux-field-container {
.select2-container,
select {
width: 96% !important;
}
}
@media (max-width: 1405px) {
.redux-box-side .redux-main .redux-field-container {
.select2-container,
select {
width: 92% !important;
}
}
}
@media (max-width: 1125px) {
.redux-box-side .redux-main .redux-field-container {
.select2-container,
select {
width: 100% !important;
}
}
}
@media (max-width: 1405px) {
.redux-main {
.form-table > tbody > tr > td {
padding-top: 0 !important;
padding-bottom: 0 !important;
}
.redux-field-container {
padding: 0 0 20px 0 !important;
padding-bottom: 10px !important;
}
}
.postbox .form-table > tbody > tr > th {
padding-bottom: 0 !important;
}
.redux_field_th {
padding-top: 0 !important;
padding-bottom: 10px !important;
}
}
.redux-no-sections .redux-group-tab {
display: block !important;
}
@mixin metaboxesAdminThemeColorOverrides ($darkColor, $textColor) {
#poststuff .redux-metabox h3.hndle,
.metabox-holder .redux-metabox h3.hndle {
background: $darkColor;
color: $textColor;
}
}
/* Light fresh theme */
.admin-color-fresh {
@include metaboxesAdminThemeColorOverrides(#222222, #fff);
}
/* Light admin theme */
.admin-color-light {
@include metaboxesAdminThemeColorOverrides(#888888, #fff);
}
/* Blue admin theme */
.admin-color-blue {
@include metaboxesAdminThemeColorOverrides(#096484, #fff);
}
/* Coffee admin theme */
.admin-color-coffee {
@include metaboxesAdminThemeColorOverrides(#46403c, #fff);
}
/* Ectoplasm admin theme */
.admin-color-ectoplasm {
@include metaboxesAdminThemeColorOverrides(#413256, #fff);
}
/* Midnight admin theme */
.admin-color-midnight {
@include metaboxesAdminThemeColorOverrides(#363b3f, #fff);
}
/* Ocean admin theme */
.admin-color-ocean {
@include metaboxesAdminThemeColorOverrides(#627c83, #fff);
}
/* Sunrise admin theme */
.admin-color-sunrise {
@include metaboxesAdminThemeColorOverrides(#b43c38, #fff);
}
.redux-notices {
margin-bottom: 0;
border: 0;
}
.redux-metabox {
.redux-container {
margin-top: 0;
}
.inside {
margin: 0 !important;
padding: 0 !important;
}
.redux-no-sections {
.redux-main {
padding: 6px 15px 15px 15px !important;
.default_br {
display: none;
}
.redux-field-container {
padding: 10px 0 20px !important;
}
.redux_field_th {
padding-top: 5px !important;
}
}
&.redux-box-side {
.redux-main {
padding: 6px 8px 8px 8px !important;
input[type=text] {
width: 100% !important;
}
}
}
}
}
.wp-color-result {
margin: 0 6px 0 0 !important;
}
.redux-container .ui-button-text-only .ui-button-text {
padding: 0;
}
.wpseotab tr {
display: table-row !important
}

View File

@@ -0,0 +1,54 @@
<?php
/**
* Redux Metabox Extension Helpers
*
* @package Redux
*/
defined( 'ABSPATH' ) || exit;
if ( ! function_exists( 'redux_metaboxes_loop_start' ) ) {
/**
* Start loop.
*
* @param string $opt_name Panel opt_name.
* @param array $the_post Post object.
*/
function redux_metaboxes_loop_start( string $opt_name, array $the_post = array() ) {
$redux = ReduxFrameworkInstances::get_instance( $opt_name );
$metaboxes = $redux->extensions['metaboxes'];
$metaboxes->loop_start( $the_post );
}
}
if ( ! function_exists( 'redux_metaboxes_loop_end' ) ) {
/**
* End loop.
*
* @param string $opt_name Panel opt_name.
* @param array $the_post Post object.
*/
function redux_metaboxes_loop_end( string $opt_name, array $the_post = array() ) {
$redux = ReduxFrameworkInstances::get_instance( $opt_name );
$metaboxes = $redux->extensions['metaboxes'];
$metaboxes->loop_end();
}
}
if ( ! function_exists( 'redux_post_meta' ) ) {
/**
* Retrieve post meta values/settings.
*
* @param string $opt_name Panel opt_name.
* @param mixed $the_post Post ID.
* @param string $meta_key Meta key.
* @param mixed $def_val Default value.
*
* @return string|void
*/
function redux_post_meta( string $opt_name = '', $the_post = array(), string $meta_key = '', $def_val = '' ) {
return Redux::get_post_meta( $opt_name, $the_post, $meta_key, $def_val );
}
}

Some files were not shown because too many files have changed in this diff Show More