Skip to content

Commit 93a903d

Browse files
committed
Initial expansion release
1 parent d8c2ad4 commit 93a903d

11 files changed

+604
-0
lines changed

.editorconfig

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# EditorConfig helps developers define and maintain consistent
2+
# coding styles between different editors and IDEs
3+
# editorconfig.org
4+
5+
root = true
6+
7+
8+
[*]
9+
10+
indent_style = tab
11+
indent_size = 4
12+
end_of_line = lf
13+
charset = utf-8
14+
trim_trailing_whitespace = true
15+
insert_final_newline = true
16+
17+
[*.md]
18+
trim_trailing_whitespace = false
19+
20+
[*.js]
21+
indent_style = space
22+
23+
[package.json]
24+
indent_style = space
25+
indent_size = 2
26+
27+
[bower.json]
28+
indent_style = space
29+
indent_size = 2

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
## 1.0 - 11-20-2015
5+
6+
* Initial expansion release

README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# CMB2 EXPANSION
2+
3+
**Authors:** [Mike Estrada](https://bleucellar.com)
4+
**Tags:** cmb2, metaboxes, expansion
5+
6+
## Description
7+
8+
CMB2 EXPANSION is a plugin which adds features to the plugin [CMB2](https://github.com/WebDevStudios/CMB2).
9+
10+
## Features:
11+
12+
* Responsive Tab Navigation for Metaboxes
13+
* Adds show_on support for slug and front-page
14+
* Adds repeat limit for fields AND groups (partial integration from [CMB2 Snippet Library](https://github.com/WebDevStudios/CMB2-Snippet-Library))
15+
16+
## Installation
17+
18+
1. Place the CMB2 EXPANSION directory inside of your plugins directory (typically /wp-content/plugins).
19+
2. Activate plugin through the Plugins Admin page
20+
21+
### 1.0 - 11-20-2015
22+
23+
* Initial expansion release

assets/cmb2-exp.admin.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
jQuery(function($) {
2+
// close CMB2 sub group boxes if more than one is available
3+
$('.cmb-repeatable-group').each(function() {
4+
var $this = $(this),
5+
$boxes = $this.find('.postbox');
6+
7+
if ( $boxes.length > 1 ) { $boxes.addClass('closed'); }
8+
} );
9+
$('.cmb2-metabox').each(function() {
10+
var $this = $(this),
11+
$boxes = $this.find('.cmb-repeat-group-wrap'),
12+
$tags = $this.find('.cmb-repeatable-grouping');
13+
14+
if ( $boxes.length > 1 ) { $tags.addClass('closed'); }
15+
} );
16+
17+
} );

assets/tab-navigation.admin.css

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#post-body #normal-sortables{
2+
min-height: 0;
3+
}
4+
/* wrapper for tabs */
5+
.nav-tab-wrapper{
6+
margin: 20px 0 0;
7+
border-bottom: 1px solid #ccc;
8+
}
9+
/* tabs */
10+
.nav-tab-wrapper .nav-tab{
11+
border-bottom: 1px solid #ccc;
12+
font-weight: bold;
13+
z-index: 1;
14+
}
15+
.nav-tab-wrapper .nav-tab.hidden{
16+
display: none;
17+
}
18+
/* selected tab */
19+
.nav-tab-wrapper .nav-tab.nav-tab-active{
20+
border-bottom: 1px solid #f1f1f1; /* color of WP admin background */
21+
z-index: 9999;
22+
}
23+
/* override WP focus and active stylings */
24+
.nav-tab-wrapper .nav-tab:active,
25+
.nav-tab-wrapper .nav-tab:focus{
26+
color: #464646;
27+
box-shadow: none;
28+
}
29+
30+
/* no margin on right so tabs turn into accordion view at proper window width */
31+
.nav-tab-wrapper a:not(.hidden):last-child{
32+
margin-right: 0;
33+
}
34+
.cmb2-exp-hidden{
35+
display: none !important;
36+
}
37+
/* switch to accordion type of view if tabs nav splits into two rows */
38+
.alt-tabs-display{
39+
display: none;
40+
}
41+
.alt-meta-display{
42+
display: block !important;
43+
visibility: visible !important;
44+
margin-bottom: 0;
45+
}

assets/tab-navigation.admin.js

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
'use strict';
2+
3+
jQuery(function($){
4+
// metabox tab navigation
5+
var $active,
6+
$content,
7+
$tabNav = $('.nav-tab-wrapper'),
8+
$links = $tabNav.find('a'),
9+
singleTabHeight = $('.nav-tab').outerHeight();
10+
11+
$active = $($links.filter(':visible')[0]).addClass('nav-tab-active');
12+
13+
$content = $( $($active[0]).attr('href') );
14+
15+
// hide all metaboxes that are hidden in nav-tab as well
16+
$links.not($active).each(function() {
17+
// use specific class instead of show/hide so metaboxes don't appear during checkbox toggle in "Screen Options"
18+
$(this.hash).addClass('cmb2-exp-hidden');
19+
});
20+
21+
// screen options metabox functionality
22+
$('.metabox-prefs input[type="checkbox"]').each(function(){
23+
var $this = $(this),
24+
$tab = '#'+$this.val();
25+
26+
$this.on('click', function(e){
27+
//on click, toggle appearance in .nav-tab-wrapper
28+
$tabNav.find('[href="'+ $tab +'"]').toggleClass('hidden');
29+
responsiveTabs();
30+
});
31+
32+
});
33+
34+
// click actions for tab nav links
35+
$tabNav.on('click', 'a', function(e){
36+
$active.removeClass('nav-tab-active');
37+
$content.addClass('cmb2-exp-hidden');
38+
39+
$active = $(this);
40+
$content = $(this.hash);
41+
42+
$active.addClass('nav-tab-active');
43+
$content.removeClass('closed cmb2-exp-hidden');
44+
45+
e.preventDefault();
46+
//return false;
47+
});
48+
49+
//check if CMB2 admin-tabs are breaking into rows
50+
function responsiveTabs(){
51+
var tabsDisplay = $tabNav.css('display'),
52+
tabsParentWidth = $tabNav.parent().width(),
53+
$sidebar_width = $('#side-sortables').css('width'),
54+
$metaBoxes = $();
55+
56+
// grab metaboxes based on class in the .nav-tab-wrapper
57+
$links.not('.hidden').each(function(){
58+
var $div = $($(this).attr('href'));
59+
$metaBoxes = $metaBoxes.add( $div );
60+
});
61+
62+
// collapse sidebar metaboxes only when in mobile view (when post content width == sidebar width)
63+
var contentWidth = $('#post-body-content').width(),
64+
sideBarWidth = $('#postbox-container-1').width(),
65+
$sideMbxs = $('#side-sortables .postbox');
66+
67+
if( contentWidth == sideBarWidth ){
68+
$sideMbxs.addClass('alt-meta-display closed');
69+
}else{
70+
$sideMbxs.removeClass('alt-meta-display closed');
71+
}
72+
73+
// set width of .nav-tab-wrapper to its parent's width, THEN grab the height (flor fluid collapse of nav tabs)
74+
$tabNav.outerWidth(tabsParentWidth);
75+
var tabsHeight = $tabNav.height();
76+
77+
if(tabsDisplay == 'block' && tabsHeight > singleTabHeight){
78+
$metaBoxes
79+
.addClass('alt-meta-display closed')
80+
.on('click', function(){
81+
$metaBoxes.not($(this)).addClass('closed');
82+
});
83+
$tabNav.addClass('alt-tabs-display');
84+
}else if(tabsHeight <= singleTabHeight){
85+
$tabNav.removeClass('alt-tabs-display');
86+
$metaBoxes.removeClass('alt-meta-display closed');
87+
}
88+
}
89+
responsiveTabs();
90+
$(window).on('resize', responsiveTabs);
91+
92+
});
93+
94+
95+
(function($) {
96+
// Override the WP heartbeat ajax-admin function that saves the hidden metaboxes,
97+
// and instead use the unchecked boxes in "Screen Options"
98+
// Original code in file /wp-admin/js/postbox.js
99+
if( 'undefined' !== typeof postboxes ) {
100+
postboxes.save_state = function( page ) {
101+
var closed = $('.postbox').filter('.closed').map(function() { return this.id; }).get().join(','),
102+
hidden = $('.hide-postbox-tog').not(':checked').map(function() { return this.value; }).get().join(',');
103+
104+
$.post(ajaxurl, {
105+
action: 'closed-postboxes',
106+
closed: closed,
107+
hidden: hidden,
108+
closedpostboxesnonce: jQuery('#closedpostboxesnonce').val(),
109+
page: page
110+
});
111+
}
112+
}
113+
114+
}(jQuery));

cmb2-expansion.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
/**
3+
* Plugin Name: CMB2 Expansion
4+
* Description: Expansion plugin for CMB2
5+
* Version: 1.0
6+
* Author: Mike Estrada
7+
*/
8+
9+
if ( !defined('ABSPATH') )
10+
die ( 'YOU SHALL NOT PASS!' );
11+
12+
define( 'CMB2_EXP_DIR', plugin_dir_path(__FILE__) );
13+
define( 'CMB2_EXP_URL', plugin_dir_url(__FILE__) );
14+
define( 'CMB2_EXP_BASE', plugin_basename( __FILE__ ) );
15+
define( 'CMB2_EXP_VERSION', '1.0' );
16+
17+
// check if CMB2 class is defined (possibly use the PRE ACTIVATION hook)
18+
function cmb2_exp_espansion_plugin_init() {
19+
//check if CMB2 is loaded
20+
if( defined( 'CMB2_LOADED' ) ) {
21+
22+
// add functionality into cmb2_show_on
23+
if ( file_exists( CMB2_EXP_DIR . '/includes/show-on-support.php' ) ) {
24+
require_once( CMB2_EXP_DIR . '/includes/show-on-support.php' );
25+
}
26+
27+
// add 'repeat_limit' option for repeatable fields/groups
28+
if ( file_exists( CMB2_EXP_DIR . '/includes/repeat-limit.php' ) ) {
29+
require_once( CMB2_EXP_DIR . '/includes/repeat-limit.php' );
30+
}
31+
32+
// add tab navigation for meta boxes
33+
if ( file_exists( CMB2_EXP_DIR . '/includes/tab-navigation.php' ) ) {
34+
require_once( CMB2_EXP_DIR . '/includes/tab-navigation.php' );
35+
}
36+
37+
// add custom scripts/styles
38+
add_action( 'admin_print_scripts-post-new.php', 'cmb2_exp_scripts' );
39+
add_action( 'admin_print_scripts-post.php', 'cmb2_exp_scripts' );
40+
function cmb2_exp_scripts() {
41+
wp_enqueue_script( 'cmb2-exp-scripts-admin', CMB2_EXP_URL . 'assets/cmb2-exp.admin.js', array('jquery'), false );
42+
}
43+
44+
}
45+
//IF CMB2 NOT LOADED, SHOW ALERT
46+
}
47+
add_action( 'plugins_loaded', 'cmb2_exp_espansion_plugin_init' );
48+
49+
?>

includes/repeat-limit.php

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
<?php
2+
/*
3+
Add 'repeat_limit' for repeatable meta boxes
4+
*/
5+
6+
//TO DO: add variable to check if any repeatables, if false do not run admin_footer function
7+
8+
add_action( 'cmb2_after_form', 'cmb2_repeat_limit', 10, 4 );
9+
function cmb2_repeat_limit( $cmb_id, $object_id, $object_type, $cmb ) {
10+
$fields = $cmb->meta_box['fields'];
11+
$repeatGroups = array();
12+
$repeatFields = array();
13+
14+
foreach ( $fields as $id => $field ) {
15+
//check that 'repeat_limit' is defined, as well as if it's a group
16+
if ( isset( $field['repeat_limit'] ) && $field['type'] == 'group' ) {
17+
//push to array to generate limits
18+
array_push( $repeatGroups, array(
19+
'id' => $field['id'],
20+
'limit' => $field['repeat_limit']
21+
) );
22+
} elseif ( isset( $field['repeatable'] ) && isset( $field['repeat_limit'] ) && $field['type'] != 'group' ) {
23+
//check that 'repeatable' and 'repeat_limit' are defined, as well as if it's NOT a group
24+
array_push( $repeatFields, array(
25+
'id' => $field['id'],
26+
'limit' => $field['repeat_limit']
27+
) );
28+
}
29+
}
30+
31+
if ( !empty( $repeatGroups ) || !empty( $repeatFields ) ) : ?>
32+
<script type="text/javascript">
33+
jQuery(document).ready(function($) {
34+
<?php
35+
//check if repeat array for groups exists
36+
if ( !empty( $repeatGroups ) ):
37+
foreach ($repeatGroups as $k => $v) {
38+
echo "repeatGroups.push(['{$v['id']}',{$v['limit']}]);\n";
39+
}
40+
?>
41+
for(i = 0; repeatGroups.length > i; i++) {
42+
var id = repeatGroups[i][0],
43+
limit = repeatGroups[i][1];
44+
45+
setTheLimit('group',id,limit);
46+
};
47+
<?php
48+
endif;
49+
50+
//check if repeat array for fields exists
51+
if ( !empty( $repeatFields ) ):
52+
foreach ($repeatFields as $k => $v) {
53+
echo "repeatFields.push(['{$v['id']}',{$v['limit']}]);\n";
54+
}
55+
?>
56+
for ( i = 0; repeatFields.length > i; i++ ) {
57+
var id = repeatFields[i][0],
58+
limit = repeatFields[i][1];
59+
60+
setTheLimit('field',id,limit);
61+
};
62+
<?php
63+
endif;
64+
?>
65+
})
66+
</script>
67+
<?php
68+
endif;
69+
}
70+
71+
add_action( 'admin_footer', 'cmb2_repeat_limit_admin_footer' );
72+
function cmb2_repeat_limit_admin_footer() {
73+
echo "
74+
<script type='text/javascript'>
75+
// add limit to repeatable groups
76+
var repeatGroups = [],
77+
repeatFields = [];
78+
79+
function setTheLimit( type, id, limit ) {
80+
var fieldTable = jQuery( document.getElementById( id + '_repeat' ) ),
81+
countRows = '',
82+
disableAdder = '',
83+
enableAdder = '';
84+
85+
if ( type == 'group' ) {
86+
countRows = function() { return fieldTable.find( '> .cmb-row.cmb-repeatable-grouping' ).length; };
87+
disableAdder = function() { fieldTable.find('.cmb-add-group-row.button').prop( 'disabled', true ); };
88+
enableAdder = function() { fieldTable.find('.cmb-add-group-row.button').prop( 'disabled', false ); };
89+
} else if ( type == 'field' ) {
90+
countRows = function() { return fieldTable.find( '.cmb-row.cmb-repeat-row' ).length; };
91+
disableAdder = function() { fieldTable.parents( '.cmb-repeat.table-layout' ).find('.cmb-add-row-button.button').prop( 'disabled', true ); };
92+
enableAdder = function() { fieldTable.parents( '.cmb-repeat.table-layout' ).find('.cmb-add-row-button.button').prop( 'disabled', false ); };
93+
}
94+
95+
if ( countRows() >= limit ) { disableAdder(); }
96+
97+
fieldTable
98+
.on( 'cmb2_add_row', function() {
99+
if ( countRows() >= limit ) { disableAdder(); }
100+
})
101+
.on( 'cmb2_remove_row', function() {
102+
if ( countRows() < limit ) { enableAdder(); }
103+
});
104+
};// end setTheLimit()
105+
</script>";
106+
}
107+
108+
?>

0 commit comments

Comments
 (0)