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,457 @@
<?php
/**
* CMB2 Tabs.
*
* @package WordPress\Plugins\CMB2 Tabs
* @author Team StackAdroit <stackstudio@stackadroit.com>
* @link https://stackadroit.com
* @version 1.0.6
*
* @copyright 2017 Team StackAdroit
* @license http://creativecommons.org/licenses/GPL/2.0/ GNU General Public License, version 3 or higher
*
* @wordpress-plugin
* Plugin Name: CMB2 Tabs
* Plugin URI: https://github.com/stackadroit/cmb2-extensions
* Description: CMB2 Tabs is an extension for CMB2 which allow you to organize fields into tabs.
* Author: Team StackAdroit <stackstudio@stackadroit.com>
* Author URI: https://stackadroit.com
* Github Plugin URI: https://github.com/stackadroit/cmb2-extensions
* Github Branch: master
* Version: 1.0.6
* License: GPL v3
*
* Copyright (C) 2017, Team StackAdroit - stackstudio@stackadroit.com
*
* GNU General Public License, Free Software Foundation <http://creativecommons.org/licenses/GPL/3.0/>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
if (!class_exists('CMB2_Tabs', false)) {
/**
* Class CMB2_Tabs
*
* @since 1.0.0
*
* @category WordPress_Plugin
* @package CMB2 Tabs
* @author Team StackAdroit
* @license GPL-3.0+
* @link https://stackadroit.com
*/
class CMB2_Tabs {
/**
* Priority on which our actions are hooked in.
*
* @const int
* @since 1.0.0
*/
const PRIORITY = 99996;
/**
* Current version number
*
* @const string
* @since 1.0.0
*/
const VERSION = '1.0.6';
/**
* The url which is used to load local resources
*
* @var string
* @since 1.0.0
*/
protected static $url = '';
/**
* Current CMB2 instance
*
* @var CMB2
* @since 1.0.0
*/
protected static $cmb = '';
/**
* Indicate that the instance of the class is working on a meta box that has tabs or not
* It will be set 'true' BEFORE meta box is display and 'false' AFTER
*
* @var boolean
* @since 1.0.0
*/
public $active = false;
/**
* Active Panel
*
* @var string
* @since 1.0.0
*/
public $active_panel = '';
/**
* Deactive Conditional tabs "show_on_cb"
*
* @var array
* @since 1.0.0
*/
public $conditional = array();
/**
* Store all output of fields
* This is used to put fields in correct <div> for tabs
*
* @var array
* @since 1.0.0
*/
public $fields_output = array();
/**
* Initialize the hooking into CMB2
*
* @since 1.0.0
*/
public function __construct() {
// Hook all the functions
add_action('cmb2_before_form', array($this, 'opening_div'), 10, 4);
add_action('cmb2_after_form', array($this, 'closing_div'), 20, 4);
add_action('cmb2_before_form', array($this, 'render_nav'), 20, 4);
add_action('cmb2_after_form', array($this, 'show_panels'), 10, 4);
add_filter('cmb2_wrap_classes', array($this, 'panel_wraper_class'), 10, 2);
add_filter('cmb_output_html_row', array($this, 'capture_fields'), 10, 3);
}
/**
* Display opening div for tabs for meta box
*
* @since 1.0.0
*/
public function opening_div($cmb_id, $object_id, $object_type, $cmb)
{
if (!$cmb->prop("tabs")) {
return;
}
$tab_style = $cmb->prop("tab_style");
$class = 'cmb-tabs clearfix';
if (isset($tab_style) && 'default' != $tab_style) {
$class .= ' cmb-tabs-'.$tab_style;
}
echo '<div class="'.$class.'">';
// Current cmb2 instance
CMB2_Tabs::$cmb = $cmb;
// Add cmb2_tabs custome render callback to instance
CMB2_Field::$callable_fields[] = 'cmb2_tabs_render_row_cb';
// Set 'true' to let us know that we're working on a meta box that has tabs
$this->active = true;
//setup style and script for tabs
$this->setup_admin_scripts();
}
/**
* Display closing div for tabs for meta box
*
* @since 1.0.0
*/
public function closing_div()
{
if (!$this->active) {
return;
}
echo '</div>';
// Reset to initial state to be ready for other meta boxes
$this->active = false;
$this->fields_output = array();
}
/**
* Render Navigration
*
* @since 1.0.0
*/
public function render_nav($cmb_id, $object_id, $object_type, $cmb)
{
$tabs = $cmb->prop("tabs");
if ($tabs) {
echo '<ul class="cmb-tab-nav">';
$active_nav = true;
foreach ($tabs as $key => $tab_data)
{
if (is_string($tab_data))
{
$tab_data = array('label' => $tab_data);
}
$tab_data = wp_parse_args($tab_data, array(
'icon' => '',
'label' => '',
'show_on_cb' => null,
));
if ($tab_data['show_on_cb'] && $this->do_callback($tab_data['show_on_cb'])) {
$this->conditional[] = $key;
continue;
}
//set icon defult it it's emty
$tab_data['icon'] = $tab_data['icon'] ? $tab_data['icon'] : "dashicons-admin-post";
// If icon is URL to image
if (filter_var($tab_data['icon'], FILTER_VALIDATE_URL))
{
$icon = '<img src="'.$tab_data['icon'].'">';
}
// If icon is icon font
else
{
// If icon is dashicon, auto add class 'dashicons' for users
if (false !== strpos($tab_data['icon'], 'dashicons'))
{
$tab_data['icon'] .= ' dashicons';
}
// Remove duplicate classes
$tab_data['icon'] = array_filter(array_map('trim', explode(' ', $tab_data['icon'])));
$tab_data['icon'] = implode(' ', array_unique($tab_data['icon']));
$icon = $tab_data['icon'] ? '<i class="'.$tab_data['icon'].'"></i>' : '';
}
$class = "cmb-tab-$key";
if ($active_nav) {
$class .= ' cmb-tab-active';
$this->active_panel = $key;
$active_nav = false;
}
printf(
'<li class="%s" data-panel="%s"><a href="#">%s<span>%s</span></a></li>',
$class,
$key,
$icon,
$tab_data['label']
);
}
echo '</ul>';
}
}
/**
* Add class to wraper div of CMB2 panel
*
* @since 1.0.0
*/
public function panel_wraper_class($classes, $box)
{
if ($this->active) {
$classes[] = 'cmb-tabs-panel';
}
if ($this->active && $this->fields_output) {
$classes[] = 'cmb2-wrap-tabs';
}
return array_unique($classes);
}
/**
* Modified CMB2 render row function to capture rows in a output string
*
* @since 1.0.0
*/
public static function tabs_render_row_cb($field_args, $field)
{
// Ok, callback is good, let's run it and store the result.
ob_start();
if ( 'group' === $field_args['type'] ) {
self::tabs_render_group_row_cb($field_args, $field);
}else{
if ($field->args( 'cmb2_tabs_render_row_cb' )) {
CMB2_Tabs::$cmb->peform_param_callback( 'cmb2_tabs_render_row_cb' );
} else {
$field->render_field_callback();
}
}
// Grab the result from the output buffer and store it.
$echoed = ob_get_clean();
$outer_html = $echoed ? $echoed : $returned;
$outer_html = apply_filters('cmb_output_html_row', $outer_html, $field_args, $field);
echo $outer_html;
//return $field;
}
/**
* Modified CMB2 render row function to capture Group rows in a output string
*
* @since 1.0.5
*/
public static function tabs_render_group_row_cb($field_args, $field_group)
{
// Ok, callback is good, let's run it and store the result.
ob_start();
if ($field_group->args( 'cmb2_tabs_render_row_cb' )) {
CMB2_Tabs::$cmb->render_group_callback( 'cmb2_tabs_render_row_cb' );
} else {
CMB2_Tabs::$cmb->render_group_callback($field_args, $field_group);
}
// Grab the result from the output buffer and store it.
$echoed = ob_get_clean();
$outer_html = $echoed ? $echoed : $returned;
$outer_html = apply_filters('cmb_output_html_row', $outer_html, $field_args, $field_group);
echo $outer_html;
//return $field_group;
}
/**
* Display tab navigation for meta box
* Note that: this public function is hooked to 'cmb2_after_form', when all fields are outputted
* (and captured by 'capture_fields' public function)
*
* @since 1.0.0
*/
public function show_panels($cmb_id, $object_id, $object_type, $cmb)
{
if (!$this->active) {return; }
echo '<div class="', esc_attr($cmb->box_classes()), '"><div id="cmb2-metabox-', sanitize_html_class($cmb_id), '" class="cmb2-metabox cmb-field-list">';
foreach ($this->fields_output as $tab => $fields)
{
if (!in_array($tab, $this->conditional, TRUE)) {
$active_panel = $this->active_panel == $tab ? "show" : "";
echo '<div class="'.$active_panel.' cmb-tab-panel cmb-tab-panel-'.$tab.'">';
echo implode('', $fields);
echo '</div>';
}
}
echo '</div></div>';
}
/**
* Save field output into class variable to output later
*
* @since 1.0.0
*/
public function capture_fields($output, $field_args, $field)
{
// If meta box doesn't have tabs, do nothing
if (!$this->active || !isset($field_args['tab'])) { return $output; }
$tab = $field_args['tab'];
if (!isset($this->fields_output[$tab])) {
$this->fields_output[$tab] = array();
}
$this->fields_output[$tab][] = $output;
// Return empty string to let Meta Box plugin echoes nothing
return '';
}
/**
* Enqueue scripts and styles
*
* @since 1.0.0
*/
public function setup_admin_scripts() {
wp_register_script('cmb-tabs-js', self::url('js/tabs.js'), array('jquery'), self::VERSION);
wp_enqueue_script('cmb-tabs-js');
wp_enqueue_style('cmb2-tabs-style', self::url('css/tabs.css'), array(), self::VERSION);
wp_enqueue_style('cmb2-tabs-style');
}
/**
* Defines the url which is used to load local resources. Based on, and uses,
* the CMB2_Utils class from the CMB2 library.
*
* @since 1.0.0
*/
public static function url($path = '') {
if (self::$url) { return self::$url.$path; }
/**
* Set the variable cmb2_tabs_dir
*/
$cmb2_tabs_dir = trailingslashit(dirname(__FILE__));
/**
* Use CMB2_Utils to gather the url from cmb2_tabs_dir
*/
$cmb2_tabs_url = CMB2_Utils::get_url_from_dir($cmb2_tabs_dir);
/**
* Filter the CMB2 FPSA location url
*/
self::$url = trailingslashit(apply_filters('cmb2_tabs_url', $cmb2_tabs_url, self::VERSION));
return self::$url.$path;
}
/**
* Handles metabox property callbacks, and passes this $cmb object as property.
*
* @since 1.0.0
*/
protected function do_callback($cb) {
return call_user_func($cb, CMB2_Tabs::$cmb, $this);
}
}
//Boot the hole thing
$cmb2_tabs = new CMB2_Tabs();
}

View File

@@ -0,0 +1,292 @@
/**
* CMB2 Tabs Styling
*/
/*--------------------------------------------------------------
Helper
--------------------------------------------------------------*/
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
.clearfix { display: inline-block; }
/* start commented backslash hack \*/
* html .clearfix { height: 1%; }
.clearfix { display: block; }
/* close commented backslash hack */
/*--------------------------------------------------------------
Base style
--------------------------------------------------------------*/
.cmb-tabs .cmb-th label {
color: #555;
font-size: 12px;
}
.cmb-tabs .cmb-type-group .cmb-row,
.cmb-tabs .cmb2-postbox .cmb-row {
margin: 0 0 0.8em;
padding: 0 0 0.8em;
}
.cmb-tabs span.cmb2-metabox-description {
display: block;
}
.cmb-tabs .cmb-remove-row-button {
background-color: #e60000;
border: medium none;
border-radius: 25px;
color: #fff;
height: 20px;
padding: 0;
text-indent: -999em;
width: 20px;
position: relative;
-webkit-box-shadow: none;
box-shadow: none;
}
/*.cmb-tabs .cmb-remove-row-button:hover {
background-color: #ff0000;
color: #fff;
}
.cmb-tabs .cmb-remove-row-button:after {
box-shadow: none;
content: "";
cursor: help;
font-family: Dashicons;
font-variant: normal;
height: 100%;
width: 100%;
left: 0;
line-height: 1;
margin: 0;
padding: 4px 0;
position: absolute;
text-align: center;
text-indent: 0;
top: 0;
vertical-align: middle;
}*/
.cmb-tabs .cmb-repeat-row{
position: relative;
}
.cmb-tabs .cmb-remove-row {
display: inline;
margin: 0;
padding: 0;
}
.cmb-tabs .cmb-repeat-row .cmb-td{
display: inline-block;
}
/*--------------------------------------------------------------
CMB2 Tabs
--------------------------------------------------------------*/
.cmb-tabs {
margin: -6px -12px -12px;
overflow: hidden;
}
.cmb-tabs ul.cmb-tab-nav:after {
background-color: #fafafa;
border-right: 1px solid #eee;
bottom: -9999em;
content: "";
display: block;
height: 9999em;
left: 0;
position: absolute;
width: calc(100% - 1px);
}
.cmb-tabs ul.cmb-tab-nav{
background-color: #fafafa;
-webkit-box-sizing: border-box;
box-sizing: border-box;
display: block;
line-height: 1em;
margin: 0;
padding: 0;
position: relative;
width: 20%;
float: left;
}
.cmb-tabs ul.cmb-tab-nav li {
display: block;
margin: 0;
padding: 0;
position: relative;
}
.cmb-tabs i,
.cmb-tabs i:before {
font-size: 16px;
vertical-align: middle;
}
.cmb-tabs ul.cmb-tab-nav li a {
border-right: 1px solid #eee;
border-left: 2px solid #fafafa;
-webkit-box-shadow: none;
box-shadow: none;
display: block;
line-height: 20px;
margin: 0;
padding: 10px;
text-decoration: none;
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
font-weight: 600;
}
.cmb-tabs ul.cmb-tab-nav li i {
display: -webkit-box;
display: -ms-flexbox;
display: flex;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
}
.cmb-tabs ul.cmb-tab-nav li i,
.cmb-tabs ul.cmb-tab-nav li img{
padding: 0 5px 0 0px;
}
.cmb-tabs ul.cmb-tab-nav li a {
color: #555;
border: 1px solid transparent;
}
.cmb-tabs ul.cmb-tab-nav li.cmb-tab-active a {
background-color: #fff;
position: relative;
border: 1px solid #eee;
border-left: 3px solid #00a0d2;
border-right-color: #fff;
}
.cmb-tabs ul.cmb-tab-nav li:first-of-type.cmb-tab-active a {
border-top: none;
}
.cmb-tabs .cmb-tabs-panel {
-webkit-box-sizing: border-box;
box-sizing: border-box;
color: #555;
display: -webkit-inline-box;
display: -ms-inline-flexbox;
display: inline-flex;
width: 80%;
padding: 0;
}
.cmb-tabs .cmb2-metabox{
display: block;
width: 100%;
}
.cmb-tabs .cmb-th {
width: 18%;
}
.cmb-tabs .cmb-th,
.cmb-tabs .cmb-td {
padding: 0 2% 0 2%;
-webkit-box-sizing: border-box;
box-sizing: border-box;
}
.cmb-tabs .cmb-th + .cmb-td,
.cmb-tabs .cmb-th + .cmb-td {
float: right;
width: 82%;
}
.cmb2-wrap-tabs .cmb-tab-panel{
display: none;
}
.cmb2-wrap-tabs .cmb-tab-panel.show{
display: block;
}
/*--------------------------------------------------------------
Classic Tab
--------------------------------------------------------------*/
.cmb-tabs.cmb-tabs-classic ul.cmb-tab-nav {
width: 100%;
float: none;
background-color: #fafafa;
border-right: medium none;
padding: 0;
border-bottom: 1px solid #dedede;
padding-top: 15px;
}
.cmb-tabs.cmb-tabs-classic .cmb-tab-nav li {
background: #ebebeb none repeat scroll 0 0;
margin: 0 5px -1px 5px;
display: inline-block;
}
.cmb-tabs.cmb-tabs-classic .cmb-tab-nav li:first-of-type {
margin-left: 18px;
}
.cmb-tabs.cmb-tabs-classic ul.cmb-tab-nav::after {
display: none;
}
.cmb-tabs.cmb-tabs-classic .cmb-tabs-panel {
width: 100%;
}
.cmb-tabs.cmb-tabs-classic .cmb-tab-panel{
/*background: #ebebeb none repeat scroll 0 0;*/
padding-top: 10px;
}
.cmb-tabs.cmb-tabs-classic ul.cmb-tab-nav li a{
padding: 8px 12px;
background-color: #fafafa;
border: none;
border-bottom: 1px solid #dedede;
}
.cmb-tabs.cmb-tabs-classic ul.cmb-tab-nav li.cmb-tab-active a{
background-color: #fff;
border-color: #fff;
border: none;
border-top: 2px solid #00a0d2;
border-bottom: 1px solid #fff;
}
/*--------------------------------------------------------------
Media Query
--------------------------------------------------------------*/
@media (max-width: 750px) {
.cmb-tabs ul.cmb-tab-nav {
width: 10%;
}
.cmb-tabs .cmb-tabs-panel {
width: 90%;
}
.cmb-tabs ul.cmb-tab-nav li i,
.cmb-tabs ul.cmb-tab-nav li img {
padding: 0;
margin: 0 auto;
text-align: center;
display: block;
max-width: 25px;
}
.cmb-tabs ul.cmb-tab-nav li span{
padding: 10px;
position: relative;
text-indent: -999px;
display: none;
}
}
@media (max-width: 500px) {
.cmb-tabs .cmb-th,
.cmb-tabs .cmb-th + .cmb-td,
.cmb-tabs .cmb-th + .cmb-td {
float: none;
width: 96%;
}
.cmb-tabs .cmb-repeat-row .cmb-td {
width: auto;
}
}

View File

@@ -0,0 +1,232 @@
<?php
/**
* Include and setup custom metaboxes and fields. (make sure you copy this file to outside the CMB2 directory)
*
* Be sure to replace all instances of 'cmb2_tabs_' with your project's prefix.
*
* @category WordPress_Plugin
* @package Demo_CMB2_Tabs
* @license http://www.opensource.org/licenses/gpl-license.php GPL v3.0 (or later)
* @link https://github.com/stackadroit/cmb2-extensions
*/
/**
* Get the bootstrap! If using the plugin from wordpress.org, REMOVE THIS!
*/
if (file_exists(dirname(__FILE__).'/cmb2/init.php')) {
require_once dirname(__FILE__).'/cmb2/init.php';
} elseif (file_exists(dirname(__FILE__).'/CMB2/init.php')) {
require_once dirname(__FILE__).'/CMB2/init.php';
}
/**
* Conditionally displays a metabox when used as a callback in the 'show_on_cb' cmb2_box parameter
*
* @param CMB2 object $cmb CMB2 object.
*
* @return bool True if metabox should show
*/
function cmb2_tabs_show_if_front_page($cmb) {
// Don't show this metabox if it's not the front page template.
if (get_option('page_on_front') !== $cmb->object_id) {
return false;
}
return true;
}
add_action('cmb2_admin_init', 'cmb2_tabs_register_demo_metabox');
/**
* Hook in and add a demo metabox. Can only happen on the 'cmb2_admin_init' or 'cmb2_init' hook.
*/
function cmb2_tabs_register_demo_metabox() {
$prefix = 'cmb2_tabs_';
/**
* Sample metabox to demonstrate each field type included
*/
$cmb_tabs_demo = new_cmb2_box(array(
'id' => $prefix.'metabox',
'title' => esc_html__('Test Metabox', 'cmb2_tabs'),
'object_types' => array('page'), // Post type
'tabs' => array(
'contact' => array(
'label' => __('Contact', 'cmb2_tabs'),
'show_on_cb' => 'cmb2_tabs_show_if_front_page',
),
'social' => array(
'label' => __('Social Media', 'cmb2_tabs'),
'icon' => 'dashicons-share', // Dashicon
),
'note' => array(
'label' => __('Note', 'cmb2_tabs'),
'icon' => 'dashicons-sos', // Custom icon, using image
),
),
// 'show_on_cb' => 'cmb2_tabs_show_if_front_page', // function should return a bool value
// 'context' => 'normal',
// 'priority' => 'high',
// 'show_names' => true, // Show field names on the left
// 'cmb_styles' => false, // false to disable the CMB stylesheet
// 'closed' => true, // true to keep the metabox closed by default
// 'classes' => 'extra-class', // Extra cmb2-wrap classes
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Text', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'text',
'type' => 'text',
'tab' => 'contact',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
'show_on_cb' => 'cmb2_tabs_hide_if_no_cats', // function should return a bool value
// 'on_front' => false, // Optionally designate a field to wp-admin only
// 'repeatable' => true,
// 'column' => true, // Display field value in the admin post-listing columns
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Text Small', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'textsmall',
'type' => 'text_small',
'tab' => 'contact',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'repeatable' => true,
// 'column' => array(
// 'name' => esc_html__( 'Column Title', 'cmb2_tabs' ), // Set the admin column title
// 'position' => 2, // Set as the second column.
// );
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Text Medium', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'textmedium',
'type' => 'text_medium',
'tab' => 'contact',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Read-only Disabled Field', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'readonly',
'type' => 'text_medium',
'tab' => 'social',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
'default' => esc_attr__('Hey there, I\'m a read-only field', 'cmb2_tabs'),
'save_field' => false, // Disables the saving of this field.
'attributes' => array(
'disabled' => 'disabled',
'readonly' => 'readonly',
),
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Custom Rendered Field', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'render_row_cb',
'type' => 'text',
'tab' => 'social',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Website URL', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'url',
'type' => 'text_url',
'tab' => 'social',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'protocols' => array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet'), // Array of allowed protocols
// 'repeatable' => true,
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Text Email', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'email',
'type' => 'text_email',
'tab' => 'social',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'repeatable' => true,
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Time', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'time',
'type' => 'text_time',
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'time_format' => 'H:i', // Set to 24hr format
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Time zone', 'cmb2_tabs'),
'desc' => esc_html__('Time zone', 'cmb2_tabs'),
'id' => $prefix.'timezone',
'type' => 'select_timezone',
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Date Picker', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'textdate',
'type' => 'text_date',
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'date_format' => 'Y-m-d',
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Date Picker (UNIX timestamp)', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'textdate_timestamp',
'type' => 'text_date_timestamp',
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
// 'timezone_meta_key' => $prefix . 'timezone', // Optionally make this field honor the timezone selected in the select_timezone specified above
));
$cmb_tabs_demo->add_field(array(
'name' => esc_html__('Test Date/Time Picker Combo (UNIX timestamp)', 'cmb2_tabs'),
'desc' => esc_html__('field description (optional)', 'cmb2_tabs'),
'id' => $prefix.'datetime_timestamp',
'type' => 'text_datetime_timestamp',
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_row_cb'),
));
/*******************GROUPS**************************/
$group_field_id = $cmb_tabs_demo->add_field( array(
'id' => 'wiki_test_repeat_group',
'type' => 'group',
'description' => __( 'Generates reusable form entries', 'cmb2_tabs' ),
'tab' => 'note',
'render_row_cb' => array('CMB2_Tabs', 'tabs_render_group_row_cb'),
// 'repeatable' => false, // use false if you want non-repeatable group
'options' => array(
'group_title' => __( 'Entry {#}', 'cmb2_tabs' ), // since version 1.1.4, {#} gets replaced by row number
'add_button' => __( 'Add Another Entry', 'cmb2_tabs' ),
'remove_button' => __( 'Remove Entry', 'cmb2_tabs' ),
'sortable' => true, // beta
// 'closed' => true, // true to have the groups closed by default
),
) );
// Id's for group's fields only need to be unique for the group. Prefix is not needed.
$cmb_tabs_demo->add_group_field( $group_field_id, array(
'name' => __( 'Entry Title', 'cmb2_tabs' ),
'id' => 'title',
'type' => 'text',
// 'repeatable' => true, // Repeatable fields are supported w/in repeatable groups (for most types)
) );
}

View File

@@ -0,0 +1,21 @@
/* global jQuery */
jQuery( function ( $ )
{
'use strict';
$( '.cmb-tab-nav' ).on( 'click', 'a', function ( e )
{
e.preventDefault();
var $li = $( this ).parent(),
panel = $li.data( 'panel' ),
$wrapper = $li.parents( ".cmb-tabs" ).find( '.cmb2-wrap-tabs' ),
$panel = $wrapper.find( '.cmb-tab-panel-' + panel );
$li.addClass( 'cmb-tab-active' ).siblings().removeClass( 'cmb-tab-active' );
$panel.addClass('show').siblings().removeClass('show');
} );
});

View File

@@ -0,0 +1,53 @@
=== CMB2 Tabs ===
Contributors: stackadroid, polupraneeth
Donate link: http://stackadroit.com/
Tags: metaboxes, fields, tabs
Requires at least: 3.8.0
Tested up to: 4.7.2
Stable tag: 1.0.6
License: GPLv3
License URI: http://creativecommons.org/licenses/GPL/3.0/
CMB2 Tabs is an extenstion for CMB2 which allow you to oragnize fields into tabs.
== Description ==
CMB2 Tabs is an extenstion for CMB2 which allow you to oragnize fields into tabs.
CMB2 Tabs Extension requires the most current version of the CMB2 plugin. You can find that [here](https://wordpress.org/plugins/cmb2/) . And you can find documentation on CMB2 [here](https://github.com/WebDevStudios/CMB2/wiki/).
### Contribution
Development occurs on Github, and all contributions welcome. [CONTRIBUT](https://github.com/stackadroit/cmb2-extensions).
== Links ==
* [Github project page](https://github.com/stackadroit/cmb2-extensions/)
* [Documentation (GitHub wiki)](https://github.com/stackadroit/cmb2-extensions/wiki)
== Installation ==
1. Upload `cmb2-tabs` to the `/wp-content/plugins/` directory
1. Activate the plugin through the 'Plugins' menu in WordPress
1. Copy (and rename if desired) `example-functions.php` into to your theme or plugin's directory.
1. Edit to only include the fields you need and rename the functions.
== Features: ==
* CMB2 fields management into tabs without complex syntax
== 3rd Party Resources ==
* [CMB2](https://github.com/WebDevStudios/CMB2/).
== Frequently Asked Questions ==
FAQ's usually end up in the [github wiki](https://github.com/stackadroit/cmb2-extensions/wiki).
== Changelog ==
= 1.0.2 beta 26.07.2017 =
* Error fix on plugin activation.
= 1.0.6 beta 17.11.2017 =
* Fixed group field issues