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,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' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -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 ) . '"
|
||||
/> ';
|
||||
}
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
/**
|
||||
* Silence is golden.
|
||||
*
|
||||
* @package Redux Framework
|
||||
*/
|
||||
|
||||
echo null;
|
||||
@@ -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 );
|
||||
@@ -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);
|
||||
Reference in New Issue
Block a user