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:
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
/**
|
||||
* Switch Field
|
||||
*
|
||||
* @package Redux Framework
|
||||
* @author Dovy Paukstys & Kevin Provance (kprovance)
|
||||
* @version 4.0.0
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! class_exists( 'Redux_Switch', false ) ) {
|
||||
|
||||
/**
|
||||
* Class Redux_Switch
|
||||
*/
|
||||
class Redux_Switch extends Redux_Field {
|
||||
|
||||
/**
|
||||
* Field Render Function.
|
||||
* Takes the vars and outputs the HTML for the field in the settings
|
||||
*
|
||||
* @since ReduxFramework 0.0.4
|
||||
*/
|
||||
public function render() {
|
||||
$cb_enabled = '';
|
||||
$cb_disabled = '';
|
||||
|
||||
// Get selected.
|
||||
if ( 1 === (int) $this->value ) {
|
||||
$cb_enabled = ' selected';
|
||||
} else {
|
||||
$cb_disabled = ' selected';
|
||||
}
|
||||
|
||||
// Label ON.
|
||||
$this->field['on'] = $this->field['on'] ?? esc_html__( 'On', 'redux-framework' );
|
||||
|
||||
// Label OFF.
|
||||
$this->field['off'] = $this->field['off'] ?? esc_html__( 'Off', 'redux-framework' );
|
||||
|
||||
echo '<div class="switch-options">';
|
||||
echo '<div class="cb-enable label' . esc_attr( $cb_enabled ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"><span>' . esc_html( $this->field['on'] ) . '</span></div>';
|
||||
echo '<div class="cb-disable label' . esc_attr( $cb_disabled ) . '" data-id="' . esc_attr( $this->field['id'] ) . '"><span>' . esc_html( $this->field['off'] ) . '</span></div>';
|
||||
echo '<input type="hidden" class="checkbox checkbox-input ' . esc_attr( $this->field['class'] ) . '" id="' . esc_attr( $this->field['id'] ) . '" name="' . esc_attr( $this->field['name'] . $this->field['name_suffix'] ) . '" value="' . esc_attr( $this->value ) . '" />';
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue Function.
|
||||
* If this field requires any scripts, or css define this function and register/enqueue the scripts/css
|
||||
*
|
||||
* @since ReduxFramework 0.0.4
|
||||
*/
|
||||
public function enqueue() {
|
||||
wp_enqueue_script(
|
||||
'redux-field-switch',
|
||||
Redux_Core::$url . 'inc/fields/switch/redux-switch' . Redux_Functions::is_min() . '.js',
|
||||
array( 'jquery', 'redux-js' ),
|
||||
$this->timestamp,
|
||||
true
|
||||
);
|
||||
|
||||
if ( $this->parent->args['dev_mode'] ) {
|
||||
wp_enqueue_style(
|
||||
'redux-field-switch',
|
||||
Redux_Core::$url . 'inc/fields/switch/redux-switch.css',
|
||||
array(),
|
||||
$this->timestamp
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class_alias( 'Redux_Switch', 'ReduxFramework_Switch' );
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
_deprecated_file( 'field_spinner.php', '4.3', 'class-redux-spinner.php', 'This file has been renamed and is no longer used in Redux 4. Please change any references to it as it will be removed in future versions of Redux.' );
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -0,0 +1,23 @@
|
||||
.redux-container-switch .switch-options { min-height: 30px; margin-right: 10px; }
|
||||
|
||||
.redux-container-switch .switch-options .label { cursor: pointer; }
|
||||
|
||||
.redux-container-switch .switch-options input { display: none; }
|
||||
|
||||
.redux-container-switch .cb-enable, .redux-container-switch .cb-disable { padding: 0 10px; border-width: 1px; border-style: solid; -webkit-appearance: none; white-space: nowrap; -webkit-box-sizing: border-box; box-sizing: border-box; }
|
||||
|
||||
.redux-container-switch .cb-enable span, .redux-container-switch .cb-disable span { line-height: 30px; display: block; font-weight: 700; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; }
|
||||
|
||||
.redux-container-switch .cb-enable, .redux-container-switch .cb-disable, .redux-container-switch .cb-enable span, .redux-container-switch .cb-disable span { display: block; float: left; }
|
||||
|
||||
.redux-container-switch .cb-enable { border-right: 0; border-radius: 3px 0 0 3px; -moz-border-radius: 3px 0 0 3px; -webkit-border-radius: 3px 0 0 3px; }
|
||||
|
||||
.redux-container-switch .cb-enable.selected { color: #fff; }
|
||||
|
||||
.redux-container-switch .cb-disable { border-left: 0; border-radius: 0 3px 3px 0; -moz-border-radius: 0 3px 3px 0; -webkit-border-radius: 0 3px 3px 0; }
|
||||
|
||||
.redux-container-switch .cb-disable.selected { color: #fff; }
|
||||
|
||||
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtc3dpdGNoLmNzcyIsInNvdXJjZXMiOlsicmVkdXgtc3dpdGNoLnNjc3MiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsQUFDSSx1QkFEbUIsQ0FDbkIsZUFBZSxDQUFDLEVBQ1osVUFBVSxFQUFFLElBQUksRUFDaEIsWUFBWSxFQUFFLElBQUksR0FTckI7O0FBWkwsQUFLUSx1QkFMZSxDQUNuQixlQUFlLENBSVgsTUFBTSxDQUFDLEVBQ0gsTUFBTSxFQUFFLE9BQU8sR0FDbEI7O0FBUFQsQUFTUSx1QkFUZSxDQUNuQixlQUFlLENBUVgsS0FBSyxDQUFDLEVBQ0YsT0FBTyxFQUFFLElBQUksR0FDaEI7O0FBWFQsQUFjSSx1QkFkbUIsQ0FjbkIsVUFBVSxFQWRkLHVCQUF1QixDQWVuQixXQUFXLENBQUMsRUFDUixPQUFPLEVBQUUsTUFBTSxFQUNmLFlBQVksRUFBRSxHQUFHLEVBQ2pCLFlBQVksRUFBRSxLQUFLLEVBQ25CLGtCQUFrQixFQUFFLElBQUksRUFDeEIsV0FBVyxFQUFFLE1BQU0sRUFDbkIsVUFBVSxFQUFFLFVBQVUsR0FXekI7O0FBaENMLEFBdUJRLHVCQXZCZSxDQWNuQixVQUFVLENBU04sSUFBSSxFQXZCWix1QkFBdUIsQ0FlbkIsV0FBVyxDQVFQLElBQUksQ0FBQyxFQUNELFdBQVcsRUFBRSxJQUFJLEVBQ2pCLE9BQU8sRUFBRSxLQUFLLEVBQ2QsV0FBVyxFQUFFLEdBQUcsRUFDaEIsbUJBQW1CLEVBQUUsSUFBSSxFQUN6QixnQkFBZ0IsRUFBRSxJQUFJLEVBQ3RCLGVBQWUsRUFBRSxJQUFJLEVBQ3JCLFdBQVcsRUFBRSxJQUFJLEdBQ3BCOztBQS9CVCxBQWtDSSx1QkFsQ21CLENBa0NuQixVQUFVLEVBbENkLHVCQUF1QixDQW1DbkIsV0FBVyxFQW5DZix1QkFBdUIsQ0FvQ25CLFVBQVUsQ0FBQyxJQUFJLEVBcENuQix1QkFBdUIsQ0FxQ25CLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFDYixPQUFPLEVBQUUsS0FBSyxFQUNkLEtBQUssRUFBRSxJQUFJLEdBQ2Q7O0FBeENMLEFBMENJLHVCQTFDbUIsQ0EwQ25CLFVBQVUsQ0FBQyxFQUNQLFlBQVksRUFBRSxDQUFDLEVBQ2YsYUFBYSxFQUFFLFdBQVcsRUFDMUIsa0JBQWtCLEVBQUUsV0FBVyxFQUMvQixxQkFBcUIsRUFBRSxXQUFXLEdBS3JDOztBQW5ETCxBQWdEUSx1QkFoRGUsQ0EwQ25CLFVBQVUsQUFNTCxTQUFTLENBQUMsRUFDUCxLQUFLLEVBQUUsSUFBSSxHQUNkOztBQWxEVCxBQXFESSx1QkFyRG1CLENBcURuQixXQUFXLENBQUMsRUFDUixXQUFXLEVBQUUsQ0FBQyxFQUNkLGFBQWEsRUFBRSxXQUFXLEVBQzFCLGtCQUFrQixFQUFFLFdBQVcsRUFDL0IscUJBQXFCLEVBQUUsV0FBVyxHQUtyQzs7QUE5REwsQUEyRFEsdUJBM0RlLENBcURuQixXQUFXLEFBTU4sU0FBUyxDQUFDLEVBQ1AsS0FBSyxFQUFFLElBQUksR0FDZCJ9 */
|
||||
|
||||
/*# sourceMappingURL=redux-switch.css.map */
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,96 @@
|
||||
/*global redux_change, redux*/
|
||||
|
||||
/**
|
||||
* Switch
|
||||
* Dependencies : jquery
|
||||
* Feature added by : Smartik - http://smartik.ws/
|
||||
* Date : 03.17.2013
|
||||
*/
|
||||
|
||||
(function( $ ) {
|
||||
'use strict';
|
||||
|
||||
redux.field_objects = redux.field_objects || {};
|
||||
redux.field_objects.switch = redux.field_objects.switch || {};
|
||||
|
||||
redux.field_objects.switch.init = function( selector ) {
|
||||
selector = $.redux.getSelector( selector, 'switch' );
|
||||
|
||||
$( 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( '.cb-enable' ).on(
|
||||
'click',
|
||||
function() {
|
||||
var parent;
|
||||
var obj;
|
||||
var $fold;
|
||||
|
||||
if ( $( this ).hasClass( 'selected' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent = $( this ).parents( '.switch-options' );
|
||||
|
||||
$( '.cb-disable', parent ).removeClass( 'selected' );
|
||||
$( this ).addClass( 'selected' );
|
||||
$( '.checkbox-input', parent ).val( 1 ).trigger( 'change' );
|
||||
|
||||
redux_change( $( '.checkbox-input', parent ) );
|
||||
|
||||
// Fold/unfold related options.
|
||||
obj = $( this );
|
||||
$fold = '.f_' + obj.data( 'id' );
|
||||
|
||||
el.find( $fold ).slideDown( 'normal', 'swing' );
|
||||
}
|
||||
);
|
||||
|
||||
el.find( '.cb-disable' ).on(
|
||||
'click',
|
||||
function() {
|
||||
var parent;
|
||||
var obj;
|
||||
var $fold;
|
||||
|
||||
if ( $( this ).hasClass( 'selected' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent = $( this ).parents( '.switch-options' );
|
||||
|
||||
$( '.cb-enable', parent ).removeClass( 'selected' );
|
||||
$( this ).addClass( 'selected' );
|
||||
$( '.checkbox-input', parent ).val( 0 ).trigger( 'change' );
|
||||
|
||||
redux_change( $( '.checkbox-input', parent ) );
|
||||
|
||||
// Fold/unfold related options.
|
||||
obj = $( this );
|
||||
$fold = '.f_' + obj.data( 'id' );
|
||||
|
||||
el.find( $fold ).slideUp( 'normal', 'swing' );
|
||||
}
|
||||
);
|
||||
|
||||
el.find( '.cb-enable span, .cb-disable span' ).find().attr( 'unselectable', 'on' );
|
||||
}
|
||||
);
|
||||
};
|
||||
})( jQuery );
|
||||
1
wp-content/plugins/eagle-booking/include/redux/inc/fields/switch/redux-switch.min.js
vendored
Normal file
1
wp-content/plugins/eagle-booking/include/redux/inc/fields/switch/redux-switch.min.js
vendored
Normal file
@@ -0,0 +1 @@
|
||||
!function(i){"use strict";redux.field_objects=redux.field_objects||{},redux.field_objects.switch=redux.field_objects.switch||{},redux.field_objects.switch.init=function(e){e=i.redux.getSelector(e,"switch"),i(e).each(function(){var s=i(this),e=s;(e=s.hasClass("redux-field-container")?e:s.parents(".redux-field-container:first")).is(":hidden")||e.hasClass("redux-field-init")&&(e.removeClass("redux-field-init"),s.find(".cb-enable").on("click",function(){var e;i(this).hasClass("selected")||(e=i(this).parents(".switch-options"),i(".cb-disable",e).removeClass("selected"),i(this).addClass("selected"),i(".checkbox-input",e).val(1).trigger("change"),redux_change(i(".checkbox-input",e)),e=".f_"+i(this).data("id"),s.find(e).slideDown("normal","swing"))}),s.find(".cb-disable").on("click",function(){var e;i(this).hasClass("selected")||(e=i(this).parents(".switch-options"),i(".cb-enable",e).removeClass("selected"),i(this).addClass("selected"),i(".checkbox-input",e).val(0).trigger("change"),redux_change(i(".checkbox-input",e)),e=".f_"+i(this).data("id"),s.find(e).slideUp("normal","swing"))}),s.find(".cb-enable span, .cb-disable span").find().attr("unselectable","on"))})}}(jQuery);
|
||||
@@ -0,0 +1,64 @@
|
||||
.redux-container-switch {
|
||||
.switch-options {
|
||||
min-height: 30px;
|
||||
margin-right: 10px;
|
||||
|
||||
.label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
input {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cb-enable,
|
||||
.cb-disable {
|
||||
padding: 0 10px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
-webkit-appearance: none;
|
||||
white-space: nowrap;
|
||||
box-sizing: border-box;
|
||||
|
||||
span {
|
||||
line-height: 30px;
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
}
|
||||
|
||||
.cb-enable,
|
||||
.cb-disable,
|
||||
.cb-enable span,
|
||||
.cb-disable span {
|
||||
display: block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.cb-enable {
|
||||
border-right: 0;
|
||||
border-radius: 3px 0 0 3px;
|
||||
-moz-border-radius: 3px 0 0 3px;
|
||||
-webkit-border-radius: 3px 0 0 3px;
|
||||
|
||||
&.selected {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.cb-disable {
|
||||
border-left: 0;
|
||||
border-radius: 0 3px 3px 0;
|
||||
-moz-border-radius: 0 3px 3px 0;
|
||||
-webkit-border-radius: 0 3px 3px 0;
|
||||
|
||||
&.selected {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user