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,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();
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
) );
|
||||
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
} );
|
||||
|
||||
|
||||
});
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user