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,90 @@
|
||||
<?php
|
||||
/**
|
||||
* Redux Options Object Extension Class
|
||||
*
|
||||
* @class Redux_Core
|
||||
* @version 4.0.0
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
// Don't duplicate me!
|
||||
if ( ! class_exists( 'Redux_Extension_Options_Object', false ) ) {
|
||||
|
||||
|
||||
/**
|
||||
* Main ReduxFramework options_object extension class
|
||||
*
|
||||
* @since 3.1.6
|
||||
*/
|
||||
class Redux_Extension_Options_Object extends Redux_Extension_Abstract {
|
||||
|
||||
/**
|
||||
* Ext version.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public static $version = '4.0.0';
|
||||
|
||||
/**
|
||||
* Set the name of the field. Ideally, this will also be your extension's name.
|
||||
* Please use underscores and NOT dashes.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $field_name = 'options_object';
|
||||
|
||||
/**
|
||||
* Is field bit.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $is_field = false;
|
||||
|
||||
/**
|
||||
* Class Constructor. Defines the args for the extensions class
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
*
|
||||
* @param object $redux Redux object.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $redux ) {
|
||||
parent::__construct( $redux, __FILE__ );
|
||||
|
||||
$this->add_field( $this->field_name );
|
||||
$this->is_field = Redux_Helpers::is_field_in_use( $redux, $this->field_name );
|
||||
|
||||
if ( ! $this->is_field && $this->parent->args['dev_mode'] && $this->parent->args['show_options_object'] ) {
|
||||
$this->add_section();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add section to panel.
|
||||
*/
|
||||
public function add_section() {
|
||||
$this->parent->sections[] = array(
|
||||
'id' => 'options-object',
|
||||
'title' => esc_html__( 'Options Object', 'redux-framework' ),
|
||||
'heading' => '',
|
||||
'icon' => 'el el-info-circle',
|
||||
'customizer' => false,
|
||||
'fields' => array(
|
||||
array(
|
||||
'id' => 'redux_options_object',
|
||||
'type' => 'options_object',
|
||||
'title' => '',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ReduxFramework_Extension_options_object' ) ) {
|
||||
class_alias( 'Redux_Extension_Options_Object', 'ReduxFramework_Extension_options_object' );
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* Debug Options Object
|
||||
*
|
||||
* @package ReduxFramework
|
||||
* @author Kevin Provance (kprovance)
|
||||
* @version 3.5.4
|
||||
*
|
||||
* @noinspection ALL
|
||||
*/
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
// Don't duplicate me!
|
||||
if ( ! class_exists( 'Redux_Options_Object', false ) ) {
|
||||
|
||||
/**
|
||||
* Main Redux_options_object class
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
class Redux_Options_Object extends Redux_Field {
|
||||
|
||||
public $is_field;
|
||||
|
||||
/**
|
||||
* Redux_Options_Object constructor.
|
||||
*
|
||||
* @param array $field Field array.
|
||||
* @param mixed $value Value array.
|
||||
* @param object $parent ReduxFramework object.
|
||||
*
|
||||
* @throws ReflectionException .
|
||||
*/
|
||||
public function __construct( array $field, $value, $parent ) {
|
||||
parent::__construct( $field, $value, $parent );
|
||||
|
||||
$this->is_field = $this->parent->extensions['options_object']->is_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set field defaults.
|
||||
*/
|
||||
public function set_defaults() {
|
||||
$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
|
||||
*
|
||||
* @since 1.0.0
|
||||
* @access public
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
if ( version_compare( phpversion(), '5.3.0', '>=' ) ) {
|
||||
$json = wp_json_encode( $this->parent->options, true );
|
||||
} else {
|
||||
$json = wp_json_encode( $this->parent->options );
|
||||
}
|
||||
|
||||
$defaults = array(
|
||||
'full_width' => true,
|
||||
'overflow' => 'inherit',
|
||||
);
|
||||
|
||||
$this->field = wp_parse_args( $this->field, $defaults );
|
||||
|
||||
if ( $this->is_field ) {
|
||||
$full_width = $this->field['full_width'];
|
||||
}
|
||||
|
||||
$do_close = false;
|
||||
|
||||
$id = $this->parent->args['opt_name'] . '-' . $this->field['id'];
|
||||
|
||||
if ( ! $this->is_field || ( $this->is_field && false === $full_width ) ) {
|
||||
?>
|
||||
<style>#<?php echo esc_html( $id ); ?>{padding: 0;}</style>
|
||||
<?php // phpcs:ignore WordPress.CodeAnalysis.EmptyStatement ?>
|
||||
<?php echo '</td></tr></table>'; ?>
|
||||
<table id="<?php echo esc_attr( $id ); ?>" class="form-table no-border redux-group-table redux-raw-table" style=" overflow: <?php esc_attr( $this->field['overflow'] ); ?>;">
|
||||
<tbody><tr><td>
|
||||
<?php
|
||||
$do_close = true;
|
||||
}
|
||||
?>
|
||||
<fieldset
|
||||
id="<?php echo esc_attr( $id ); ?>-fieldset"
|
||||
class="redux-field redux-container-<?php echo esc_attr( $this->field['type'] ) . ' ' . esc_attr( $this->field['class'] ); ?>"
|
||||
data-id="<?php echo esc_attr( $this->field['id'] ); ?>">
|
||||
|
||||
<h3><?php esc_html_e( 'Options Object', 'redux-framework' ); ?></h3>
|
||||
<div id="redux-object-browser"></div>
|
||||
<div id="redux-object-json" class="hide"><?php echo( $json ); // phpcs:ignore WordPress.Security.EscapeOutput ?></div>
|
||||
<a
|
||||
href="#" id="consolePrintObject"
|
||||
class="button">
|
||||
<?php esc_html_e( 'Show Object in Javascript Console Object', 'redux-framework' ); ?></a>
|
||||
|
||||
</fieldset>
|
||||
<?php if ( true === $do_close ) { ?>
|
||||
</td></tr></table>
|
||||
<table class="form-table no-border" style="margin-top: 0;">
|
||||
<tbody>
|
||||
<tr style="border-bottom: 0;">
|
||||
<th></th>
|
||||
<td>
|
||||
<?php } ?>
|
||||
<?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() {
|
||||
wp_enqueue_script(
|
||||
'redux-extension-options-object',
|
||||
$this->url . 'redux-options-object' . Redux_Functions::is_min() . '.js',
|
||||
array( 'jquery', 'redux-js' ),
|
||||
Redux_Extension_Options_Object::$version,
|
||||
true
|
||||
);
|
||||
|
||||
if ( $this->parent->args['dev_mode'] ) {
|
||||
wp_enqueue_style(
|
||||
'redux-options-object',
|
||||
$this->url . 'redux-options-object.css',
|
||||
array(),
|
||||
Redux_Extension_Options_Object::$version,
|
||||
'all'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -0,0 +1,5 @@
|
||||
#redux-object-browser { overflow: auto; word-wrap: break-word; max-height: 600px; max-width: 100%; }
|
||||
|
||||
/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtb3B0aW9ucy1vYmplY3QuY3NzIiwic291cmNlcyI6WyJyZWR1eC1vcHRpb25zLW9iamVjdC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLEFBQUEscUJBQXFCLENBQUMsRUFDbEIsUUFBUSxFQUFFLElBQUksRUFDZCxTQUFTLEVBQUUsVUFBVSxFQUNyQixVQUFVLEVBQUUsS0FBSyxFQUNqQixTQUFTLEVBQUUsSUFBSSxHQUNsQiJ9 */
|
||||
|
||||
/*# sourceMappingURL=redux-options-object.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["redux-options-object.scss","redux-options-object.css"],"names":[],"mappings":"AAAA,wBCCI,cAAc,EACd,qBAAqB,EACrB,iBAAiB,EACjB,eAAe,EAAA;;AAFnB,yWAAyW","file":"redux-options-object.css","sourcesContent":["#redux-object-browser {\r\n overflow: auto;\r\n word-wrap: break-word;\r\n max-height: 600px;\r\n max-width: 100%;\r\n}\r\n\r\n","#redux-object-browser { overflow: auto; word-wrap: break-word; max-height: 600px; max-width: 100%; }\n\n/*# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVkdXgtb3B0aW9ucy1vYmplY3QuY3NzIiwic291cmNlcyI6WyJyZWR1eC1vcHRpb25zLW9iamVjdC5zY3NzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLEFBQUEscUJBQXFCLENBQUMsRUFDbEIsUUFBUSxFQUFFLElBQUksRUFDZCxTQUFTLEVBQUUsVUFBVSxFQUNyQixVQUFVLEVBQUUsS0FBSyxFQUNqQixTQUFTLEVBQUUsSUFBSSxHQUNsQiJ9 */\n\n/*# sourceMappingURL=redux-options-object.css.map */\n"]}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*global redux, jsonView */
|
||||
|
||||
(function( $ ) {
|
||||
redux.field_objects = redux.field_objects || {};
|
||||
redux.field_objects.options_object = redux.field_objects.options_object || {};
|
||||
|
||||
redux.field_objects.options_object.init = function( selector ) {
|
||||
var parent;
|
||||
|
||||
selector = $.redux.getSelector( selector, 'options_object' );
|
||||
|
||||
parent = selector;
|
||||
|
||||
if ( ! selector.hasClass( 'redux-field-container' ) ) {
|
||||
parent = selector.parents( '.redux-field-container:first' );
|
||||
}
|
||||
|
||||
if ( parent.hasClass( 'redux-field-init' ) ) {
|
||||
parent.removeClass( 'redux-field-init' );
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
$( '#consolePrintObject' ).on(
|
||||
'click',
|
||||
function( e ) {
|
||||
e.preventDefault();
|
||||
console.log( JSON.parse( $( '#redux-object-json' ).html() ) );
|
||||
}
|
||||
);
|
||||
|
||||
if ( 'function' === typeof jsonView ) {
|
||||
jsonView( '#redux-object-json', '#redux-object-browser' );
|
||||
}
|
||||
};
|
||||
})( jQuery );
|
||||
@@ -0,0 +1 @@
|
||||
!function(t){redux.field_objects=redux.field_objects||{},redux.field_objects.options_object=redux.field_objects.options_object||{},redux.field_objects.options_object.init=function(e){var o;(o=(o=e=t.redux.getSelector(e,"options_object")).hasClass("redux-field-container")?o:e.parents(".redux-field-container:first")).hasClass("redux-field-init")&&(o.removeClass("redux-field-init"),t("#consolePrintObject").on("click",function(e){e.preventDefault(),console.log(JSON.parse(t("#redux-object-json").html()))}),"function"==typeof jsonView)&&jsonView("#redux-object-json","#redux-object-browser")}}(jQuery);
|
||||
@@ -0,0 +1,7 @@
|
||||
#redux-object-browser {
|
||||
overflow: auto;
|
||||
word-wrap: break-word;
|
||||
max-height: 600px;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user