Repository: CMB2/CMB2-Snippet-Library
Branch: master
Commit: d21e516b34da
Files: 92
Total size: 222.6 KB
Directory structure:
gitextract_4vuue3u2/
├── .gitignore
├── CONTRIBUTING.md
├── README.md
├── api/
│ ├── README.md
│ └── cmb2-file-list-ordered.php
├── conditional-display/
│ ├── exclude-for-ids.php
│ ├── hide-on-new-post-page.php
│ ├── show-for-taxonomy-terms.php
│ ├── show-if-matching-meta-value.php
│ └── show-only-for-top-level-posts.php
├── custom-field-types/
│ ├── README.md
│ ├── address-field-type/
│ │ ├── address-field-type.php
│ │ └── class-cmb2-render-address-field.php
│ ├── associate-wp-menu-field.php
│ ├── autocomplete-field-type.php
│ ├── button-field-type.php
│ ├── dashicon-radio-field/
│ │ └── dashicon-radio-field.php
│ ├── default-category-field.php
│ ├── default-tags-field.php
│ ├── form-field-field-type.php
│ ├── multicheck_posttype-field_type.php
│ ├── multicheck_title-field_type.php
│ ├── post-list-field-type.php
│ ├── select-multiple-field-type.php
│ ├── star-rating-field-type/
│ │ ├── css/
│ │ │ └── star-rating-field-type.css
│ │ └── star-rating-field-type.php
│ ├── taxonomy-radio-with-image-field-type/
│ │ ├── DJ_Taxonomy_Radio_Hierarchical_With_Image.php
│ │ ├── DJ_Taxonomy_Radio_With_Image_Display.php
│ │ └── taxonomy-radio-with-image-field-type.php
│ ├── textarea-with-checkbox.php
│ └── year-range-field-type.php
├── filters-and-actions/
│ ├── README.md
│ ├── cmb2-add-fields-dynamically.php
│ ├── cmb2_all_or_nothing_types-filter.php
│ ├── cmb2_before_form-and-cmb2_after_form-hooks.php
│ ├── cmb2_init_$cmb_id-add-fields.php
│ ├── cmb2_init_$cmb_id-modify-object-types.php
│ ├── cmb2_init_$cmb_id-remove-field.php
│ ├── cmb2_init_$cmb_id-replace-field.php
│ ├── cmb2_init_before_hookup-add-fields.php
│ ├── cmb2_init_before_hookup-remove-cmb2-metabox.php
│ ├── cmb2_init_before_hookup-update-existing-fields.php
│ ├── cmb2_override_{$field_id}_meta_value-filter.php
│ ├── custom-css-for-specific-metabox.php
│ ├── disable-styles-on-front-end-forms.php
│ ├── localize-date-format.php
│ ├── override-cmb2-data-source.php
│ └── save-default-group-field-value-based-on-other-field.php
├── front-end/
│ ├── README.md
│ ├── cmb2-front-end-editor.php
│ ├── cmb2-front-end-submit.php
│ ├── cmb2-front-end-wordpress-media-uploader.php
│ ├── cmb2-metabox-shortcode.php
│ └── output-file-list.php
├── helper-functions/
│ ├── README.md
│ ├── helper-functions.php
│ ├── modify-cmb2_metabox_form-format.php
│ ├── modify-cmb2_metabox_form-output.php
│ └── modify-cmb2_metabox_form-save-button-text.php
├── javascript/
│ ├── README.md
│ ├── cmb2-auto-scroll-to-new-group.php
│ ├── cmb2-js-validation-required.php
│ ├── dynamically-change-group-field-title-from-subfield.php
│ ├── limit-number-of-multiple-repeat-groups.php
│ ├── limit-number-of-repeat-fields.php
│ └── limit-number-of-repeat-groups.php
├── metaboxes/
│ └── README.md
├── misc/
│ ├── README.md
│ ├── add-wrap-to-group-of-fields.php
│ ├── adding-wordcount-to-cmb2-wysiwyg-field.php
│ ├── cmb2-field-in-publish-box.php
│ ├── helper-functions.php
│ ├── outputting-cmb2-fields-in-featured-image-metabox.php
│ ├── outputting-forms-outside-metaboxes.php
│ ├── replace-wp-excerpt-with-cmb2-field.php
│ └── replace-wp-title-content-thumbnail-with-cmb2-fields.php
├── modified-field-types/
│ ├── README.md
│ ├── modify-button-text-for-file-type.php
│ └── readonly-field-type.php
├── options-and-settings-pages/
│ ├── README.md
│ ├── add-cmb2-settings-to-other-settings-pages.php
│ ├── custom-display-callback.php
│ ├── genesis-cpt-archive-metabox.php
│ ├── genesis-settings-metabox.php
│ ├── network-options-cmb.php
│ ├── non-cmb2-options-page.php
│ ├── options-pages-with-submenus.php
│ ├── options-pages-with-tabs-and-submenus.php
│ ├── submenu-options-pages.php
│ └── theme-options-cmb.php
├── user-meta-and-settings/
│ └── README.md
└── widgets/
└── widget-example.php
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Created by https://www.gitignore.io/api/osx
### OSX ###
*.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
================================================
FILE: CONTRIBUTING.md
================================================
# Contribute To CMB2 Code Snippet Library
The CMB2 code snippet library is a community-maintained repository and so contributions are always welcome. Thanks to EDD for [the inspiration](https://github.com/easydigitaldownloads/library) for this library.
## Submitting a Snippet
To submit a code library for inclusion in the library, please fork the repository and then submit a [pull request](https://github.com/jtsternberg/CMB2-Snippet-Library/pulls). Pippin has an excellent tutorial for [submitting your first pull request](http://pippinsplugins.com/submitting-your-first-pull-request/).
Guidelines for submission:
- Each snippet should be placed in it's own file.
- Each file should be named appropriately based on the purpose of the snippet.
- Files should be placed in the appropriate category (folder). If no category exists, you may create one with your pull request.
- All functions and classes should be prefixed with your own unique prefix, preferrably one that contains your initials followed by `_cmb2_`. For example: `jt_cmb2_{function name here}`.
- (optional) Add [WordPress plugin headers](http://codex.wordpress.org/File_Header#Plugin_File_Header_Example) to allow others to use your snippet as a plugin.
================================================
FILE: README.md
================================================
CMB2 Code Snippet Library
========================
This is a community-maintained repository of code snippets that help modify the default behavior of [CMB2](https://github.com/WebDevStudios/CMB2/).
Snippets are organized into categories (folders) and each snippet is placed in its own file with a name that describes what it does.
Thank you to the EDD team for [the inspiration](https://github.com/easydigitaldownloads/library) for this library.
## Submitting Your Snippet
We welcome and encourage everyone to submit their code snippets. If you would like to submit your snippet, please [fork](https://github.com/WebDevStudios/CMB2-Snippet-Library/fork) the repository and then create a [pull request](https://github.com/WebDevStudios/CMB2-Snippet-Library/compare/).
Please refer to the [Contributing guidelines](https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/CONTRIBUTING.md) before submitting your pull request.
## Proposing a Snippet
If there is a snippet you are unable to find and would like to propose get written, please open an [issue](https://github.com/WebDevStudios/CMB2-Snippet-Library/issues) and describe your need.
## Notes
This is not a tutorial archive. Please see the [CMB2 github repo wiki](https://github.com/WebDevStudios/CMB2/wiki) if you're looking for official documentation and tutorials.
These snippets come with no guarantees. Due to the constant evolution of the CMB2 codebase, it is possible that the behavior of these snippets may change overtime. Find something broken? [Let us know](https://github.com/WebDevStudios/CMB2-Snippet-Library/issues)!
================================================
FILE: api/README.md
================================================
CMB2 API Snippets
==========
Snippets related to the CMB2 API endpoints/functionality.
================================================
FILE: api/cmb2-file-list-ordered.php
================================================
$file_url ) {
$value[] = array(
'id' => $file_id,
'url' => $file_url,
);
}
}
return $value;
}
/**
* Filters the value before it is sent to the REST request.
*
* "_yourprefix_demo_file_list" is a dynamic portion of the hook name, referring to the field id.
*/
add_filter( 'cmb2_get_rest_value_for__yourprefix_demo_file_list', 'yourprefix_cmb2_ordered_file_list_array_in_api', 10, 2 );
return;
// Another method to make this modification to several different file_list fields.
// Do not use both of these methods. Pick one.
define( 'YOURPREFIX_FILE_LIST_IDS', array(
'_yourprefix_demo_file_list',
'xyz'
// etc.
) );
function yourprefix_cmb2_ordered_file_list_array_in_api_2( $value, $field ) {
// Replace
if ( in_array( $field->_id(), YOURPREFIX_FILE_LIST_IDS, true ) && ! empty( $value ) && is_array( $value ) ) {
$files = $value;
$value = array();
foreach ( $files as $file_id => $file_url ) {
$value[] = array(
'id' => $file_id,
'url' => $file_url,
);
}
}
return $value;
}
add_filter( 'cmb2_get_rest_value_file_list', 'yourprefix_cmb2_ordered_file_list_array_in_api_2', 10, 2 );
================================================
FILE: conditional-display/exclude-for-ids.php
================================================
'exclude_for_ids',
'title' => 'Demo',
'exclude_ids' => array( 1, 2, 3, 55 ), // Exclude metabox on these post-ids
'show_on_cb' => 'cmb2_exclude_for_ids', // function should return a bool value
) );
/**
* Exclude metabox on specific IDs
* @param object $cmb CMB2 object
* @return bool True/false whether to show the metabox
*/
function cmb2_exclude_for_ids( $cmb ) {
$ids_to_exclude = $cmb->prop( 'exclude_ids', array() );
$excluded = in_array( $cmb->object_id(), $ids_to_exclude, true );
return ! $excluded;
}
================================================
FILE: conditional-display/hide-on-new-post-page.php
================================================
'exclude_for_ids',
'title' => 'Demo',
'exclude_from' => array( 'post-new.php' ), // Exclude metabox on new-post screen
'show_on_cb' => 'tgm_exclude_from_new', // function should return a bool value
) );
/**
* Removes metabox from appearing on post new screens before the post
* ID has been set.
* @author Thomas Griffin
* @param object $cmb CMB2 object
* @return bool True/false whether to show the metabox
*/
function tgm_exclude_from_new( $cmb ) {
global $pagenow;
$exclude_from = $cmb->prop( 'exclude_from', array( 'post-new.php' ) );
$excluded = in_array( $pagenow, $exclude_from, true );
return ! $excluded;
}
================================================
FILE: conditional-display/show-for-taxonomy-terms.php
================================================
'show_for_taxonomy_terms',
'title' => 'Demo',
'show_on_cb' => 'be_taxonomy_show_on_filter', // function should return a bool value
'show_on_terms' => array(
'category' => array( 'featured' ),
'post_tag' => array( 'best-of' ),
),
) );
/**
* Taxonomy show_on filter
* @author Bill Erickson
* @param object $cmb CMB2 object
* @return bool True/false whether to show the metabox
*/
function be_taxonomy_show_on_filter( $cmb ) {
$tax_terms_to_show_on = $cmb->prop( 'show_on_terms', array() );
if ( empty( $tax_terms_to_show_on ) || ! $cmb->object_id() ) {
return false;
}
$post_id = $cmb->object_id();
$post = get_post( $post_id );
foreach( (array) $tax_terms_to_show_on as $taxonomy => $slugs ) {
if ( ! is_array( $slugs ) ) {
$slugs = array( $slugs );
}
$terms = $post
? get_the_terms( $post, $taxonomy )
: wp_get_object_terms( $post_id, $taxonomy );
if ( ! empty( $terms ) ) {
foreach( $terms as $term ) {
if ( in_array( $term->slug, $slugs, true ) ) {
wp_die( '
: '. print_r( 'show it', true ) .'' );
// Ok, show this metabox
return true;
}
}
}
}
return false;
}
================================================
FILE: conditional-display/show-if-matching-meta-value.php
================================================
'wiki_status_metabox',
'title' => 'Status Metabox',
'object_types' => array( 'page', ), // Post type
) );
$cmb->add_field( array(
'name' => 'Status',
'id' => 'wiki_status',
'type' => 'select',
'default' => 'internal',
'options' => array(
'internal' => 'Internal',
'external' => 'External',
),
) );
/**
* Metabox to conditionally display if the 'status' is set to 'External'.
*/
$cmb = new_cmb2_box( array(
'id' => 'wiki_conditonal_metabox',
'title' => 'Contact Info',
'object_types' => array( 'page', ), // Post type
'show_on_cb' => 'cmb_only_show_for_external', // function should return a bool value
) );
$cmb->add_field( array(
'name' => 'Email',
'id' => 'wiki_email',
'type' => 'text_email',
) );
}
/**
* Only display a metabox if the page's 'status' is 'external'
* @param object $cmb CMB2 object
* @return bool True/false whether to show the metabox
*/
function cmb_only_show_for_external( $cmb ) {
$status = get_post_meta( $cmb->object_id(), 'wiki_status', 1 );
// Only show if status is 'external'
return 'external' === $status;
}
================================================
FILE: conditional-display/show-only-for-top-level-posts.php
================================================
'exclude_for_ids',
'title' => 'Demo',
'show_on_cb' => 'ba_metabox_add_for_top_level_posts_only', // function should return a bool value
) );
/**
* Exclude metabox on non top level posts
* @author Travis Northcutt
* @param object $cmb CMB2 object
* @return bool True/false whether to show the metabox
*/
function ba_metabox_add_for_top_level_posts_only( $cmb ) {
$has_parent = $cmb->object_id() && get_post_ancestors( $cmb->object_id() );
return ! $has_parent;
}
================================================
FILE: custom-field-types/README.md
================================================
Custom Field Types
==========
Snippets for [adding custom CMB2 field types](https://github.com/WebDevStudios/CMB2/wiki/Adding-your-own-field-types).
================================================
FILE: custom-field-types/address-field-type/address-field-type.php
================================================
'',
'address-2' => '',
'city' => '',
'state' => '',
'zip' => '',
'country' => '',
) );
$output = '
rendered( ob_get_clean() );
}
/**
* Optionally save the Address values into separate fields
*/
public static function maybe_save_split_values( $override_value, $value, $object_id, $field_args ) {
if ( ! isset( $field_args['split_values'] ) || ! $field_args['split_values'] ) {
// Don't do the override.
return $override_value;
}
$address_keys = array( 'address-1', 'address-2', 'city', 'state', 'zip' );
foreach ( $address_keys as $key ) {
if ( ! empty( $value[ $key ] ) ) {
update_post_meta( $object_id, $field_args['id'] . 'addr_' . $key, sanitize_text_field( $value[ $key ] ) );
}
}
remove_filter( 'cmb2_sanitize_address', array( __CLASS__, 'sanitize' ), 10, 5 );
// Tell CMB2 we already did the update.
return true;
}
public static function sanitize( $check, $meta_value, $object_id, $field_args, $sanitize_object ) {
// if not repeatable, bail out.
if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
return $check;
}
foreach ( $meta_value as $key => $val ) {
$meta_value[ $key ] = array_filter( array_map( 'sanitize_text_field', $val ) );
}
return array_filter( $meta_value );
}
public static function escape( $check, $meta_value, $field_args, $field_object ) {
// if not repeatable, bail out.
if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
return $check;
}
foreach ( $meta_value as $key => $val ) {
$meta_value[ $key ] = array_filter( array_map( 'esc_attr', $val ) );
}
return array_filter( $meta_value );
}
public static function get_split_meta_value( $data, $object_id, $field_args, $field ) {
if ( 'address' !== $field->args['type'] ) {
return $data;
}
if ( ! isset( $field->args['split_values'] ) || ! $field->args['split_values'] ) {
// Don't do the override.
return $data;
}
$prefix = $field->args['id'] . 'addr_';
// Construct an array to iterate to fetch individual meta values for our override.
// Should match the values in the render() method.
$metakeys = array(
'address-1',
'address-2',
'city',
'state',
'zip',
'country',
);
$newdata = array();
foreach ( $metakeys as $metakey ) {
// Use our prefix to construct the whole meta key from the postmeta table.
$newdata[ $metakey ] = get_post_meta( $object_id, $prefix . $metakey, true );
}
return $newdata;
}
}
================================================
FILE: custom-field-types/associate-wp-menu-field.php
================================================
menu_types = array( 'post', 'page' );
$menu_assoc->metabox_id = 'associated_post_menu_box';
$menu_assoc->menu_meta_key = 'associated_post_menu';
if ( is_admin() ) {
// Register menu association metabox to post types
$cmb = $menu_assoc->register_post_menu_box();
}
}
add_action( 'cmb2_init', 'cmb2_register_post_menu_box' );
class CMB2_Post_Menu_Association {
public $menu_types = array();
public $metabox_id = '';
public $menu_meta_key = '';
public $menu_title_meta_key = '';
protected static $single_instance = null;
protected $associated_post = null;
protected $menu_id = 0;
/**
* Creates or returns an instance of this class.
* @since 0.1.0
* @return CMB2_Post_Menu_Association A single instance of this class.
*/
public static function get_instance() {
if ( null === self::$single_instance ) {
self::$single_instance = new self();
}
return self::$single_instance;
}
protected function __construct() {
add_action( 'all_admin_notices', array( $this, 'associate_menu_post_message' ) );
add_action( 'wp_create_nav_menu', array( $this, 'set_menu_to_post' ) );
}
public function register_post_menu_box() {
return new_cmb2_box( $this->register_post_menu_box_args() );
}
public function register_post_menu_box_args() {
$title_key = $this->menu_title_meta_key();
return apply_filters( 'register_post_menu_box_args', array(
'id' => $this->metabox_id,
'title' => 'Associated Menu',
'object_types' => $this->menu_types, // Post type
'context' => 'side',
'priority' => 'low',
'fields' => array(
$title_key => array(
'name' => 'Menu Widget Title',
'id' => $title_key,
'type' => 'text',
),
$this->menu_meta_key => array(
'desc' => 'If no menu is selected, associated menu widget will not show.',
'id' => $this->menu_meta_key,
'type' => 'select',
'options_cb' => array( $this, 'get_menus_list_options' ),
'after' => array( $this, 'post_menu_edit_or_create_link' ),
),
),
) );
}
public function get_menus_list_options() {
$menus = wp_get_nav_menus();
if ( ! empty( $menus ) ) {
$menus = wp_list_pluck( $menus, 'name', 'term_id' );
} else {
$menus = array();
}
$menus = array( '' => 'Select Menu' ) + $menus;
return $menus;
}
function post_menu_edit_or_create_link( $args, $field ) {
static $script_added = false;
$menu_id = get_post_meta( $field->object_id(), $this->menu_meta_key, 1 );
$url = admin_url( '/nav-menus.php?action=edit&menu=' . absint( $menu_id ) . '&post_association=' . $field->object_id() );
$link_title = $menu_id ? 'Edit Selected Menu' : 'Create New Menu';
?>
Note: In order for this menu to display, you will need to ensure the "Associated Post Menu" widget is placed in the widget area for this template.
menu_meta_key ) {
return;
}
if ( empty( $_REQUEST['menu'] ) ) {
$this->associate_menu_message( $_REQUEST['post_association'], 'When created, this Menu will be set as the %s Menu for: %s (%d)' );
} else {
$this->associate_menu_message( $_REQUEST['post_association'], 'This Menu is set as the %s Menu for: %s (%d)' );
}
}
public function associate_menu_message( $post_id, $message ) {
global $pagenow;
if ( empty( $post_id ) || 'nav-menus.php' !== $pagenow ) {
return;
}
$post = get_post( absint( $post_id ) );
if ( empty( $post ) ) {
return;
}
$pt = get_post_type_object( $post->post_type );
printf(
'
%s
',
sprintf(
$message,
$pt->labels->singular_name,
get_edit_post_link( $post->ID ) .'#'. $this->metabox_id,
get_the_title( $post->ID ),
$post->ID
)
);
}
public function set_menu_to_post( $menu_id ) {
if ( empty( $_REQUEST['post_association'] ) || empty( $menu_id ) || ! $this->menu_meta_key ) {
return;
}
$post = get_post( absint( $_REQUEST['post_association'] ) );
if ( empty( $post ) || ! in_array( $post->post_type, $this->menu_types, true ) ) {
return;
}
$this->menu_id = $menu_id;
$this->associated_post = $post;
update_post_meta( $post->ID, $this->menu_meta_key, $menu_id );
// Modify the post-menu-save redirect to add our query var.
add_filter( 'wp_redirect', array( $this, 'redirect_with_post_association' ) );
}
public function redirect_with_post_association( $location ) {
if ( $this->menu_id && $location === admin_url( 'nav-menus.php?menu='. $this->menu_id ) ) {
// Add our associated post id query var.
$location = add_query_arg( 'post_association', $this->associated_post->ID, $location );
}
return $location;
}
public function menu_title_meta_key() {
return $this->menu_title_meta_key ? $this->menu_title_meta_key : $this->menu_meta_key . '_widget_title';
}
}
CMB2_Post_Menu_Association::get_instance();
/**
* Handles the Post Menu Widget
*
* @since 3.0.0
*
* @see WP_Widget
*/
class CMB2_Post_Menu_Widget extends WP_Widget {
/**
* Sets up a new Associated Post Menu widget instance.
*
* @since 3.0.0
* @access public
*/
public function __construct() {
$widget_ops = array(
'customize_selective_refresh' => true,
'description' => 'Shows an associated custom menu in your sidebar, if it is set.',
'classname' => 'associated-post-menu',
);
parent::__construct( 'associated-post-menu', 'Associated Post Menu', $widget_ops );
}
/**
* Outputs the content for the associated Menu widget instance.
*
* @since 3.0.0
* @access public
*
* @param array $args Display arguments including 'before_title', 'after_title',
* 'before_widget', and 'after_widget'.
* @param array $instance Settings for the current Associated Post Menu widget instance.
*/
public function widget( $args, $instance ) {
// Get menu
$menu_id = absint( get_post_meta( get_the_ID(), CMB2_Post_Menu_Association::get_instance()->menu_meta_key, 1 ) );
$nav_menu = ! empty( $menu_id ) ? wp_get_nav_menu_object( $menu_id ) : false;
if ( ! $nav_menu ) {
return;
}
$widget_title = get_post_meta( get_the_ID(), CMB2_Post_Menu_Association::get_instance()->menu_title_meta_key(), 1 );
if ( empty( $widget_title ) ) {
$widget_title = isset( $instance['title'] ) ? $instance['title'] : '';
}
/** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
$widget_title = apply_filters( 'widget_title', empty( $widget_title ) ? '' : $widget_title, $instance, $this->id_base );
echo $args['before_widget'];
if ( ! empty( $widget_title ) ) {
echo $args['before_title'] . $widget_title . $args['after_title'];
}
$nav_menu_args = array(
'fallback_cb' => '',
'menu' => $nav_menu,
);
/**
* Filters the arguments for the Associated Post Menu widget.
*
* @since 4.2.0
* @since 4.4.0 Added the `$instance` parameter.
*
* @param array $nav_menu_args {
* An array of arguments passed to wp_nav_menu() to retrieve a custom menu.
*
* @type callable|bool $fallback_cb Callback to fire if the menu doesn't exist. Default empty.
* @type mixed $menu Menu ID, slug, or name.
* }
* @param WP_Term $nav_menu Nav menu object for the current menu.
* @param array $args Display arguments for the current widget.
* @param array $instance Array of settings for the current widget.
*/
wp_nav_menu( apply_filters( 'widget_nav_menu_args', $nav_menu_args, $nav_menu, $args, $instance ) );
echo $args['after_widget'];
}
/**
* Handles updating settings for the current Associated Post Menu widget instance.
*
* @since 3.0.0
* @access public
*
* @param array $new_instance New settings for this instance as input by the user via
* WP_Widget::form().
* @param array $old_instance Old settings for this instance.
* @return array Updated settings to save.
*/
public function update( $new_instance, $old_instance ) {
$instance = array();
if ( ! empty( $new_instance['title'] ) ) {
$instance['title'] = sanitize_text_field( $new_instance['title'] );
}
return $instance;
}
/**
* Outputs the settings form for the Associated Post Menu widget.
*
* @since 3.0.0
* @access public
*
* @param array $instance Current settings.
*/
public function form( $instance ) {
$title = isset( $instance['title'] ) ? $instance['title'] : '';
// If no menus exists, direct the user to go and create some.
?>
'autocomplete_test',
'title' => __('Autocomplete Field Examples', 'autocomplete_cmb2'),
'object_types' => array('post'),
) );
$cmb->add_field( array(
'name' => __('Related Fruit', 'autocomplete_cmb2'),
'desc' => __('Fruit that is related to this post', 'autocomplete_cmb2'),
'id' => $prefix.'related_fruit',
'type' => 'autocomplete',
'options' => array(
array('value' => 1, 'name' => 'Apple'),
array('value' => 2, 'name' => 'Orange'),
array('value' => 3, 'name' => 'Grape')
)
) );
$cmb->add_field( array(
'name' => __('Related Fruits', 'autocomplete_cmb2'),
'desc' => __('Repeatable related fruits', 'autocomplete_cmb2'),
'id' => $prefix.'related_fruits',
'type' => 'autocomplete',
'repeatable' => true,
'repeatable_class' => 'related-fruits',
'options' => array(
array('value' => 1, 'name' => 'Apple'),
array('value' => 2, 'name' => 'Orange'),
array('value' => 3, 'name' => 'Grape')
)
) );
$cmb->add_field( array(
'name' => __('Related Post', 'autocomplete_cmb2'),
'desc' => __('Post that is related to this one', 'autocomplete_cmb2'),
'id' => $prefix.'related_post',
'type' => 'autocomplete',
'source' => 'get_post_options',
'mapping_function' => 'autocomplete_cmb2_get_post_title_from_id'
) );
$cmb->add_field( array(
'name' => __('Related Posts', 'autocomplete_cmb2'),
'desc' => __('Posts that are related to this one', 'autocomplete_cmb2'),
'id' => $prefix.'related_posts',
'repeatable' => true,
'type' => 'autocomplete',
'source' => 'get_post_options',
'repeatable_class' => 'related-posts',
'mapping_function' => 'autocomplete_cmb2_get_post_title_from_id'
) );
}
/**
* Gets the post title from the ID for mapping purposes in autocompletes.
*
* @param int $id
* @return string
*/
function autocomplete_cmb2_get_post_title_from_id($id) {
if (empty($id)) {
return '';
}
$post = get_post($id);
return $post->post_title;
}
/**
* Renders the autocomplete type
*
* @param CMB2_Field $field_object
* @param string $escaped_value The value of this field passed through the escaping filter. It defaults to sanitize_text_field.
* If you need the unescaped value, you can access it via $field_type_object->value().
* @param string $object_id The id of the object you are working with. Most commonly, the post id.
* @param string $object_type The type of object you are working with. Most commonly, post (this applies to all post-types),
* but could also be comment, user or options-page.
* @param CMB2_Object $field_type_object This is an instance of the CMB2 object and gives you access to all of the methods that CMB2 uses to build its field types.
*/
function autocomplete_cmb2_render_autocomplete($field_object, $escaped_value, $object_id, $object_type, $field_type_object) {
// Store the value in a hidden field.
echo $field_type_object->hidden();
if (isset($field_object->args['repeatable_class'])) {
$repeatable_class = $field_object->args['repeatable_class'];
}
$options = $field_object->options();
// Set up the options or source PHP variables.
if (empty($options)) {
$source = $field_object->args['source'];
$value = $field_object->args['mapping_function']($field_object->escaped_value);
} else {
// Set the value.
if (empty($field_object->escaped_value)) {
$value = '';
} else {
foreach ($options as $option) {
if ($option['value'] == $field_object->escaped_value) {
$value = $option['name'];
break;
}
}
}
}
// Set up the autocomplete field. Replace the '_' with '-' to not interfere with the ID from CMB2.
$id = str_replace('_', '-', $field_object->args['id']);
if ( '_' !== substr( $field_object->args['id'], 0, 1 ) ) {
$id = '-' . $field_object->args['id'];
}
// Don't use the ID on repeatable elements as it won't change; use the class instead.
echo '';
if (!$field_object->args['repeatable'] && isset($field_object->args['desc'])) {
echo '
';
}
================================================
FILE: filters-and-actions/cmb2_init_$cmb_id-add-fields.php
================================================
add_field(
array(
'name' => __( 'New at the top', 'your_textdomain' ),
'desc' => __( 'Using the "cmb2_init_{$cmb_id}" hook', 'your_textdomain' ),
'id' => '_new_at_the_top',
'type' => 'text',
),
1
);
}
add_action( 'cmb2_init__yourprefix_demo_metabox', 'yourprefix_add_new_field_to_top_of_demo_metabox' );
================================================
FILE: filters-and-actions/cmb2_init_$cmb_id-modify-object-types.php
================================================
box_types();
$types[] = 'books'; // Your custom post type slug.
// Bam.
$cmb->set_prop( 'object_types', $types );
}
add_action( 'cmb2_init_yourprefix_demo_metabox', 'yourprefix_demo_metabox_modify_object_types' );
================================================
FILE: filters-and-actions/cmb2_init_$cmb_id-remove-field.php
================================================
remove_field( '_yourprefix_demo_textsmall' );
}
add_action( 'cmb2_init__yourprefix_demo_metabox', 'yourprefix_remove_field_from_demo_metabox' );
================================================
FILE: filters-and-actions/cmb2_init_$cmb_id-replace-field.php
================================================
remove_field( '_yourprefix_demo_textsmall' );
$cmb->add_field(
array(
'name' => __( 'REPLACED Text Small Field', 'cmb2' ),
'desc' => __( 'Using the "cmb2_init_{$cmb_id}" hook', 'your_textdomain' ),
'id' => '_yourprefix_demo_textsmall',
'type' => 'text_money',
),
17 /* This needs to be the nth position of the original field */
);
}
}
add_action( 'cmb2_init_hookup__yourprefix_demo_metaboxx', 'yourprefix_replace_field_in_demo_metaboxx', 999 );
================================================
FILE: filters-and-actions/cmb2_init_before_hookup-add-fields.php
================================================
update_field_property( '_yourprefix_demo_text2', 'type', 'text' );
/**
* Since '_yourprefix_demo_text2' doesn't exist, Let's create it.
* Always need to compare this value strictly to false, as a field_id COULD be 0 or ''
*/
if ( false === $field_id ) {
$cmb->add_field(
// Normal field setup
array(
'name' => __( 'Test Text 2', 'your_textdomain' ),
'desc' => __( 'Test Text 2 description', 'your_textdomain' ),
'id' => '_yourprefix_demo_text2',
'type' => 'text',
'attributes' => array( 'placeholder' => __( "I'm some placeholder text", 'your_textdomain' ) ),
),
3 // Insert this field in the third position
);
}
}
add_action( 'cmb2_init_before_hookup', 'yourprefix_add_new_field_in_3rd_position' );
function yourprefix_add_new_field_to_group() {
// Try to get a metabox w/ the id of '_yourprefix_group_metabox'
if ( $cmb_group_demo = cmb2_get_metabox( '_yourprefix_group_metabox' ) ) {
$cmb_group_demo->add_group_field(
array(
'name' => __( 'Test Text 2', 'your_textdomain' ),
'desc' => __( 'field description (optional)', 'your_textdomain' ),
'id' => 'text2',
'type' => 'text',
'attributes' => array( 'placeholder' => __( "I'm some placeholder text", 'your_textdomain' ) ),
),
'_yourprefix_group_demo', // Add this to the _yourprefix_group_demo group field
2 // And insert it into the 2nd position
);
}
}
add_action( 'cmb2_init_before_hookup', 'yourprefix_add_new_field_to_group' );
================================================
FILE: filters-and-actions/cmb2_init_before_hookup-remove-cmb2-metabox.php
================================================
update_field_property( '_yourprefix_demo_text', 'show_on_cb', false );
/**
* Always need to compare this value strictly to false, as a field_id COULD be 0 or ''
*/
if ( false !== $field_id ) {
/**
* Because we don't want to 'stomp' a field's 'attributes' property
* (It may already have some attributes), we're going to get
* the field's attributes property and append to it.
*/
// Get all fields for this metabox
$fields = $cmb->prop( 'fields' );
// Get the attributes array if it exists, or else create it
$attributes = isset( $fields['_yourprefix_demo_text']['attributes'] )
? $fields['_yourprefix_demo_text']['attributes']
: array();
// Add placeholder text
$attributes['placeholder'] = __( "I'm some placeholder text", 'your_textdomain' );
// Update the field's 'attributes' property
$cmb->update_field_property( '_yourprefix_demo_text', 'attributes', $attributes );
}
}
add_action( 'cmb2_init_before_hookup', 'yourprefix_update_fields_properties' );
================================================
FILE: filters-and-actions/cmb2_override_{$field_id}_meta_value-filter.php
================================================
get( $args['field_id'] )
: get_metadata( $args['type'], $args['id'], $args['field_id'], ( $args['single'] || $args['repeat'] ) );
// Get the default values from JSON
if ( null === $defaults ) {
// Get your JSON blob.. hard-coded for demo.
$json = '[{"description":"This is a description<\/strong>","image":"\/wp-content\/uploads\/2016\/10\/default-image-1.jpg","image_id":663},{"title":"2nd Title","description":"This is a second description<\/strong>","image":"\/wp-content\/uploads\/2016\/10\/default-image-2.jpg","image_id":655,"image_caption":"This is an image caption."}]';
$defaults = json_decode( $json, 1 );
}
// Set our group field value to the default.
$value = $defaults;
// If the group field's retrieved value is not empty...
if ( ! empty( $data ) ) {
$value = array();
// Then loop the defaults and mash the field's value up w/ the default.
foreach ( $defaults as $key => $default_group_val ) {
$value[ $key ] = isset( $data[ $key ] )
? wp_parse_args( $data[ $key ], $default_group_val )
: $default_group_val;
}
}
return $value;
}
add_filter( 'cmb2_override_yourprefix_group_demo_meta_value', 'yourprefix_get_default_group_value_from_json', 10, 4 );
================================================
FILE: filters-and-actions/custom-css-for-specific-metabox.php
================================================
'custom_css_test',
'title' => __( 'Custom CSS Test', 'cmb2' ),
'object_types' => array( 'page', ),
) );
$cmb->add_field( array(
'id' => '_cmb2_test_text',
'type' => 'text',
) );
}
add_action( 'cmb2_admin_init', 'js_custom_css_for_metabox' );
function js_add_custom_css_for_metabox( $post_id, $cmb ) {
?>
'Hey, this is your first entry',
'description' => 'Go ahead and delete this entry, or update its contents',
),
// Default group 2.
array(
'title' => 'Hey, this is your 2nd entry',
'description' => '#2',
),
) );
}
$cmb_group = new_cmb2_box( array(
'id' => 'yourprefix_group_alt_data_metabox',
'title' => __( 'Repeating Field Group', 'cmb2' ),
'object_types' => array( 'post', ),
'show_on' => array( 'id' => array( 1000, ) ),
'show_in_rest' => WP_REST_Server::ALLMETHODS,
) );
// $group_field_id is the field id string, so in this case: '_yourprefix_group_demo'
$group_field_id = $cmb_group->add_field( array(
'id' => 'yourprefix_group_alt_data_demo',
'type' => 'group',
'options' => array(
'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
'add_button' => __( 'Add Another Entry', 'cmb2' ),
'remove_button' => __( 'Remove Entry', 'cmb2' ),
'sortable' => true, // beta
),
) );
/**
* Group fields works the same, except ids only need
* to be unique to the group. Prefix is not needed.
*
* The parent field's id needs to be passed as the second argument.
*/
$cmb_group->add_group_field( $group_field_id, array(
'name' => 'Entry Title',
'id' => 'title',
'type' => 'text',
) );
$cmb_group->add_group_field( $group_field_id, array(
'name' => 'Description',
'description' => 'Write a short description for this entry',
'id' => 'description',
'type' => 'wysiwyg',
'options' => array(
'textarea_rows' => 3,
),
) );
};
add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_value', 'yourprefix_group_alt_data_demo_override_meta_value', 10, 4 );
function yourprefix_group_alt_data_demo_override_meta_value( $data, $object_id, $args, $field ) {
// Here, we're pulling from the options table, but you can query from any data source here.
// If from a custom table, you can use the $object_id to query against.
return get_option( 'yourprefix_group_alt_data_demo', array() );
}
add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_save', 'yourprefix_group_alt_data_demo_override_meta_save', 10, 4 );
function yourprefix_group_alt_data_demo_override_meta_save( $override, $args, $field_args, $field ) {
// Here, we're storing the data to the options table, but you can store to any data source here.
// If to a custom table, you can use the $args['id'] as the reference id.
$updated = update_option( 'yourprefix_group_alt_data_demo', $args['value'] );
return !! $updated;
}
add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_remove', 'yourprefix_group_alt_data_demo_override_meta_remove', 10, 4 );
function yourprefix_group_alt_data_demo_override_meta_remove( $override, $args, $field_args, $field ) {
// Here, we're removing from the options table, but you can query to remove from any data source here.
// If from a custom table, you can use the $args['id'] to query against.
// (If we do "delete_option", then our default value will be re-applied, which isn't desired.)
$updated = update_option( 'yourprefix_group_alt_data_demo', array() );
return !! $updated;
}
================================================
FILE: filters-and-actions/save-default-group-field-value-based-on-other-field.php
================================================
'yourprefix_group_metabox',
'title' => __( 'Repeating Field Group', 'cmb2' ),
'object_types' => array( 'page', ),
) );
$cmb->add_field( $group_field_id, array(
'name' => __( 'Radio', 'cmb2' ),
'id' => 'yourprefix_group_radio',
'type' => 'radio',
'options' => array(
'standard' => __( 'Option One', 'cmb2' ),
'custom' => __( 'Option Two', 'cmb2' ),
'none' => __( 'Option Three', 'cmb2' ),
),
) );
$group_field_id = $cmb->add_field( array(
'id' => 'yourprefix_group_demo',
'type' => 'group',
'description' => __( 'Generates reusable form entries', 'cmb2' ),
'options' => array(
'group_title' => __( 'Entry {#}', 'cmb2' ),
'add_button' => __( 'Add Another Entry', 'cmb2' ),
'remove_button' => __( 'Remove Entry', 'cmb2' ),
'sortable' => true,
),
) );
$cmb->add_group_field( $group_field_id, array(
'name' => 'Entry Title',
'id' => 'title',
'type' => 'text',
) );
$cmb->add_group_field( $group_field_id, array(
'name' => 'Description',
'description' => 'Write a short description for this entry',
'id' => 'description',
'type' => 'textarea_small',
) );
}
add_action( 'cmb2_init', 'yourprefix_register_repeatable_group_field_metabox' );
// If the radio field is set to 'standard', then update the group field value to have one group filled-in.
function hook_in_and_add_default_group_value( $post_id, $updated, $cmb ) {
// If 'my_meta_key' was updated, then proceed w/ my stuff.
if ( in_array( 'yourprefix_group_radio', $updated ) ) {
if ( 'standard' === get_post_meta( $post_id, 'yourprefix_group_radio', 1 ) ) {
// do stuff
update_post_meta( $post_id, 'yourprefix_group_demo', array(
array(
'title' => 'Title of group 1',
'description' => 'Description of group 1',
)
) );
}
}
}
add_action( 'cmb2_save_post_fields_yourprefix_group_metabox', 'hook_in_and_add_default_group_value', 10, 3 );
================================================
FILE: front-end/README.md
================================================
Front-end
==========
Snippets that use CMB2 on the front-end (not wp-admin) side of your site.
================================================
FILE: front-end/cmb2-front-end-editor.php
================================================
You do not have permission to edit this post.';
}
}
return $content;
}
add_filter( 'the_content', 'jt_add_edit_form_to_frontend' );
/**
* Modify the edit links to point to the front-end editor.
*/
function jt_modify_edit_link( $link ) {
if ( ! is_admin() ) {
$link = esc_url_raw( wp_nonce_url( remove_query_arg( 'edit' ), 'edit', 'edit' ) );
}
return $link;
}
add_filter( 'get_edit_post_link', 'jt_modify_edit_link' );
/**
* Hook in later and prepend our title/content fields to our existing metabox
*/
function jt_edit_core_fields() {
if ( ! is_admin() ) { // only if on front-end
// Get existing metabox
$cmb = cmb2_get_metabox( '_yourprefix_demo_metabox' );
// and prepend title
$cmb->add_field( array(
'name' => __( 'Title', 'cmb2' ),
'id' => 'post_title',
'type' => 'text',
'before' => 'jt_edit_core_maybe_redirect',
), 1 );
// and content fields
$cmb->add_field( array(
'name' => __( 'Content', 'cmb2' ),
'id' => 'post_content',
'type' => 'wysiwyg',
), 2 );
}
}
add_action( 'cmb2_init', 'jt_edit_core_fields', 99 );
/**
* If edit was saved, redirect to non-edit page
*/
function jt_edit_core_maybe_redirect() {
if ( isset( $_POST['post_content'] ) ) {
$url = esc_url_raw( remove_query_arg( 'edit' ) );
echo "";
}
}
/**
* We don't want CMB2 to fetch data from meta for post title and post content
*/
function jt_cmb2_override_core_field_get( $val, $object_id, $a, $field ) {
global $post;
if ( in_array( $field->id(), array( 'post_title', 'post_content' ), true ) ) {
if ( isset( $post->ID ) ) {
$val = get_post_field( $field->id(), $post );
} else {
$val = '';
}
}
return $val;
}
add_filter( 'cmb2_override_meta_value', 'jt_cmb2_override_core_field_get', 10, 4 );
/**
* We don't want CMB2 to save data to meta for post title and post content
*/
function jt_cmb2_override_core_field_set( $status, $a, $args, $field ) {
global $post;
if ( in_array( $field->id(), array( 'post_title', 'post_content' ), true ) ) {
if ( isset( $post->ID ) ) {
$status = wp_update_post( array(
$field->id() => $a['value'],
'ID' => $post->ID,
) );
} else {
$status = false;
}
}
return $status;
}
add_filter( 'cmb2_override_meta_save', 'jt_cmb2_override_core_field_set', 10, 4 );
================================================
FILE: front-end/cmb2-front-end-submit.php
================================================
'front-end-post-form',
'object_types' => array( 'post' ),
'hookup' => false,
'save_fields' => false,
) );
$cmb->add_field( array(
'name' => __( 'New Post Title', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_post_title',
'type' => 'text',
'default' => ! empty( $_POST['submitted_post_title'] )
? $_POST['submitted_post_title']
: __( 'New Post', 'YOURTEXTDOMAIN' ),
) );
$cmb->add_field( array(
'default_cb' => 'yourprefix_maybe_set_default_from_posted_values',
'name' => __( 'New Post Content', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_post_content',
'type' => 'wysiwyg',
'options' => array(
'textarea_rows' => 12,
'media_buttons' => false,
),
) );
$cmb->add_field( array(
'default_cb' => 'yourprefix_maybe_set_default_from_posted_values',
'name' => __( 'Featured Image for New Post', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_post_thumbnail',
'type' => 'text',
'attributes' => array(
'type' => 'file', // Let's use a standard file upload field
),
) );
$cmb->add_field( array(
'default_cb' => 'yourprefix_maybe_set_default_from_posted_values',
'name' => __( 'Categories', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_categories',
'type' => 'taxonomy_multicheck',
'taxonomy' => 'category', // Taxonomy Slug
) );
$cmb->add_field( array(
'default_cb' => 'yourprefix_maybe_set_default_from_posted_values',
'name' => __( 'Your Name', 'YOURTEXTDOMAIN' ),
'desc' => __( 'Please enter your name for author credit on the new post.', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_author_name',
'type' => 'text',
) );
$cmb->add_field( array(
'default_cb' => 'yourprefix_maybe_set_default_from_posted_values',
'name' => __( 'Your Email', 'YOURTEXTDOMAIN' ),
'desc' => __( 'Please enter your email so we can contact you if we use your post.', 'YOURTEXTDOMAIN' ),
'id' => 'submitted_author_email',
'type' => 'text_email',
) );
}
add_action( 'cmb2_init', 'yourprefix_frontend_form_register' );
/**
* Sets the front-end-post-form field values if form has already been submitted.
*
* @return string
*/
function yourprefix_maybe_set_default_from_posted_values( $args, $field ) {
if ( ! empty( $_POST[ $field->id() ] ) ) {
return $_POST[ $field->id() ];
}
return '';
}
/**
* Gets the front-end-post-form cmb instance
*
* @return CMB2 object
*/
function yourprefix_frontend_cmb2_get() {
// Use ID of metabox in yourprefix_frontend_form_register
$metabox_id = 'front-end-post-form';
// Post/object ID is not applicable since we're using this form for submission
$object_id = 'fake-oject-id';
// Get CMB2 metabox object
return cmb2_get_metabox( $metabox_id, $object_id );
}
/**
* Handle the cmb_frontend_form shortcode
*
* @param array $atts Array of shortcode attributes
* @return string Form html
*/
function yourprefix_do_frontend_form_submission_shortcode( $atts = array() ) {
// Get CMB2 metabox object
$cmb = yourprefix_frontend_cmb2_get();
// Get $cmb object_types
$post_types = $cmb->prop( 'object_types' );
// Current user
$user_id = get_current_user_id();
// Parse attributes
$atts = shortcode_atts( array(
'post_author' => $user_id ? $user_id : 1, // Current user, or admin
'post_status' => 'pending',
'post_type' => reset( $post_types ), // Only use first object_type in array
), $atts, 'cmb_frontend_form' );
/*
* Let's add these attributes as hidden fields to our cmb form
* so that they will be passed through to our form submission
*/
foreach ( $atts as $key => $value ) {
$cmb->add_hidden_field( array(
'field_args' => array(
'id' => "atts[$key]",
'type' => 'hidden',
'default' => $value,
),
) );
}
// Initiate our output variable
$output = '';
// Get any submission errors
if ( ( $error = $cmb->prop( 'submission_error' ) ) && is_wp_error( $error ) ) {
// If there was an error with the submission, add it to our ouput.
$output .= '
' . sprintf( __( 'There was an error in the submission: %s', 'YOURTEXTDOMAIN' ), ''. $error->get_error_message() .'' ) . '
';
}
// If the post was submitted successfully, notify the user.
if ( isset( $_GET['post_submitted'] ) && ( $post = get_post( absint( $_GET['post_submitted'] ) ) ) ) {
// Get submitter's name
$name = get_post_meta( $post->ID, 'submitted_author_name', 1 );
$name = $name ? ' '. $name : '';
// Add notice of submission to our output
$output .= '
' . sprintf( __( 'Thank you%s, your new post has been submitted and is pending review by a site administrator.', 'YOURTEXTDOMAIN' ), esc_html( $name ) ) . '
';
}
// Get our form
$output .= cmb2_get_metabox_form( $cmb, 'fake-oject-id', array( 'save_button' => __( 'Submit Post', 'YOURTEXTDOMAIN' ) ) );
return $output;
}
add_shortcode( 'cmb_frontend_form', 'yourprefix_do_frontend_form_submission_shortcode' );
/**
* Handles form submission on save. Redirects if save is successful, otherwise sets an error message as a cmb property
*
* @return void
*/
function yourprefix_handle_frontend_new_post_form_submission() {
// If no form submission, bail
if ( empty( $_POST ) || ! isset( $_POST['submit-cmb'], $_POST['object_id'] ) ) {
return false;
}
// Get CMB2 metabox object
$cmb = yourprefix_frontend_cmb2_get();
$post_data = array();
// Get our shortcode attributes and set them as our initial post_data args
if ( isset( $_POST['atts'] ) ) {
foreach ( (array) $_POST['atts'] as $key => $value ) {
$post_data[ $key ] = sanitize_text_field( $value );
}
unset( $_POST['atts'] );
}
// Check security nonce
if ( ! isset( $_POST[ $cmb->nonce() ] ) || ! wp_verify_nonce( $_POST[ $cmb->nonce() ], $cmb->nonce() ) ) {
return $cmb->prop( 'submission_error', new WP_Error( 'security_fail', __( 'Security check failed.' ) ) );
}
// Check title submitted
if ( empty( $_POST['submitted_post_title'] ) ) {
return $cmb->prop( 'submission_error', new WP_Error( 'post_data_missing', __( 'New post requires a title.' ) ) );
}
// And that the title is not the default title
if ( $cmb->get_field( 'submitted_post_title' )->default() == $_POST['submitted_post_title'] ) {
return $cmb->prop( 'submission_error', new WP_Error( 'post_data_missing', __( 'Please enter a new title.' ) ) );
}
/**
* Fetch sanitized values
*/
$sanitized_values = $cmb->get_sanitized_values( $_POST );
// Set our post data arguments
$post_data['post_title'] = $sanitized_values['submitted_post_title'];
unset( $sanitized_values['submitted_post_title'] );
$post_data['post_content'] = $sanitized_values['submitted_post_content'];
unset( $sanitized_values['submitted_post_content'] );
// Create the new post
$new_submission_id = wp_insert_post( $post_data, true );
// If we hit a snag, update the user
if ( is_wp_error( $new_submission_id ) ) {
return $cmb->prop( 'submission_error', $new_submission_id );
}
$cmb->save_fields( $new_submission_id, 'post', $sanitized_values );
/**
* Other than post_type and post_status, we want
* our uploaded attachment post to have the same post-data
*/
unset( $post_data['post_type'] );
unset( $post_data['post_status'] );
// Try to upload the featured image
$img_id = yourprefix_frontend_form_photo_upload( $new_submission_id, $post_data );
// If our photo upload was successful, set the featured image
if ( $img_id && ! is_wp_error( $img_id ) ) {
set_post_thumbnail( $new_submission_id, $img_id );
}
/*
* Redirect back to the form page with a query variable with the new post ID.
* This will help double-submissions with browser refreshes
*/
wp_redirect( esc_url_raw( add_query_arg( 'post_submitted', $new_submission_id ) ) );
exit;
}
add_action( 'cmb2_after_init', 'yourprefix_handle_frontend_new_post_form_submission' );
/**
* Handles uploading a file to a WordPress post
*
* @param int $post_id Post ID to upload the photo to
* @param array $attachment_post_data Attachement post-data array
*/
function yourprefix_frontend_form_photo_upload( $post_id, $attachment_post_data = array() ) {
// Make sure the right files were submitted
if (
empty( $_FILES )
|| ! isset( $_FILES['submitted_post_thumbnail'] )
|| isset( $_FILES['submitted_post_thumbnail']['error'] ) && 0 !== $_FILES['submitted_post_thumbnail']['error']
) {
return;
}
// Filter out empty array values
$files = array_filter( $_FILES['submitted_post_thumbnail'] );
// Make sure files were submitted at all
if ( empty( $files ) ) {
return;
}
// Make sure to include the WordPress media uploader API if it's not (front-end)
if ( ! function_exists( 'media_handle_upload' ) ) {
require_once( ABSPATH . 'wp-admin/includes/image.php' );
require_once( ABSPATH . 'wp-admin/includes/file.php' );
require_once( ABSPATH . 'wp-admin/includes/media.php' );
}
// Upload the file and send back the attachment post ID
return media_handle_upload( 'submitted_post_thumbnail', $post_id, $attachment_post_data );
}
================================================
FILE: front-end/cmb2-front-end-wordpress-media-uploader.php
================================================
add_cap( 'upload_files' );
}
add_action( 'init', 'nevestam_allow_contributor_uploads' );
/**
* Display only user-uploaded files to each user
*
* @param WP_Query $wp_query_obj
*/
function nevestam_restrict_media_library( $wp_query_obj ) {
global $current_user, $pagenow;
if ( ! is_a( $current_user, 'WP_User' ) ) {
return;
}
if ( 'admin-ajax.php' != $pagenow || 'query-attachments' != $_REQUEST['action'] ) {
return;
}
if ( ! current_user_can( 'manage_media_library' ) ) {
$wp_query_obj->set( 'author', $current_user->ID );
}
}
add_action( 'pre_get_posts', 'nevestam_restrict_media_library' );
================================================
FILE: front-end/cmb2-metabox-shortcode.php
================================================
ID;
}
// If no metabox id is set, yell about it
if ( empty( $atts['id'] ) ) {
return 'Please add an "id" attribute to specify the CMB2 form to display.';
}
$metabox_id = esc_attr( $atts['id'] );
$object_id = absint( $atts['post_id'] );
// Get our form
$form = cmb2_get_metabox_form( $metabox_id, $object_id );
return $form;
}
add_shortcode( 'cmb-form', 'jt_cmb2_do_frontend_form_shortcode' );
================================================
FILE: front-end/output-file-list.php
================================================
$attachment_url ) {
$images .= '
{$field};
}
throw new Exception( 'Invalid property: ' . $field );
}
}
/**
* Helper function to get/return the Prefix_Add_CMB2_To_Settings_Page object
* @since 0.1.0
* @return Prefix_Add_CMB2_To_Settings_Page object
*/
function myprefix_cmb2_on_settings() {
return Prefix_Add_CMB2_To_Settings_Page::get_instance();
}
/**
* Wrapper function around cmb2_get_option
* @since 0.1.0
* @param string $key Options array key
* @param mixed $default Optional default value
* @return mixed Option value
*/
function myprefix_get_option( $key = '', $default = false ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( myprefix_cmb2_on_settings()->key, $key, $default );
}
// Fallback to get_option if CMB2 is not loaded yet.
$opts = get_option( myprefix_cmb2_on_settings()->key, $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
// Get it started
myprefix_cmb2_on_settings();
================================================
FILE: options-and-settings-pages/custom-display-callback.php
================================================
'yourprefix_theme_options_page',
'title' => 'Theme Options',
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_theme_options',
'icon_url' => 'dashicons-palmtree',
'display_cb' => 'yourprefix_theme_options_page_output', // Override the options-page form output (CMB2_Hookup::options_page_output()).
'description' => 'Custom description', // Will be displayed via our display_cb.
) );
$cmb_options->add_field( array(
'name' => 'Site Background Color',
'desc' => 'field description (optional)',
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
}
function yourprefix_theme_options_page_output( $hookup ) {
// Output custom markup for the options-page.
?>
cmb->prop( 'title' ) ) : ?>
cmb->prop( 'title' ) ); ?>
cmb->prop( 'description' ) ) : ?>
cmb->prop( 'description' ) ); ?>
hooks();
}
return self::$instances[ $post_type ];
}
/**
* Constructor
*
* @since 0.1.0
*
* @param string $post_type Post type slug.
*/
protected function __construct( $post_type ) {
$this->post_type = $post_type;
$this->admin_hook = sprintf( $this->admin_hook, $post_type );
$this->key = sprintf( $this->key, $post_type );
$this->metabox_id = sprintf( $this->metabox_id, $post_type );
}
/**
* Initiate our hooks
*
* @since 0.1.0
*/
public function hooks() {
add_action( 'init', array( $this, 'init' ) );
add_action( 'admin_menu', array( $this, 'admin_hooks' ) );
add_action( 'cmb2_admin_init', array( $this, 'init_metabox' ) );
}
/**
* Initiate admin hooks.
*
* @since 0.1.0
*/
public function init() {
// Add custom archive support for CPT.
add_post_type_support( $this->post_type, 'genesis-cpt-archives-settings' );
}
/**
* Add admin hooks.
*
* @since 0.1.0
*/
public function admin_hooks() {
// Include CMB CSS in the head to avoid FOUC.
add_action( "admin_print_styles-{$this->admin_hook}", array( 'CMB2_hookup', 'enqueue_cmb_css' ) );
// Hook into the genesis cpt settings save and add in the CMB2 sanitized values.
add_filter( "sanitize_option_genesis-cpt-archive-settings-{$this->post_type}", array( $this, 'add_sanitized_values' ), 999 );
// Hook up our Genesis metabox.
add_action( 'genesis_cpt_archives_settings_metaboxes', array( $this, 'add_meta_box' ) );
}
/**
* Hook up our Genesis metabox.
*
* @since 0.1.0
*/
public function add_meta_box() {
$cmb = $this->init_metabox();
add_meta_box(
$cmb->cmb_id,
$cmb->prop( 'title' ),
array( $this, 'output_metabox' ),
$this->admin_hook,
$cmb->prop( 'context' ),
$cmb->prop( 'priority' )
);
}
/**
* Output our Genesis metabox.
*
* @since 0.1.0
*/
public function output_metabox() {
$cmb = $this->init_metabox();
$cmb->show_form( $cmb->object_id(), $cmb->object_type() );
}
/**
* If saving the cpt settings option, add the CMB2 sanitized values.
*
* @since 0.1.0
*
* @param array $new_value Array of values for the setting.
*
* @return array Updated array of values for the setting.
*/
public function add_sanitized_values( $new_value ) {
if ( ! empty( $_POST ) ) {
$cmb = $this->init_metabox();
$new_value = array_merge(
$new_value,
$cmb->get_sanitized_values( $_POST )
);
}
return $new_value;
}
/**
* Register our Genesis metabox and return the CMB2 instance.
*
* @since 0.1.0
*
* @return CMB2 instance.
*/
public function init_metabox() {
if ( null !== $this->cmb ) {
return $this->cmb;
}
$this->cmb = cmb2_get_metabox( array(
'id' => $this->metabox_id,
'title' => __( 'I\'m a Genesis Archive Settings CMB2 metabox', 'myprefix' ),
'hookup' => false, // We'll handle ourselves. (add_sanitized_values())
'cmb_styles' => false, // We'll handle ourselves. (admin_hooks())
'context' => 'main', // Important for Genesis.
// 'priority' => 'low', // Defaults to 'high'.
'object_types' => array( $this->admin_hook ),
'show_on' => array(
// These are important, don't remove.
'key' => 'options-page',
'value' => array( $this->key ),
),
), $this->key, 'options-page' );
// Set our CMB2 fields.
$this->cmb->add_field( array(
'name' => __( 'Test Text', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_text',
'type' => 'text',
// 'default' => 'Default Text',
) );
$this->cmb->add_field( array(
'name' => __( 'Test Color Picker', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_colorpicker',
'type' => 'colorpicker',
'default' => '#bada55',
) );
return $this->cmb;
}
/**
* Public getter method for retrieving protected/private variables
*
* @since 0.1.0
*
* @param string $field Field to retrieve.
*
* @throws Exception Throws an exception if the field is invalid.
*
* @return mixed Field value or exception is thrown
*/
public function __get( $field ) {
// Allowed fields to retrieve.
if ( 'cmb' === $field ) {
return $this->init_metabox();
}
if ( in_array( $field, array( 'metabox_id', 'post_type', 'admin_hook', 'key' ), true ) ) {
return $this->{$field};
}
throw new Exception( 'Invalid property: ' . $field );
}
}
/**
* Helper function to get/return the Myprefix_Genesis_CPT_Settings_Metabox object.
*
* @since 0.1.0
*
* @param string $post_type Post type slug.
*
* @return Myprefix_Genesis_CPT_Settings_Metabox object
*/
function myprefix_genesis_cpt_settings( $post_type ) {
return Myprefix_Genesis_CPT_Settings_Metabox::get_instance( $post_type );
}
// Get it started.
// myprefix_genesis_cpt_settings( 'custom-post-type-slug' );
================================================
FILE: options-and-settings-pages/genesis-settings-metabox.php
================================================
hooks();
}
return self::$instance;
}
/**
* Constructor
*
* @since 0.1.0
*/
protected function __construct() {
}
/**
* Initiate our hooks
*
* @since 0.1.0
*/
public function hooks() {
add_action( 'admin_menu', array( $this, 'admin_hooks' ) );
add_action( 'cmb2_admin_init', array( $this, 'init_metabox' ) );
}
/**
* Add menu options page
*
* @since 0.1.0
*/
public function admin_hooks() {
// Include CMB CSS in the head to avoid FOUC.
add_action( "admin_print_styles-{$this->admin_hook}", array( 'CMB2_hookup', 'enqueue_cmb_css' ) );
// Hook into the genesis cpt setttings save and add in the CMB2 sanitized values.
add_filter( "sanitize_option_{$this->key}", array( $this, 'add_sanitized_values' ), 999 );
// Hook up our Genesis metabox.
add_action( 'genesis_theme_settings_metaboxes', array( $this, 'add_meta_box' ) );
}
/**
* Hook up our Genesis metabox.
*
* @since 0.1.0
*/
public function add_meta_box() {
$cmb = $this->init_metabox();
add_meta_box(
$cmb->cmb_id,
$cmb->prop( 'title' ),
array( $this, 'output_metabox' ),
$this->admin_hook,
$cmb->prop( 'context' ),
$cmb->prop( 'priority' )
);
}
/**
* Output our Genesis metabox.
*
* @since 0.1.0
*/
public function output_metabox() {
$cmb = $this->init_metabox();
$cmb->show_form( $cmb->object_id(), $cmb->object_type() );
}
/**
* If saving the cpt settings option, add the CMB2 sanitized values.
*
* @since 0.1.0
*
* @param array $new_value Array of values for the setting.
*
* @return array Updated array of values for the setting.
*/
public function add_sanitized_values( $new_value ) {
if ( ! empty( $_POST ) ) {
$cmb = $this->init_metabox();
$new_value = array_merge(
$new_value,
$cmb->get_sanitized_values( $_POST )
);
}
return $new_value;
}
/**
* Register our Genesis metabox and return the CMB2 instance.
*
* @since 0.1.0
*
* @return CMB2 instance.
*/
public function init_metabox() {
if ( null !== $this->cmb ) {
return $this->cmb;
}
$this->cmb = cmb2_get_metabox( array(
'id' => $this->metabox_id,
'title' => __( 'I\'m a Genesis Settings CMB2 metabox', 'myprefix' ),
'hookup' => false, // We'll handle ourselves. (add_sanitized_values())
'cmb_styles' => false, // We'll handle ourselves. (admin_hooks())
'context' => 'main', // Important for Genesis.
// 'priority' => 'low', // Defaults to 'high'.
'object_types' => array( $this->admin_hook ),
'show_on' => array(
// These are important, don't remove.
'key' => 'options-page',
'value' => array( $this->key ),
),
), $this->key, 'options-page' );
// Set our CMB2 fields.
$this->cmb->add_field( array(
'name' => __( 'Test Text', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_text',
'type' => 'text',
// 'default' => 'Default Text',
) );
$this->cmb->add_field( array(
'name' => __( 'Test Color Picker', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_colorpicker',
'type' => 'colorpicker',
'default' => '#bada55',
) );
return $this->cmb;
}
/**
* Public getter method for retrieving protected/private variables.
*
* @since 0.1.0
*
* @param string $field Field to retrieve.
*
* @throws Exception Throws an exception if the field is invalid.
*
* @return mixed Field value or exception is thrown
*/
public function __get( $field ) {
if ( 'cmb' === $field ) {
return $this->init_metabox();
}
// Allowed fields to retrieve.
if ( in_array( $field, array( 'key', 'admin_page', 'metabox_id', 'admin_hook' ), true ) ) {
return $this->{$field};
}
throw new Exception( 'Invalid property: ' . $field );
}
}
/**
* Helper function to get/return the Myprefix_Genesis_Settings_Metabox object
*
* @since 0.1.0
*
* @return Myprefix_Genesis_Settings_Metabox object
*/
function myprefix_genesis_settings_metabox() {
return Myprefix_Genesis_Settings_Metabox::get_instance();
}
// Get it started.
myprefix_genesis_settings_metabox();
================================================
FILE: options-and-settings-pages/network-options-cmb.php
================================================
'myprefix_network_option_metabox',
'title' => esc_html__( 'Network Setting', 'myprefix' ),
'object_types' => array( 'options-page' ),
/*
* The following parameters are specific to the options-page box
* Several of these parameters are passed along to add_menu_page()/add_submenu_page().
*/
'option_key' => 'myprefix_network_options', // The option key and admin menu page slug.
// 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
// 'menu_title' => esc_html__( 'Options', 'myprefix' ), // Falls back to 'title' (above).
// 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
// 'capability' => 'manage_options', // Cap required to view options-page.
// 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
// 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
// 'save_button' => esc_html__( 'Save Theme Options', 'myprefix' ), // The text for the options-page save button. Defaults to 'Save'.
) );
/*
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$cmb_options->add_field( array(
'name' => __( 'Test Text', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_text',
'type' => 'text',
'default' => 'Default Text',
) );
$cmb_options->add_field( array(
'name' => __( 'Test Color Picker', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_colorpicker',
'type' => 'colorpicker',
'default' => '#bada55',
) );
}
/**
* Wrapper function around cmb2_get_option
* @since 0.1.0
* @param string $key Options array key
* @param mixed $default Optional default value
* @return mixed Option value
*/
function myprefix_get_network_option( $key = '', $default = false ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( 'myprefix_network_options', $key, $default );
}
// Fallback to get_site_option if CMB2 is not loaded yet.
$opts = get_site_option( 'myprefix_network_options', $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
================================================
FILE: options-and-settings-pages/non-cmb2-options-page.php
================================================
'wporg_field_pill',
'class' => 'wporg_row',
'wporg_custom_data' => 'custom',
)
);
}
/**
* Register our wporg_settings_init to the admin_init action hook.
*/
add_action( 'admin_init', 'wporg_settings_init' );
/**
* Custom option and settings:
* - callback functions
*/
/**
* Developers section callback function.
*
* @param array $args The settings array, defining title, id, callback.
*/
function wporg_section_developers_callback( $args ) {
?>
.
* - the "class" key value is used for the "class" attribute of the
containing the field.
* Note: you can add custom key value pairs to be used inside your callbacks.
*
* @param array $args
*/
function wporg_field_pill_cb( $args ) {
// Get the value of the setting we've registered with register_setting()
$options = get_option( 'wporg_options' );
?>
options_page_tab_nav_output(); ?>
'yourprefix_main_options_page',
'title' => esc_html__( 'Main Options', 'cmb2' ),
'object_types' => array( 'options-page' ),
/*
* The following parameters are specific to the options-page box
* Several of these parameters are passed along to add_menu_page()/add_submenu_page().
*/
'option_key' => 'yourprefix_main_options', // The option key and admin menu page slug.
// 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
// 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
// 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
// 'capability' => 'manage_options', // Cap required to view options-page.
// 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
// 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
// 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
// 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
// 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
// 'message_cb' => 'yourprefix_options_page_message_callback',
) );
/**
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$main_options->add_field( array(
'name' => esc_html__( 'Site Background Color', 'cmb2' ),
'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
/**
* Registers secondary options page, and set main item as parent.
*/
$secondary_options = new_cmb2_box( array(
'id' => 'yourprefix_secondary_options_page',
'title' => esc_html__( 'Secondary Options', 'cmb2' ),
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_secondary_options',
'parent_slug' => 'yourprefix_main_options',
) );
$secondary_options->add_field( array(
'name' => esc_html__( 'Test Radio', 'cmb2' ),
'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
'id' => 'radio',
'type' => 'radio',
'options' => array(
'option1' => esc_html__( 'Option One', 'cmb2' ),
'option2' => esc_html__( 'Option Two', 'cmb2' ),
'option3' => esc_html__( 'Option Three', 'cmb2' ),
),
) );
/**
* Registers tertiary options page, and set main item as parent.
*/
$tertiary_options = new_cmb2_box( array(
'id' => 'yourprefix_tertiary_options_page',
'title' => esc_html__( 'Tertiary Options', 'cmb2' ),
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_tertiary_options',
'parent_slug' => 'yourprefix_main_options',
) );
$tertiary_options->add_field( array(
'name' => esc_html__( 'Test Text Area for Code', 'cmb2' ),
'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
'id' => 'textarea_code',
'type' => 'textarea_code',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
================================================
FILE: options-and-settings-pages/options-pages-with-tabs-and-submenus.php
================================================
'yourprefix_main_options_page',
'title' => 'Main Options',
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Main',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$main_options = new_cmb2_box( $args );
/**
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$main_options->add_field( array(
'name' => 'Site Background Color',
'desc' => 'field description (optional)',
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
/**
* Registers secondary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_secondary_options_page',
'menu_title' => 'Secondary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_secondary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Secondary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$secondary_options = new_cmb2_box( $args );
$secondary_options->add_field( array(
'name' => 'Test Radio',
'desc' => 'field description (optional)',
'id' => 'radio',
'type' => 'radio',
'options' => array(
'option1' => 'Option One',
'option2' => 'Option Two',
'option3' => 'Option Three',
),
) );
/**
* Registers tertiary options page, and set main item as parent.
*/
$args = array(
'id' => 'yourprefix_tertiary_options_page',
'menu_title' => 'Tertiary Options', // Use menu title, & not title to hide main h2.
'object_types' => array( 'options-page' ),
'option_key' => 'yourprefix_tertiary_options',
'parent_slug' => 'yourprefix_main_options',
'tab_group' => 'yourprefix_main_options',
'tab_title' => 'Tertiary',
);
// 'tab_group' property is supported in > 2.4.0.
if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
$args['display_cb'] = 'yourprefix_options_display_with_tabs';
}
$tertiary_options = new_cmb2_box( $args );
$tertiary_options->add_field( array(
'name' => 'Test Text Area for Code',
'desc' => 'field description (optional)',
'id' => 'textarea_code',
'type' => 'textarea_code',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
/**
* A CMB2 options-page display callback override which adds tab navigation among
* CMB2 options pages which share this same display callback.
*
* @param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
*/
function yourprefix_options_display_with_tabs( $cmb_options ) {
$tabs = yourprefix_options_page_tabs( $cmb_options );
?>
$tab_title ) : ?>
cmb->prop( 'tab_group' );
$tabs = array();
foreach ( CMB2_Boxes::get_all() as $cmb_id => $cmb ) {
if ( $tab_group === $cmb->prop( 'tab_group' ) ) {
$tabs[ $cmb->options_page_keys()[0] ] = $cmb->prop( 'tab_title' )
? $cmb->prop( 'tab_title' )
: $cmb->prop( 'title' );
}
}
return $tabs;
}
================================================
FILE: options-and-settings-pages/submenu-options-pages.php
================================================
'yourprefix_options_submenu_page',
'title' => esc_html__( 'Page Options', 'cmb2' ),
'object_types' => array( 'options-page' ),
/*
* The following parameters are specific to the options-page box
* Several of these parameters are passed along to add_menu_page()/add_submenu_page().
*/
'option_key' => 'yourprefix_page_options', // The option key and admin menu page slug.
// 'icon_url' => '', // Menu icon. Only applicable if 'parent_slug' is left empty.
// 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
'parent_slug' => 'edit.php?post_type=page', // Make options page a submenu item of the themes menu.
// 'capability' => 'manage_options', // Cap required to view options-page.
// 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
// 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
// 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
// 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
// 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
// 'message_cb' => 'yourprefix_options_page_message_callback',
) );
$cmb->add_field( array(
'name' => esc_html__( 'Background Color for Pages', 'cmb2' ),
'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_options_submenu_for_page_post_type' );
/**
* Hook in and register a submenu options page for the Appearance menu.
*/
function yourprefix_register_options_submenu_appearance_menu() {
/**
* Registers options page menu item and form.
*/
$cmb_options = new_cmb2_box( array(
'id' => 'yourprefix_options_submenu_appearance_menu',
'title' => esc_html__( 'Appearance Options', 'cmb2' ),
'object_types' => array( 'options-page' ),
/*
* The following parameters are specific to the options-page box
* Several of these parameters are passed along to add_menu_page()/add_submenu_page().
*/
'option_key' => 'yourprefix_theme_appearance_options', // The option key and admin menu page slug.
// 'icon_url' => '', // Menu icon. Only applicable if 'parent_slug' is left empty.
// 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
// 'capability' => 'manage_options', // Cap required to view options-page.
// 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
// 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
// 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
// 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
// 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
// 'message_cb' => 'yourprefix_options_page_message_callback',
) );
/**
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$cmb_options->add_field( array(
'name' => esc_html__( 'Site Background Color', 'cmb2' ),
'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
'id' => 'bg_color',
'type' => 'colorpicker',
'default' => '#ffffff',
) );
}
add_action( 'cmb2_admin_init', 'yourprefix_register_options_submenu_appearance_menu' );
================================================
FILE: options-and-settings-pages/theme-options-cmb.php
================================================
'myprefix_option_metabox',
'title' => esc_html__( 'Site Options', 'myprefix' ),
'object_types' => array( 'options-page' ),
/*
* The following parameters are specific to the options-page box
* Several of these parameters are passed along to add_menu_page()/add_submenu_page().
*/
'option_key' => 'myprefix_options', // The option key and admin menu page slug.
// 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
// 'menu_title' => esc_html__( 'Options', 'myprefix' ), // Falls back to 'title' (above).
// 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
// 'capability' => 'manage_options', // Cap required to view options-page.
// 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
// 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
// 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
// 'save_button' => esc_html__( 'Save Theme Options', 'myprefix' ), // The text for the options-page save button. Defaults to 'Save'.
) );
/*
* Options fields ids only need
* to be unique within this box.
* Prefix is not needed.
*/
$cmb_options->add_field( array(
'name' => __( 'Test Text', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_text',
'type' => 'text',
'default' => 'Default Text',
) );
$cmb_options->add_field( array(
'name' => __( 'Test Color Picker', 'myprefix' ),
'desc' => __( 'field description (optional)', 'myprefix' ),
'id' => 'test_colorpicker',
'type' => 'colorpicker',
'default' => '#bada55',
) );
}
/**
* Wrapper function around cmb2_get_option
* @since 0.1.0
* @param string $key Options array key
* @param mixed $default Optional default value
* @return mixed Option value
*/
function myprefix_get_option( $key = '', $default = false ) {
if ( function_exists( 'cmb2_get_option' ) ) {
// Use cmb2_get_option as it passes through some key filters.
return cmb2_get_option( 'myprefix_options', $key, $default );
}
// Fallback to get_option if CMB2 is not loaded yet.
$opts = get_option( 'myprefix_options', $default );
$val = $default;
if ( 'all' == $key ) {
$val = $opts;
} elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
$val = $opts[ $key ];
}
return $val;
}
================================================
FILE: user-meta-and-settings/README.md
================================================
User Meta and Settings
==========
These are examples of [using CMB2 to generate user fields](https://github.com/WebDevStudios/CMB2/wiki/Adding-metaboxes-to-user-profile).
================================================
FILE: widgets/widget-example.php
================================================
widget_slug,
esc_html__( 'CMB2 Widget Boilerplate Title', 'your-textdomain' ),
array(
'classname' => $this->widget_slug,
'customize_selective_refresh' => true,
'description' => esc_html__( 'A CMB2 widget boilerplate description.', 'your-textdomain' ),
)
);
self::$defaults = array(
'title' => esc_html__( 'CMB2 Widget Title', 'your-textdomain' ),
'image' => '',
'desc' => '',
'color' => '#bada55',
);
$this->cmb2_fields = array(
array(
'name' => 'Title',
'id_key' => 'title',
'id' => 'title',
'type' => 'text',
),
array(
'name' => 'Image',
'desc' => 'Upload an image or enter an URL.',
'id_key' => 'image',
'id' => 'image',
'type' => 'file',
'options' => array(
'url' => false
),
'text' => array(
'add_upload_file_text' => 'Upload An Image'
),
),
array(
'name' => 'Description',
'id_key' => 'desc',
'id' => 'desc',
'type' => 'textarea',
),
array(
'name' => 'Color',
'id_key' => 'color',
'id' => 'color',
'type' => 'colorpicker',
),
);
add_action( 'save_post', array( $this, 'flush_widget_cache' ) );
add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) );
add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) );
add_shortcode( self::$shortcode, array( __CLASS__, 'get_widget' ) );
}
/**
* Delete this widget's cache.
*
* Note: Could also delete any transients
* delete_transient( 'some-transient-generated-by-this-widget' );
*/
public function flush_widget_cache() {
wp_cache_delete( $this->id, 'widget' );
}
/**
* Front-end display of widget.
*
* @param array $args The widget arguments set up when a sidebar is registered.
* @param array $instance The widget settings as set by user.
*/
public function widget( $args, $instance ) {
echo self::get_widget( array(
'args' => $args,
'instance' => $instance,
'cache_id' => $this->id, // whatever the widget id is
) );
}
/**
* Return the widget/shortcode output
*
* @param array $atts Array of widget/shortcode attributes/args
* @return string Widget output
*/
public static function get_widget( $atts ) {
$widget = '';
// Set up default values for attributes
$atts = shortcode_atts(
array(
// Ensure variables
'instance' => array(),
'before_widget' => '',
'after_widget' => '',
'before_title' => '',
'after_title' => '',
'cache_id' => '',
'flush_cache' => isset( $_GET['delete-trans'] ), // Check for cache-buster
),
isset( $atts['args'] ) ? (array) $atts['args'] : array(),
self::$shortcode
);
$instance = shortcode_atts(
self::$defaults,
! empty( $atts['instance'] ) ? (array) $atts['instance'] : array(),
self::$shortcode
);
/*
* If cache_id is not passed, we're not using the widget (but the shortcode),
* so generate a hash cache id from the shortcode arguments
*/
if ( empty( $atts['cache_id'] ) ) {
$atts['cache_id'] = md5( serialize( $atts ) );
}
// Get from cache unless being requested not to
$widget = ! $atts['flush_cache']
? wp_cache_get( $atts['cache_id'], 'widget' )
: '';
// If $widget is empty, rebuild our cache
if ( empty( $widget ) ) {
$widget = '';
// Before widget hook
$widget .= $atts['before_widget'];
$widget .= '
';
// After widget hook
$widget .= $atts['after_widget'];
wp_cache_set( $atts['cache_id'], $widget, 'widget', WEEK_IN_SECONDS );
}
return $widget;
}
/**
* Update form values as they are saved.
*
* @param array $new_instance New settings for this instance as input by the user.
* @param array $old_instance Old settings for this instance.
* @return array Settings to save or bool false to cancel saving.
*/
public function update( $new_instance, $old_instance ) {
$this->flush_widget_cache();
$sanitized = $this->cmb2( true )->get_sanitized_values( $new_instance );
return $sanitized;
}
/**
* Back-end widget form with defaults.
*
* @param array $instance Current settings.
*/
public function form( $instance ) {
// If there are no settings, set up defaults
$this->_instance = wp_parse_args( (array) $instance, self::$defaults );
$cmb2 = $this->cmb2();
$cmb2->object_id( $this->option_name );
CMB2_hookup::enqueue_cmb_css();
CMB2_hookup::enqueue_cmb_js();
$cmb2->show_form();
}
/**
* Creates a new instance of CMB2 and adds some fields
* @since 0.1.0
* @return CMB2
*/
public function cmb2( $saving = false ) {
// Create a new box in the class
$cmb2 = new CMB2( array(
'id' => $this->option_name .'_box', // Option name is taken from the WP_Widget class.
'hookup' => false,
'show_on' => array(
'key' => 'options-page', // Tells CMB2 to handle this as an option
'value' => array( $this->option_name )
),
), $this->option_name );
foreach ( $this->cmb2_fields as $field ) {
if ( ! $saving ) {
$field['id'] = $this->get_field_name( $field['id'] );
}
$field['default_cb'] = array( $this, 'default_cb' );
$cmb2->add_field( $field );
}
return $cmb2;
}
/**
* Sets the field default, or the field value.
*
* @param array $field_args CMB2 field args array
* @param CMB2_Field $field CMB2 Field object.
*
* @return mixed Field value.
*/
public function default_cb( $field_args, $field ) {
return isset( $this->_instance[ $field->args( 'id_key' ) ] )
? $this->_instance[ $field->args( 'id_key' ) ]
: null;
}
}
/**
* Register this widget with WordPress.
*/
function register_wds_widget_boilerplate() {
register_widget( 'CMB2_Widget_Boilerplate' );
}
add_action( 'widgets_init', 'register_wds_widget_boilerplate' );