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,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;