',
- esc_attr( $id ),
- esc_attr( $name ),
- esc_attr( $field_id )
- );
-
- if ( $this->is_placeholder() ) {
-
- // For placeholder, output the markup for the editor in a JS var.
- ob_start();
- $this->args['options']['textarea_name'] = 'cmb-placeholder-name-' . $field_id;
- wp_editor( '', 'cmb-placeholder-id-' . $field_id, $this->args['options'] );
- $editor = ob_get_clean();
- $editor = str_replace( array( "\n", "\r" ), '', $editor );
- $editor = str_replace( array( "'" ), '"', $editor );
-
- ?>
-
-
-
- args['options']['textarea_name'] = $name;
- echo wp_editor( $this->get_value(), $id, $this->args['options'] );
-
- }
-
- echo '
';
-
- }
-
- /**
- * Check if this is a placeholder field.
- * Either the field itself, or because it is part of a repeatable group.
- *
- * @return bool
- */
- public function is_placeholder() {
-
- if ( isset( $this->parent ) && ! is_int( $this->parent->field_index ) ) {
- return true;
- } else {
- return ! is_int( $this->field_index );
- }
-
- }
-}
-
-/**
- * Standard select field.
- *
- * @supports "data_delegate"
- * @args
- * 'options' => array Array of options to show in the select, optionally use data_delegate instead
- * 'allow_none' => bool|string Allow no option to be selected (will place a "None" at the top of the select)
- * 'multiple' => bool whether multiple can be selected
- *
- * @since 1.0.0
- *
- * @extends CMB_Field
- */
-class CMB_Select extends CMB_Field {
-
- /**
- * CMB_Select constructor.
- */
- public function __construct() {
-
- $args = func_get_args();
-
- call_user_func_array( array( 'parent', '__construct' ), $args );
-
- }
-
- /**
- * Get default arguments for field including custom parameters.
- *
- * @return array Default arguments for field.
- */
- public function get_default_args() {
- return array_merge(
- parent::get_default_args(),
- array(
- 'options' => array(),
- 'multiple' => false,
- 'select2_options' => array(),
- 'allow_none' => false,
- )
- );
- }
-
- /**
- * Ensure values are saved as an array if multiple is set.
- */
- public function parse_save_values() {
-
- if ( isset( $this->parent ) && isset( $this->args['multiple'] ) && $this->args['multiple'] ) {
- $this->values = array( $this->values );
- }
-
- }
-
- /**
- * Get options for field.
- *
- * @return mixed
- */
- public function get_options() {
-
- if ( $this->has_data_delegate() ) {
- $this->args['options'] = $this->get_delegate_data();
- }
-
- return $this->args['options'];
- }
-
- /**
- * Enqueue all scripts required by the field.
- *
- * @uses wp_enqueue_script()
- */
- public function enqueue_scripts() {
-
- parent::enqueue_scripts();
-
- wp_enqueue_script( 'select2', trailingslashit( CMB_URL ) . 'js/vendor/select2/select2.js', array( 'jquery' ) );
- wp_enqueue_script( 'field-select', trailingslashit( CMB_URL ) . 'js/field.select.js', array( 'jquery', 'select2', 'cmb-scripts' ) );
- }
-
- /**
- * Enqueue all styles required by the field.
- *
- * @uses wp_enqueue_style()
- */
- public function enqueue_styles() {
-
- parent::enqueue_styles();
-
- wp_enqueue_style( 'select2', trailingslashit( CMB_URL ) . 'js/vendor/select2/select2.css' );
- }
-
- /**
- * Print out field HTML.
- */
- public function html() {
-
- if ( $this->has_data_delegate() ) {
- $this->args['options'] = $this->get_delegate_data();
- }
-
- $this->output_field();
-
- $this->output_script();
-
- }
-
- /**
- * Compile field HTML.
- */
- public function output_field() {
-
- $val = (array) $this->get_value();
-
- $name = $this->get_the_name_attr();
- $name .= ! empty( $this->args['multiple'] ) ? '[]' : null;
-
- $none = is_string( $this->args['allow_none'] ) ? $this->args['allow_none'] : __( 'None', 'cmb' );
-
- ?>
-
-
+
+ args['repeatable'] ) {
+ $this->delete_button_markup();
+ } ?>
+ html(); ?>
+
+
+
+ repeatable_button_markup();
+ } else {
+
+ $this->value = $this->get_values();
+ ?>
+
+
+
+ args['repeatable'] ) {
+ $this->delete_button_markup();
+ } ?>
+
+ html(); ?>
+
+
+
+ args['repeatable'] ) {
+ $this->repeatable_button_markup();
+ }
+ }
+
+ /**
+ * Markup to print an "add" button and for a repeatable field.
+ */
+ protected function repeatable_button_markup() {
+ // X used to distinguish hidden fields.
+ $this->field_index = 'x';
+ $this->value = '';
+ ?>
+
+ ',
+ esc_attr( $id ),
+ esc_attr( $name ),
+ esc_attr( $field_id )
+ );
+
+ if ( $this->is_placeholder() ) {
+
+ // For placeholder, output the markup for the editor in a JS var.
+ ob_start();
+ $this->args['options']['textarea_name'] = 'cmb-placeholder-name-' . $field_id;
+ wp_editor( '', 'cmb-placeholder-id-' . $field_id, $this->args['options'] );
+ $editor = ob_get_clean();
+ $editor = str_replace( array( "\n", "\r" ), '', $editor );
+ $editor = str_replace( array( "'" ), '"', $editor );
+
+ ?>
+
+
+
+ args['options']['textarea_name'] = $name;
+ wp_editor( $this->get_value(), $id, $this->args['options'] );
+
+ }
+
+ echo '
';
+
+ }
+
+ /**
+ * Check if this is a placeholder field.
+ * Either the field itself, or because it is part of a repeatable group.
+ *
+ * @return bool
+ */
+ public function is_placeholder() {
+
+ if ( isset( $this->parent ) && ! is_int( $this->parent->field_index ) ) {
+ return true;
+ } else {
+ return ! is_int( $this->field_index );
+ }
+
+ }
+}
diff --git a/js/cmb.js b/js/cmb.js
index 1c7c761d..7c9a664a 100644
--- a/js/cmb.js
+++ b/js/cmb.js
@@ -101,7 +101,10 @@ var CMB = {
e.preventDefault();
jQuery( this ).blur();
- if ( ! confirm( CMBData.strings.confirmDeleteField ) ) {
+ fieldItem = jQuery( this ).closest( '.field-item' );
+ field = fieldItem.closest( '.field' );
+
+ if ( false !== field.data( 'confirm-delete' ) && ! confirm( CMBData.strings.confirmDeleteField ) ) {
return;
}
@@ -325,6 +328,34 @@ var CMB = {
this._sortEndCallbacks[fieldName] = this._sortEndCallbacks[fieldName] ? this._sortEndCallbacks[fieldName] : [];
this._sortEndCallbacks[fieldName].push( callback );
+ },
+
+ /**
+ * Simple debouncing function.
+ *
+ * @param func func function to run after wait period.
+ * @param wait int Wait interval.
+ * @param immediate bool Whether to run immediately or not.
+ * @returns {Function}
+ */
+ debounce: function debounce( func, wait, immediate ) {
+ var timeout;
+ return function() {
+ var context = this,
+ args = arguments;
+ var later = function() {
+ timeout = null;
+ if ( ! immediate ) {
+ func.apply( context, args );
+ }
+ };
+ var callNow = immediate && ! timeout;
+ clearTimeout( timeout );
+ timeout = setTimeout( later, wait );
+ if ( callNow ) {
+ func.apply( context, args );
+ }
+ };
}
};
diff --git a/js/field-gmap.js b/js/field-gmap.js
index 30e8dade..b8baad3f 100644
--- a/js/field-gmap.js
+++ b/js/field-gmap.js
@@ -100,6 +100,6 @@
CMB.addCallbackForClonedField( ['CMB_Gmap_Field'], CMBGmapsInit );
};
- $.getScript( '//maps.google.com/maps/api/js?sensor=true&libraries=places&callback=CMB_CMAPS_INIT&key=' + CMBGmaps.key );
+ $.getScript( '//maps.google.com/maps/api/js?sensor=true&libraries=places&language=' + CMBGmaps.language + '&callback=CMB_CMAPS_INIT&key=' + CMBGmaps.key );
}(jQuery));
diff --git a/js/field-wysiwyg.js b/js/field-wysiwyg.js
index b7640210..a1c32ea8 100644
--- a/js/field-wysiwyg.js
+++ b/js/field-wysiwyg.js
@@ -63,16 +63,17 @@ CMB.addCallbackForClonedField( 'CMB_wysiwyg', function( newT ) {
var ed = tinymce.init( tinyMCEPreInit.mceInit[id] );
} else if ( tinyMCE.majorVersion === '3' ) {
var ed = new tinymce.Editor( id, tinyMCEPreInit.mceInit[id] );
+ ed.render();
}
- ed.render();
}
- // Init Quicktags.
- QTags.instances[0] = undefined;
- try {
- quicktags( tinyMCEPreInit.qtInit[ id ] );
- } catch ( e ) {}
-
+ // Init Quicktags, only if we have have QuickTags specified.
+ if ( ! jQuery.isEmptyObject( newQTS ) ) {
+ QTags.instances[ 0 ] = undefined;
+ try {
+ quicktags( tinyMCEPreInit.qtInit[ id ] );
+ } catch ( e ) {}
+ }
} );
} );
diff --git a/js/file-upload.js b/js/file-upload.js
index ebd07886..14a81881 100644
--- a/js/file-upload.js
+++ b/js/file-upload.js
@@ -99,8 +99,7 @@ jQuery( document ).ready( function() {
var el = jQuery( this ),
container = el.closest( '.postbox' ),
- width = container.width() - 12 - 10 - 10,
- ratio = el.height() / el.width();
+ width = container.width() - 12 - 10 - 10 - 2;
if ( el.attr( 'data-original-width' ) ) {
el.width( el.attr( 'data-original-width' ) );
@@ -114,18 +113,30 @@ jQuery( document ).ready( function() {
el.attr( 'data-original-height', el.height() );
}
- if ( el.width() > width ) {
- el.width( width );
- el.find( '.cmb-file-wrap-placeholder' ).width( width - 8 );
- el.height( width * ratio );
- el.css( 'line-height', ( width * ratio ) + 'px' );
- el.find( '.cmb-file-wrap-placeholder' ).height( ( width * ratio ) - 8 );
+ var ratio = el.height() / el.width();
+
+ if ( el.width() > width || ( width > el.width() && width <= el.data( 'max-width' ) ) ) {
+ resizeFileBox( el, width, ratio );
}
} );
+
+ function resizeFileBox( element, width, ratio ) {
+ element.width( width );
+ element.find( '.cmb-file-wrap-placeholder' ).width( width - 8 );
+ element.height( width * ratio );
+ element.css( 'line-height', ( width * ratio ) + 'px' );
+ element.find( '.cmb-file-wrap-placeholder' ).height( ( width * ratio ) - 8 );
+ }
};
recalculateFileFieldSize();
- jQuery( window ).resize( recalculateFileFieldSize );
+
+ var debounce = CMB.debounce( function() {
+ recalculateFileFieldSize();
+ }, 100 );
+
+ // Recheck the width every time that the window is re-sized, debounced.
+ window.addEventListener( 'resize', debounce );
} );
diff --git a/languages/cmb-de_DE.mo b/languages/cmb-de_DE.mo
new file mode 100644
index 00000000..07460485
Binary files /dev/null and b/languages/cmb-de_DE.mo differ
diff --git a/languages/cmb-de_DE.po b/languages/cmb-de_DE.po
new file mode 100644
index 00000000..b10e2b2f
--- /dev/null
+++ b/languages/cmb-de_DE.po
@@ -0,0 +1,104 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Custom Meta Boxes\n"
+"POT-Creation-Date: 2017-02-07 11:11+0100\n"
+"PO-Revision-Date: 2017-02-07 11:12+0100\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: de_DE\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.11\n"
+"X-Poedit-Basepath: ..\n"
+"X-Poedit-WPHeader: custom-meta-boxes.php\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
+"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
+"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPathExcluded-0: *.js\n"
+
+#: class.cmb-meta-box.php:163
+msgid "Are you sure you want to delete this field?"
+msgstr "Sind Sie sicher, dass Sie dieses Feld löschen wollen?"
+
+#: class.cmb-meta-box.php:455
+msgid ""
+"Calling sortable on a non-repeatable field. A field cannot be sortable "
+"without being repeatable."
+msgstr ""
+"Das \"sortable\" Attribut ist ein nicht-wiederholbares Feld zugewiesen. Ein "
+"Feld kann nicht \"sortable\" sein wenn es nicht \"repeatable\" ist."
+
+#: classes.fields.php:92
+msgid "Add New"
+msgstr "Neu hinzufügen"
+
+#: classes.fields.php:93 classes.fields.php:729 classes.fields.php:816
+msgid "Remove"
+msgstr "Entfernen"
+
+#: classes.fields.php:707
+msgid "Add File"
+msgstr "Datei hinzufügen"
+
+#: classes.fields.php:804
+msgid "Add Image"
+msgstr "Bild hinzufügen"
+
+#: classes.fields.php:1539
+msgid "None"
+msgstr "Keine"
+
+#: classes.fields.php:1572
+msgid "Type to search"
+msgstr "Suchbegriff"
+
+#: classes.fields.php:1970
+msgid "Add New Group"
+msgstr "Neue Gruppe hinzufügen"
+
+#: classes.fields.php:1971
+msgid "Remove Group"
+msgstr "Gruppe löschen"
+
+#: example-functions.php:42
+msgid "Name"
+msgstr "Name"
+
+#: example-functions.php:45
+msgid "Repeatable"
+msgstr "Wiederholbar"
+
+#: example-functions.php:200 fields/class-cmb-gmap-field.php:37
+msgid "Drag to set the exact location"
+msgstr "Platziere die Markierung, um den genauen Standort fest zu legen"
+
+#: example-functions.php:203 fields/class-cmb-gmap-field.php:38
+msgid "Google Maps API not loaded."
+msgstr "Google Maps API nicht geladen."
+
+#. Plugin Name of the plugin/theme
+msgid "Custom Meta Boxes"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://github.com/humanmade/Custom-Meta-Boxes"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"Lets you easily create metaboxes with custom fields that will blow your "
+"mind. Originally a fork of https://github.com/jaredatch/Custom-Metaboxes-and-"
+"Fields-for-WordPress."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Human Made Limited"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://hmn.md"
+msgstr ""
diff --git a/languages/cmb-hi_IN.mo b/languages/cmb-hi_IN.mo
new file mode 100644
index 00000000..611dab98
Binary files /dev/null and b/languages/cmb-hi_IN.mo differ
diff --git a/languages/cmb-hi_IN.po b/languages/cmb-hi_IN.po
new file mode 100644
index 00000000..167bec6b
--- /dev/null
+++ b/languages/cmb-hi_IN.po
@@ -0,0 +1,90 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Custom Meta Boxes\n"
+"POT-Creation-Date: 2017-01-12 23:28+0530\n"
+"PO-Revision-Date: 2017-01-12 23:53+0530\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: hi_IN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.7\n"
+"X-Poedit-Basepath: ..\n"
+"X-Poedit-WPHeader: custom-meta-boxes.php\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
+"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
+"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPathExcluded-0: *.js\n"
+
+#: class.cmb-meta-box.php:144
+msgid "Are you sure you want to delete this field?"
+msgstr "आप इस फील्ड को नष्ट करना चाहते हैं आप सुनिश्चित हैं?"
+
+#: classes.fields.php:94
+msgid "Add New"
+msgstr "नया जोड़ें"
+
+#: classes.fields.php:95 classes.fields.php:622 classes.fields.php:709
+msgid "Remove"
+msgstr "हटाना"
+
+#: classes.fields.php:600
+msgid "Add File"
+msgstr "फाइल जोडें"
+
+#: classes.fields.php:697
+msgid "Add Image"
+msgstr "छवि जोड़ें"
+
+#: classes.fields.php:1433
+msgid "None"
+msgstr "कुछ नहीं "
+
+#: classes.fields.php:1466
+msgid "Type to search"
+msgstr "खोजने के लिए लिखें"
+
+#: classes.fields.php:1862
+msgid "Add New Group"
+msgstr "नया समूह जोड़ें"
+
+#: classes.fields.php:1863
+msgid "Remove Group"
+msgstr "समूह को निकालें"
+
+#: classes.fields.php:2099
+msgid "Drag to set the exact location"
+msgstr "खींचें सटीक स्थान निर्धारित करने के लिए"
+
+#: classes.fields.php:2100
+msgid "Google Maps API not loaded."
+msgstr "गूगल मैप्स एपीआई लोड नहीं।"
+
+#. Plugin Name of the plugin/theme
+msgid "Custom Meta Boxes"
+msgstr "कस्टम मेटा बक्से"
+
+#. Plugin URI of the plugin/theme
+msgid "https://github.com/humanmade/Custom-Meta-Boxes"
+msgstr "https://github.com/humanmade/Custom-Meta-Boxes"
+
+#. Description of the plugin/theme
+msgid ""
+"Lets you easily create metaboxes with custom fields that will blow your "
+"mind. Originally a fork of https://github.com/jaredatch/Custom-Metaboxes-and-"
+"Fields-for-WordPress."
+msgstr ""
+"आप आसानी से कस्टम मेट बॉक्सेस और फ़ील्ड्स बना सकते हैं। मूलतः https://github.com/"
+"jaredatch/Custom-Metaboxes-and-Fields-for-WordPress"
+
+#. Author of the plugin/theme
+msgid "Human Made Limited"
+msgstr "ह्यूमन मेड लिमिटेड "
+
+#. Author URI of the plugin/theme
+msgid "http://hmn.md"
+msgstr "http://hmn.md"
diff --git a/languages/cmb-nl_NL.mo b/languages/cmb-nl_NL.mo
new file mode 100644
index 00000000..c385b83e
Binary files /dev/null and b/languages/cmb-nl_NL.mo differ
diff --git a/languages/cmb-nl_NL.po b/languages/cmb-nl_NL.po
new file mode 100644
index 00000000..8c052f32
--- /dev/null
+++ b/languages/cmb-nl_NL.po
@@ -0,0 +1,104 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: Custom Meta Boxes\n"
+"POT-Creation-Date: 2017-02-07 11:12+0100\n"
+"PO-Revision-Date: 2017-02-07 11:15+0100\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: nl_NL\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 1.8.11\n"
+"X-Poedit-Basepath: ..\n"
+"X-Poedit-WPHeader: custom-meta-boxes.php\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"X-Poedit-SourceCharset: UTF-8\n"
+"X-Poedit-KeywordsList: __;_e;_n:1,2;_x:1,2c;_ex:1,2c;_nx:4c,1,2;esc_attr__;"
+"esc_attr_e;esc_attr_x:1,2c;esc_html__;esc_html_e;esc_html_x:1,2c;_n_noop:1,2;"
+"_nx_noop:3c,1,2;__ngettext_noop:1,2\n"
+"X-Poedit-SearchPath-0: .\n"
+"X-Poedit-SearchPathExcluded-0: *.js\n"
+
+#: class.cmb-meta-box.php:163
+msgid "Are you sure you want to delete this field?"
+msgstr "Weet je zeker dat je dit veld wilt wissen?"
+
+#: class.cmb-meta-box.php:455
+msgid ""
+"Calling sortable on a non-repeatable field. A field cannot be sortable "
+"without being repeatable."
+msgstr ""
+"Sortable op een niet-herhaalbare veld opgeroepen. Een veld kan niet "
+"sorteerbaar zijn zonder dat het herhaalbaar is."
+
+#: classes.fields.php:92
+msgid "Add New"
+msgstr "Toevoegen"
+
+#: classes.fields.php:93 classes.fields.php:729 classes.fields.php:816
+msgid "Remove"
+msgstr "Verwijder"
+
+#: classes.fields.php:707
+msgid "Add File"
+msgstr "Bestand Toevoegen"
+
+#: classes.fields.php:804
+msgid "Add Image"
+msgstr "Afbeelding toevoegen"
+
+#: classes.fields.php:1539
+msgid "None"
+msgstr "Geen"
+
+#: classes.fields.php:1572
+msgid "Type to search"
+msgstr "Type hier om te zoeken"
+
+#: classes.fields.php:1970
+msgid "Add New Group"
+msgstr "Nieuwe groep toevoegen"
+
+#: classes.fields.php:1971
+msgid "Remove Group"
+msgstr "Verwijder groep"
+
+#: example-functions.php:42
+msgid "Name"
+msgstr "Naam"
+
+#: example-functions.php:45
+msgid "Repeatable"
+msgstr "Herhaalbaar"
+
+#: example-functions.php:200 fields/class-cmb-gmap-field.php:37
+msgid "Drag to set the exact location"
+msgstr "Sleep de marker om de exacte locatie in te stellen"
+
+#: example-functions.php:203 fields/class-cmb-gmap-field.php:38
+msgid "Google Maps API not loaded."
+msgstr "Google Maps API niet geladen."
+
+#. Plugin Name of the plugin/theme
+msgid "Custom Meta Boxes"
+msgstr ""
+
+#. Plugin URI of the plugin/theme
+msgid "https://github.com/humanmade/Custom-Meta-Boxes"
+msgstr ""
+
+#. Description of the plugin/theme
+msgid ""
+"Lets you easily create metaboxes with custom fields that will blow your "
+"mind. Originally a fork of https://github.com/jaredatch/Custom-Metaboxes-and-"
+"Fields-for-WordPress."
+msgstr ""
+
+#. Author of the plugin/theme
+msgid "Human Made Limited"
+msgstr ""
+
+#. Author URI of the plugin/theme
+msgid "http://hmn.md"
+msgstr ""
diff --git a/package.json b/package.json
index a560acb7..7454a104 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "Custom-Meta-Boxes",
- "version": "1.0.1",
+ "version": "1.1.0",
"description": "Lets you easily create metaboxes with custom fields that will blow your mind.",
"homepage": "https://github.com/humanmade/Custom-Meta-Boxes/",
"repository": {
diff --git a/readme.md b/readme.md
index 20cbdafe..abc4d846 100644
--- a/readme.md
+++ b/readme.md
@@ -2,7 +2,7 @@
HM Custom Meta Boxes for WordPress
- A framework for easily adding custom fields to the WordPress post edit page
+ A framework for easily adding custom fields to the WordPress post edit page
|
@@ -46,6 +46,10 @@ This plugin is maintained by [Human Made Limited](http://hmn.md)
It began as a fork of [Custom Meta Boxes](https://github.com/jaredatch/Custom-Metaboxes-and-Fields-for-WordPress), but is no longer compatible.
+## Minimum Requirements:
+* PHP >= 5.4
+* WP >= 4.1
+
## Known Issues
* Some fields do not work well as repeatable fields.
* Some fields do not work well in repeatable groups.
@@ -56,6 +60,25 @@ See [CONTRIBUTING.md](https://github.com/humanmade/Custom-Meta-Boxes/blob/master
## Changelog ##
+**1.1**
+
+_Enhancements_
+ - Added group field filter
+ - Cleaned up file upload styles
+ - Added Hindi translation (props @ajitbohra)
+ - Move all field classes to their own files
+ - Add min/max attributes to number input (props @shadvb)
+ - Use site language with Google Maps field (props @barryceelen)
+
+_Bug Fixes_
+ - Filter all arguments, not just select ones
+ - Only attempt to call getimagesize() if the icon is local (props @joehoyle)
+ - Add Dutch and German translations (props @barryceelen)
+ - Align the file button vertically (props @ocean90)
+ - Fix for multiple wysiwyg fields not displaying in groups (props @tareiking)
+ - Fix incorrect gmap grouped field structure (props @dan-westall)
+ - Fix enqueuing of cmb-scripts (props @barryceelen)
+
**1.0.3**
* Fix repeatable fields bugs (props @barryceelen )
* Fix gmaps field bug where key doesn't pass in correctly (props: @shadyvb )
diff --git a/tests/bootstrap.php b/tests/bootstrap.php
index 9d9bcebf..4d56e165 100644
--- a/tests/bootstrap.php
+++ b/tests/bootstrap.php
@@ -1,5 +1,19 @@
getMethod( $method_name );
+ $method->setAccessible( true );
+
+ return $method->invokeArgs( $object, $parameters );
+}
\ No newline at end of file
diff --git a/tests/class-test-field-case.php b/tests/class-test-field-case.php
new file mode 100644
index 00000000..66f1e556
--- /dev/null
+++ b/tests/class-test-field-case.php
@@ -0,0 +1,190 @@
+ 1,
+ 'post_status' => 'publish',
+ 'post_content' => rand_str(),
+ 'post_title' => rand_str(),
+ 'post_type' => 'post',
+ ];
+
+ // Setup a default post for usage within test.
+ $factory = new WP_UnitTest_Factory();
+ self::$post = $factory->post->create_and_get( $post_args );
+
+ // Capture WP Scripts object before usage.
+ self::$old_wp_scripts = isset( $GLOBALS['wp_scripts'] ) ? $GLOBALS['wp_scripts'] : null;
+ }
+
+ /**
+ * Clean up fixtures.
+ */
+ public static function tearDownAfterClass() {
+ parent::tearDownAfterClass();
+
+ wp_delete_post( self::$post->ID );
+ $GLOBALS['wp_scripts'] = self::$old_wp_scripts;
+ }
+
+ /**
+ * Update the argument set on a field class.
+ *
+ * @param $new_arguments
+ */
+ public function update_arguments( $new_arguments ) {
+ $this->instance->set_arguments( $new_arguments );
+ }
+
+ /**
+ * Reset the wp_script globals
+ */
+ public function reset_wp_scripts() {
+ $GLOBALS['wp_scripts'] = new WP_Scripts();
+ $GLOBALS['wp_scripts']->default_version = get_bloginfo( 'version' );
+ }
+
+ /**
+ * Verify that the field outputs with no errors for each argument set.
+ *
+ * @dataProvider argumentsProvider
+ *
+ * @param array $arguments Arguments to parse against.
+ */
+ public function test_field_output( $arguments ) {
+ $this->update_arguments( $arguments );
+
+ // Check the default HTML output.
+ // The point of these checks is to ensure that the field doesn't error out with each argument set.
+ $this->expectOutputRegex( '/data-class=\"' . get_class( $this->instance ) . '\"/' );
+ $this->instance->display();
+ }
+
+ /**
+ * Verify that the field saves values correctly to meta.
+ *
+ * @dataProvider valuesProvider
+ *
+ * @param mixed $value Value to save
+ * @param mixed $expected_value Optional. Expected value to save.
+ */
+ function test_save_value( $value, $expected_value = false ) {
+ $this->instance->save( self::$post->ID, $value );
+
+ // Usually, we only want to pass one value and not a parsed value. Accomodate this here.
+ if ( false === $expected_value ) {
+ $expected_value = $value;
+ }
+
+ // Verify single value is properly saved.
+ $this->assertEquals(
+ $expected_value,
+ get_post_meta( self::$post->ID, get_class( $this->instance ), false )
+ );
+ }
+
+ /**
+ * Provide a set of arguments to test against.
+ *
+ * Here we provide a default set of arguments to test each field against.
+ *
+ * @return array Default argument set.
+ */
+ public function argumentsProvider() {
+ return [
+ [ [] ],
+ [ [
+ 'id' => 'my-ID',
+ ] ],
+ [ [
+ 'id' => 'my-ID',
+ 'name' => 'My Name'
+ ] ],
+ [ [
+ 'id' => 'my-ID',
+ 'name' => 'My Name',
+ 'desc' => 'A long description',
+ ] ],
+ [ [
+ 'id' => 'my-ID',
+ 'name' => 'My Name',
+ 'desc' => 'A long description',
+ 'repeatable' => false,
+ 'sortable' => true,
+ ] ],
+ [ [
+ 'id' => 'my-ID',
+ 'name' => 'My Name',
+ 'desc' => 'A long description',
+ 'repeatable' => true,
+ 'sortable' => false,
+ ] ],
+ [ [
+ 'id' => 'my-ID',
+ 'name' => 'My Name',
+ 'desc' => 'A long description',
+ 'repeatable' => true,
+ 'sortable' => true,
+ 'cols' => 6,
+ 'readonly' => true,
+ 'disabled' => true,
+ 'class' => 'my-fancy-fancy-class',
+ ] ],
+
+ // @todo:: add default
+ ];
+ }
+
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * @return array Default values set.
+ */
+ public function valuesProvider() {
+ return [
+ [ [ 'A string' ] ],
+ [ [ 162735 ] ],
+ [ [ true ] ],
+ ];
+ }
+}
diff --git a/tests/fields/test-checkbox-field.php b/tests/fields/test-checkbox-field.php
new file mode 100644
index 00000000..8c2b81b3
--- /dev/null
+++ b/tests/fields/test-checkbox-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Checkbox( 'CMB_Checkbox', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-checkbox-multi-field.php b/tests/fields/test-checkbox-multi-field.php
new file mode 100644
index 00000000..dd754a97
--- /dev/null
+++ b/tests/fields/test-checkbox-multi-field.php
@@ -0,0 +1,75 @@
+instance = new CMB_Checkbox_Multi( 'CMB_Checkbox_Multi', 'Field', [] );
+ }
+
+ /**
+ * Test that the number field outputs correctly against an empty value set.
+ */
+ public function testEmptyFieldOutput() {
+ $field = new CMB_Checkbox_Multi( 'foo', 'Foo', array( 'value' => 'value' ), array( 'options' => array( 'value' => 'value' ) ) );
+
+ if ( ! self::$post ) {
+ $this->markTestSkipped( 'Post not found' );
+ }
+
+ $this->expectOutputRegex( '/(type=\"checkbox\".*?id=\"foo-cmb-field-0-item-value\".*?checked=\'checked\')/s' );
+
+ // Trigger output.
+ $field->html();
+ }
+
+ /**
+ * Test that the number field outputs correctly against a saved value set.
+ */
+ public function testSavedFieldOutput() {
+ $field = new CMB_Checkbox_Multi( 'foo', 'Foo', array( 'value' => 'value' ), array( 'options' => array( 'value' => 'value', 'value2' => 'value2' ) ) );
+
+ if ( ! self::$post ) {
+ $this->markTestSkipped( 'Post not found' );
+ }
+
+ $field->save( self::$post->ID, array( 'value2' => 'on' ) );
+
+ $this->expectOutputRegex( '/(type=\"checkbox\".*?id=\"foo-cmb-field-0-item-value2\".*?checked=\'checked\')/s' );
+
+ // Trigger output.
+ $field->html();
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'options' => [ 'Option 1', 'Option 2', 'Option 3' ],
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-color-field.php b/tests/fields/test-color-field.php
new file mode 100644
index 00000000..aa16cff3
--- /dev/null
+++ b/tests/fields/test-color-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Color_Picker( 'CMB_Color_Picker', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-date-field.php b/tests/fields/test-date-field.php
new file mode 100644
index 00000000..d3fdf6dc
--- /dev/null
+++ b/tests/fields/test-date-field.php
@@ -0,0 +1,58 @@
+instance = new CMB_Date_Field( 'CMB_Date_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that all required scripts & styles are correctly loaded.
+ */
+ function testAssets() {
+ global $wp_version;
+
+ $this->reset_wp_scripts();
+
+ // Register CMB-Scripts as this is a dependency.
+ wp_register_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
+
+ $this->instance->enqueue_scripts();
+ $this->instance->enqueue_styles();
+
+ $scripts_output = get_echo( 'wp_print_scripts' );
+ $styles_output = get_echo( 'wp_print_styles' );
+
+ // Scripts
+ $this->assertContains( '/js/field.datetime.js', $scripts_output );
+ $this->assertContains( '/js/cmb.js', $scripts_output );
+ if ( version_compare( $wp_version, '4.1', '>=' ) ) {
+ $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/core.min.js', $scripts_output );
+ $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/datepicker.min.js', $scripts_output );
+ } else {
+ $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/jquery.ui.core.min.js', $scripts_output );
+ $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js', $scripts_output );
+ }
+
+ // Styles
+ $this->assertContains( 'css/vendor/jquery-ui/jquery-ui.css', $styles_output );
+ }
+}
diff --git a/tests/fields/test-date-time-timestamp-field.php b/tests/fields/test-date-time-timestamp-field.php
new file mode 100644
index 00000000..a4d5c4e7
--- /dev/null
+++ b/tests/fields/test-date-time-timestamp-field.php
@@ -0,0 +1,73 @@
+instance = new CMB_Datetime_Timestamp_Field( 'CMB_Datetime_Timestamp_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that all required scripts & styles are correctly loaded.
+ */
+ function testAssets() {
+ $this->reset_wp_scripts();
+
+ // Register CMB-Scripts as this is a dependency.
+ wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
+
+ $this->instance->enqueue_scripts();
+
+ $scripts_output = get_echo( 'wp_print_scripts' );
+
+ // Scripts
+ $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
+ }
+
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * @return array Default values set.
+ */
+ public function valuesProvider() {
+ return [
+ [
+ [
+ [
+ 'date' => '12/12/2012',
+ 'time' => '12:00 am',
+ ],
+ ],
+ [ '1355270400' ],
+ ],
+ [
+ [
+ [
+ 'date' => '12/12/2112',
+ 'time' => '12:00 am',
+ ],
+ ],
+ [ '4510944000' ],
+ ],
+ ];
+ }
+}
diff --git a/tests/fields/test-date-timestamp-field.php b/tests/fields/test-date-timestamp-field.php
new file mode 100644
index 00000000..8f1c8bc2
--- /dev/null
+++ b/tests/fields/test-date-timestamp-field.php
@@ -0,0 +1,57 @@
+instance = new CMB_Date_Timestamp_Field( 'CMB_Date_Timestamp_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that all required scripts & styles are correctly loaded.
+ */
+ function testAssets() {
+ $this->reset_wp_scripts();
+
+ // Register CMB-Scripts as this is a dependency.
+ wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
+
+ $this->instance->enqueue_scripts();
+
+ $scripts_output = get_echo( 'wp_print_scripts' );
+
+ // Scripts
+ $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
+ }
+
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * @return array Default values set.
+ */
+ public function valuesProvider() {
+ return [
+ [ [ '12/12/2012' ], [ '1355270400' ] ],
+ [ [ '12/12/2112' ], [ '4510944000' ] ],
+ ];
+ }
+}
diff --git a/tests/fields/test-email-field.php b/tests/fields/test-email-field.php
new file mode 100644
index 00000000..a3b1ca3f
--- /dev/null
+++ b/tests/fields/test-email-field.php
@@ -0,0 +1,55 @@
+instance = new CMB_Email_Field( 'CMB_Email_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that the number field outputs correctly against more specific field output.
+ */
+ function testFieldOutput() {
+ $field = new CMB_Email_Field( 'foo', 'Foo', array( 'hm@hmn.md' ) );
+
+ if ( ! self::$post ) {
+ $this->markTestSkipped( 'Post not found' );
+ }
+
+ $this->expectOutputRegex( '/(type=\"email\".*?id=\"foo-cmb-field-0\".*?value=\"hm@hmn.md\")/s' );
+
+ // Trigger output.
+ $field->html();
+ }
+
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * @return array Default values set.
+ */
+ public function valuesProvider() {
+ return [
+ [ [ 'A string' ] ],
+ [ [ 'hm@md.com' ] ],
+ [ [ 'mike@mike.co.uk' ] ],
+ ];
+ }
+}
diff --git a/tests/fields/test-gmap-field.php b/tests/fields/test-gmap-field.php
new file mode 100644
index 00000000..1da4158d
--- /dev/null
+++ b/tests/fields/test-gmap-field.php
@@ -0,0 +1,43 @@
+instance = new CMB_Gmap_Field( 'CMB_Gmap_Field', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'google_api_key' => 'abcdefghijk',
+ 'default_lat' => '1.234',
+ 'default_long' => '1.234',
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/testGroupField.php b/tests/fields/test-group-field.php
similarity index 61%
rename from tests/testGroupField.php
rename to tests/fields/test-group-field.php
index 58cfecb6..93c170a0 100644
--- a/tests/testGroupField.php
+++ b/tests/fields/test-group-field.php
@@ -1,9 +1,34 @@
instance = new CMB_Group_Field( 'CMB_Group_Field', 'Field', [] );
+ }
-class GroupFieldTestCase extends WP_UnitTestCase {
-
+ /**
+ * Test that a fields are correctly added to a group field.
+ */
function testAddField() {
-
$group = new CMB_Group_Field( 'group', 'Group Title', array() );
$field1 = new CMB_Text_Field( 'foo', 'Title', array( 1 ) );
$field2 = new CMB_Text_Field( 'bar', 'Title', array( 2, 3 ), array( 'repeatable' => true ) );
@@ -13,11 +38,12 @@ function testAddField() {
$this->assertArrayHasKey( 'foo', $group->get_fields() );
$this->assertArrayHasKey( 'bar', $group->get_fields() );
-
}
+ /**
+ * Test that value retrieval within a group field works correctly.
+ */
function testGetValues() {
-
$group = new CMB_Group_Field( 'group', 'Group Title', array() );
$field1 = new CMB_Text_Field( 'foo', 'Title', array() );
$field2 = new CMB_Text_Field( 'bar', 'Title', array() );
@@ -33,11 +59,12 @@ function testGetValues() {
);
$this->assertEquals( $group->get_values(), $values );
-
}
+ /**
+ * Test that vsaving values within a group field works correctly.
+ */
function testParseSaveValues() {
-
$group = new CMB_Group_Field( 'group', 'Group Title', array() );
$field1 = new CMB_Text_Field( 'foo', 'Title', array( 1 ) );
$field2 = new CMB_Text_Field( 'bar', 'Title', array( 2, 3 ), array( 'repeatable' => true ) );
@@ -62,11 +89,12 @@ function testParseSaveValues() {
$group->parse_save_values();
$this->assertEquals( $group->get_values(), $expected );
-
}
+ /**
+ * Test that the name attribute works correctly.
+ */
function testFieldNameAttrValue() {
-
$group = new CMB_Group_Field( 'group', 'Group Title', array() );
$field1 = new CMB_Text_Field( 'foo', 'Title', array( 1, 2 ) );
@@ -98,11 +126,12 @@ function testFieldNameAttrValue() {
$id_attr = $field1->get_the_name_attr();
$this->assertEquals( $id_attr, 'group[cmb-group-12][foo][cmb-field-0]' );
$group->field_index = 0; // Unset
-
}
+ /**
+ * Test that the ID attribute works correctly.
+ */
function testFieldIdAttrValue() {
-
$group = new CMB_Group_Field( 'group', 'Group Title', array() );
$field1 = new CMB_Text_Field( 'foo', 'Title', array( 1, 2 ) );
@@ -134,6 +163,83 @@ function testFieldIdAttrValue() {
$id_attr = $field1->get_the_id_attr();
$this->assertEquals( $id_attr, 'group-cmb-group-12-foo-cmb-field-0' );
$group->field_index = 0; // Unset
+ }
+
+ /**
+ * Verify that the field saves values correctly to meta.
+ *
+ * We need to override this method because inner fields must be setup
+ * in order for saving to work correctly.
+ *
+ * @dataProvider valuesProvider
+ *
+ * @param mixed $value Value to save
+ * @param mixed $expected_value Optional. Expected value to save.
+ */
+ function test_save_value( $value, $expected_value = false ) {
+ $this->instance->add_field( new CMB_Text_Field( 'foo', 'Title', array( 1, 2 ) ) );
+
+ $this->instance->save( self::$post->ID, $value );
+
+ // Usually, we only want to pass one value and not a parsed value. Accomodate this here.
+ if ( false === $expected_value ) {
+ $expected_value = $value;
+ }
+
+ // Verify single value is properly saved.
+ $this->assertEquals(
+ $expected_value,
+ get_post_meta( self::$post->ID, get_class( $this->instance ), false )
+ );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'fields' => [
+ [
+ 'id' => 'gac-4-f-1',
+ 'name' => 'Text input field',
+ 'type' => 'text',
+ ],
+ [
+ 'id' => 'gac-4-f-2',
+ 'name' => 'Text input field',
+ 'type' => 'text',
+ ],
+ ],
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * P.S. the data structure for this field is NUTS.
+ *
+ * @return array Values set.
+ */
+ public function valuesProvider() {
+ return [
+ [
+ [ [ 'foo' => [ 'A string' ] ] ],
+ [ [ 'foo' => 'A string' ] ],
+ ],
+ [
+ [ [ 'foo' => [ 162735 ] ] ],
+ [ [ 'foo' => 162735 ] ],
+ ],
+ [
+ [ [ 'foo' => [ true ] ] ],
+ [ [ 'foo' => true ] ],
+ ],
+ ];
}
}
diff --git a/tests/fields/test-hidden-field.php b/tests/fields/test-hidden-field.php
new file mode 100644
index 00000000..217e0b78
--- /dev/null
+++ b/tests/fields/test-hidden-field.php
@@ -0,0 +1,42 @@
+instance = new CMB_Hidden_Field( 'CMB_Hidden_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that the number field outputs correctly against more specific field output.
+ */
+ function testFieldOutput() {
+ $field = new CMB_Hidden_Field( 'foo', 'Foo', array( 'value' ) );
+
+ if ( ! self::$post ) {
+ $this->markTestSkipped( 'Post not found' );
+ }
+
+ $this->expectOutputRegex( '/(type=\"hidden\".*?id=\"foo-cmb-field-0\".*?value=\"value\")/s' );
+
+ // Trigger output.
+ $field->html();
+ }
+}
diff --git a/tests/fields/test-image-field.php b/tests/fields/test-image-field.php
new file mode 100644
index 00000000..441e3f06
--- /dev/null
+++ b/tests/fields/test-image-field.php
@@ -0,0 +1,37 @@
+instance = new CMB_Image_Field( 'CMB_Image_Field', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'size' => 175,
+ ],
+ [
+ 'size' => 175,
+ 'show_size' => true,
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-number-field.php b/tests/fields/test-number-field.php
new file mode 100644
index 00000000..408bd795
--- /dev/null
+++ b/tests/fields/test-number-field.php
@@ -0,0 +1,55 @@
+instance = new CMB_Number_Field( 'CMB_Number_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that the number field outputs correctly against more specific field output.
+ */
+ function testFieldOutput() {
+ $field = new CMB_Number_Field( 'foo', 'Foo', array( 0.5 ), array( 'min' => 0.4, 'max' => 1 ) );
+
+ if ( ! self::$post ) {
+ $this->markTestSkipped( 'Post not found' );
+ }
+
+ $this->expectOutputRegex( '/min="0.4".*max="1".*(type=\"number\".*?id=\"foo-cmb-field-0\".*?value=\"0.5\")/s' );
+
+ // Trigger output.
+ $field->html();
+ }
+
+ /**
+ * Provide a default set of values to test saving against.
+ *
+ * @return array Default values set.
+ */
+ public function valuesProvider() {
+ return [
+ [ [ '1' ] ],
+ [ [ 162735 ] ],
+ [ [ 0.5 ] ],
+ ];
+ }
+}
diff --git a/tests/fields/test-post-select-field.php b/tests/fields/test-post-select-field.php
new file mode 100644
index 00000000..9ca982e6
--- /dev/null
+++ b/tests/fields/test-post-select-field.php
@@ -0,0 +1,52 @@
+instance = new CMB_Post_Select( 'CMB_Post_Select', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'use_ajax' => true,
+ ],
+ [
+ 'use_ajax' => true,
+ 'multiple' => true,
+ ],
+ [
+ 'use_ajax' => true,
+ 'multiple' => true,
+ 'query' => [
+ 'posts_per_page' => 20,
+ ],
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-radio-field.php b/tests/fields/test-radio-field.php
new file mode 100644
index 00000000..dbacb2da
--- /dev/null
+++ b/tests/fields/test-radio-field.php
@@ -0,0 +1,41 @@
+instance = new CMB_Radio_Field( 'CMB_Radio_Field', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'options' => [ 'Option 1', 'Option 2', 'Option 3' ],
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-select-field.php b/tests/fields/test-select-field.php
new file mode 100644
index 00000000..312b2990
--- /dev/null
+++ b/tests/fields/test-select-field.php
@@ -0,0 +1,49 @@
+instance = new CMB_Select( 'CMB_Select', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'options' => [ 'Option 1', 'Option 2', 'Option 3' ],
+ 'select2_options' => [ 'an' => 'option' ],
+ 'allow_none' => true,
+ 'multiple' => true,
+ ],
+ [
+ 'options' => [ 'Option 1', 'Option 2', 'Option 3' ],
+ 'allow_none' => true,
+ 'multiple' => false,
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-taxonomy-field.php b/tests/fields/test-taxonomy-field.php
new file mode 100644
index 00000000..2a8299f7
--- /dev/null
+++ b/tests/fields/test-taxonomy-field.php
@@ -0,0 +1,53 @@
+instance = new CMB_Taxonomy( 'CMB_Taxonomy', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'taxonomy' => 'post_tag',
+ 'hide_empty' => false,
+ 'multiple' => true,
+ ],
+ [
+ 'taxonomy' => 'post_tag',
+ 'hide_empty' => true,
+ 'multiple' => true,
+ ],
+ [
+ 'taxonomy' => 'post_tag',
+ 'hide_empty' => false,
+ 'multiple' => false,
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/fields/test-text-field.php b/tests/fields/test-text-field.php
new file mode 100644
index 00000000..87cb20fa
--- /dev/null
+++ b/tests/fields/test-text-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Text_Field( 'CMB_Text_Field', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-text-small-field.php b/tests/fields/test-text-small-field.php
new file mode 100644
index 00000000..1bbfc280
--- /dev/null
+++ b/tests/fields/test-text-small-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Text_Small_Field( 'CMB_Text_Small_Field', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-textarea-code-field.php b/tests/fields/test-textarea-code-field.php
new file mode 100644
index 00000000..b6205e38
--- /dev/null
+++ b/tests/fields/test-textarea-code-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Textarea_Field_Code( 'CMB_Textarea_Field_Code', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-textarea-field.php b/tests/fields/test-textarea-field.php
new file mode 100644
index 00000000..4a1469a3
--- /dev/null
+++ b/tests/fields/test-textarea-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Textarea_Field( 'CMB_Textarea_Field', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-time-field.php b/tests/fields/test-time-field.php
new file mode 100644
index 00000000..f7dca55b
--- /dev/null
+++ b/tests/fields/test-time-field.php
@@ -0,0 +1,45 @@
+instance = new CMB_Time_Field( 'CMB_Time_Field', 'Field', [] );
+ }
+
+ /**
+ * Test that all required scripts & styles are correctly loaded.
+ */
+ function testAssets() {
+ $this->reset_wp_scripts();
+
+ // Register CMB-Scripts as this is a dependency.
+ wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
+
+ $this->instance->enqueue_scripts();
+
+ $scripts_output = get_echo( 'wp_print_scripts' );
+
+ // Scripts
+ $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
+ $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
+ }
+}
diff --git a/tests/fields/test-title-code-field.php b/tests/fields/test-title-code-field.php
new file mode 100644
index 00000000..29aa1061
--- /dev/null
+++ b/tests/fields/test-title-code-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_Title( 'CMB_Title', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-url-code-field.php b/tests/fields/test-url-code-field.php
new file mode 100644
index 00000000..8f886ca3
--- /dev/null
+++ b/tests/fields/test-url-code-field.php
@@ -0,0 +1,26 @@
+instance = new CMB_URL_Field( 'CMB_URL_Field', 'Field', [] );
+ }
+}
diff --git a/tests/fields/test-wysiwyg-code-field.php b/tests/fields/test-wysiwyg-code-field.php
new file mode 100644
index 00000000..5fa1ffc8
--- /dev/null
+++ b/tests/fields/test-wysiwyg-code-field.php
@@ -0,0 +1,41 @@
+instance = new CMB_wysiwyg( 'CMB_wysiwyg', 'Field', [] );
+ }
+
+ /**
+ * Update our default argument set with specific args.
+ *
+ * @return array
+ */
+ public function argumentsProvider() {
+ $args = [
+ [
+ 'options' => [ 'editor_height' => 500 ],
+ ],
+ ];
+
+ return array_merge( $args, parent::argumentsProvider() );
+ }
+}
diff --git a/tests/testCmbMetaBoxClass.php b/tests/testCmbMetaBoxClass.php
new file mode 100644
index 00000000..e7b60e73
--- /dev/null
+++ b/tests/testCmbMetaBoxClass.php
@@ -0,0 +1,188 @@
+factory();
+ } else {
+ $factory = $this->factory;
+ }
+
+ // Create a test post.
+ $this->post_id = $factory->post->create(
+ array(
+ 'post_author' => get_current_user_id(),
+ 'post_title' => 'My test post',
+ 'post_type' => 'post',
+ 'post_status' => 'publish',
+ )
+ );
+
+ $this->simple_fields = array(
+ 'title' => 'Simple',
+ 'pages' => 'post',
+ 'fields' => array(
+ array(
+ 'id' => 'text',
+ 'name' => 'Simple',
+ 'type' => 'text',
+ 'repeatable' => false,
+ ),
+ ),
+ );
+
+ $this->group_fields = array(
+ 'title' => 'Simple',
+ 'pages' => 'post',
+ 'fields' => array(
+ array(
+ 'id' => 'text',
+ 'name' => 'Simple',
+ 'type' => 'group',
+ 'fields' => array(
+ array(
+ 'id' => 'text',
+ 'name' => 'Simple',
+ 'type' => 'text',
+ ),
+ array(
+ 'id' => 'text2',
+ 'name' => 'Simple 2',
+ 'type' => 'text',
+ ),
+ ),
+ ),
+ ),
+ );
+
+ // Assign an admin user as we now check that you have proper permissions before passing a field.
+ wp_set_current_user( $this->factory->user->create( array( 'role' => 'administrator' ) ) );
+
+ }
+
+ /**
+ * Clean up after a test.
+ */
+ function tearDown() {
+ wp_delete_post( $this->post_id );
+ parent::tearDown();
+ }
+
+
+ function test_values_from_init_non_repeatable() {
+
+ $values = array( 1, 2, 3, 4, 5 );
+
+ $field = $this->intialize_fields( $this->simple_fields, $values );
+
+ // Check that a non-repeatable field only returns one value.
+ // The new instance of the field is 1.
+ $this->assertEquals( array( 1 ), $field->values );
+ }
+
+ function test_values_from_init_repeatable() {
+
+ // Change simple field to be a repeatable.
+ $this->simple_fields['fields'][0]['repeatable'] = true;
+
+ $values = array( 1, 2, 3, 4, 5 );
+
+ $field = $this->intialize_fields( $this->simple_fields, $values );
+
+ // Check that a non-repeatable field only returns one value.
+ // The new instance of the field is 1.
+ $this->assertEquals( array( 1, 2, 3, 4, 5 ), $field->values );
+ }
+
+ function test_values_from_init_group_non_repeatable() {
+
+ $values = array(
+ array(
+ 'text' => array( 'one', 'two', 'three' ),
+ 'text2' => array( 'four', 'five', 'six' ),
+ )
+ );
+
+ $field = $this->intialize_fields( $this->group_fields, $values );
+
+ // Check that a non-repeatable field only returns one value.
+ // The new instance of the field is 1.
+ $this->assertEquals( array( array( 'text' => 'one', 'text2' => 'four' ) ), $field->values );
+ }
+
+ function test_values_from_init_group_repeatable() {
+
+ // Change fields to be a repeatable.
+ $this->group_fields['fields'][0]['fields'][0]['repeatable'] = true;
+ $this->group_fields['fields'][0]['fields'][1]['repeatable'] = true;
+
+ $values = array(
+ array(
+ 'text' => array( 'one', 'two', 'three' ),
+ 'text2' => array( 'four', 'five', 'six' ),
+ ),
+ );
+
+ $field = $this->intialize_fields( $this->group_fields, $values );
+
+ // Check that a non-repeatable field only returns one value.
+ // The new instance of the field is 1.
+ $this->assertEquals(
+ array(
+ array(
+ 'text' => array( 'one', 'two', 'three' ),
+ 'text2' => array( 'four', 'five', 'six' ),
+ ),
+ ),
+ $field->values
+ );
+ }
+
+ /**
+ * Mock up a CMB_MetaBox instance, save a field value and the return the boxes for testing
+ *
+ * @param $fields
+ * @param $values
+ * @return object Field type class instance.
+ */
+ private function intialize_fields( $fields, $values ) {
+ $boxes = new CMB_Meta_Box( $fields );
+ $boxes->init_fields( $this->post_id );
+
+ // Save some values for testing.
+ $boxes->fields[0]->save( $this->post_id, $values );
+
+ // Re-initialize the boxes and check the data.
+ $boxes->init_fields( $this->post_id );
+
+ return $boxes->fields[1];
+ }
+}
diff --git a/tests/testDateField.php b/tests/testDateField.php
deleted file mode 100644
index 8c2f070f..00000000
--- a/tests/testDateField.php
+++ /dev/null
@@ -1,103 +0,0 @@
-old_wp_scripts = isset( $GLOBALS['wp_scripts'] ) ? $GLOBALS['wp_scripts'] : null;
- $GLOBALS['wp_scripts'] = new WP_Scripts();
- $GLOBALS['wp_scripts']->default_version = get_bloginfo( 'version' );
- }
-
- function tearDown() {
- $GLOBALS['wp_scripts'] = $this->old_wp_scripts;
- parent::tearDown();
- }
-
- /**
- * Test that all required scripts & styles are correctly loaded.
- */
- function testDateFieldAssets() {
- global $wp_version;
-
- $field = new CMB_Date_Field( 'foo', 'Title', array() );
-
- // Register CMB-Scripts as this is a dependency.
- wp_register_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
-
- $field->enqueue_scripts();
- $field->enqueue_styles();
-
- $scripts_output = get_echo( 'wp_print_scripts' );
- $styles_output = get_echo( 'wp_print_styles' );
-
- // Scripts
- $this->assertContains( '/js/field.datetime.js', $scripts_output );
- $this->assertContains( '/js/cmb.js', $scripts_output );
- if ( version_compare( $wp_version, '4.1', '>=' ) ) {
- $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/core.min.js', $scripts_output );
- $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/datepicker.min.js', $scripts_output );
- } else {
- $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/jquery.ui.core.min.js', $scripts_output );
- $this->assertContains( site_url() . '/wp-includes/js/jquery/ui/jquery.ui.datepicker.min.js', $scripts_output );
- }
-
- // Styles
- $this->assertContains( 'css/vendor/jquery-ui/jquery-ui.css', $styles_output );
-
- }
-
- function testTimeFieldAssets() {
-
- $field = new CMB_Time_Field( 'foo', 'Title', array() );
-
- // Register CMB-Scripts as this is a dependency.
- wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
-
- $field->enqueue_scripts();
-
- $scripts_output = get_echo( 'wp_print_scripts' );
-
- // Scripts
- $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
-
- }
-
- function testDateTimestampFieldAssets() {
-
- $field = new CMB_Date_Timestamp_Field( 'foo', 'Title', array() );
-
- // Register CMB-Scripts as this is a dependency.
- wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
-
- $field->enqueue_scripts();
-
- $scripts_output = get_echo( 'wp_print_scripts' );
-
- // Scripts
- $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
-
- }
-
- function testDatetimeTimestampFieldAssets() {
-
- $field = new CMB_Datetime_Timestamp_Field( 'foo', 'Title', array() );
-
- // Register CMB-Scripts as this is a dependency.
- wp_enqueue_script( 'cmb-scripts', trailingslashit( CMB_URL ) . 'js/cmb.js', array( 'jquery' ) );
-
- $field->enqueue_scripts();
-
- $scripts_output = get_echo( 'wp_print_scripts' );
-
- // Scripts
- $this->assertContains( CMB_URL . '/js/cmb.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/jquery.timePicker.min.js', $scripts_output );
- $this->assertContains( CMB_URL . '/js/field.datetime.js', $scripts_output );
-
- }
-}
diff --git a/tests/testField.php b/tests/testField.php
index fc5be6a0..d4f82249 100644
--- a/tests/testField.php
+++ b/tests/testField.php
@@ -4,27 +4,29 @@ class FieldTestCase extends WP_UnitTestCase {
private $post;
- function setUp() {
+ private $users = array();
+ function setUp() {
parent::setUp();
- $args = array(
- 'post_author' => 1,
- 'post_status' => 'publish',
- 'post_content' => rand_str(),
- 'post_title' => rand_str(),
- 'post_type' => 'post',
- );
-
- $id = wp_insert_post( $args );
-
- $this->post = get_post( $id );
+ // Setup some users to test our display logic.
+ $this->users['admin'] = $this->factory->user->create( array( 'role' => 'administrator' ) );
+ $this->users['author'] = $this->factory->user->create( array( 'role' => 'author' ) );
+ // Setup a post for testing is_displayed.
+ $this->post = $this->factory->post->create_and_get( array(
+ 'post_author' => 1,
+ 'post_status' => 'publish',
+ 'post_content' => rand_str(),
+ 'post_title' => rand_str(),
+ 'post_type' => 'post',
+ ) );
}
function tearDown() {
wp_delete_post( $this->post->ID, true );
unset( $this->post );
+ wp_set_current_user( 0 );
parent::tearDown();
}
@@ -144,7 +146,6 @@ function testEmptyFieldOutput() {
// Trigger output.
$field->html();
-
}
function testSavedFieldOutput() {
@@ -163,4 +164,84 @@ function testSavedFieldOutput() {
$field->html();
}
+ function testDisplayedRepeatableButtonDiv() {
+ $field = new CMB_Text_Field( 'foo', 'Title', array( 1 ), array( 'repeatable' => true ) );
+
+ // Set expectation for an empty output.
+ $this->expectOutputRegex( '/\ /' );
+
+ hmcmb_invoke_method( $field, 'repeatable_button_markup' );
+ }
+
+ function testDisplayedRepeatableButtonButton() {
+ $field = new CMB_Text_Field( 'foo', 'Title', array( 1 ), array( 'repeatable' => true ) );
+
+ // Set expectation for an empty output.
+ $this->expectOutputRegex( '/\ |