├── .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
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/osx
3 |
4 | ### OSX ###
5 | *.DS_Store
6 | .AppleDouble
7 | .LSOverride
8 |
9 | # Icon must end with two \r
10 | Icon
11 | # Thumbnails
12 | ._*
13 | # Files that might appear in the root of a volume
14 | .DocumentRevisions-V100
15 | .fseventsd
16 | .Spotlight-V100
17 | .TemporaryItems
18 | .Trashes
19 | .VolumeIcon.icns
20 | .com.apple.timemachine.donotpresent
21 | # Directories potentially created on remote AFP share
22 | .AppleDB
23 | .AppleDesktop
24 | Network Trash Folder
25 | Temporary Items
26 | .apdisk
27 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contribute To CMB2 Code Snippet Library
2 |
3 | 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.
4 |
5 | ## Submitting a Snippet
6 |
7 | 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/).
8 |
9 | Guidelines for submission:
10 |
11 | - Each snippet should be placed in it's own file.
12 | - Each file should be named appropriately based on the purpose of the snippet.
13 | - Files should be placed in the appropriate category (folder). If no category exists, you may create one with your pull request.
14 | - 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}`.
15 | - (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.
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | CMB2 Code Snippet Library
2 | ========================
3 |
4 | This is a community-maintained repository of code snippets that help modify the default behavior of [CMB2](https://github.com/WebDevStudios/CMB2/).
5 |
6 | Snippets are organized into categories (folders) and each snippet is placed in its own file with a name that describes what it does.
7 |
8 | Thank you to the EDD team for [the inspiration](https://github.com/easydigitaldownloads/library) for this library.
9 |
10 | ## Submitting Your Snippet
11 |
12 | 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/).
13 |
14 | Please refer to the [Contributing guidelines](https://github.com/WebDevStudios/CMB2-Snippet-Library/blob/master/CONTRIBUTING.md) before submitting your pull request.
15 |
16 | ## Proposing a Snippet
17 |
18 | 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.
19 |
20 | ## Notes
21 |
22 | 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.
23 |
24 | 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)!
--------------------------------------------------------------------------------
/api/README.md:
--------------------------------------------------------------------------------
1 | CMB2 API Snippets
2 | ==========
3 |
4 | Snippets related to the CMB2 API endpoints/functionality.
5 |
--------------------------------------------------------------------------------
/api/cmb2-file-list-ordered.php:
--------------------------------------------------------------------------------
1 | $file_url ) {
22 | $value[] = array(
23 | 'id' => $file_id,
24 | 'url' => $file_url,
25 | );
26 | }
27 | }
28 |
29 | return $value;
30 | }
31 |
32 | /**
33 | * Filters the value before it is sent to the REST request.
34 | *
35 | * "_yourprefix_demo_file_list" is a dynamic portion of the hook name, referring to the field id.
36 | */
37 | add_filter( 'cmb2_get_rest_value_for__yourprefix_demo_file_list', 'yourprefix_cmb2_ordered_file_list_array_in_api', 10, 2 );
38 |
39 | return;
40 |
41 | // Another method to make this modification to several different file_list fields.
42 | // Do not use both of these methods. Pick one.
43 |
44 | define( 'YOURPREFIX_FILE_LIST_IDS', array(
45 | '_yourprefix_demo_file_list',
46 | 'xyz'
47 | // etc.
48 | ) );
49 |
50 | function yourprefix_cmb2_ordered_file_list_array_in_api_2( $value, $field ) {
51 | // Replace
52 | if ( in_array( $field->_id(), YOURPREFIX_FILE_LIST_IDS, true ) && ! empty( $value ) && is_array( $value ) ) {
53 | $files = $value;
54 | $value = array();
55 | foreach ( $files as $file_id => $file_url ) {
56 | $value[] = array(
57 | 'id' => $file_id,
58 | 'url' => $file_url,
59 | );
60 | }
61 | }
62 |
63 | return $value;
64 | }
65 | add_filter( 'cmb2_get_rest_value_file_list', 'yourprefix_cmb2_ordered_file_list_array_in_api_2', 10, 2 );
--------------------------------------------------------------------------------
/conditional-display/exclude-for-ids.php:
--------------------------------------------------------------------------------
1 | 'exclude_for_ids',
9 | 'title' => 'Demo',
10 | 'exclude_ids' => array( 1, 2, 3, 55 ), // Exclude metabox on these post-ids
11 | 'show_on_cb' => 'cmb2_exclude_for_ids', // function should return a bool value
12 | ) );
13 |
14 | /**
15 | * Exclude metabox on specific IDs
16 | * @param object $cmb CMB2 object
17 | * @return bool True/false whether to show the metabox
18 | */
19 | function cmb2_exclude_for_ids( $cmb ) {
20 | $ids_to_exclude = $cmb->prop( 'exclude_ids', array() );
21 | $excluded = in_array( $cmb->object_id(), $ids_to_exclude, true );
22 |
23 | return ! $excluded;
24 | }
25 |
--------------------------------------------------------------------------------
/conditional-display/hide-on-new-post-page.php:
--------------------------------------------------------------------------------
1 | 'exclude_for_ids',
10 | 'title' => 'Demo',
11 | 'exclude_from' => array( 'post-new.php' ), // Exclude metabox on new-post screen
12 | 'show_on_cb' => 'tgm_exclude_from_new', // function should return a bool value
13 | ) );
14 |
15 | /**
16 | * Removes metabox from appearing on post new screens before the post
17 | * ID has been set.
18 | * @author Thomas Griffin
19 | * @param object $cmb CMB2 object
20 | * @return bool True/false whether to show the metabox
21 | */
22 | function tgm_exclude_from_new( $cmb ) {
23 | global $pagenow;
24 |
25 | $exclude_from = $cmb->prop( 'exclude_from', array( 'post-new.php' ) );
26 | $excluded = in_array( $pagenow, $exclude_from, true );
27 |
28 | return ! $excluded;
29 | }
30 |
--------------------------------------------------------------------------------
/conditional-display/show-for-taxonomy-terms.php:
--------------------------------------------------------------------------------
1 | 'show_for_taxonomy_terms',
10 | 'title' => 'Demo',
11 | 'show_on_cb' => 'be_taxonomy_show_on_filter', // function should return a bool value
12 | 'show_on_terms' => array(
13 | 'category' => array( 'featured' ),
14 | 'post_tag' => array( 'best-of' ),
15 | ),
16 | ) );
17 |
18 | /**
19 | * Taxonomy show_on filter
20 | * @author Bill Erickson
21 | * @param object $cmb CMB2 object
22 | * @return bool True/false whether to show the metabox
23 | */
24 | function be_taxonomy_show_on_filter( $cmb ) {
25 | $tax_terms_to_show_on = $cmb->prop( 'show_on_terms', array() );
26 | if ( empty( $tax_terms_to_show_on ) || ! $cmb->object_id() ) {
27 | return false;
28 | }
29 |
30 | $post_id = $cmb->object_id();
31 | $post = get_post( $post_id );
32 |
33 | foreach( (array) $tax_terms_to_show_on as $taxonomy => $slugs ) {
34 | if ( ! is_array( $slugs ) ) {
35 | $slugs = array( $slugs );
36 | }
37 |
38 | $terms = $post
39 | ? get_the_terms( $post, $taxonomy )
40 | : wp_get_object_terms( $post_id, $taxonomy );
41 |
42 | if ( ! empty( $terms ) ) {
43 | foreach( $terms as $term ) {
44 | if ( in_array( $term->slug, $slugs, true ) ) {
45 | wp_die( '
: '. print_r( 'show it', true ) .' ' );
46 | // Ok, show this metabox
47 | return true;
48 | }
49 | }
50 | }
51 | }
52 |
53 | return false;
54 | }
55 |
56 |
--------------------------------------------------------------------------------
/conditional-display/show-if-matching-meta-value.php:
--------------------------------------------------------------------------------
1 | 'wiki_status_metabox',
17 | 'title' => 'Status Metabox',
18 | 'object_types' => array( 'page', ), // Post type
19 | ) );
20 |
21 | $cmb->add_field( array(
22 | 'name' => 'Status',
23 | 'id' => 'wiki_status',
24 | 'type' => 'select',
25 | 'default' => 'internal',
26 | 'options' => array(
27 | 'internal' => 'Internal',
28 | 'external' => 'External',
29 | ),
30 | ) );
31 |
32 | /**
33 | * Metabox to conditionally display if the 'status' is set to 'External'.
34 | */
35 | $cmb = new_cmb2_box( array(
36 | 'id' => 'wiki_conditonal_metabox',
37 | 'title' => 'Contact Info',
38 | 'object_types' => array( 'page', ), // Post type
39 | 'show_on_cb' => 'cmb_only_show_for_external', // function should return a bool value
40 | ) );
41 |
42 | $cmb->add_field( array(
43 | 'name' => 'Email',
44 | 'id' => 'wiki_email',
45 | 'type' => 'text_email',
46 | ) );
47 | }
48 |
49 | /**
50 | * Only display a metabox if the page's 'status' is 'external'
51 | * @param object $cmb CMB2 object
52 | * @return bool True/false whether to show the metabox
53 | */
54 | function cmb_only_show_for_external( $cmb ) {
55 | $status = get_post_meta( $cmb->object_id(), 'wiki_status', 1 );
56 |
57 | // Only show if status is 'external'
58 | return 'external' === $status;
59 | }
60 |
--------------------------------------------------------------------------------
/conditional-display/show-only-for-top-level-posts.php:
--------------------------------------------------------------------------------
1 | 'exclude_for_ids',
9 | 'title' => 'Demo',
10 | 'show_on_cb' => 'ba_metabox_add_for_top_level_posts_only', // function should return a bool value
11 | ) );
12 |
13 | /**
14 | * Exclude metabox on non top level posts
15 | * @author Travis Northcutt
16 | * @param object $cmb CMB2 object
17 | * @return bool True/false whether to show the metabox
18 | */
19 | function ba_metabox_add_for_top_level_posts_only( $cmb ) {
20 | $has_parent = $cmb->object_id() && get_post_ancestors( $cmb->object_id() );
21 |
22 | return ! $has_parent;
23 | }
24 |
--------------------------------------------------------------------------------
/custom-field-types/README.md:
--------------------------------------------------------------------------------
1 | Custom Field Types
2 | ==========
3 |
4 | Snippets for [adding custom CMB2 field types](https://github.com/WebDevStudios/CMB2/wiki/Adding-your-own-field-types).
--------------------------------------------------------------------------------
/custom-field-types/address-field-type/address-field-type.php:
--------------------------------------------------------------------------------
1 | '',
37 | 'address-2' => '',
38 | 'city' => '',
39 | 'state' => '',
40 | 'zip' => '',
41 | 'country' => '',
42 | ) );
43 |
44 | $output = '';
45 | $output .= '
Address: ' . esc_html( $address['address-1'] ) . '
';
46 | if ( $address['address-2'] ) {
47 | $output .= '
' . esc_html( $address['address-2'] ) . '
';
48 | }
49 | $output .= '
City: ' . esc_html( $address['city'] ) . '
';
50 | $output .= '
State: ' . esc_html( $address['state'] ) . '
';
51 | $output .= '
Zip: ' . esc_html( $address['zip'] ) . '
';
52 | $output .= '
';
53 |
54 | return apply_filters( 'jt_cmb2_get_address_field', $output );
55 | }
56 |
57 | function cmb2_init_address_field() {
58 | require_once dirname( __FILE__ ) . '/class-cmb2-render-address-field.php';
59 | CMB2_Render_Address_Field::init();
60 | }
61 | add_action( 'cmb2_init', 'cmb2_init_address_field' );
62 |
--------------------------------------------------------------------------------
/custom-field-types/address-field-type/class-cmb2-render-address-field.php:
--------------------------------------------------------------------------------
1 | 'Alabama', 'AK' => 'Alaska', 'AZ' => 'Arizona', 'AR' => 'Arkansas', 'CA' => 'California', 'CO' => 'Colorado', 'CT' => 'Connecticut', 'DE' => 'Delaware', 'DC' => 'District Of Columbia', 'FL' => 'Florida', 'GA' => 'Georgia', 'HI' => 'Hawaii', 'ID' => 'Idaho', 'IL' => 'Illinois', 'IN' => 'Indiana', 'IA' => 'Iowa', 'KS' => 'Kansas', 'KY' => 'Kentucky', 'LA' => 'Louisiana', 'ME' => 'Maine', 'MD' => 'Maryland', 'MA' => 'Massachusetts', 'MI' => 'Michigan', 'MN' => 'Minnesota', 'MS' => 'Mississippi', 'MO' => 'Missouri', 'MT' => 'Montana', 'NE' => 'Nebraska', 'NV' => 'Nevada', 'NH' => 'New Hampshire', 'NJ' => 'New Jersey', 'NM' => 'New Mexico', 'NY' => 'New York', 'NC' => 'North Carolina', 'ND' => 'North Dakota', 'OH' => 'Ohio', 'OK' => 'Oklahoma', 'OR' => 'Oregon', 'PA' => 'Pennsylvania', 'RI' => 'Rhode Island', 'SC' => 'South Carolina', 'SD' => 'South Dakota', 'TN' => 'Tennessee', 'TX' => 'Texas', 'UT' => 'Utah', 'VT' => 'Vermont', 'VA' => 'Virginia', 'WA' => 'Washington', 'WV' => 'West Virginia', 'WI' => 'Wisconsin', 'WY' => 'Wyoming' );
14 |
15 | public static function init() {
16 | add_filter( 'cmb2_render_class_address', array( __CLASS__, 'class_name' ) );
17 | add_filter( 'cmb2_sanitize_address', array( __CLASS__, 'maybe_save_split_values' ), 12, 4 );
18 |
19 | /**
20 | * The following snippets are required for allowing the address field
21 | * to work as a repeatable field, or in a repeatable group.
22 | */
23 | add_filter( 'cmb2_sanitize_address', array( __CLASS__, 'sanitize' ), 10, 5 );
24 | add_filter( 'cmb2_types_esc_address', array( __CLASS__, 'escape' ), 10, 4 );
25 | add_filter( 'cmb2_override_meta_value', array( __CLASS__, 'get_split_meta_value' ), 12, 4 );
26 | }
27 |
28 | public static function class_name() { return __CLASS__; }
29 |
30 | /**
31 | * Handles outputting the address field.
32 | */
33 | public function render() {
34 |
35 | // make sure we assign each part of the value we need.
36 | $value = wp_parse_args( $this->field->escaped_value(), array(
37 | 'address-1' => '',
38 | 'address-2' => '',
39 | 'city' => '',
40 | 'state' => '',
41 | 'zip' => '',
42 | 'country' => '',
43 | ) );
44 |
45 | if ( ! $this->field->args( 'do_country' ) ) {
46 | $state_list = $this->field->args( 'state_list', array() );
47 | if ( empty( $state_list ) ) {
48 | $state_list = self::$state_list;
49 | }
50 |
51 | // Add the "label" option. Can override via the field text param.
52 | $state_list = array( '' => esc_html( $this->_text( 'address_select_state_text', 'Select a State' ) ) ) + $state_list;
53 |
54 | $state_options = '';
55 | foreach ( $state_list as $abrev => $state ) {
56 | $state_options .= '' . $state . ' ';
57 | }
58 | }
59 |
60 | $state_label = 'State';
61 | if ( $this->field->args( 'do_country' ) ) {
62 | $state_label .= '/Province';
63 | }
64 |
65 | ob_start();
66 | // Do html.
67 | ?>
68 | _text( 'address_address_1_text', 'Address 1' ) ); ?>
69 | types->input( array(
70 | 'name' => $this->_name( '[address-1]' ),
71 | 'id' => $this->_id( '_address_1' ),
72 | 'value' => $value['address-1'],
73 | 'desc' => '',
74 | ) ); ?>
75 |
76 | _text( 'address_address_2_text', 'Address 2' ) ); ?>
77 | types->input( array(
78 | 'name' => $this->_name( '[address-2]' ),
79 | 'id' => $this->_id( '_address_2' ),
80 | 'value' => $value['address-2'],
81 | 'desc' => '',
82 | ) ); ?>
83 |
84 |
85 |
_text( 'address_city_text', 'City' ) ); ?>
86 | types->input( array(
87 | 'class' => 'cmb_text_small',
88 | 'name' => $this->_name( '[city]' ),
89 | 'id' => $this->_id( '_city' ),
90 | 'value' => $value['city'],
91 | 'desc' => '',
92 | ) ); ?>
93 |
94 |
_text( 'address_state_text', $state_label ) ); ?>
95 | field->args( 'do_country' ) ) : ?>
96 | types->input( array(
97 | 'class' => 'cmb_text_small',
98 | 'name' => $this->_name( '[state]' ),
99 | 'id' => $this->_id( '_state' ),
100 | 'value' => $value['state'],
101 | 'desc' => '',
102 | ) ); ?>
103 |
104 | types->select( array(
105 | 'name' => $this->_name( '[state]' ),
106 | 'id' => $this->_id( '_state' ),
107 | 'options' => $state_options,
108 | 'desc' => '',
109 | ) ); ?>
110 |
111 |
112 |
_text( 'address_zip_text', 'Zip' ) ); ?>
113 | types->input( array(
114 | 'class' => 'cmb_text_small',
115 | 'name' => $this->_name( '[zip]' ),
116 | 'id' => $this->_id( '_zip' ),
117 | 'value' => $value['zip'],
118 | 'type' => 'number',
119 | 'desc' => '',
120 | ) ); ?>
121 |
122 |
123 | field->args( 'do_country' ) ) : ?>
124 | _text( 'address_country_text', 'Country' ) ); ?>
125 | types->input( array(
126 | 'name' => $this->_name( '[country]' ),
127 | 'id' => $this->_id( '_country' ),
128 | 'value' => $value['country'],
129 | 'desc' => '',
130 | ) ); ?>
131 |
132 |
133 |
134 | _desc();?>
135 |
136 | rendered( ob_get_clean() );
140 | }
141 |
142 | /**
143 | * Optionally save the Address values into separate fields
144 | */
145 | public static function maybe_save_split_values( $override_value, $value, $object_id, $field_args ) {
146 | if ( ! isset( $field_args['split_values'] ) || ! $field_args['split_values'] ) {
147 | // Don't do the override.
148 | return $override_value;
149 | }
150 |
151 | $address_keys = array( 'address-1', 'address-2', 'city', 'state', 'zip' );
152 |
153 | foreach ( $address_keys as $key ) {
154 | if ( ! empty( $value[ $key ] ) ) {
155 | update_post_meta( $object_id, $field_args['id'] . 'addr_' . $key, sanitize_text_field( $value[ $key ] ) );
156 | }
157 | }
158 |
159 | remove_filter( 'cmb2_sanitize_address', array( __CLASS__, 'sanitize' ), 10, 5 );
160 |
161 | // Tell CMB2 we already did the update.
162 | return true;
163 | }
164 |
165 | public static function sanitize( $check, $meta_value, $object_id, $field_args, $sanitize_object ) {
166 |
167 | // if not repeatable, bail out.
168 | if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
169 | return $check;
170 | }
171 |
172 | foreach ( $meta_value as $key => $val ) {
173 | $meta_value[ $key ] = array_filter( array_map( 'sanitize_text_field', $val ) );
174 | }
175 |
176 | return array_filter( $meta_value );
177 | }
178 |
179 | public static function escape( $check, $meta_value, $field_args, $field_object ) {
180 | // if not repeatable, bail out.
181 | if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
182 | return $check;
183 | }
184 |
185 | foreach ( $meta_value as $key => $val ) {
186 | $meta_value[ $key ] = array_filter( array_map( 'esc_attr', $val ) );
187 | }
188 |
189 | return array_filter( $meta_value );
190 | }
191 |
192 | public static function get_split_meta_value( $data, $object_id, $field_args, $field ) {
193 | if ( 'address' !== $field->args['type'] ) {
194 | return $data;
195 | }
196 | if ( ! isset( $field->args['split_values'] ) || ! $field->args['split_values'] ) {
197 | // Don't do the override.
198 | return $data;
199 | }
200 |
201 | $prefix = $field->args['id'] . 'addr_';
202 | // Construct an array to iterate to fetch individual meta values for our override.
203 | // Should match the values in the render() method.
204 | $metakeys = array(
205 | 'address-1',
206 | 'address-2',
207 | 'city',
208 | 'state',
209 | 'zip',
210 | 'country',
211 | );
212 |
213 | $newdata = array();
214 | foreach ( $metakeys as $metakey ) {
215 | // Use our prefix to construct the whole meta key from the postmeta table.
216 | $newdata[ $metakey ] = get_post_meta( $object_id, $prefix . $metakey, true );
217 | }
218 |
219 | return $newdata;
220 | }
221 | }
222 |
--------------------------------------------------------------------------------
/custom-field-types/autocomplete-field-type.php:
--------------------------------------------------------------------------------
1 | 'autocomplete_test',
43 | 'title' => __('Autocomplete Field Examples', 'autocomplete_cmb2'),
44 | 'object_types' => array('post'),
45 | ) );
46 |
47 | $cmb->add_field( array(
48 | 'name' => __('Related Fruit', 'autocomplete_cmb2'),
49 | 'desc' => __('Fruit that is related to this post', 'autocomplete_cmb2'),
50 | 'id' => $prefix.'related_fruit',
51 | 'type' => 'autocomplete',
52 | 'options' => array(
53 | array('value' => 1, 'name' => 'Apple'),
54 | array('value' => 2, 'name' => 'Orange'),
55 | array('value' => 3, 'name' => 'Grape')
56 | )
57 | ) );
58 | $cmb->add_field( array(
59 | 'name' => __('Related Fruits', 'autocomplete_cmb2'),
60 | 'desc' => __('Repeatable related fruits', 'autocomplete_cmb2'),
61 | 'id' => $prefix.'related_fruits',
62 | 'type' => 'autocomplete',
63 | 'repeatable' => true,
64 | 'repeatable_class' => 'related-fruits',
65 | 'options' => array(
66 | array('value' => 1, 'name' => 'Apple'),
67 | array('value' => 2, 'name' => 'Orange'),
68 | array('value' => 3, 'name' => 'Grape')
69 | )
70 | ) );
71 | $cmb->add_field( array(
72 | 'name' => __('Related Post', 'autocomplete_cmb2'),
73 | 'desc' => __('Post that is related to this one', 'autocomplete_cmb2'),
74 | 'id' => $prefix.'related_post',
75 | 'type' => 'autocomplete',
76 | 'source' => 'get_post_options',
77 | 'mapping_function' => 'autocomplete_cmb2_get_post_title_from_id'
78 | ) );
79 | $cmb->add_field( array(
80 | 'name' => __('Related Posts', 'autocomplete_cmb2'),
81 | 'desc' => __('Posts that are related to this one', 'autocomplete_cmb2'),
82 | 'id' => $prefix.'related_posts',
83 | 'repeatable' => true,
84 | 'type' => 'autocomplete',
85 | 'source' => 'get_post_options',
86 | 'repeatable_class' => 'related-posts',
87 | 'mapping_function' => 'autocomplete_cmb2_get_post_title_from_id'
88 | ) );
89 | }
90 |
91 | /**
92 | * Gets the post title from the ID for mapping purposes in autocompletes.
93 | *
94 | * @param int $id
95 | * @return string
96 | */
97 | function autocomplete_cmb2_get_post_title_from_id($id) {
98 | if (empty($id)) {
99 | return '';
100 | }
101 |
102 | $post = get_post($id);
103 |
104 | return $post->post_title;
105 | }
106 |
107 | /**
108 | * Renders the autocomplete type
109 | *
110 | * @param CMB2_Field $field_object
111 | * @param string $escaped_value The value of this field passed through the escaping filter. It defaults to sanitize_text_field.
112 | * If you need the unescaped value, you can access it via $field_type_object->value().
113 | * @param string $object_id The id of the object you are working with. Most commonly, the post id.
114 | * @param string $object_type The type of object you are working with. Most commonly, post (this applies to all post-types),
115 | * but could also be comment, user or options-page.
116 | * @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.
117 | */
118 | function autocomplete_cmb2_render_autocomplete($field_object, $escaped_value, $object_id, $object_type, $field_type_object) {
119 |
120 | // Store the value in a hidden field.
121 | echo $field_type_object->hidden();
122 |
123 | if (isset($field_object->args['repeatable_class'])) {
124 | $repeatable_class = $field_object->args['repeatable_class'];
125 | }
126 |
127 | $options = $field_object->options();
128 |
129 | // Set up the options or source PHP variables.
130 | if (empty($options)) {
131 | $source = $field_object->args['source'];
132 | $value = $field_object->args['mapping_function']($field_object->escaped_value);
133 | } else {
134 |
135 | // Set the value.
136 | if (empty($field_object->escaped_value)) {
137 | $value = '';
138 | } else {
139 | foreach ($options as $option) {
140 | if ($option['value'] == $field_object->escaped_value) {
141 | $value = $option['name'];
142 | break;
143 | }
144 | }
145 | }
146 | }
147 |
148 | // Set up the autocomplete field. Replace the '_' with '-' to not interfere with the ID from CMB2.
149 | $id = str_replace('_', '-', $field_object->args['id']);
150 | if ( '_' !== substr( $field_object->args['id'], 0, 1 ) ) {
151 | $id = '-' . $field_object->args['id'];
152 | }
153 |
154 | // Don't use the ID on repeatable elements as it won't change; use the class instead.
155 | echo ' ';
157 |
158 | if (!$field_object->args['repeatable'] && isset($field_object->args['desc'])) {
159 | echo ''.$field_object->args['desc'].'
';
160 | }
161 |
162 | // Now, set up the script.
163 | ?>
164 |
229 | get_results($wpdb->prepare("
252 | SELECT ID, post_title
253 | FROM $wpdb->posts
254 | WHERE post_status = 'publish' AND post_type IN $post_type_query AND post_title LIKE %s
255 | ORDER BY post_title ASC
256 | ", $like_test), OBJECT);
257 |
258 | if ($include_empty) {
259 | $post_options = array(array('name' => '--- Select ---', 'value' => ''));
260 | } else {
261 | $post_options = array();
262 | }
263 |
264 | foreach ($posts as $post) {
265 | $post_options[] = array(
266 | 'name' => $post->post_title,
267 | 'value' => $post->ID
268 | );
269 | }
270 |
271 | return $post_options;
272 | }
273 |
274 |
275 | /**
276 | * Gets the jQuery autocomplete widget ready.
277 | */
278 | function autocomplete_cmb2_admin_enqueue_scripts() {
279 | wp_enqueue_script('jquery-ui-autocomplete');
280 | }
281 |
282 | /**
283 | * Gets the post options in JSON format for the autocomplete
284 | */
285 | function autocomplete_cmb2_get_post_autocomplete_options() {
286 | die(json_encode(autocomplete_cmb2_get_post_options_using_post_type('post', false, '%'.$_GET['q'].'%')));
287 | }
288 |
289 | add_action('cmb2_render_autocomplete', 'autocomplete_cmb2_render_autocomplete', 10, 5);
290 | add_action('admin_enqueue_scripts', 'autocomplete_cmb2_admin_enqueue_scripts');
291 | add_action('wp_ajax_get_post_options', 'autocomplete_cmb2_get_post_autocomplete_options');
292 | add_filter('cmb2_admin_init', 'autocomplete_cmb2_meta_boxes');
293 |
--------------------------------------------------------------------------------
/custom-field-types/button-field-type.php:
--------------------------------------------------------------------------------
1 | 'demo_metabox',
14 | * 'title' => __( 'Test Metabox', 'yourprefix' ),
15 | * 'object_types' => array( 'page', ),
16 | * ) );
17 | *
18 | * $cmb_demo->add_field( array(
19 | * 'type' => 'button',
20 | * 'name' => __( 'Button', 'yourprefix' ),
21 | * 'desc' => __( 'Button description (optional)', 'yourprefix' ),
22 | * 'id' => '_yourprefix_demo_button',
23 | * 'attributes' => array(
24 | * 'value' => 'Click Me',
25 | * 'onclick' => 'alert(\'You clicked the button!\');',
26 | * ),
27 | * ) );
28 | * }
29 | * add_action( 'cmb2_init', 'yourprefix_register_demo_metabox' );
30 | */
31 |
32 | // render button
33 | add_action( 'cmb2_render_button', 'jt_cmb2__cmb_render_button', 10, 5 );
34 | function jt_cmb2__cmb_render_button( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
35 | echo $field_type_object->input( array(
36 | 'class' => 'button',
37 | 'type' => 'button',
38 | ) );
39 | }
40 |
--------------------------------------------------------------------------------
/custom-field-types/default-category-field.php:
--------------------------------------------------------------------------------
1 | args( 'taxonomy' );
20 | $taxonomy = $taxonomy ? $taxonomy : 'category';
21 |
22 | if ( 'post' !== $object_type ) {
23 | wp_die( 'This won\'t work for non-"post" object types!' );
24 | }
25 |
26 | remove_meta_box( "{$object_type}div", 'post', 'side' );
27 |
28 | post_categories_meta_box( get_post( $object_id ), array(
29 | 'args' => array(
30 | 'taxonomy' => $taxonomy,
31 | ),
32 | ) );
33 | }
34 | add_action( 'cmb2_render_default_categories', 'cmb2_render_default_categories_field_type', 10, 4 );
35 |
36 | function cmb2_default_categories_let_wp_save( $null, $a, $field_args, $field ) {
37 | if ( 'default_categories' === $field->args( 'type' ) ) {
38 | // Let WP handle it.
39 | return false;
40 | }
41 |
42 | return $null;
43 | }
44 | add_filter( 'cmb2_override_meta_save', 'cmb2_default_categories_let_wp_save', 10, 4 );
45 |
46 | function cmb2_remove_default_category_metabox_for_taxonomy() {
47 | foreach ( CMB2_Boxes::get_all() as $cmb ) {
48 | foreach ( $cmb->prop( 'fields' ) as $field ) {
49 | if ( 'default_categories' === $field['type'] ) {
50 | $taxonomy = isset( $field['taxonomy'] ) ? $field['taxonomy'] : 'category';
51 | remove_meta_box( "{$taxonomy}div", 'post', 'side' );
52 | }
53 | }
54 | }
55 | }
56 | add_action( 'admin_init', 'cmb2_remove_default_category_metabox_for_taxonomy' );
57 |
--------------------------------------------------------------------------------
/custom-field-types/default-tags-field.php:
--------------------------------------------------------------------------------
1 | args( 'taxonomy' );
20 | $taxonomy = $taxonomy ? $taxonomy : 'post_tag';
21 |
22 | if ( 'post' !== $object_type ) {
23 | wp_die( 'This won\'t work for non-"post" object types!' );
24 | }
25 |
26 | wp_enqueue_script( 'tags-box' );
27 | add_action( 'admin_footer', 'cmb2_init_post_tag_box' );
28 |
29 | post_tags_meta_box( get_post( $object_id ), array(
30 | 'args' => array(
31 | 'taxonomy' => $taxonomy,
32 | ),
33 | ) );
34 | }
35 | add_action( 'cmb2_render_default_tags', 'cmb2_render_default_tags_field_type', 10, 4 );
36 |
37 | function cmb2_init_post_tag_box() {
38 | ?>
39 |
44 | args( 'type' ) ) {
49 | // Let WP handle it.
50 | return false;
51 | }
52 |
53 | return $null;
54 | }
55 | add_filter( 'cmb2_override_meta_save', 'cmb2_default_tags_let_wp_save', 10, 4 );
56 |
57 | function cmb2_remove_default_tag_metabox_for_taxonomy() {
58 | foreach ( CMB2_Boxes::get_all() as $cmb ) {
59 | foreach ( $cmb->prop( 'fields' ) as $field ) {
60 | if ( 'default_tags' === $field['type'] ) {
61 | $taxonomy = isset( $field['taxonomy'] ) ? $field['taxonomy'] : 'post_tag';
62 | remove_meta_box( "tagsdiv-{$taxonomy}", 'post', 'side' );
63 | }
64 | }
65 | }
66 | }
67 | add_action( 'admin_init', 'cmb2_remove_default_tag_metabox_for_taxonomy' );
68 |
69 |
--------------------------------------------------------------------------------
/custom-field-types/form-field-field-type.php:
--------------------------------------------------------------------------------
1 | add_field( array(
12 | * 'name' => 'Campos',
13 | * 'desc' => 'Adiciona campos ao formulário',
14 | * 'id' => '_form_fields',
15 | * 'type' => 'formfield',
16 | * 'repeatable' => true,
17 | * 'text' => array(
18 | * 'add_row_text' => 'Adicionar Campo',
19 | * 'formfield_field_id_label' => 'ID do Campo',
20 | * 'formfield_field_label_label' => 'Título do campo',
21 | * 'formfield_field_type_label' => 'Tipo do campo',
22 | * 'formfield_field_size_label' => 'Tamanho do campo',
23 | * 'formfield_text_field_option_label' => 'Texto',
24 | * 'formfield_email_field_option_label' => 'Email',
25 | * 'formfield_money_field_option_label' => 'Dinheiro',
26 | * 'formfield_date_field_option_label' => 'Data',
27 | * ),
28 | * ) );
29 | *
30 | */
31 |
32 |
33 | /**
34 | * Render 'formfield' custom field type
35 | *
36 | * @since 0.1.0
37 | *
38 | * @param array $field The passed in `CMB2_Field` object
39 | * @param mixed $value The value of this field escaped.
40 | * It defaults to `sanitize_text_field`.
41 | * If you need the unescaped value, you can access it
42 | * via `$field->value()`
43 | * @param int $object_id The ID of the current object
44 | * @param string $object_type The type of object you are working with.
45 | * Most commonly, `post` (this applies to all post-types),
46 | * but could also be `comment`, `user` or `options-page`.
47 | * @param object $field_type The `CMB2_Types` object
48 | */
49 | function jt_cmb2_render_formfield_field_callback( $field, $value, $object_id, $object_type, $field_type ) {
50 |
51 | // make sure we specify each part of the value we need.
52 | $value = wp_parse_args( $value, array(
53 | 'id' => '',
54 | 'label' => '',
55 | 'type' => 'text',
56 | 'size' => '',
57 | ) );
58 |
59 | $type_options = array(
60 | 'text' => $field_type->_text( 'formfield_text_field_option_label', 'Text' ),
61 | 'email' => $field_type->_text( 'formfield_email_field_option_label', 'Email' ),
62 | 'money' => $field_type->_text( 'formfield_money_field_option_label', 'Money' ),
63 | 'date' => $field_type->_text( 'formfield_date_field_option_label', 'Date' ),
64 | );
65 |
66 | $types = '';
67 | foreach ( $type_options as $type => $label ) {
68 | $selected = selected( $value['type'], $type, false );
69 | $label = esc_html( $label );
70 | $types .= "{$label} ";
71 | }
72 |
73 | ?>
74 |
75 |
76 |
77 | _text( 'formfield_field_id_label', 'Field ID' ) ); ?>
78 | input( array(
80 | 'name' => $field_type->_name( '[id]' ),
81 | 'id' => $field_type->_id( '_id' ),
82 | 'value' => $value['id'],
83 | 'desc' => ''
84 | ) )
85 | ?>
86 |
87 |
88 |
89 |
90 | _text( 'formfield_field_label_label', 'Field label' ) ); ?>
91 | input( array(
93 | 'name' => $field_type->_name( '[label]' ),
94 | 'id' => $field_type->_id( '_label' ),
95 | 'value' => $value['label'],
96 | 'desc' => ''
97 | ) )
98 | ?>
99 |
100 |
101 |
102 |
103 | _text( 'formfield_field_type_label', 'Field type' ) ); ?>
104 | select( array(
106 | 'name' => $field_type->_name( '[type]' ),
107 | 'id' => $field_type->_id( '_type' ),
108 | 'options' => $types,
109 | 'desc' => ''
110 | ) )
111 | ?>
112 |
113 |
114 |
115 |
116 | _text( 'formfield_field_size_label', 'Field Size' ) ); ?>
117 | input( array(
119 | 'name' => $field_type->_name( '[size]' ),
120 | 'id' => $field_type->_id( '_size' ),
121 | 'value' => $value['size'],
122 | 'desc' => ''
123 | ) )
124 | ?>
125 |
126 |
127 |
128 | _desc() ) : ?>
129 |
130 | _desc();?>
131 |
132 | $val ) {
148 | $val['type'] = isset( $val['type'] ) ? $val['type'] : 'text';
149 | if ( 'text' === $val['type'] ) {
150 | unset( $val['type'] );
151 | $val = array_filter( $val );
152 | if ( empty( $val ) ) {
153 | unset( $meta_value[ $key ] );
154 | continue;
155 | } else {
156 | $val['type'] = 'text';
157 | }
158 | }
159 | $meta_value[ $key ] = array_map( 'sanitize_text_field', $val );
160 | }
161 |
162 | return $meta_value;
163 | }
164 | add_filter( 'cmb2_sanitize_formfield', 'jt_cmb2_sanitize_formfield_field', 10, 4 );
165 |
166 | function jt_cmb2_types_esc_formfield_field( $check, $meta_value, $field_args ) {
167 |
168 | // Nothing needed if not array value or not a repeatable field.
169 | if ( ! is_array( $meta_value ) || empty( $field_args['repeatable'] ) ) {
170 | return $check;
171 | }
172 |
173 | foreach ( $meta_value as $key => $val ) {
174 | $meta_value[ $key ] = array_map( 'esc_attr', $val );
175 | }
176 |
177 | return $meta_value;
178 | }
179 | add_filter( 'cmb2_types_esc_formfield', 'jt_cmb2_types_esc_formfield_field', 10, 3 );
--------------------------------------------------------------------------------
/custom-field-types/multicheck_posttype-field_type.php:
--------------------------------------------------------------------------------
1 | =' ) ) {
14 | $field_type_object->type = new CMB2_Type_Radio( $field_type_object );
15 | }
16 |
17 | $cpts = get_post_types();
18 | // To disable the avalaibility of post types
19 | unset( $cpts[ 'nav_menu_item' ] );
20 | unset( $cpts[ 'revision' ] );
21 | $cpts = apply_filters( 'multicheck_posttype_' . $field->args[ '_id' ], $cpts );
22 | $options = '';
23 | $i = 1;
24 | $values = (array) $escaped_value;
25 |
26 | if ( $cpts ) {
27 | foreach ( $cpts as $cpt ) {
28 | $args = array(
29 | 'value' => $cpt,
30 | 'label' => $cpt,
31 | 'type' => 'checkbox',
32 | 'name' => $field->args['_name'] . '[]',
33 | );
34 |
35 | if ( in_array( $cpt, $values ) ) {
36 | $args[ 'checked' ] = 'checked';
37 | }
38 | $options .= $field_type_object->list_input( $args, $i );
39 | $i++;
40 | }
41 | }
42 |
43 | $classes = false === $field->args( 'select_all_button' ) ? 'cmb2-checkbox-list no-select-all cmb2-list' : 'cmb2-checkbox-list cmb2-list';
44 | echo $field_type_object->radio( array( 'class' => $classes, 'options' => $options ), 'multicheck_posttype' );
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/custom-field-types/multicheck_title-field_type.php:
--------------------------------------------------------------------------------
1 | add_field( array(
15 | 'name' => __( 'Fields Extra', $this->plugin_slug ),
16 | 'id' => 'extra_fields',
17 | 'type' => 'multicheck_title',
18 | 'data' => $fields
19 | ) );
20 | */
21 |
22 | // render Title multicheck
23 | add_action( 'cmb2_render_multicheck_title', 'cmb_render_multicheck_title', 10, 5 );
24 |
25 | function cmb_render_multicheck_title( $field, $escaped_value, $object_id, $object_type, $field_type_object ) {
26 | $data_field = $field->args[ 'data' ];
27 | $values = ( array ) $escaped_value;
28 | $i = 0;
29 |
30 | if ( version_compare( CMB2_VERSION, '2.2.2', '>=' ) ) {
31 | $field_type_object->type = new CMB2_Type_Multicheck( $field_type_object );
32 | }
33 |
34 | if ( $data_field ) {
35 | foreach ( $data_field as $title => $extra_fields ) {
36 | $options = '';
37 | foreach ( $extra_fields as $extra_field => $value ) {
38 | $args = array(
39 | 'value' => $extra_field,
40 | 'label' => $value,
41 | 'type' => 'checkbox',
42 | 'name' => $field->args[ '_name' ] . '[]',
43 | );
44 |
45 | if ( in_array( $extra_field, $values) ) {
46 | $args[ 'checked' ] = 'checked';
47 | }
48 | $options .= $field_type_object->list_input( $args, $i );
49 | $i++;
50 | }
51 | echo ''.$title.' ';
52 | $classes = false === $field->args( 'select_all_button' ) ? 'cmb2-checkbox-list no-select-all cmb2-list' : 'cmb2-checkbox-list cmb2-list';
53 | echo $field_type_object->radio( array( 'class' => $classes, 'options' => $options ), 'title_multicheck' );
54 | }
55 | } else {
56 | echo __( 'Nothing' );
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/custom-field-types/post-list-field-type.php:
--------------------------------------------------------------------------------
1 | args( 'select_type' );
9 |
10 | echo $field_type->input( array(
11 | 'autocomplete' => 'off',
12 | 'style' => 'display:none'
13 | ) );
14 | echo '';
15 | if ( !empty( $field->escaped_value ) ) {
16 | $list = explode( ',', $field->escaped_value );
17 | foreach ( $list as $value ) {
18 | echo '' . __( 'Title' ) . ': ' . get_the_title( $value );
19 | echo '
';
20 | echo ' ';
21 | }
22 | }
23 | echo ' ';
24 |
25 | // JS needed for modal
26 | wp_enqueue_script( 'jquery' );
27 | wp_enqueue_script( 'jquery-ui-sortable' );
28 |
29 | if ( !is_admin() ) {
30 | // Will need custom styling!
31 | // @todo add styles for front-end
32 | require_once( ABSPATH . 'wp-admin/includes/template.php' );
33 | }
34 |
35 | ?>
36 |
72 | args['_name'] . '[]" id="' . $field->args['_id'] . '"';
19 | foreach ( $field->args['attributes'] as $attribute => $value ) {
20 | $select_multiple .= " $attribute=\"$value\"";
21 | }
22 | $select_multiple .= ' />';
23 |
24 | foreach ( $field->options() as $value => $name ) {
25 | $selected = ( $escaped_value && in_array( $value, $escaped_value ) ) ? 'selected="selected"' : '';
26 | $select_multiple .= '' . esc_html( $name ) . ' ';
27 | }
28 |
29 | $select_multiple .= '';
30 | $select_multiple .= $field_type_object->_desc( true );
31 |
32 | echo $select_multiple; // WPCS: XSS ok.
33 | }
34 | add_action( 'cmb2_render_select_multiple', 'cmb2_render_select_multiple_field_type', 10, 5 );
35 |
36 |
37 | /**
38 | * Sanitize the selected value.
39 | */
40 | function cmb2_sanitize_select_multiple_callback( $override_value, $value ) {
41 | if ( is_array( $value ) ) {
42 | foreach ( $value as $key => $saved_value ) {
43 | $value[$key] = sanitize_text_field( $saved_value );
44 | }
45 |
46 | return $value;
47 | }
48 |
49 | return;
50 | }
51 | add_filter( 'cmb2_sanitize_select_multiple', 'cmb2_sanitize_select_multiple_callback', 10, 2 );
52 |
53 |
--------------------------------------------------------------------------------
/custom-field-types/star-rating-field-type/css/star-rating-field-type.css:
--------------------------------------------------------------------------------
1 | @charset "UTF-8";
2 | #cmb2-star-rating-metabox .star-cb-group {
3 | /* remove inline-block whitespace */
4 | font-size: 0;
5 | /* flip the order so we can use the + and ~ combinators */
6 | unicode-bidi: bidi-override;
7 | direction: rtl;
8 | /* the hidden clearer */
9 | }
10 | #cmb2-star-rating-metabox .star-cb-group * {
11 | font-size: 1rem;
12 | }
13 | #cmb2-star-rating-metabox .star-cb-group > input {
14 | display: none;
15 | }
16 | #cmb2-star-rating-metabox .star-cb-group > input + label {
17 | /* only enough room for the star */
18 | display: inline-block;
19 | overflow: hidden;
20 | text-indent: 9999px;
21 | width: 1.75em;
22 | white-space: nowrap;
23 | cursor: pointer;
24 | }
25 | #cmb2-star-rating-metabox .star-cb-group > input + label:before {
26 | display: inline-block;
27 | text-indent: -9999px;
28 | content: "\f154";
29 | font-family: 'dashicons';
30 | color: #888;
31 | font-size: 1.75em;
32 | }
33 | #cmb2-star-rating-metabox .star-cb-group > input:checked ~ label:before,
34 | #cmb2-star-rating-metabox .star-cb-group > input + label:hover ~ label:before,
35 | #cmb2-star-rating-metabox .star-cb-group > input + label:hover:before {
36 | content: "\f155";
37 | font-family: 'dashicons';
38 | color: #FFC926;
39 | text-shadow: 0 0 1px #333;
40 | font-size: 1.75em;
41 | }
42 | #cmb2-star-rating-metabox .star-cb-group > .star-cb-clear + label {
43 | text-indent: -9999px;
44 | width: .5em;
45 | margin-left: -.5em;
46 | }
47 | #cmb2-star-rating-metabox .star-cb-group > .star-cb-clear + label:before {
48 | width: .5em;
49 | }
50 | #cmb2-star-rating-metabox .star-cb-group:hover > input + label:before {
51 | content: "\f154";
52 | font-family: 'dashicons';
53 | color: #888;
54 | text-shadow: none;
55 | font-size: 1.75em;
56 | }
57 | #cmb2-star-rating-metabox .star-cb-group:hover > input + label:hover ~ label:before,
58 | #cmb2-star-rating-metabox .star-cb-group:hover > input + label:hover:before {
59 | content: "\f155";
60 | font-family: 'dashicons';
61 | color: #FFC926;
62 | text-shadow: 0 0 1px #333;
63 | font-size: 1.75em;
64 | }
65 | #cmb2-star-rating-metabox fieldset {
66 | border: 0;
67 | background: transparent;
68 | border-radius: 1px;
69 | }
--------------------------------------------------------------------------------
/custom-field-types/star-rating-field-type/star-rating-field-type.php:
--------------------------------------------------------------------------------
1 | ';
34 | $x = 1;
35 | $total = 5;
36 | while( $x <= $rating ) {
37 | $stars_container .= ' ';
38 | $x++;
39 | }
40 | if( $rating < $total ) {
41 | while( $rating < $total ) {
42 | $stars_container .= ' ';
43 | $rating++;
44 | }
45 | }
46 | $stars_container .= '';
47 | wp_enqueue_style( 'dashicons' );
48 | return $stars_container;
49 | }
50 |
51 | /**
52 | * Render 'star rating' custom field type
53 | *
54 | * @since 0.1.0
55 | *
56 | * @param array $field The passed in `CMB2_Field` object
57 | * @param mixed $value The value of this field escaped.
58 | * It defaults to `sanitize_text_field`.
59 | * If you need the unescaped value, you can access it
60 | * via `$field->value()`
61 | * @param int $object_id The ID of the current object
62 | * @param string $object_type The type of object you are working with.
63 | * Most commonly, `post` (this applies to all post-types),
64 | * but could also be `comment`, `user` or `options-page`.
65 | * @param object $field_type_object The `CMB2_Types` object
66 | */
67 | function eh_cmb2_render_star_rating_field_callback( $field, $value, $object_id, $object_type, $field_type_object ) {
68 | // enqueue styles
69 | wp_enqueue_style( 'star-rating-metabox-css', plugin_dir_url(__FILE__) . '/css/star-rating-field-type.css', array( 'cmb2-styles' ), 'all', false );
70 | ?>
71 |
87 | _desc( true );
89 |
90 | }
91 | add_filter( 'cmb2_render_star_rating', 'eh_cmb2_render_star_rating_field_callback', 10, 5 );
--------------------------------------------------------------------------------
/custom-field-types/taxonomy-radio-with-image-field-type/DJ_Taxonomy_Radio_Hierarchical_With_Image.php:
--------------------------------------------------------------------------------
1 | term_id ) ) {
20 | return '';
21 | }
22 |
23 | $this->parent = $parent_term->term_id;
24 |
25 | $terms = $this->get_terms();
26 | $options = '';
27 |
28 | if ( ! empty( $terms ) && is_array( $terms ) ) {
29 | // DJ - BEGIN
30 | $options = '';
31 | $options .= $this->loop_terms( $terms, $saved );
32 | $options .= ' ';
33 | // DJ - END
34 | }
35 |
36 | return $options;
37 | }
38 |
39 | protected function list_term_input( $term, $saved_term ) {
40 | $this->term = $term;
41 | $this->saved_term = $saved_term;
42 | return parent::list_term_input( $term, $saved_term );
43 | }
44 |
45 | public function list_input( $args = array(), $i ) {
46 | if ( empty( $this->term ) ) {
47 | return parent::list_input( $args, $i );
48 | }
49 |
50 | $a = $this->parse_args( 'list_input', array(
51 | 'type' => 'radio',
52 | 'class' => 'cmb2-option',
53 | 'name' => $this->_name(),
54 | 'id' => $this->_id( $i ),
55 | 'value' => $this->field->escaped_value(),
56 | 'label' => '',
57 | ), $args );
58 |
59 | $taxonomy = $this->field->args( 'taxonomy' );
60 | $image = '';
61 | $is_parent = '';
62 |
63 | $image_url = isset( $this->term->term_id ) ? get_term_meta( $this->term->term_id, 'yourprefix_category_avatar', true ) : '';
64 |
65 | if ( ! empty( $image_url ) && $this->term->parent == 0 ) {
66 | $image = ' ';
67 | } else {
68 | $image = '';
69 | }
70 |
71 | $atts = $this->concat_attrs( $a, array( 'label' ) );
72 | if ( isset( $this->term->term_id ) && get_term_children( $this->term->term_id, $taxonomy ) ) {
73 | $is_parent = 'class="parent"';
74 | return sprintf( "\t" . '%s%s ' . "\n", $is_parent, $atts, $a['id'], $image, $a['label'] );
75 | } else {
76 | return sprintf( "\t" . '%s%s ' . "\n", $is_parent, $atts, $a['id'], $image, $a['label'] );
77 | }
78 |
79 | }
80 |
81 | }
82 |
--------------------------------------------------------------------------------
/custom-field-types/taxonomy-radio-with-image-field-type/DJ_Taxonomy_Radio_With_Image_Display.php:
--------------------------------------------------------------------------------
1 | taxonomy();
31 | return $sanitize_object->_is_empty_array( $sanitized_value ) ? '' : $sanitized_value;
32 | }
33 |
34 |
35 | function cmb2_init_taxonomy_radio_with_image_field_type() {
36 | add_filter( 'cmb2_render_class_taxonomy_radio_with_image', 'dj_taxonomy_radio_with_image_field_type_class_name' );
37 | add_filter( 'cmb2_display_class_taxonomy_radio_with_image', 'dj_taxonomy_radio_with_image_field_type_display_class_name' );
38 | add_filter( 'cmb2_all_or_nothing_types', 'dj_add_taxonomy_radio_with_image' );
39 | add_filter( 'cmb2_non_repeatable_fields', 'dj_add_taxonomy_radio_with_image' );
40 |
41 | /**
42 | * The following snippet is required for allowing the taxonomy_radio_with_image field
43 | * to save to the term fields.
44 | */
45 | add_filter( 'cmb2_sanitize_taxonomy_radio_with_image', 'dj_taxonomy_radio_with_image_sanitize', 10, 5 );
46 | }
47 | add_action( 'cmb2_init', 'cmb2_init_taxonomy_radio_with_image_field_type' );
48 |
--------------------------------------------------------------------------------
/custom-field-types/textarea-with-checkbox.php:
--------------------------------------------------------------------------------
1 | '',
35 | 'status' => '',
36 | ] );
37 | $checked = false;
38 | if ( ! empty( $field_escaped_value['status'] ) ) {
39 | $checked = true;
40 | }
41 | ?>
42 |
43 | = $field_type_object->textarea( [
44 | 'name' => $field_type_object->_name( '[text]' ),
45 | 'id' => $field_type_object->_id( '_text' ),
46 | 'value' => $field_escaped_value['text'],
47 | ] ); ?>
48 |
49 |
50 |
= $field_type_object->field->args('title_checkbox'); ?>
51 | = $field_type_object->checkbox( [
52 | 'type' => 'checkbox',
53 | 'name' => $field_type_object->_name( '[status]' ),
54 | 'id' => $field_type_object->_id( '_status' ),
55 | ], $checked ); ?>
56 |
57 | _desc( true );
59 | }
60 |
61 | /**
62 | * Sanitize Field.
63 | */
64 | public static function sanitize_textarea_with_checkbox( $check, $meta_value, $object_id, $field_args, $sanitize_object ) {
65 | if ( !is_array( $meta_value ) || !( array_key_exists('repeatable', $field_args ) && $field_args['repeatable'] == TRUE ) ) {
66 | return $check;
67 | }
68 |
69 | $new_values = array();
70 | foreach ( $meta_value as $key => $val ) {
71 | if( !empty( $meta_value[$key]['text'] ) ) {
72 | $new_values[$key] = array_filter( array_map( 'sanitize_text_field', $val ) );
73 | }
74 | }
75 |
76 | return array_filter( array_values( $new_values ) );
77 | }
78 |
79 | /**
80 | * Escape Field.
81 | */
82 | public static function escape_textarea_with_checkbox( $check, $meta_value, $field_args, $field_object ) {
83 | if ( !is_array( $meta_value ) || ! $field_args['repeatable'] ) {
84 | return $check;
85 | }
86 |
87 | $new_values = array();
88 | foreach ( $meta_value as $key => $val ) {
89 | if( !empty( $meta_value[$key]['text'] ) ) {
90 | $new_values[$key] = array_filter( array_map( 'esc_attr', $val ) );
91 | }
92 | }
93 |
94 | return array_filter( array_values( $new_values ) );
95 | }
96 | }
97 |
98 | $cmb2_field_textarea_with_checkbox = new CMB2_Field_Textarea_With_Checkbox();
99 | }
100 |
--------------------------------------------------------------------------------
/custom-field-types/year-range-field-type.php:
--------------------------------------------------------------------------------
1 | 'demo_metabox',
14 | * 'title' => __( 'Test Metabox', 'cmb2' ),
15 | * 'object_types' => array( 'page', ),
16 | * ) );
17 | *
18 | * $cmb_demo->add_field( array(
19 | * 'name' => __( 'Date Year Range', 'cmb2' ),
20 | * 'desc' => __( 'field description (optional)', 'cmb2' ),
21 | * 'id' => 'yourprefix_demo_date_year_range',
22 | * 'type' => 'date_year_range',
23 | * // Optionally set default values.
24 | * 'options' => array(
25 | * 'earliest' => 1930, // Set the earliest year that should be shown.
26 | * // 'start_reverse_sort' => true,
27 | * // 'finish_reverse_sort' => false,
28 | * ),
29 | * 'default' => array(
30 | * 'start' => 1930,
31 | * 'finish' => 'current',
32 | * ),
33 | * // 'text' => array(
34 | * // 'start_label' => 'Start', // Optionally change start text.
35 | * // 'finish_label' => 'Finish', // Optionally change finish text.
36 | * // 'separator' => ' to ', // Optionally change separator string/text.
37 | * // ),
38 | * // 'split_values' => true, // Split values to sep. meta fields.
39 | * ) );
40 | *
41 | * }
42 | * add_action( 'cmb2_init', 'yourprefix_register_demo_metabox' );
43 | */
44 |
45 |
46 | /**
47 | * Render 'date_year_range' custom field type
48 | *
49 | * @since 0.1.0
50 | *
51 | * @param array $field The passed in `CMB2_Field` object
52 | * @param mixed $value The value of this field escaped.
53 | * It defaults to `sanitize_text_field`.
54 | * If you need the unescaped value, you can access it
55 | * via `$field->value()`
56 | * @param int $object_id The ID of the current object
57 | * @param string $object_type The type of object you are working with.
58 | * Most commonly, `post` (this applies to all post-types),
59 | * but could also be `comment`, `user` or `options-page`.
60 | * @param object $type_object The `CMB2_Types` object
61 | */
62 | function jt_cmb2_date_year_range( $field, $value, $object_id, $object_type, $type_object ) {
63 | $earliest = $field->options( 'earliest' );
64 | $earliest = $earliest ? absint( $earliest ) : 1900;
65 |
66 | $start_reverse_sort = $field->options( 'start_reverse_sort' );
67 | $start_reverse_sort = $start_reverse_sort ? true : false;
68 |
69 | $finish_reverse_sort = $field->options( 'finish_reverse_sort' );
70 | $finish_reverse_sort = $finish_reverse_sort ? true : false;
71 |
72 | $value = wp_parse_args( $value, array(
73 | 'start' => '',
74 | 'finish' => '',
75 | ) );
76 |
77 | $desc = $field->args( 'description' );
78 | $field->args['description'] = '';
79 | $type_object->type = new CMB2_Type_Select( $type_object );
80 |
81 | echo ''. $type_object->_text( 'start_label', 'Starting Year' ) . ' ';
82 |
83 | $start_options = jt_cmb2_date_year_range_options( $type_object, $earliest, $value['start'], $start_reverse_sort );
84 | echo $type_object->select( array(
85 | 'name' => $type_object->_name( '[start]' ),
86 | 'id' => $type_object->_id( '_start' ),
87 | 'value' => $value['start'],
88 | 'class' => 'cmb2_select cmb2-year-range-start',
89 | 'options' => $start_options,
90 | 'desc' => '',
91 | ) );
92 |
93 | echo $type_object->_text( 'separator', ' — ' );
94 |
95 | $end_options = jt_cmb2_date_year_range_options( $type_object, $earliest, $value['finish'], $finish_reverse_sort );
96 | echo $type_object->select( array(
97 | 'name' => $type_object->_name( '[finish]' ),
98 | 'id' => $type_object->_id( '_finish' ),
99 | 'value' => $value['finish'],
100 | 'class' => 'cmb2_select cmb2-year-range-end',
101 | 'options' => $end_options,
102 | 'desc' => '',
103 | ) );
104 | echo ' '. $type_object->_text( 'finish_label', 'Final Year' ) . ' ';
105 |
106 | $field->args['description'] = $desc;
107 |
108 | $type_object->_desc( true, true );
109 |
110 | add_action( is_admin() ? 'admin_footer' : 'wp_footer', 'jt_cmb2_date_year_range_js' );
111 |
112 | }
113 | add_filter( 'cmb2_render_date_year_range', 'jt_cmb2_date_year_range', 10, 5 );
114 |
115 | function jt_cmb2_date_year_range_js() {
116 | static $done = false;
117 | if ( ! $done ) {
118 | $done = true;
119 | }
120 | ?>
121 |
170 | '',
178 | 'label' => __( 'Not Set' ),
179 | );
180 |
181 | if ( cmb2_utils()->isempty( $value ) ) {
182 | $not_set['checked'] = 'checked';
183 | }
184 |
185 | for ( $i = $earliest; $i <= date( 'Y' ); $i++ ) {
186 |
187 | $a = array( 'value' => $i, 'label' => $i );
188 | if ( absint( $value ) === $i ) {
189 | $a['checked'] = 'checked';
190 | }
191 |
192 | $options[] = $a;
193 | }
194 |
195 | $a = array(
196 | 'value' => 'current',
197 | 'label' => __( 'Current' ),
198 | );
199 |
200 | if ( 'current' === $value ) {
201 | $a['checked'] = 'checked';
202 | }
203 |
204 | $options[] = $a;
205 |
206 | if ( $reverse ) {
207 | $options = array_reverse( $options );
208 | }
209 |
210 | array_unshift( $options, $not_set );
211 |
212 | return implode( "\n", array_map( array( $type_object, 'select_option' ), $options ) );
213 | }
214 |
215 | /**
216 | * Optionally save the values into separate fields.
217 | */
218 | function jt_cmb2_date_year_range_split_values( $override_value, $value, $object_id, $field_args ) {
219 | if ( ! isset( $field_args['split_values'] ) || ! $field_args['split_values'] ) {
220 | // Don't do the override
221 | return $override_value;
222 | }
223 |
224 | $keys = array( 'start', 'finish' );
225 |
226 | foreach ( $keys as $key ) {
227 | if ( ! empty( $value[ $key ] ) ) {
228 | update_post_meta( $object_id, $field_args['id'] . '_'. $key, $value[ $key ] );
229 | }
230 | }
231 |
232 | // Tell CMB2 we already did the update
233 | return true;
234 | }
235 | add_filter( 'cmb2_sanitize_date_year_range', 'jt_cmb2_date_year_range_split_values', 12, 4 );
236 |
237 | /**
238 | * Optionally fetch the values from separate fields as well.
239 | */
240 | function jt_cmb2_date_year_range_get_split_values( $no_override, $object_id, $args, $field ) {
241 | if ( 'date_year_range' !== $field->args( 'type' ) || ! $field->args( 'split_values' ) ) {
242 | return $no_override;
243 | }
244 |
245 | $value = array(
246 | 'start' => get_post_meta( $object_id, $args['field_id'] . '_start', 1 ),
247 | 'finish' => get_post_meta( $object_id, $args['field_id'] . '_finish', 1 ),
248 | );
249 |
250 | return $value;
251 | }
252 | add_filter( 'cmb2_override_meta_value', 'jt_cmb2_date_year_range_get_split_values', 10, 4 );
253 |
254 | /**
255 | * The following snippets are required for allowing the date_year_range field
256 | * to work as a repeatable field, or in a repeatable group
257 | */
258 |
259 | function jt_cmb2_sanitize_date_year_range( $check, $meta_value, $object_id, $field_args, $sanitizer ) {
260 |
261 | // if not repeatable, bail out.
262 | if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
263 | return $check;
264 | }
265 |
266 | foreach ( $meta_value as $key => $val ) {
267 | $meta_value[ $key ] = array_filter( array_map( 'sanitize_text_field', $val ) );
268 | }
269 |
270 | return array_filter( $meta_value );
271 | }
272 | add_filter( 'cmb2_sanitize_date_year_range', 'jt_cmb2_sanitize_date_year_range', 10, 5 );
273 |
274 | function jt_cmb2_esc_date_year_range( $check, $meta_value, $field_args, $field_object ) {
275 |
276 | // if not repeatable, bail out.
277 | if ( ! is_array( $meta_value ) || ! $field_args['repeatable'] ) {
278 | return $check;
279 | }
280 |
281 | foreach ( $meta_value as $key => $val ) {
282 | $meta_value[ $key ] = array_filter( array_map( 'esc_attr', $val ) );
283 | }
284 |
285 | return array_filter( $meta_value );
286 | }
287 | add_filter( 'cmb2_types_esc_date_year_range', 'jt_cmb2_esc_date_year_range', 10, 4 );
288 |
--------------------------------------------------------------------------------
/filters-and-actions/README.md:
--------------------------------------------------------------------------------
1 | CMB2 Filters and Actions
2 | ==========
3 |
4 | CMB2 has many filters and actions. Included here are snippets which demonstrate some handy ways to use those hooks.
--------------------------------------------------------------------------------
/filters-and-actions/cmb2-add-fields-dynamically.php:
--------------------------------------------------------------------------------
1 | 'dynamic_fields_box',
11 | 'title' => 'Some test metaboxes',
12 | 'object_types' => array( 'page', 'post' ),
13 | ) );
14 |
15 | $cmb->add_field( array(
16 | 'name' => 'Set number of next item',
17 | 'id' => 'number_of_next_item',
18 | 'type' => 'text',
19 | 'default' => '1',
20 | 'attributes' => array(
21 | 'type' => 'number',
22 | 'pattern' => '\d*',
23 | ),
24 | 'sanitization_cb' => 'absint',
25 | 'escape_cb' => 'absint',
26 | ) );
27 |
28 | // Add dynamic fields during normal view.
29 | add_action( 'cmb2_init_hookup_dynamic_fields_box', 'add_fields_dynamically_to_box' );
30 |
31 | // Add dynamic fields during save process.
32 | add_action( 'cmb2_post_process_fields_dynamic_fields_box', 'add_fields_dynamically_to_box' );
33 | }
34 |
35 | function add_fields_dynamically_to_box( $cmb ) {
36 | if ( $cmb->object_id() ) {
37 | $position = 2;
38 |
39 | // Loop through however many items are selected in previous field
40 | $number_of_items = get_post_meta( $cmb->object_id(), 'number_of_next_item', true );
41 | $number = 1;
42 | while ( $number <= $number_of_items ) {
43 |
44 | $cmb->add_field( array(
45 | 'name' => 'Item #' . $number,
46 | 'desc' => 'item_' . $number,
47 | 'id' => 'item_' . $number,
48 | 'type' => 'text',
49 | ), $position++ );
50 |
51 | $number++;
52 | }
53 | }
54 | }
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_all_or_nothing_types-filter.php:
--------------------------------------------------------------------------------
1 | ';
17 | echo 'Welcome to my metabox! ';
18 |
19 | add_action( 'cmb2_after_form', 'yourprefix_add_html_after_cmb2_output', 10, 4 );
20 | }
21 | add_action( 'cmb2_before_form', 'yourprefix_add_html_before_cmb2_output', 10, 4 );
22 |
23 | function yourprefix_add_html_after_cmb2_output( $cmb_id, $object_id, $object_type, $cmb ) {
24 | echo '';
25 | }
26 |
27 |
28 | // This can be done a bit more simply this way:
29 |
30 | function add_html_before_yourprefix_demo_metabox_output( $cmb_id, $object_id, $object_type, $cmb ) {
31 | echo '';
32 | echo '
Welcome to my metabox! ';
33 |
34 | add_action( "cmb2_after_{$object_type}_form_{$cmb_id}", 'add_html_after_yourprefix_demo_metabox_output', 10, 4 );
35 | }
36 | // Only output above the _yourprefix_demo_metabox metabox.
37 | add_action( 'cmb2_before_post_form__yourprefix_demo_metabox', 'add_html_before_yourprefix_demo_metabox_output', 10, 4 );
38 |
39 | function add_html_after_yourprefix_demo_metabox_output( $cmb_id, $object_id, $object_type, $cmb ) {
40 | echo '';
41 | }
42 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_$cmb_id-add-fields.php:
--------------------------------------------------------------------------------
1 | add_field(
9 | array(
10 | 'name' => __( 'New at the top', 'your_textdomain' ),
11 | 'desc' => __( 'Using the "cmb2_init_{$cmb_id}" hook', 'your_textdomain' ),
12 | 'id' => '_new_at_the_top',
13 | 'type' => 'text',
14 | ),
15 | 1
16 | );
17 |
18 | }
19 | add_action( 'cmb2_init__yourprefix_demo_metabox', 'yourprefix_add_new_field_to_top_of_demo_metabox' );
20 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_$cmb_id-modify-object-types.php:
--------------------------------------------------------------------------------
1 | box_types();
14 |
15 | $types[] = 'books'; // Your custom post type slug.
16 |
17 | // Bam.
18 | $cmb->set_prop( 'object_types', $types );
19 | }
20 | add_action( 'cmb2_init_yourprefix_demo_metabox', 'yourprefix_demo_metabox_modify_object_types' );
21 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_$cmb_id-remove-field.php:
--------------------------------------------------------------------------------
1 | remove_field( '_yourprefix_demo_textsmall' );
8 | }
9 | add_action( 'cmb2_init__yourprefix_demo_metabox', 'yourprefix_remove_field_from_demo_metabox' );
10 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_$cmb_id-replace-field.php:
--------------------------------------------------------------------------------
1 | remove_field( '_yourprefix_demo_textsmall' );
14 |
15 | $cmb->add_field(
16 | array(
17 | 'name' => __( 'REPLACED Text Small Field', 'cmb2' ),
18 | 'desc' => __( 'Using the "cmb2_init_{$cmb_id}" hook', 'your_textdomain' ),
19 | 'id' => '_yourprefix_demo_textsmall',
20 | 'type' => 'text_money',
21 | ),
22 | 17 /* This needs to be the nth position of the original field */
23 | );
24 | }
25 |
26 | }
27 | add_action( 'cmb2_init_hookup__yourprefix_demo_metaboxx', 'yourprefix_replace_field_in_demo_metaboxx', 999 );
28 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_before_hookup-add-fields.php:
--------------------------------------------------------------------------------
1 | update_field_property( '_yourprefix_demo_text2', 'type', 'text' );
15 |
16 | /**
17 | * Since '_yourprefix_demo_text2' doesn't exist, Let's create it.
18 | * Always need to compare this value strictly to false, as a field_id COULD be 0 or ''
19 | */
20 | if ( false === $field_id ) {
21 | $cmb->add_field(
22 | // Normal field setup
23 | array(
24 | 'name' => __( 'Test Text 2', 'your_textdomain' ),
25 | 'desc' => __( 'Test Text 2 description', 'your_textdomain' ),
26 | 'id' => '_yourprefix_demo_text2',
27 | 'type' => 'text',
28 | 'attributes' => array( 'placeholder' => __( "I'm some placeholder text", 'your_textdomain' ) ),
29 | ),
30 | 3 // Insert this field in the third position
31 | );
32 |
33 | }
34 |
35 | }
36 | add_action( 'cmb2_init_before_hookup', 'yourprefix_add_new_field_in_3rd_position' );
37 |
38 | function yourprefix_add_new_field_to_group() {
39 | // Try to get a metabox w/ the id of '_yourprefix_group_metabox'
40 | if ( $cmb_group_demo = cmb2_get_metabox( '_yourprefix_group_metabox' ) ) {
41 |
42 | $cmb_group_demo->add_group_field(
43 | array(
44 | 'name' => __( 'Test Text 2', 'your_textdomain' ),
45 | 'desc' => __( 'field description (optional)', 'your_textdomain' ),
46 | 'id' => 'text2',
47 | 'type' => 'text',
48 | 'attributes' => array( 'placeholder' => __( "I'm some placeholder text", 'your_textdomain' ) ),
49 | ),
50 | '_yourprefix_group_demo', // Add this to the _yourprefix_group_demo group field
51 | 2 // And insert it into the 2nd position
52 | );
53 |
54 | }
55 | }
56 | add_action( 'cmb2_init_before_hookup', 'yourprefix_add_new_field_to_group' );
57 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_init_before_hookup-remove-cmb2-metabox.php:
--------------------------------------------------------------------------------
1 | update_field_property( '_yourprefix_demo_text', 'show_on_cb', false );
18 |
19 | /**
20 | * Always need to compare this value strictly to false, as a field_id COULD be 0 or ''
21 | */
22 | if ( false !== $field_id ) {
23 |
24 | /**
25 | * Because we don't want to 'stomp' a field's 'attributes' property
26 | * (It may already have some attributes), we're going to get
27 | * the field's attributes property and append to it.
28 | */
29 |
30 | // Get all fields for this metabox
31 | $fields = $cmb->prop( 'fields' );
32 |
33 | // Get the attributes array if it exists, or else create it
34 | $attributes = isset( $fields['_yourprefix_demo_text']['attributes'] )
35 | ? $fields['_yourprefix_demo_text']['attributes']
36 | : array();
37 |
38 | // Add placeholder text
39 | $attributes['placeholder'] = __( "I'm some placeholder text", 'your_textdomain' );
40 |
41 | // Update the field's 'attributes' property
42 | $cmb->update_field_property( '_yourprefix_demo_text', 'attributes', $attributes );
43 |
44 | }
45 |
46 | }
47 | add_action( 'cmb2_init_before_hookup', 'yourprefix_update_fields_properties' );
48 |
--------------------------------------------------------------------------------
/filters-and-actions/cmb2_override_{$field_id}_meta_value-filter.php:
--------------------------------------------------------------------------------
1 | get( $args['field_id'] )
43 | : get_metadata( $args['type'], $args['id'], $args['field_id'], ( $args['single'] || $args['repeat'] ) );
44 |
45 | // Get the default values from JSON
46 | if ( null === $defaults ) {
47 | // Get your JSON blob.. hard-coded for demo.
48 | $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."}]';
49 |
50 | $defaults = json_decode( $json, 1 );
51 | }
52 |
53 | // Set our group field value to the default.
54 | $value = $defaults;
55 |
56 | // If the group field's retrieved value is not empty...
57 | if ( ! empty( $data ) ) {
58 | $value = array();
59 | // Then loop the defaults and mash the field's value up w/ the default.
60 | foreach ( $defaults as $key => $default_group_val ) {
61 | $value[ $key ] = isset( $data[ $key ] )
62 | ? wp_parse_args( $data[ $key ], $default_group_val )
63 | : $default_group_val;
64 | }
65 | }
66 |
67 | return $value;
68 | }
69 |
70 | add_filter( 'cmb2_override_yourprefix_group_demo_meta_value', 'yourprefix_get_default_group_value_from_json', 10, 4 );
71 |
--------------------------------------------------------------------------------
/filters-and-actions/custom-css-for-specific-metabox.php:
--------------------------------------------------------------------------------
1 | 'custom_css_test',
12 | 'title' => __( 'Custom CSS Test', 'cmb2' ),
13 | 'object_types' => array( 'page', ),
14 | ) );
15 |
16 | $cmb->add_field( array(
17 | 'id' => '_cmb2_test_text',
18 | 'type' => 'text',
19 | ) );
20 | }
21 | add_action( 'cmb2_admin_init', 'js_custom_css_for_metabox' );
22 |
23 | function js_add_custom_css_for_metabox( $post_id, $cmb ) {
24 | ?>
25 |
30 | 'Hey, this is your first entry',
20 | 'description' => 'Go ahead and delete this entry, or update its contents',
21 | ),
22 | // Default group 2.
23 | array(
24 | 'title' => 'Hey, this is your 2nd entry',
25 | 'description' => '#2',
26 | ),
27 | ) );
28 | }
29 |
30 | $cmb_group = new_cmb2_box( array(
31 | 'id' => 'yourprefix_group_alt_data_metabox',
32 | 'title' => __( 'Repeating Field Group', 'cmb2' ),
33 | 'object_types' => array( 'post', ),
34 | 'show_on' => array( 'id' => array( 1000, ) ),
35 | 'show_in_rest' => WP_REST_Server::ALLMETHODS,
36 | ) );
37 |
38 | // $group_field_id is the field id string, so in this case: '_yourprefix_group_demo'
39 | $group_field_id = $cmb_group->add_field( array(
40 | 'id' => 'yourprefix_group_alt_data_demo',
41 | 'type' => 'group',
42 | 'options' => array(
43 | 'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
44 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
45 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
46 | 'sortable' => true, // beta
47 | ),
48 | ) );
49 |
50 | /**
51 | * Group fields works the same, except ids only need
52 | * to be unique to the group. Prefix is not needed.
53 | *
54 | * The parent field's id needs to be passed as the second argument.
55 | */
56 | $cmb_group->add_group_field( $group_field_id, array(
57 | 'name' => 'Entry Title',
58 | 'id' => 'title',
59 | 'type' => 'text',
60 | ) );
61 |
62 | $cmb_group->add_group_field( $group_field_id, array(
63 | 'name' => 'Description',
64 | 'description' => 'Write a short description for this entry',
65 | 'id' => 'description',
66 | 'type' => 'wysiwyg',
67 | 'options' => array(
68 | 'textarea_rows' => 3,
69 | ),
70 | ) );
71 | };
72 |
73 | add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_value', 'yourprefix_group_alt_data_demo_override_meta_value', 10, 4 );
74 | function yourprefix_group_alt_data_demo_override_meta_value( $data, $object_id, $args, $field ) {
75 |
76 | // Here, we're pulling from the options table, but you can query from any data source here.
77 | // If from a custom table, you can use the $object_id to query against.
78 | return get_option( 'yourprefix_group_alt_data_demo', array() );
79 | }
80 |
81 | add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_save', 'yourprefix_group_alt_data_demo_override_meta_save', 10, 4 );
82 | function yourprefix_group_alt_data_demo_override_meta_save( $override, $args, $field_args, $field ) {
83 |
84 | // Here, we're storing the data to the options table, but you can store to any data source here.
85 | // If to a custom table, you can use the $args['id'] as the reference id.
86 | $updated = update_option( 'yourprefix_group_alt_data_demo', $args['value'] );
87 | return !! $updated;
88 | }
89 |
90 | add_filter( 'cmb2_override_yourprefix_group_alt_data_demo_meta_remove', 'yourprefix_group_alt_data_demo_override_meta_remove', 10, 4 );
91 | function yourprefix_group_alt_data_demo_override_meta_remove( $override, $args, $field_args, $field ) {
92 |
93 | // Here, we're removing from the options table, but you can query to remove from any data source here.
94 | // If from a custom table, you can use the $args['id'] to query against.
95 | // (If we do "delete_option", then our default value will be re-applied, which isn't desired.)
96 | $updated = update_option( 'yourprefix_group_alt_data_demo', array() );
97 | return !! $updated;
98 | }
99 |
--------------------------------------------------------------------------------
/filters-and-actions/save-default-group-field-value-based-on-other-field.php:
--------------------------------------------------------------------------------
1 | 'yourprefix_group_metabox',
14 | 'title' => __( 'Repeating Field Group', 'cmb2' ),
15 | 'object_types' => array( 'page', ),
16 | ) );
17 |
18 | $cmb->add_field( $group_field_id, array(
19 | 'name' => __( 'Radio', 'cmb2' ),
20 | 'id' => 'yourprefix_group_radio',
21 | 'type' => 'radio',
22 | 'options' => array(
23 | 'standard' => __( 'Option One', 'cmb2' ),
24 | 'custom' => __( 'Option Two', 'cmb2' ),
25 | 'none' => __( 'Option Three', 'cmb2' ),
26 | ),
27 | ) );
28 |
29 | $group_field_id = $cmb->add_field( array(
30 | 'id' => 'yourprefix_group_demo',
31 | 'type' => 'group',
32 | 'description' => __( 'Generates reusable form entries', 'cmb2' ),
33 | 'options' => array(
34 | 'group_title' => __( 'Entry {#}', 'cmb2' ),
35 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
36 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
37 | 'sortable' => true,
38 | ),
39 | ) );
40 |
41 | $cmb->add_group_field( $group_field_id, array(
42 | 'name' => 'Entry Title',
43 | 'id' => 'title',
44 | 'type' => 'text',
45 | ) );
46 |
47 | $cmb->add_group_field( $group_field_id, array(
48 | 'name' => 'Description',
49 | 'description' => 'Write a short description for this entry',
50 | 'id' => 'description',
51 | 'type' => 'textarea_small',
52 | ) );
53 |
54 | }
55 | add_action( 'cmb2_init', 'yourprefix_register_repeatable_group_field_metabox' );
56 |
57 |
58 | // If the radio field is set to 'standard', then update the group field value to have one group filled-in.
59 | function hook_in_and_add_default_group_value( $post_id, $updated, $cmb ) {
60 | // If 'my_meta_key' was updated, then proceed w/ my stuff.
61 | if ( in_array( 'yourprefix_group_radio', $updated ) ) {
62 | if ( 'standard' === get_post_meta( $post_id, 'yourprefix_group_radio', 1 ) ) {
63 | // do stuff
64 | update_post_meta( $post_id, 'yourprefix_group_demo', array(
65 | array(
66 | 'title' => 'Title of group 1',
67 | 'description' => 'Description of group 1',
68 | )
69 | ) );
70 | }
71 | }
72 | }
73 | add_action( 'cmb2_save_post_fields_yourprefix_group_metabox', 'hook_in_and_add_default_group_value', 10, 3 );
74 |
--------------------------------------------------------------------------------
/front-end/README.md:
--------------------------------------------------------------------------------
1 | Front-end
2 | ==========
3 |
4 | Snippets that use CMB2 on the front-end (not wp-admin) side of your site.
--------------------------------------------------------------------------------
/front-end/cmb2-front-end-editor.php:
--------------------------------------------------------------------------------
1 | You do not have permission to edit this post.';
12 | }
13 | }
14 |
15 | return $content;
16 | }
17 | add_filter( 'the_content', 'jt_add_edit_form_to_frontend' );
18 |
19 | /**
20 | * Modify the edit links to point to the front-end editor.
21 | */
22 | function jt_modify_edit_link( $link ) {
23 | if ( ! is_admin() ) {
24 | $link = esc_url_raw( wp_nonce_url( remove_query_arg( 'edit' ), 'edit', 'edit' ) );
25 | }
26 | return $link;
27 | }
28 | add_filter( 'get_edit_post_link', 'jt_modify_edit_link' );
29 |
30 | /**
31 | * Hook in later and prepend our title/content fields to our existing metabox
32 | */
33 | function jt_edit_core_fields() {
34 | if ( ! is_admin() ) { // only if on front-end
35 |
36 | // Get existing metabox
37 | $cmb = cmb2_get_metabox( '_yourprefix_demo_metabox' );
38 |
39 | // and prepend title
40 | $cmb->add_field( array(
41 | 'name' => __( 'Title', 'cmb2' ),
42 | 'id' => 'post_title',
43 | 'type' => 'text',
44 | 'before' => 'jt_edit_core_maybe_redirect',
45 | ), 1 );
46 |
47 | // and content fields
48 | $cmb->add_field( array(
49 | 'name' => __( 'Content', 'cmb2' ),
50 | 'id' => 'post_content',
51 | 'type' => 'wysiwyg',
52 | ), 2 );
53 | }
54 | }
55 | add_action( 'cmb2_init', 'jt_edit_core_fields', 99 );
56 |
57 | /**
58 | * If edit was saved, redirect to non-edit page
59 | */
60 | function jt_edit_core_maybe_redirect() {
61 | if ( isset( $_POST['post_content'] ) ) {
62 | $url = esc_url_raw( remove_query_arg( 'edit' ) );
63 | echo "";
64 | }
65 | }
66 |
67 | /**
68 | * We don't want CMB2 to fetch data from meta for post title and post content
69 | */
70 | function jt_cmb2_override_core_field_get( $val, $object_id, $a, $field ) {
71 | global $post;
72 |
73 | if ( in_array( $field->id(), array( 'post_title', 'post_content' ), true ) ) {
74 | if ( isset( $post->ID ) ) {
75 | $val = get_post_field( $field->id(), $post );
76 | } else {
77 | $val = '';
78 | }
79 | }
80 |
81 | return $val;
82 | }
83 | add_filter( 'cmb2_override_meta_value', 'jt_cmb2_override_core_field_get', 10, 4 );
84 |
85 | /**
86 | * We don't want CMB2 to save data to meta for post title and post content
87 | */
88 | function jt_cmb2_override_core_field_set( $status, $a, $args, $field ) {
89 | global $post;
90 |
91 | if ( in_array( $field->id(), array( 'post_title', 'post_content' ), true ) ) {
92 | if ( isset( $post->ID ) ) {
93 | $status = wp_update_post( array(
94 | $field->id() => $a['value'],
95 | 'ID' => $post->ID,
96 | ) );
97 |
98 | } else {
99 | $status = false;
100 | }
101 | }
102 |
103 | return $status;
104 | }
105 | add_filter( 'cmb2_override_meta_save', 'jt_cmb2_override_core_field_set', 10, 4 );
106 |
--------------------------------------------------------------------------------
/front-end/cmb2-front-end-wordpress-media-uploader.php:
--------------------------------------------------------------------------------
1 | add_cap( 'upload_files' );
30 |
31 | }
32 |
33 | add_action( 'init', 'nevestam_allow_contributor_uploads' );
34 |
35 | /**
36 | * Display only user-uploaded files to each user
37 | *
38 | * @param WP_Query $wp_query_obj
39 | */
40 | function nevestam_restrict_media_library( $wp_query_obj ) {
41 | global $current_user, $pagenow;
42 |
43 | if ( ! is_a( $current_user, 'WP_User' ) ) {
44 | return;
45 | }
46 |
47 | if ( 'admin-ajax.php' != $pagenow || 'query-attachments' != $_REQUEST['action'] ) {
48 | return;
49 | }
50 |
51 | if ( ! current_user_can( 'manage_media_library' ) ) {
52 | $wp_query_obj->set( 'author', $current_user->ID );
53 | }
54 | }
55 |
56 | add_action( 'pre_get_posts', 'nevestam_restrict_media_library' );
57 |
--------------------------------------------------------------------------------
/front-end/cmb2-metabox-shortcode.php:
--------------------------------------------------------------------------------
1 | ID;
31 | }
32 |
33 | // If no metabox id is set, yell about it
34 | if ( empty( $atts['id'] ) ) {
35 | return 'Please add an "id" attribute to specify the CMB2 form to display.';
36 | }
37 |
38 | $metabox_id = esc_attr( $atts['id'] );
39 | $object_id = absint( $atts['post_id'] );
40 | // Get our form
41 | $form = cmb2_get_metabox_form( $metabox_id, $object_id );
42 |
43 | return $form;
44 | }
45 | add_shortcode( 'cmb-form', 'jt_cmb2_do_frontend_form_shortcode' );
46 |
--------------------------------------------------------------------------------
/front-end/output-file-list.php:
--------------------------------------------------------------------------------
1 | $attachment_url ) {
34 | $images .= '';
35 | $images .= wp_get_attachment_image( $attachment_id, $img_size );
36 | $images .= '
';
37 | }
38 |
39 | return $images ? '' . $images . '
' : '';
40 | }
41 |
--------------------------------------------------------------------------------
/helper-functions/README.md:
--------------------------------------------------------------------------------
1 | CMB2 Helper Functions
2 | ==========
3 |
4 | Snippets for working with the [included helper functions](https://github.com/WebDevStudios/CMB2/blob/master/includes/helper-functions.php).
5 |
6 | Related CMB2 issues:
7 | * [#130](https://github.com/WebDevStudios/CMB2/issues/130#issuecomment-68160722)
8 |
--------------------------------------------------------------------------------
/helper-functions/helper-functions.php:
--------------------------------------------------------------------------------
1 | autoembed( $content );
120 | $content = $wp_embed->run_shortcode( $content );
121 | $content = wpautop( $content );
122 | $content = do_shortcode( $content );
123 |
124 | return $content;
125 | }
126 |
127 | /**
128 | * Sample template tag function for outputting a cmb2 file_list.
129 | *
130 | * @link https://github.com/WebDevStudios/CMB2/wiki/Field-Types#sample-function-for-getting-and-outputting-file_list-images Wiki
131 | *
132 | * @param string $meta_key The 'file_list' field meta key.
133 | * @param string $img_size Size of image to display.
134 | */
135 | function yourprefix_cmb2_output_file_list( $meta_key, $img_size = 'medium' ) {
136 |
137 | // Get the list of files
138 | $files = get_post_meta( get_the_ID(), $meta_key, 1 );
139 |
140 | echo '';
141 | // Loop through them and output an image
142 | foreach ( (array) $files as $attachment_id => $attachment_url ) {
143 | echo '
';
144 | echo wp_get_attachment_image( $attachment_id, $img_size );
145 | echo '
';
146 | }
147 | echo '
';
148 | }
149 |
--------------------------------------------------------------------------------
/helper-functions/modify-cmb2_metabox_form-format.php:
--------------------------------------------------------------------------------
1 | '',
13 | ) );
14 |
--------------------------------------------------------------------------------
/helper-functions/modify-cmb2_metabox_form-output.php:
--------------------------------------------------------------------------------
1 | cmb_id to retrieve the metabox ID
19 | *
20 | * @return string Possibly modified form output
21 | */
22 | function myprefix_options_modify_cmb2_metabox_form_format( $form_format, $object_id, $cmb ) {
23 |
24 | if ( 'myprefix_options' == $object_id && 'option_metabox' == $cmb->cmb_id ) {
25 |
26 | $form_format = '';
27 | }
28 |
29 | return $form_format;
30 | }
31 | add_filter( 'cmb2_get_metabox_form_format', 'myprefix_options_modify_cmb2_metabox_form_format', 10, 3 );
32 |
--------------------------------------------------------------------------------
/helper-functions/modify-cmb2_metabox_form-save-button-text.php:
--------------------------------------------------------------------------------
1 | __( 'Save Settings', 'your-textdomain' ),
10 | ) );
11 |
--------------------------------------------------------------------------------
/javascript/README.md:
--------------------------------------------------------------------------------
1 | CMB2 Javascript
2 | ==========
3 |
4 | Custom javascript snippets for interacting with CMB2.
--------------------------------------------------------------------------------
/javascript/cmb2-auto-scroll-to-new-group.php:
--------------------------------------------------------------------------------
1 |
18 |
42 |
23 |
96 | 'yourprefix_group_titles_metabox',
18 | 'title' => __( 'Repeating Field Group with Updating Titles', 'cmb2' ),
19 | 'object_types' => array( 'page', ),
20 | 'show_in_rest' => 'read_and_write',
21 | ) );
22 |
23 | $group_field_id = $cmb_group->add_field( array(
24 | 'id' => 'yourprefix_group_titles_demo',
25 | 'type' => 'group',
26 | 'description' => __( 'Generates reusable form entries', 'cmb2' ),
27 | 'options' => array(
28 | 'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
29 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
30 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
31 | 'sortable' => true, // beta
32 | ),
33 | 'after_group' => 'yourprefix_add_js_for_repeatable_titles',
34 | ) );
35 |
36 | $cmb_group->add_group_field( $group_field_id, array(
37 | 'name' => 'Title',
38 | 'id' => 'title',
39 | 'type' => 'text',
40 | ) );
41 |
42 | $cmb_group->add_group_field( $group_field_id, array(
43 | 'name' => 'Description',
44 | 'id' => 'description',
45 | 'type' => 'textarea_small',
46 | ) );
47 | }
48 | add_action( 'cmb2_init', 'yourprefix_register_repeatable_group_field_title_example' );
49 |
50 | function yourprefix_add_js_for_repeatable_titles() {
51 | add_action( is_admin() ? 'admin_footer' : 'wp_footer', 'yourprefix_add_js_for_repeatable_titles_to_footer' );
52 | }
53 |
54 | function yourprefix_add_js_for_repeatable_titles_to_footer() {
55 | ?>
56 |
96 | 'field_group_test_one',
15 | 'title' => __( 'Repeating Field Group One', 'cmb2' ),
16 | 'object_types' => array( 'page', ),
17 | 'rows_limit' => 3, // custom attribute to use in our JS
18 | 'groupId' => '_cmb2_repeat_group_one', // custom attribute to use in our JS to retrieve the ID of the group that should be handled
19 | ) );
20 |
21 | $cmb_two = new_cmb2_box( array(
22 | 'id' => 'field_group_test_two',
23 | 'title' => __( 'Repeating Field Group Two', 'cmb2' ),
24 | 'object_types' => array( 'page', ),
25 | 'rows_limit' => 2, // custom attribute to use in our JS
26 | 'groupId' => '_cmb2_repeat_group_two', // custom attribute to use in our JS to retrieve the ID of the group that should be handled
27 | ) );
28 |
29 | $group_one = $cmb_one->add_field( array(
30 | 'id' => '_cmb2_repeat_group_one',
31 | 'type' => 'group',
32 | 'description' => __( 'Generates reusable form entries', 'cmb2' ),
33 | 'options' => array(
34 | 'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
35 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
36 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
37 | 'sortable' => true, // beta
38 | ),
39 | ) );
40 |
41 | $cmb_one->add_group_field( $group_one, array(
42 | 'name' => 'Entry Title',
43 | 'id' => 'title',
44 | 'type' => 'text',
45 | ) );
46 |
47 | $cmb_one->add_group_field( $group_one, array(
48 | 'name' => 'Description',
49 | 'desc' => 'Write a short description for this entry',
50 | 'id' => 'description',
51 | 'type' => 'textarea_small',
52 | ) );
53 |
54 | $group_two = $cmb_two->add_field( array(
55 | 'id' => '_cmb2_repeat_group_two',
56 | 'type' => 'group',
57 | 'description' => __( 'Generates reusable form entries', 'cmb2' ),
58 | 'options' => array(
59 | 'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
60 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
61 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
62 | 'sortable' => true, // beta
63 | ),
64 | ) );
65 |
66 | $cmb_two->add_group_field( $group_two, array(
67 | 'name' => 'Entry Title',
68 | 'id' => 'title',
69 | 'type' => 'text',
70 | ) );
71 |
72 | $cmb_two->add_group_field( $group_two, array(
73 | 'name' => 'Description',
74 | 'desc' => 'Write a short description for this entry',
75 | 'id' => 'description',
76 | 'type' => 'textarea_small',
77 | ) );
78 |
79 | }
80 | add_action( 'cmb2_admin_init', 'js_limited_group_setup', 9999 );
81 |
82 |
83 | $repeater_metaboxes = array('field_group_test_one','field_group_test_two'); // IDs of the metabox containing the repeater group
84 |
85 | foreach ($repeater_metaboxe as $value) {
86 | add_action( 'cmb2_after_post_form_'.$value, 'js_limit_group_repeat', 10, 2);
87 | }
88 |
89 | function js_limit_group_repeat( $post_id, $cmb ) {
90 | // Grab the custom attribute to determine the limit
91 | $limit = absint( $cmb->prop( 'rows_limit' ) );
92 | $limit = $limit ? $limit : 0;
93 | $group = $cmb->prop( 'groupId' )
94 | ?>
95 |
123 | 'test_limit_rows',
14 | 'title' => __( 'Repeating Field Group', 'cmb2' ),
15 | 'object_types' => array( 'page', ),
16 | 'rows_limit' => 3,
17 | ) );
18 |
19 | $cmb->add_field( array(
20 | 'name' => 'Entry Title',
21 | 'id' => 'text_repeat_test',
22 | 'type' => 'text',
23 | 'repeatable' => true, // Repeatable fields are supported w/in repeatable groups (for most types)
24 | ) );
25 | }
26 | add_action( 'cmb2_admin_init', 'js_limited_repeat_field_setup', 9999 );
27 |
28 | function js_limit_field_repeat( $post_id, $cmb ) {
29 | // Grab the custom attribute to determine the limit
30 | $limit = absint( $cmb->prop( 'rows_limit' ) );
31 | $limit = $limit ? $limit : 0;
32 | ?>
33 |
68 | 'field_group_test',
16 | 'title' => __( 'Repeating Field Group', 'cmb2' ),
17 | 'object_types' => array( 'page', ),
18 | 'rows_limit' => 3, // custom attribute to use in our JS
19 | ) );
20 |
21 | $group_id = $cmb->add_field( array(
22 | 'id' => '_cmb2_repeat_group',
23 | 'type' => 'group',
24 | 'description' => __( 'Generates reusable form entries', 'cmb2' ),
25 | 'options' => array(
26 | 'group_title' => __( 'Entry {#}', 'cmb2' ), // {#} gets replaced by row number
27 | 'add_button' => __( 'Add Another Entry', 'cmb2' ),
28 | 'remove_button' => __( 'Remove Entry', 'cmb2' ),
29 | 'sortable' => true, // beta
30 | ),
31 | ) );
32 |
33 | $cmb->add_group_field( $group_id, array(
34 | 'name' => 'Entry Title',
35 | 'id' => 'title',
36 | 'type' => 'text',
37 | ) );
38 |
39 | $cmb->add_group_field( $group_id, array(
40 | 'name' => 'Description',
41 | 'desc' => 'Write a short description for this entry',
42 | 'id' => 'description',
43 | 'type' => 'textarea_small',
44 | ) );
45 | }
46 | add_action( 'cmb2_admin_init', 'js_limited_group_setup', 9999 );
47 |
48 | function js_limit_group_repeat( $post_id, $cmb ) {
49 | // Grab the custom attribute to determine the limit
50 | $limit = absint( $cmb->prop( 'rows_limit' ) );
51 | $limit = $limit ? $limit : 0;
52 | ?>
53 |
93 | id in the above example.
97 | add_action( 'cmb2_after_post_form_field_group_test', 'js_limit_group_repeat', 10, 2 );
98 |
--------------------------------------------------------------------------------
/metaboxes/README.md:
--------------------------------------------------------------------------------
1 | Metaboxes
2 | ==========
3 |
4 | These are examples of different metabox configurations.
--------------------------------------------------------------------------------
/misc/README.md:
--------------------------------------------------------------------------------
1 | Miscellaneous Snippets
2 | ==========
3 |
4 | Random CMB2 and WordPress snippets
5 |
--------------------------------------------------------------------------------
/misc/add-wrap-to-group-of-fields.php:
--------------------------------------------------------------------------------
1 | $prefix . 'metabox',
16 | 'title' => esc_html__( 'Test Metabox', 'cmb2' ),
17 | 'object_types' => array( 'page', ), // Post type
18 | ) );
19 |
20 | // Markup to add a metabox-like toggle box: http://b.ustin.co/12Uba
21 | $advanced_open = '
22 |
23 |
Click to toggle
24 |
Toggle Advanced Options
25 |
26 | ';
27 | $advanced_close = '
';
28 |
29 | $cmb->add_field( array(
30 | 'before_row' => $advanced_open,
31 | 'name' => esc_html__( 'Test Text', 'cmb2' ),
32 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
33 | 'id' => $prefix . 'text',
34 | 'type' => 'text',
35 | ) );
36 |
37 | $cmb->add_field( array(
38 | 'name' => esc_html__( 'Test Text Small', 'cmb2' ),
39 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
40 | 'id' => $prefix . 'textsmall',
41 | 'type' => 'text_small',
42 | ) );
43 |
44 | $cmb->add_field( array(
45 | 'name' => esc_html__( 'Test Text Medium', 'cmb2' ),
46 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
47 | 'id' => $prefix . 'textmedium',
48 | 'type' => 'text_medium',
49 | 'after_row' => $advanced_close,
50 | ) );
51 |
52 | // Optionally do other fields here...
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/misc/adding-wordcount-to-cmb2-wysiwyg-field.php:
--------------------------------------------------------------------------------
1 | 'hold-my-wysiwyg',
10 | 'object_types' => array( 'post' ),
11 | ) );
12 |
13 | $cmb->add_field( array(
14 | 'name' => __( 'WYSIWYG content', 'YOURTEXTDOMAIN' ),
15 | 'id' => 'wysiwyg_content',
16 | 'type' => 'wysiwyg',
17 | 'after' => 'cmb2_wysiwyg_word_counter',
18 | ) );
19 |
20 | }
21 | add_action( 'cmb2_admin_init', 'yourprefix_feat_img_fields' );
22 |
23 | /**
24 | * Outputs wordcount for wysiwyg field.
25 | *
26 | * Basically copied from: https://github.com/WordPress/WordPress/blob/3099f4d9edc5f2f2b6ef8becc966135edde909a8/wp-admin/js/post.js#L1219-L1271
27 | * and: https://github.com/WordPress/WordPress/blob/3099f4d9edc5f2f2b6ef8becc966135edde909a8/wp-admin/edit-form-advanced.php#L714
28 | */
29 | function cmb2_wysiwyg_word_counter( $args, $field ) {
30 | wp_enqueue_script( 'word-count', array( 'jquery', 'underscore', 'word-count' ) );
31 | ?>
32 |
33 | 0' ); ?>
34 |
35 |
94 |
6 | * @link https://joebuckle.me/quickie/wordpress-add-options-to-post-admin-publish-meta-box/
7 | * @link https://github.com/CMB2/CMB2-Snippet-Library/blob/master/misc/outputting-forms-outside-metaboxes.php
8 | * @link https://codex.wordpress.org/Plugin_API/Action_Reference/post_submitbox_misc_actions
9 | */
10 |
11 | /**
12 | * Register the CMB2 metabox.
13 | */
14 | function yourprefix_cmb2_fields() {
15 | $prefix = '_yourprefix_';
16 |
17 | $cmb = new_cmb2_box( [
18 | 'id' => $prefix . 'publish_box',
19 | 'object_types' => [ 'post' ], // Any public post type.
20 | 'show_names' => false, // Disables the display for the CMB2 label.
21 | ] );
22 |
23 | $cmb->add_field( [
24 | 'before' => '' . __( 'Your field name', 'cmb2' ) . ' ', // Output the label w/o the default CMB2 styles.
25 | 'id' => $prefix . 'field',
26 | 'desc' => __( 'Field description (optional)', 'cmb2' ),
27 | 'type' => 'text', // Any valid CMB2 field type.
28 | 'attributes' => [
29 | 'style' => 'max-width: 80%;', // Cleans up the default CMB2 styles a bit. Move to stylesheet?
30 | ]
31 | ] );
32 | }
33 |
34 | add_action( 'post_submitbox_misc_actions', 'yourprefix_filter_publish_box' );
35 |
36 | /**
37 | * Display the CMB2 form in the WordPress publish metabox.
38 | *
39 | * @param object $post The WP_Post object.
40 | */
41 | function yourprefix_filter_publish_box( $post ) {
42 | $cmb = cmb2_get_metabox( '_yourprefix_publish_box' ); // Must match the box ID.
43 |
44 | if ( in_array( $post->post_type, $cmb->prop( 'object_types' ), true ) ) {
45 | $cmb->show_form();
46 | }
47 | }
48 |
49 | add_action( 'cmb2_admin_init', 'yourprefix_cmb2_fields' );
50 |
--------------------------------------------------------------------------------
/misc/helper-functions.php:
--------------------------------------------------------------------------------
1 | value data for saving. Likely $_POST data.
15 | */
16 | function cmb2_save_metabox_fields_data( $meta_box_id, $object_id, array $data_to_save ) {
17 | $cmb = cmb2_get_metabox( $meta_box_id, $object_id );
18 | $cmb->save_fields( $object_id, $cmb->object_type(), $data_to_save );
19 | }
20 |
21 | /**
22 | * Returns array of sanitized field values (without saving them) from
23 | * provided array of values (Likely $_POST data.)
24 | *
25 | * Combined with the metabox `'save_fields' => false` config option, you can use this to
26 | * save the box data somewhere else.
27 | *
28 | * @link https://wordpress.org/support/topic/sanitizing-data-outside-metabox-context Forum post
29 | *
30 | * @param mixed $meta_box_id Metabox ID (or metabox config array)
31 | * @param int $object_id ID of post/user/comment/options-page to save the data against
32 | * @param array $data_to_save Array of key => value data for saving. Likely $_POST data.
33 | */
34 | function cmb2_get_metabox_sanitized_values( $meta_box_id, array $data_to_save ) {
35 | $cmb = cmb2_get_metabox( $meta_box_id );
36 | $cmb->get_sanitized_values( $data_to_save );
37 | }
38 |
--------------------------------------------------------------------------------
/misc/outputting-cmb2-fields-in-featured-image-metabox.php:
--------------------------------------------------------------------------------
1 | 'feat-image-fields',
10 | 'object_types' => array( 'post' ),
11 | ) );
12 |
13 | $cmb->add_field( array(
14 | 'name' => 'Featured Image Position',
15 | 'id' => 'feat_img_placement',
16 | 'type' => 'select',
17 | 'options' => array(
18 | '' => 'Center', // The default -- no value. Keeps out of the database.
19 | 'left' => 'Left',
20 | 'right' => 'Right',
21 | ),
22 | 'before' => '',
29 | ) );
30 |
31 | }
32 | add_action( 'cmb2_admin_init', 'yourprefix_feat_img_fields' );
33 |
34 | function yourprefix_feat_img_output_fields( $content, $post_id, $thumbnail_id ) {
35 | $cmb = cmb2_get_metabox( 'feat-image-fields' );
36 |
37 | if ( $cmb && in_array( get_post_type(), $cmb->prop( 'object_types' ), 1 ) ) {
38 | ob_start();
39 | $cmb->show_form();
40 | // grab the data from the output buffer and add it to our $content variable
41 | $content .= ob_get_clean();
42 | }
43 |
44 | return $content;
45 | }
46 | add_filter( 'admin_post_thumbnail_html', 'yourprefix_feat_img_output_fields', 10, 3 );
47 |
--------------------------------------------------------------------------------
/misc/outputting-forms-outside-metaboxes.php:
--------------------------------------------------------------------------------
1 | '_yourprefix_display_title',
13 | 'object_types' => array( 'page' ),
14 | //'title' => '', omit the 'title' field to keep the normal wp metabox from displaying
15 | ) );
16 |
17 | $cmb->add_field( array(
18 | 'name' => 'Display title for this page?',
19 | 'id' => '_yourprefix_display_title',
20 | 'type' => 'checkbox',
21 | ) );
22 |
23 | $cmb->add_field( array(
24 | 'name' => 'A textarea',
25 | 'id' => '_yourprefix_display_title_text',
26 | 'type' => 'textarea',
27 | ) );
28 |
29 | }
30 | add_action( 'cmb2_admin_init', 'yourprefix_register_cmb2_fields' );
31 |
32 |
33 | /**
34 | * Display checkbox metabox below title field
35 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L517-L523
36 | */
37 | function yourprefix_output_custom_mb_location() {
38 | $cmb = cmb2_get_metabox( '_yourprefix_display_title' );
39 |
40 | if ( in_array( get_post_type(), $cmb->prop( 'object_types' ), 1 ) ) {
41 | $cmb->show_form();
42 | }
43 | }
44 | add_action( 'edit_form_after_title', 'yourprefix_output_custom_mb_location' );
45 |
46 | /**
47 | * More hooks in the post-editor screen as of 4.1
48 | */
49 |
50 | /**
51 | * Display checkbox metabox below wysiwyg editor field
52 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L560-L567
53 | */
54 | // add_action( 'edit_form_after_editor', 'yourprefix_output_custom_mb_location' );
55 |
56 | /**
57 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L217-L225
58 | */
59 | // add_action( 'dbx_post_advanced', 'yourprefix_output_custom_mb_location' );
60 |
61 | /**
62 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L241-L249
63 | */
64 | // add_action( 'add_meta_boxes', 'yourprefix_output_custom_mb_location' );
65 |
66 | /**
67 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L416-L423
68 | */
69 | // add_action( 'post_edit_form_tag', 'yourprefix_output_custom_mb_location' );
70 |
71 | /**
72 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L447-L456
73 | */
74 | // add_action( 'edit_form_top', 'yourprefix_output_custom_mb_location' );
75 |
76 | /**
77 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L480-L487
78 | */
79 | // add_action( 'edit_form_before_permalink', 'yourprefix_output_custom_mb_location' );
80 |
81 | /**
82 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L516-L523
83 | */
84 | // add_action( 'edit_form_after_title', 'yourprefix_output_custom_mb_location' );
85 |
86 | /**
87 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L560-L567
88 | */
89 | // add_action( 'edit_form_after_editor', 'yourprefix_output_custom_mb_location' );
90 |
91 | /**
92 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L574-L597
93 | */
94 | // add_action( 'submitpost_box', 'yourprefix_output_custom_mb_location' );
95 | // add_action( 'submitpage_box', 'yourprefix_output_custom_mb_location' );
96 |
97 | /**
98 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L609-L628
99 | */
100 | // add_action( 'edit_form_advanced', 'yourprefix_output_custom_mb_location' );
101 | // add_action( 'edit_page_form', 'yourprefix_output_custom_mb_location' );
102 |
103 | /**
104 | * @link https://github.com/WordPress/WordPress/blob/56d6682461be82da1a3bafc454dad2c9da451a38/wp-admin/edit-form-advanced.php#L636-L643
105 | */
106 | // add_action( 'dbx_post_sidebar', 'yourprefix_output_custom_mb_location' );
107 |
--------------------------------------------------------------------------------
/misc/replace-wp-excerpt-with-cmb2-field.php:
--------------------------------------------------------------------------------
1 | 'cmb2_excerpt',
11 | 'title' => 'Excerpt',
12 | 'object_types' => array( 'post', ), // Post type
13 | // 'context' => 'side',
14 | ) );
15 |
16 | $cmb->add_field( array(
17 | /*
18 | * As long as the 'id' matches the name field of the regular WP field,
19 | * WP will handle the saving for you.
20 | */
21 | 'id' => 'excerpt',
22 | 'name' => 'Excerpt',
23 | 'desc' => 'Excerpts are optional hand-crafted summaries of your content that can be used in your theme. Learn more about manual excerpts. ',
24 | 'type' => 'textarea',
25 | 'escape_cb' => false,
26 | ) );
27 |
28 | }
29 | add_action( 'cmb2_admin_init', 'cmb2_register_excerpt_replacement_box' );
30 |
31 |
32 | /**
33 | * Remove the default WordPress excerpt field.
34 | */
35 | function cmb2_admin_hide_excerpt_field() {
36 | add_action( 'add_meta_boxes', '_cmb2_admin_hide_excerpt_field' );
37 | }
38 | add_filter( 'admin_init', 'cmb2_admin_hide_excerpt_field' );
39 |
40 | function _cmb2_admin_hide_excerpt_field() {
41 | $screen = get_current_screen();
42 |
43 | if ( isset( $screen->post_type ) && 'post' === $screen->post_type ) {
44 | remove_meta_box( 'postexcerpt', null, 'normal' );
45 | }
46 | }
47 |
48 |
49 | /**
50 | * Override the WordPress Excerpt field
51 | */
52 | function cmb2_override_excerpt_display( $data, $post_id ) {
53 | return get_post_field( 'post_excerpt', $post_id );
54 | }
55 | add_filter( 'cmb2_override_excerpt_meta_value', 'cmb2_override_excerpt_display', 10, 2 );
56 |
57 | /*
58 | * WP will handle the saving for us, so don't save to meta.
59 | */
60 | add_filter( 'cmb2_override_excerpt_meta_save', '__return_true' );
61 |
--------------------------------------------------------------------------------
/misc/replace-wp-title-content-thumbnail-with-cmb2-fields.php:
--------------------------------------------------------------------------------
1 | 'CPT',
12 | 'singular_name' => 'CPT',
13 | 'menu_name' => 'CPT',
14 | 'parent_item_colon' => 'Parent CPT',
15 | 'all_items' => 'All CPT',
16 | 'view_item' => 'View CPT',
17 | 'add_new_item' => 'Add New CPT',
18 | 'add_new' => 'Add New',
19 | 'edit_item' => 'Edit CPT',
20 | 'update_item' => 'Update CPT',
21 | 'search_items' => 'Search CPT',
22 | 'not_found' => 'Not Found',
23 | 'not_found_in_trash' => 'Not found in Trash',
24 | );
25 |
26 | register_post_type( 'cpt', array(
27 | 'labels' => $labels,
28 | 'supports' => array( 'title' ),
29 | 'supports' => array( '' ),
30 | 'public' => true,
31 | 'has_archive' => true,
32 | ) );
33 | }
34 | add_action( 'init', 'register_test_cpt' );
35 |
36 | function register_test_cpt_metabox() {
37 |
38 | $cmb_subsub = new_cmb2_box( array (
39 | 'id' => 'metabox',
40 | 'title' => 'Edit',
41 | 'object_types' => array( 'cpt' ),
42 | ) );
43 |
44 | $cmb_subsub->add_field( array(
45 | 'id' => 'post_title', // Saves to WP post title, allows the_title()
46 | 'name' => 'Title',
47 | 'desc' => 'Provide a title.',
48 | 'default' => '',
49 | 'type' => 'text',
50 | ) );
51 |
52 | $cmb_subsub->add_field( array(
53 | 'id' => 'post_content', // Saves to WP post content, allows the_content()
54 | 'name' => 'Description',
55 | 'desc' => 'Enter a brief description',
56 | 'type' => 'textarea', // wysiwyg is problematic when replacing post_content
57 | ) );
58 |
59 | $cmb_subsub->add_field( array(
60 | 'id' => '_thumbnail', // Saves to WP post thumbnail, allows the_post_thumbnail()
61 | 'name' => 'Image',
62 | 'desc' => 'Upload/Select an image.',
63 | 'type' => 'file',
64 | 'options' => array(
65 | 'url' => false,
66 | ),
67 | 'text' => array(
68 | 'add_upload_file_text' => 'Add Image'
69 | ),
70 | ) );
71 |
72 | };
73 | add_action( 'cmb2_admin_init', 'register_test_cpt_metabox' );
74 |
75 | /*
76 | * Override the title/content field retrieval so CMB2 doesn't look in post-meta.
77 | */
78 | function cmb2_override_post_title_display( $data, $post_id ) {
79 | return get_post_field( 'post_title', $post_id );
80 | }
81 | function cmb2_override_post_content_display( $data, $post_id ) {
82 | return get_post_field( 'post_content', $post_id );
83 | }
84 | add_filter( 'cmb2_override_post_title_meta_value', 'cmb2_override_post_title_display', 10, 2 );
85 | add_filter( 'cmb2_override_post_content_meta_value', 'cmb2_override_post_content_display', 10, 2 );
86 |
87 | /*
88 | * WP will handle the saving for us, so don't save title/content to meta.
89 | */
90 | add_filter( 'cmb2_override_post_title_meta_save', '__return_true' );
91 | add_filter( 'cmb2_override_post_content_meta_save', '__return_true' );
92 |
--------------------------------------------------------------------------------
/modified-field-types/README.md:
--------------------------------------------------------------------------------
1 | Modified Field Types
2 | ==========
3 |
4 | These are examples of using the built-in [CMB2 field-types](https://github.com/WebDevStudios/CMB2/wiki/Field-Types), but modifiying them with the [available parameters](https://github.com/WebDevStudios/CMB2/wiki/Field-Types#common-field-parameters).
--------------------------------------------------------------------------------
/modified-field-types/modify-button-text-for-file-type.php:
--------------------------------------------------------------------------------
1 | add_field( array(
11 | 'name' => 'Image',
12 | 'desc' => 'Upload an image.',
13 | 'id' => '_jt_cmb2_image',
14 | 'type' => 'file',
15 | 'options' => array(
16 | 'add_upload_file_text' => __( 'Add or Upload Image', 'jt_cmb2' ),
17 | ),
18 | ) );
19 |
--------------------------------------------------------------------------------
/modified-field-types/readonly-field-type.php:
--------------------------------------------------------------------------------
1 | add_field( array(
10 | 'name' => 'Read Only',
11 | 'description' => 'The value of this input should be saved somewhere else.',
12 | 'id' => '_jtcmb2_readonly',
13 | 'type' => 'text',
14 | 'save_field' => false, // Otherwise CMB2 will end up removing the value.
15 | 'attributes' => array(
16 | 'readonly' => 'readonly',
17 | 'disabled' => 'disabled',
18 | ),
19 | ) );
20 |
--------------------------------------------------------------------------------
/options-and-settings-pages/README.md:
--------------------------------------------------------------------------------
1 | Options and Settings Pages
2 | ==========
3 |
4 | These snippets demonstrate how to create options page metaboxes or hook into genesis settings metaboxes.
5 |
6 | There are also examples for how you can retrieve an option, using `myprefix_get_option( 'test_text' )`.
7 |
8 | Obviously replace all instances of `myprefix` with a unique project-specific prefix.
9 |
10 | [Check these snippets out](https://github.com/WebDevStudios/CMB2-Snippet-Library/tree/master/helper-functions) if you're looking to modify the form output of the `cmb2_metabox_form` function.
11 |
--------------------------------------------------------------------------------
/options-and-settings-pages/add-cmb2-settings-to-other-settings-pages.php:
--------------------------------------------------------------------------------
1 | hooks();
48 | }
49 | return self::$instance;
50 | }
51 |
52 | /**
53 | * Initiate our hooks
54 | * @since 0.1.0
55 | */
56 | public function hooks() {
57 | add_action( 'cmb2_admin_init', array( $this, 'register_metabox' ) );
58 | add_action( 'current_screen', array( $this, 'maybe_save' ) );
59 | add_filter( 'admin_footer' , array( $this , 'maybe_hookup_fields' ), 2 /* Early before all scripts are output. */ );
60 | }
61 |
62 | /**
63 | * Add the options metabox to the array of metaboxes
64 | * @since 0.1.0
65 | */
66 | function register_metabox() {
67 | $cmb = new_cmb2_box( array(
68 | 'id' => $this->metabox_id,
69 | 'hookup' => false,
70 | 'object_types' => array( 'options-page' ),
71 | ) );
72 |
73 | // Set our CMB2 fields
74 |
75 | $cmb->add_field( array(
76 | 'name' => __( 'Test Text', 'myprefix' ),
77 | 'desc' => __( 'field description (optional)', 'myprefix' ),
78 | 'id' => 'test_text',
79 | 'type' => 'text',
80 | // 'default' => 'Default Text',
81 | ) );
82 |
83 | $cmb->add_field( array(
84 | 'name' => __( 'Test Color Picker', 'myprefix' ),
85 | 'desc' => __( 'field description (optional)', 'myprefix' ),
86 | 'id' => 'test_colorpicker',
87 | 'type' => 'colorpicker',
88 | 'default' => '#bada55',
89 | ) );
90 |
91 | }
92 |
93 | /**
94 | * Register our setting to WP
95 | * @since 0.1.0
96 | */
97 | public function maybe_save() {
98 | if ( empty( $_POST ) ) {
99 | return;
100 | }
101 |
102 | $url = wp_get_referer();
103 | // Check if our screen id is in the referrer url.
104 | if ( false === strpos( $url, $this->screen_id ) ) {
105 | return;
106 | }
107 |
108 | // Hook into whitelist_options as we know it's only called if the default save-checks have finished.
109 | add_filter( 'whitelist_options', array( $this, 'save_our_options' ) );
110 | }
111 |
112 | /**
113 | * Simply used as a options.php life-cycle hook to save our settings
114 | * (since there doesn't appear to be any proper hooks)
115 | *
116 | * @since 0.1.0
117 | *
118 | * @param array $whitelist_options
119 | *
120 | * @return array
121 | */
122 | public function save_our_options( $whitelist_options ) {
123 | $cmb = cmb2_get_metabox( $this->metabox_id, $this->key );
124 | if ( $cmb ) {
125 |
126 | $hookup = new CMB2_hookup( $cmb );
127 |
128 | if ( $hookup->can_save( 'options-page' ) ) {
129 | $cmb->save_fields( $this->key, 'options-page', $_POST );
130 | }
131 | }
132 |
133 | // Our saving is done, so cleanup.
134 | remove_filter( 'whitelist_options', array( $this, 'save_our_options' ) );
135 |
136 | return $whitelist_options;
137 | }
138 |
139 | /**
140 | * Maybe hookup our CMB2 fields.
141 | *
142 | * @since 0.1.0
143 | */
144 | public function maybe_hookup_fields() {
145 | $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : (object) array( 'id' => null );
146 |
147 | // Only show on our screen.
148 | if ( $this->screen_id !== $screen->id ) {
149 | return;
150 | }
151 |
152 | CMB2_hookup::enqueue_cmb_css();
153 | $this->admin_page_display();
154 | }
155 |
156 | /**
157 | * CMB2 fields output
158 | * Wile hide by default in the footer, then use JS to move it inside the form. Hacky, yep.
159 | *
160 | * @since 0.1.0
161 | */
162 | public function admin_page_display() {
163 | ?>
164 |
165 | metabox_id, $this->key, 'options-page' )->show_form(); ?>
166 |
167 |
173 | {$field};
186 | }
187 |
188 | throw new Exception( 'Invalid property: ' . $field );
189 | }
190 |
191 | }
192 |
193 | /**
194 | * Helper function to get/return the Prefix_Add_CMB2_To_Settings_Page object
195 | * @since 0.1.0
196 | * @return Prefix_Add_CMB2_To_Settings_Page object
197 | */
198 | function myprefix_cmb2_on_settings() {
199 | return Prefix_Add_CMB2_To_Settings_Page::get_instance();
200 | }
201 |
202 |
203 | /**
204 | * Wrapper function around cmb2_get_option
205 | * @since 0.1.0
206 | * @param string $key Options array key
207 | * @param mixed $default Optional default value
208 | * @return mixed Option value
209 | */
210 | function myprefix_get_option( $key = '', $default = false ) {
211 | if ( function_exists( 'cmb2_get_option' ) ) {
212 | // Use cmb2_get_option as it passes through some key filters.
213 | return cmb2_get_option( myprefix_cmb2_on_settings()->key, $key, $default );
214 | }
215 | // Fallback to get_option if CMB2 is not loaded yet.
216 | $opts = get_option( myprefix_cmb2_on_settings()->key, $default );
217 | $val = $default;
218 | if ( 'all' == $key ) {
219 | $val = $opts;
220 | } elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
221 | $val = $opts[ $key ];
222 | }
223 | return $val;
224 | }
225 |
226 | // Get it started
227 | myprefix_cmb2_on_settings();
--------------------------------------------------------------------------------
/options-and-settings-pages/custom-display-callback.php:
--------------------------------------------------------------------------------
1 | 'yourprefix_theme_options_page',
10 | 'title' => 'Theme Options',
11 | 'object_types' => array( 'options-page' ),
12 | 'option_key' => 'yourprefix_theme_options',
13 | 'icon_url' => 'dashicons-palmtree',
14 | 'display_cb' => 'yourprefix_theme_options_page_output', // Override the options-page form output (CMB2_Hookup::options_page_output()).
15 | 'description' => 'Custom description', // Will be displayed via our display_cb.
16 | ) );
17 |
18 | $cmb_options->add_field( array(
19 | 'name' => 'Site Background Color',
20 | 'desc' => 'field description (optional)',
21 | 'id' => 'bg_color',
22 | 'type' => 'colorpicker',
23 | 'default' => '#ffffff',
24 | ) );
25 |
26 | }
27 |
28 | function yourprefix_theme_options_page_output( $hookup ) {
29 | // Output custom markup for the options-page.
30 | ?>
31 |
32 | cmb->prop( 'title' ) ) : ?>
33 |
cmb->prop( 'title' ) ); ?>
34 |
35 | cmb->prop( 'description' ) ) : ?>
36 | cmb->prop( 'description' ) ); ?>
37 |
38 |
43 |
44 | hooks();
71 | }
72 |
73 | return self::$instances[ $post_type ];
74 | }
75 |
76 | /**
77 | * Constructor
78 | *
79 | * @since 0.1.0
80 | *
81 | * @param string $post_type Post type slug.
82 | */
83 | protected function __construct( $post_type ) {
84 | $this->post_type = $post_type;
85 | $this->admin_hook = sprintf( $this->admin_hook, $post_type );
86 | $this->key = sprintf( $this->key, $post_type );
87 | $this->metabox_id = sprintf( $this->metabox_id, $post_type );
88 | }
89 |
90 | /**
91 | * Initiate our hooks
92 | *
93 | * @since 0.1.0
94 | */
95 | public function hooks() {
96 | add_action( 'init', array( $this, 'init' ) );
97 | add_action( 'admin_menu', array( $this, 'admin_hooks' ) );
98 | add_action( 'cmb2_admin_init', array( $this, 'init_metabox' ) );
99 | }
100 |
101 |
102 | /**
103 | * Initiate admin hooks.
104 | *
105 | * @since 0.1.0
106 | */
107 | public function init() {
108 | // Add custom archive support for CPT.
109 | add_post_type_support( $this->post_type, 'genesis-cpt-archives-settings' );
110 | }
111 |
112 | /**
113 | * Add admin hooks.
114 | *
115 | * @since 0.1.0
116 | */
117 | public function admin_hooks() {
118 | // Include CMB CSS in the head to avoid FOUC.
119 | add_action( "admin_print_styles-{$this->admin_hook}", array( 'CMB2_hookup', 'enqueue_cmb_css' ) );
120 |
121 | // Hook into the genesis cpt settings save and add in the CMB2 sanitized values.
122 | add_filter( "sanitize_option_genesis-cpt-archive-settings-{$this->post_type}", array( $this, 'add_sanitized_values' ), 999 );
123 |
124 | // Hook up our Genesis metabox.
125 | add_action( 'genesis_cpt_archives_settings_metaboxes', array( $this, 'add_meta_box' ) );
126 | }
127 |
128 | /**
129 | * Hook up our Genesis metabox.
130 | *
131 | * @since 0.1.0
132 | */
133 | public function add_meta_box() {
134 | $cmb = $this->init_metabox();
135 | add_meta_box(
136 | $cmb->cmb_id,
137 | $cmb->prop( 'title' ),
138 | array( $this, 'output_metabox' ),
139 | $this->admin_hook,
140 | $cmb->prop( 'context' ),
141 | $cmb->prop( 'priority' )
142 | );
143 | }
144 |
145 | /**
146 | * Output our Genesis metabox.
147 | *
148 | * @since 0.1.0
149 | */
150 | public function output_metabox() {
151 | $cmb = $this->init_metabox();
152 | $cmb->show_form( $cmb->object_id(), $cmb->object_type() );
153 | }
154 |
155 | /**
156 | * If saving the cpt settings option, add the CMB2 sanitized values.
157 | *
158 | * @since 0.1.0
159 | *
160 | * @param array $new_value Array of values for the setting.
161 | *
162 | * @return array Updated array of values for the setting.
163 | */
164 | public function add_sanitized_values( $new_value ) {
165 | if ( ! empty( $_POST ) ) {
166 | $cmb = $this->init_metabox();
167 |
168 | $new_value = array_merge(
169 | $new_value,
170 | $cmb->get_sanitized_values( $_POST )
171 | );
172 | }
173 |
174 | return $new_value;
175 | }
176 |
177 | /**
178 | * Register our Genesis metabox and return the CMB2 instance.
179 | *
180 | * @since 0.1.0
181 | *
182 | * @return CMB2 instance.
183 | */
184 | public function init_metabox() {
185 | if ( null !== $this->cmb ) {
186 | return $this->cmb;
187 | }
188 |
189 | $this->cmb = cmb2_get_metabox( array(
190 | 'id' => $this->metabox_id,
191 | 'title' => __( 'I\'m a Genesis Archive Settings CMB2 metabox', 'myprefix' ),
192 | 'hookup' => false, // We'll handle ourselves. (add_sanitized_values())
193 | 'cmb_styles' => false, // We'll handle ourselves. (admin_hooks())
194 | 'context' => 'main', // Important for Genesis.
195 | // 'priority' => 'low', // Defaults to 'high'.
196 | 'object_types' => array( $this->admin_hook ),
197 | 'show_on' => array(
198 | // These are important, don't remove.
199 | 'key' => 'options-page',
200 | 'value' => array( $this->key ),
201 | ),
202 | ), $this->key, 'options-page' );
203 |
204 | // Set our CMB2 fields.
205 | $this->cmb->add_field( array(
206 | 'name' => __( 'Test Text', 'myprefix' ),
207 | 'desc' => __( 'field description (optional)', 'myprefix' ),
208 | 'id' => 'test_text',
209 | 'type' => 'text',
210 | // 'default' => 'Default Text',
211 | ) );
212 |
213 | $this->cmb->add_field( array(
214 | 'name' => __( 'Test Color Picker', 'myprefix' ),
215 | 'desc' => __( 'field description (optional)', 'myprefix' ),
216 | 'id' => 'test_colorpicker',
217 | 'type' => 'colorpicker',
218 | 'default' => '#bada55',
219 | ) );
220 |
221 | return $this->cmb;
222 | }
223 |
224 | /**
225 | * Public getter method for retrieving protected/private variables
226 | *
227 | * @since 0.1.0
228 | *
229 | * @param string $field Field to retrieve.
230 | *
231 | * @throws Exception Throws an exception if the field is invalid.
232 | *
233 | * @return mixed Field value or exception is thrown
234 | */
235 | public function __get( $field ) {
236 | // Allowed fields to retrieve.
237 | if ( 'cmb' === $field ) {
238 | return $this->init_metabox();
239 | }
240 |
241 | if ( in_array( $field, array( 'metabox_id', 'post_type', 'admin_hook', 'key' ), true ) ) {
242 | return $this->{$field};
243 | }
244 |
245 | throw new Exception( 'Invalid property: ' . $field );
246 | }
247 |
248 | }
249 |
250 | /**
251 | * Helper function to get/return the Myprefix_Genesis_CPT_Settings_Metabox object.
252 | *
253 | * @since 0.1.0
254 | *
255 | * @param string $post_type Post type slug.
256 | *
257 | * @return Myprefix_Genesis_CPT_Settings_Metabox object
258 | */
259 | function myprefix_genesis_cpt_settings( $post_type ) {
260 | return Myprefix_Genesis_CPT_Settings_Metabox::get_instance( $post_type );
261 | }
262 |
263 | // Get it started.
264 | // myprefix_genesis_cpt_settings( 'custom-post-type-slug' );
265 |
--------------------------------------------------------------------------------
/options-and-settings-pages/genesis-settings-metabox.php:
--------------------------------------------------------------------------------
1 | hooks();
64 | }
65 |
66 | return self::$instance;
67 | }
68 |
69 | /**
70 | * Constructor
71 | *
72 | * @since 0.1.0
73 | */
74 | protected function __construct() {
75 | }
76 |
77 | /**
78 | * Initiate our hooks
79 | *
80 | * @since 0.1.0
81 | */
82 | public function hooks() {
83 | add_action( 'admin_menu', array( $this, 'admin_hooks' ) );
84 | add_action( 'cmb2_admin_init', array( $this, 'init_metabox' ) );
85 | }
86 |
87 | /**
88 | * Add menu options page
89 | *
90 | * @since 0.1.0
91 | */
92 | public function admin_hooks() {
93 | // Include CMB CSS in the head to avoid FOUC.
94 | add_action( "admin_print_styles-{$this->admin_hook}", array( 'CMB2_hookup', 'enqueue_cmb_css' ) );
95 |
96 | // Hook into the genesis cpt setttings save and add in the CMB2 sanitized values.
97 | add_filter( "sanitize_option_{$this->key}", array( $this, 'add_sanitized_values' ), 999 );
98 |
99 | // Hook up our Genesis metabox.
100 | add_action( 'genesis_theme_settings_metaboxes', array( $this, 'add_meta_box' ) );
101 | }
102 |
103 |
104 | /**
105 | * Hook up our Genesis metabox.
106 | *
107 | * @since 0.1.0
108 | */
109 | public function add_meta_box() {
110 | $cmb = $this->init_metabox();
111 | add_meta_box(
112 | $cmb->cmb_id,
113 | $cmb->prop( 'title' ),
114 | array( $this, 'output_metabox' ),
115 | $this->admin_hook,
116 | $cmb->prop( 'context' ),
117 | $cmb->prop( 'priority' )
118 | );
119 | }
120 |
121 | /**
122 | * Output our Genesis metabox.
123 | *
124 | * @since 0.1.0
125 | */
126 | public function output_metabox() {
127 | $cmb = $this->init_metabox();
128 | $cmb->show_form( $cmb->object_id(), $cmb->object_type() );
129 | }
130 |
131 | /**
132 | * If saving the cpt settings option, add the CMB2 sanitized values.
133 | *
134 | * @since 0.1.0
135 | *
136 | * @param array $new_value Array of values for the setting.
137 | *
138 | * @return array Updated array of values for the setting.
139 | */
140 | public function add_sanitized_values( $new_value ) {
141 | if ( ! empty( $_POST ) ) {
142 | $cmb = $this->init_metabox();
143 |
144 | $new_value = array_merge(
145 | $new_value,
146 | $cmb->get_sanitized_values( $_POST )
147 | );
148 | }
149 |
150 | return $new_value;
151 | }
152 |
153 | /**
154 | * Register our Genesis metabox and return the CMB2 instance.
155 | *
156 | * @since 0.1.0
157 | *
158 | * @return CMB2 instance.
159 | */
160 | public function init_metabox() {
161 | if ( null !== $this->cmb ) {
162 | return $this->cmb;
163 | }
164 |
165 | $this->cmb = cmb2_get_metabox( array(
166 | 'id' => $this->metabox_id,
167 | 'title' => __( 'I\'m a Genesis Settings CMB2 metabox', 'myprefix' ),
168 | 'hookup' => false, // We'll handle ourselves. (add_sanitized_values())
169 | 'cmb_styles' => false, // We'll handle ourselves. (admin_hooks())
170 | 'context' => 'main', // Important for Genesis.
171 | // 'priority' => 'low', // Defaults to 'high'.
172 | 'object_types' => array( $this->admin_hook ),
173 | 'show_on' => array(
174 | // These are important, don't remove.
175 | 'key' => 'options-page',
176 | 'value' => array( $this->key ),
177 | ),
178 | ), $this->key, 'options-page' );
179 |
180 | // Set our CMB2 fields.
181 | $this->cmb->add_field( array(
182 | 'name' => __( 'Test Text', 'myprefix' ),
183 | 'desc' => __( 'field description (optional)', 'myprefix' ),
184 | 'id' => 'test_text',
185 | 'type' => 'text',
186 | // 'default' => 'Default Text',
187 | ) );
188 |
189 | $this->cmb->add_field( array(
190 | 'name' => __( 'Test Color Picker', 'myprefix' ),
191 | 'desc' => __( 'field description (optional)', 'myprefix' ),
192 | 'id' => 'test_colorpicker',
193 | 'type' => 'colorpicker',
194 | 'default' => '#bada55',
195 | ) );
196 |
197 | return $this->cmb;
198 | }
199 |
200 | /**
201 | * Public getter method for retrieving protected/private variables.
202 | *
203 | * @since 0.1.0
204 | *
205 | * @param string $field Field to retrieve.
206 | *
207 | * @throws Exception Throws an exception if the field is invalid.
208 | *
209 | * @return mixed Field value or exception is thrown
210 | */
211 | public function __get( $field ) {
212 | if ( 'cmb' === $field ) {
213 | return $this->init_metabox();
214 | }
215 |
216 | // Allowed fields to retrieve.
217 | if ( in_array( $field, array( 'key', 'admin_page', 'metabox_id', 'admin_hook' ), true ) ) {
218 | return $this->{$field};
219 | }
220 |
221 | throw new Exception( 'Invalid property: ' . $field );
222 | }
223 |
224 | }
225 |
226 | /**
227 | * Helper function to get/return the Myprefix_Genesis_Settings_Metabox object
228 | *
229 | * @since 0.1.0
230 | *
231 | * @return Myprefix_Genesis_Settings_Metabox object
232 | */
233 | function myprefix_genesis_settings_metabox() {
234 | return Myprefix_Genesis_Settings_Metabox::get_instance();
235 | }
236 |
237 | // Get it started.
238 | myprefix_genesis_settings_metabox();
239 |
--------------------------------------------------------------------------------
/options-and-settings-pages/network-options-cmb.php:
--------------------------------------------------------------------------------
1 | 'myprefix_network_option_metabox',
20 | 'title' => esc_html__( 'Network Setting', 'myprefix' ),
21 | 'object_types' => array( 'options-page' ),
22 |
23 | /*
24 | * The following parameters are specific to the options-page box
25 | * Several of these parameters are passed along to add_menu_page()/add_submenu_page().
26 | */
27 |
28 | 'option_key' => 'myprefix_network_options', // The option key and admin menu page slug.
29 | // 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
30 | // 'menu_title' => esc_html__( 'Options', 'myprefix' ), // Falls back to 'title' (above).
31 | // 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
32 | // 'capability' => 'manage_options', // Cap required to view options-page.
33 | // 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
34 | 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
35 | // 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
36 | // 'save_button' => esc_html__( 'Save Theme Options', 'myprefix' ), // The text for the options-page save button. Defaults to 'Save'.
37 | ) );
38 |
39 | /*
40 | * Options fields ids only need
41 | * to be unique within this box.
42 | * Prefix is not needed.
43 | */
44 |
45 | $cmb_options->add_field( array(
46 | 'name' => __( 'Test Text', 'myprefix' ),
47 | 'desc' => __( 'field description (optional)', 'myprefix' ),
48 | 'id' => 'test_text',
49 | 'type' => 'text',
50 | 'default' => 'Default Text',
51 | ) );
52 |
53 | $cmb_options->add_field( array(
54 | 'name' => __( 'Test Color Picker', 'myprefix' ),
55 | 'desc' => __( 'field description (optional)', 'myprefix' ),
56 | 'id' => 'test_colorpicker',
57 | 'type' => 'colorpicker',
58 | 'default' => '#bada55',
59 | ) );
60 |
61 |
62 | }
63 |
64 | /**
65 | * Wrapper function around cmb2_get_option
66 | * @since 0.1.0
67 | * @param string $key Options array key
68 | * @param mixed $default Optional default value
69 | * @return mixed Option value
70 | */
71 | function myprefix_get_network_option( $key = '', $default = false ) {
72 | if ( function_exists( 'cmb2_get_option' ) ) {
73 | // Use cmb2_get_option as it passes through some key filters.
74 | return cmb2_get_option( 'myprefix_network_options', $key, $default );
75 | }
76 |
77 | // Fallback to get_site_option if CMB2 is not loaded yet.
78 | $opts = get_site_option( 'myprefix_network_options', $default );
79 |
80 | $val = $default;
81 |
82 | if ( 'all' == $key ) {
83 | $val = $opts;
84 | } elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
85 | $val = $opts[ $key ];
86 | }
87 |
88 | return $val;
89 | }
90 |
--------------------------------------------------------------------------------
/options-and-settings-pages/non-cmb2-options-page.php:
--------------------------------------------------------------------------------
1 | 'wporg_field_pill',
35 | 'class' => 'wporg_row',
36 | 'wporg_custom_data' => 'custom',
37 | )
38 | );
39 | }
40 |
41 | /**
42 | * Register our wporg_settings_init to the admin_init action hook.
43 | */
44 | add_action( 'admin_init', 'wporg_settings_init' );
45 |
46 |
47 | /**
48 | * Custom option and settings:
49 | * - callback functions
50 | */
51 |
52 |
53 | /**
54 | * Developers section callback function.
55 | *
56 | * @param array $args The settings array, defining title, id, callback.
57 | */
58 | function wporg_section_developers_callback( $args ) {
59 | ?>
60 |
61 | .
69 | * - the "class" key value is used for the "class" attribute of the containing the field.
70 | * Note: you can add custom key value pairs to be used inside your callbacks.
71 | *
72 | * @param array $args
73 | */
74 | function wporg_field_pill_cb( $args ) {
75 | // Get the value of the setting we've registered with register_setting()
76 | $options = get_option( 'wporg_options' );
77 | ?>
78 |
83 | >
84 |
85 |
86 | >
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
144 |
145 |
146 | options_page_tab_nav_output(); ?>
147 |
158 |
159 | 'yourprefix_main_options_page',
13 | 'title' => esc_html__( 'Main Options', 'cmb2' ),
14 | 'object_types' => array( 'options-page' ),
15 |
16 | /*
17 | * The following parameters are specific to the options-page box
18 | * Several of these parameters are passed along to add_menu_page()/add_submenu_page().
19 | */
20 |
21 | 'option_key' => 'yourprefix_main_options', // The option key and admin menu page slug.
22 | // 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
23 | // 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
24 | // 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
25 | // 'capability' => 'manage_options', // Cap required to view options-page.
26 | // 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
27 | // 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
28 | // 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
29 | // 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
30 | // 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
31 | // 'message_cb' => 'yourprefix_options_page_message_callback',
32 | ) );
33 |
34 | /**
35 | * Options fields ids only need
36 | * to be unique within this box.
37 | * Prefix is not needed.
38 | */
39 | $main_options->add_field( array(
40 | 'name' => esc_html__( 'Site Background Color', 'cmb2' ),
41 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
42 | 'id' => 'bg_color',
43 | 'type' => 'colorpicker',
44 | 'default' => '#ffffff',
45 | ) );
46 |
47 | /**
48 | * Registers secondary options page, and set main item as parent.
49 | */
50 | $secondary_options = new_cmb2_box( array(
51 | 'id' => 'yourprefix_secondary_options_page',
52 | 'title' => esc_html__( 'Secondary Options', 'cmb2' ),
53 | 'object_types' => array( 'options-page' ),
54 | 'option_key' => 'yourprefix_secondary_options',
55 | 'parent_slug' => 'yourprefix_main_options',
56 | ) );
57 |
58 | $secondary_options->add_field( array(
59 | 'name' => esc_html__( 'Test Radio', 'cmb2' ),
60 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
61 | 'id' => 'radio',
62 | 'type' => 'radio',
63 | 'options' => array(
64 | 'option1' => esc_html__( 'Option One', 'cmb2' ),
65 | 'option2' => esc_html__( 'Option Two', 'cmb2' ),
66 | 'option3' => esc_html__( 'Option Three', 'cmb2' ),
67 | ),
68 | ) );
69 |
70 | /**
71 | * Registers tertiary options page, and set main item as parent.
72 | */
73 | $tertiary_options = new_cmb2_box( array(
74 | 'id' => 'yourprefix_tertiary_options_page',
75 | 'title' => esc_html__( 'Tertiary Options', 'cmb2' ),
76 | 'object_types' => array( 'options-page' ),
77 | 'option_key' => 'yourprefix_tertiary_options',
78 | 'parent_slug' => 'yourprefix_main_options',
79 | ) );
80 |
81 | $tertiary_options->add_field( array(
82 | 'name' => esc_html__( 'Test Text Area for Code', 'cmb2' ),
83 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
84 | 'id' => 'textarea_code',
85 | 'type' => 'textarea_code',
86 | ) );
87 |
88 | }
89 | add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
90 |
--------------------------------------------------------------------------------
/options-and-settings-pages/options-pages-with-tabs-and-submenus.php:
--------------------------------------------------------------------------------
1 | 'yourprefix_main_options_page',
12 | 'title' => 'Main Options',
13 | 'object_types' => array( 'options-page' ),
14 | 'option_key' => 'yourprefix_main_options',
15 | 'tab_group' => 'yourprefix_main_options',
16 | 'tab_title' => 'Main',
17 | );
18 |
19 | // 'tab_group' property is supported in > 2.4.0.
20 | if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
21 | $args['display_cb'] = 'yourprefix_options_display_with_tabs';
22 | }
23 |
24 | $main_options = new_cmb2_box( $args );
25 |
26 | /**
27 | * Options fields ids only need
28 | * to be unique within this box.
29 | * Prefix is not needed.
30 | */
31 | $main_options->add_field( array(
32 | 'name' => 'Site Background Color',
33 | 'desc' => 'field description (optional)',
34 | 'id' => 'bg_color',
35 | 'type' => 'colorpicker',
36 | 'default' => '#ffffff',
37 | ) );
38 |
39 | /**
40 | * Registers secondary options page, and set main item as parent.
41 | */
42 | $args = array(
43 | 'id' => 'yourprefix_secondary_options_page',
44 | 'menu_title' => 'Secondary Options', // Use menu title, & not title to hide main h2.
45 | 'object_types' => array( 'options-page' ),
46 | 'option_key' => 'yourprefix_secondary_options',
47 | 'parent_slug' => 'yourprefix_main_options',
48 | 'tab_group' => 'yourprefix_main_options',
49 | 'tab_title' => 'Secondary',
50 | );
51 |
52 | // 'tab_group' property is supported in > 2.4.0.
53 | if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
54 | $args['display_cb'] = 'yourprefix_options_display_with_tabs';
55 | }
56 |
57 | $secondary_options = new_cmb2_box( $args );
58 |
59 | $secondary_options->add_field( array(
60 | 'name' => 'Test Radio',
61 | 'desc' => 'field description (optional)',
62 | 'id' => 'radio',
63 | 'type' => 'radio',
64 | 'options' => array(
65 | 'option1' => 'Option One',
66 | 'option2' => 'Option Two',
67 | 'option3' => 'Option Three',
68 | ),
69 | ) );
70 |
71 | /**
72 | * Registers tertiary options page, and set main item as parent.
73 | */
74 | $args = array(
75 | 'id' => 'yourprefix_tertiary_options_page',
76 | 'menu_title' => 'Tertiary Options', // Use menu title, & not title to hide main h2.
77 | 'object_types' => array( 'options-page' ),
78 | 'option_key' => 'yourprefix_tertiary_options',
79 | 'parent_slug' => 'yourprefix_main_options',
80 | 'tab_group' => 'yourprefix_main_options',
81 | 'tab_title' => 'Tertiary',
82 | );
83 |
84 | // 'tab_group' property is supported in > 2.4.0.
85 | if ( version_compare( CMB2_VERSION, '2.4.0' ) ) {
86 | $args['display_cb'] = 'yourprefix_options_display_with_tabs';
87 | }
88 |
89 | $tertiary_options = new_cmb2_box( $args );
90 |
91 | $tertiary_options->add_field( array(
92 | 'name' => 'Test Text Area for Code',
93 | 'desc' => 'field description (optional)',
94 | 'id' => 'textarea_code',
95 | 'type' => 'textarea_code',
96 | ) );
97 |
98 | }
99 | add_action( 'cmb2_admin_init', 'yourprefix_register_main_options_metabox' );
100 |
101 | /**
102 | * A CMB2 options-page display callback override which adds tab navigation among
103 | * CMB2 options pages which share this same display callback.
104 | *
105 | * @param CMB2_Options_Hookup $cmb_options The CMB2_Options_Hookup object.
106 | */
107 | function yourprefix_options_display_with_tabs( $cmb_options ) {
108 | $tabs = yourprefix_options_page_tabs( $cmb_options );
109 | ?>
110 |
111 |
112 |
113 |
114 |
115 | $tab_title ) : ?>
116 |
117 |
118 |
119 |
124 |
125 | cmb->prop( 'tab_group' );
138 | $tabs = array();
139 |
140 | foreach ( CMB2_Boxes::get_all() as $cmb_id => $cmb ) {
141 | if ( $tab_group === $cmb->prop( 'tab_group' ) ) {
142 | $tabs[ $cmb->options_page_keys()[0] ] = $cmb->prop( 'tab_title' )
143 | ? $cmb->prop( 'tab_title' )
144 | : $cmb->prop( 'title' );
145 | }
146 | }
147 |
148 | return $tabs;
149 | }
150 |
--------------------------------------------------------------------------------
/options-and-settings-pages/submenu-options-pages.php:
--------------------------------------------------------------------------------
1 | 'yourprefix_options_submenu_page',
13 | 'title' => esc_html__( 'Page Options', 'cmb2' ),
14 | 'object_types' => array( 'options-page' ),
15 |
16 | /*
17 | * The following parameters are specific to the options-page box
18 | * Several of these parameters are passed along to add_menu_page()/add_submenu_page().
19 | */
20 |
21 | 'option_key' => 'yourprefix_page_options', // The option key and admin menu page slug.
22 | // 'icon_url' => '', // Menu icon. Only applicable if 'parent_slug' is left empty.
23 | // 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
24 | 'parent_slug' => 'edit.php?post_type=page', // Make options page a submenu item of the themes menu.
25 | // 'capability' => 'manage_options', // Cap required to view options-page.
26 | // 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
27 | // 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
28 | // 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
29 | // 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
30 | // 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
31 | // 'message_cb' => 'yourprefix_options_page_message_callback',
32 | ) );
33 |
34 | $cmb->add_field( array(
35 | 'name' => esc_html__( 'Background Color for Pages', 'cmb2' ),
36 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
37 | 'id' => 'bg_color',
38 | 'type' => 'colorpicker',
39 | 'default' => '#ffffff',
40 | ) );
41 |
42 | }
43 | add_action( 'cmb2_admin_init', 'yourprefix_register_options_submenu_for_page_post_type' );
44 |
45 | /**
46 | * Hook in and register a submenu options page for the Appearance menu.
47 | */
48 | function yourprefix_register_options_submenu_appearance_menu() {
49 |
50 | /**
51 | * Registers options page menu item and form.
52 | */
53 | $cmb_options = new_cmb2_box( array(
54 | 'id' => 'yourprefix_options_submenu_appearance_menu',
55 | 'title' => esc_html__( 'Appearance Options', 'cmb2' ),
56 | 'object_types' => array( 'options-page' ),
57 |
58 | /*
59 | * The following parameters are specific to the options-page box
60 | * Several of these parameters are passed along to add_menu_page()/add_submenu_page().
61 | */
62 |
63 | 'option_key' => 'yourprefix_theme_appearance_options', // The option key and admin menu page slug.
64 | // 'icon_url' => '', // Menu icon. Only applicable if 'parent_slug' is left empty.
65 | // 'menu_title' => esc_html__( 'Options', 'cmb2' ), // Falls back to 'title' (above).
66 | 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
67 | // 'capability' => 'manage_options', // Cap required to view options-page.
68 | // 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
69 | // 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
70 | // 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
71 | // 'save_button' => esc_html__( 'Save Theme Options', 'cmb2' ), // The text for the options-page save button. Defaults to 'Save'.
72 | // 'disable_settings_errors' => true, // On settings pages (not options-general.php sub-pages), allows disabling.
73 | // 'message_cb' => 'yourprefix_options_page_message_callback',
74 | ) );
75 |
76 | /**
77 | * Options fields ids only need
78 | * to be unique within this box.
79 | * Prefix is not needed.
80 | */
81 | $cmb_options->add_field( array(
82 | 'name' => esc_html__( 'Site Background Color', 'cmb2' ),
83 | 'desc' => esc_html__( 'field description (optional)', 'cmb2' ),
84 | 'id' => 'bg_color',
85 | 'type' => 'colorpicker',
86 | 'default' => '#ffffff',
87 | ) );
88 |
89 | }
90 | add_action( 'cmb2_admin_init', 'yourprefix_register_options_submenu_appearance_menu' );
91 |
--------------------------------------------------------------------------------
/options-and-settings-pages/theme-options-cmb.php:
--------------------------------------------------------------------------------
1 | 'myprefix_option_metabox',
20 | 'title' => esc_html__( 'Site Options', 'myprefix' ),
21 | 'object_types' => array( 'options-page' ),
22 |
23 | /*
24 | * The following parameters are specific to the options-page box
25 | * Several of these parameters are passed along to add_menu_page()/add_submenu_page().
26 | */
27 |
28 | 'option_key' => 'myprefix_options', // The option key and admin menu page slug.
29 | // 'icon_url' => 'dashicons-palmtree', // Menu icon. Only applicable if 'parent_slug' is left empty.
30 | // 'menu_title' => esc_html__( 'Options', 'myprefix' ), // Falls back to 'title' (above).
31 | // 'parent_slug' => 'themes.php', // Make options page a submenu item of the themes menu.
32 | // 'capability' => 'manage_options', // Cap required to view options-page.
33 | // 'position' => 1, // Menu position. Only applicable if 'parent_slug' is left empty.
34 | // 'admin_menu_hook' => 'network_admin_menu', // 'network_admin_menu' to add network-level options page.
35 | // 'display_cb' => false, // Override the options-page form output (CMB2_Hookup::options_page_output()).
36 | // 'save_button' => esc_html__( 'Save Theme Options', 'myprefix' ), // The text for the options-page save button. Defaults to 'Save'.
37 | ) );
38 |
39 | /*
40 | * Options fields ids only need
41 | * to be unique within this box.
42 | * Prefix is not needed.
43 | */
44 |
45 | $cmb_options->add_field( array(
46 | 'name' => __( 'Test Text', 'myprefix' ),
47 | 'desc' => __( 'field description (optional)', 'myprefix' ),
48 | 'id' => 'test_text',
49 | 'type' => 'text',
50 | 'default' => 'Default Text',
51 | ) );
52 |
53 | $cmb_options->add_field( array(
54 | 'name' => __( 'Test Color Picker', 'myprefix' ),
55 | 'desc' => __( 'field description (optional)', 'myprefix' ),
56 | 'id' => 'test_colorpicker',
57 | 'type' => 'colorpicker',
58 | 'default' => '#bada55',
59 | ) );
60 |
61 | }
62 |
63 | /**
64 | * Wrapper function around cmb2_get_option
65 | * @since 0.1.0
66 | * @param string $key Options array key
67 | * @param mixed $default Optional default value
68 | * @return mixed Option value
69 | */
70 | function myprefix_get_option( $key = '', $default = false ) {
71 | if ( function_exists( 'cmb2_get_option' ) ) {
72 | // Use cmb2_get_option as it passes through some key filters.
73 | return cmb2_get_option( 'myprefix_options', $key, $default );
74 | }
75 |
76 | // Fallback to get_option if CMB2 is not loaded yet.
77 | $opts = get_option( 'myprefix_options', $default );
78 |
79 | $val = $default;
80 |
81 | if ( 'all' == $key ) {
82 | $val = $opts;
83 | } elseif ( is_array( $opts ) && array_key_exists( $key, $opts ) && false !== $opts[ $key ] ) {
84 | $val = $opts[ $key ];
85 | }
86 |
87 | return $val;
88 | }
89 |
--------------------------------------------------------------------------------
/user-meta-and-settings/README.md:
--------------------------------------------------------------------------------
1 | User Meta and Settings
2 | ==========
3 |
4 | These are examples of [using CMB2 to generate user fields](https://github.com/WebDevStudios/CMB2/wiki/Adding-metaboxes-to-user-profile).
--------------------------------------------------------------------------------
/widgets/widget-example.php:
--------------------------------------------------------------------------------
1 | widget_slug,
69 | esc_html__( 'CMB2 Widget Boilerplate Title', 'your-textdomain' ),
70 | array(
71 | 'classname' => $this->widget_slug,
72 | 'customize_selective_refresh' => true,
73 | 'description' => esc_html__( 'A CMB2 widget boilerplate description.', 'your-textdomain' ),
74 | )
75 | );
76 |
77 | self::$defaults = array(
78 | 'title' => esc_html__( 'CMB2 Widget Title', 'your-textdomain' ),
79 | 'image' => '',
80 | 'desc' => '',
81 | 'color' => '#bada55',
82 | );
83 |
84 | $this->cmb2_fields = array(
85 | array(
86 | 'name' => 'Title',
87 | 'id_key' => 'title',
88 | 'id' => 'title',
89 | 'type' => 'text',
90 | ),
91 | array(
92 | 'name' => 'Image',
93 | 'desc' => 'Upload an image or enter an URL.',
94 | 'id_key' => 'image',
95 | 'id' => 'image',
96 | 'type' => 'file',
97 | 'options' => array(
98 | 'url' => false
99 | ),
100 | 'text' => array(
101 | 'add_upload_file_text' => 'Upload An Image'
102 | ),
103 | ),
104 | array(
105 | 'name' => 'Description',
106 | 'id_key' => 'desc',
107 | 'id' => 'desc',
108 | 'type' => 'textarea',
109 | ),
110 | array(
111 | 'name' => 'Color',
112 | 'id_key' => 'color',
113 | 'id' => 'color',
114 | 'type' => 'colorpicker',
115 | ),
116 | );
117 |
118 | add_action( 'save_post', array( $this, 'flush_widget_cache' ) );
119 | add_action( 'deleted_post', array( $this, 'flush_widget_cache' ) );
120 | add_action( 'switch_theme', array( $this, 'flush_widget_cache' ) );
121 | add_shortcode( self::$shortcode, array( __CLASS__, 'get_widget' ) );
122 | }
123 |
124 | /**
125 | * Delete this widget's cache.
126 | *
127 | * Note: Could also delete any transients
128 | * delete_transient( 'some-transient-generated-by-this-widget' );
129 | */
130 | public function flush_widget_cache() {
131 | wp_cache_delete( $this->id, 'widget' );
132 | }
133 |
134 | /**
135 | * Front-end display of widget.
136 | *
137 | * @param array $args The widget arguments set up when a sidebar is registered.
138 | * @param array $instance The widget settings as set by user.
139 | */
140 | public function widget( $args, $instance ) {
141 |
142 | echo self::get_widget( array(
143 | 'args' => $args,
144 | 'instance' => $instance,
145 | 'cache_id' => $this->id, // whatever the widget id is
146 | ) );
147 |
148 | }
149 |
150 | /**
151 | * Return the widget/shortcode output
152 | *
153 | * @param array $atts Array of widget/shortcode attributes/args
154 | * @return string Widget output
155 | */
156 | public static function get_widget( $atts ) {
157 | $widget = '';
158 |
159 | // Set up default values for attributes
160 | $atts = shortcode_atts(
161 | array(
162 | // Ensure variables
163 | 'instance' => array(),
164 | 'before_widget' => '',
165 | 'after_widget' => '',
166 | 'before_title' => '',
167 | 'after_title' => '',
168 | 'cache_id' => '',
169 | 'flush_cache' => isset( $_GET['delete-trans'] ), // Check for cache-buster
170 | ),
171 | isset( $atts['args'] ) ? (array) $atts['args'] : array(),
172 | self::$shortcode
173 | );
174 |
175 | $instance = shortcode_atts(
176 | self::$defaults,
177 | ! empty( $atts['instance'] ) ? (array) $atts['instance'] : array(),
178 | self::$shortcode
179 | );
180 |
181 | /*
182 | * If cache_id is not passed, we're not using the widget (but the shortcode),
183 | * so generate a hash cache id from the shortcode arguments
184 | */
185 | if ( empty( $atts['cache_id'] ) ) {
186 | $atts['cache_id'] = md5( serialize( $atts ) );
187 | }
188 |
189 | // Get from cache unless being requested not to
190 | $widget = ! $atts['flush_cache']
191 | ? wp_cache_get( $atts['cache_id'], 'widget' )
192 | : '';
193 |
194 | // If $widget is empty, rebuild our cache
195 | if ( empty( $widget ) ) {
196 |
197 | $widget = '';
198 |
199 | // Before widget hook
200 | $widget .= $atts['before_widget'];
201 |
202 | $widget .= '';
203 |
204 | // Title
205 | $widget .= ( $instance['title'] ) ? $atts['before_title'] . esc_html( $instance['title'] ) . $atts['after_title'] : '';
206 |
207 | $widget .= wpautop( wp_kses_post( $instance['desc'] ) );
208 |
209 | $widget .= '
';
210 |
211 | // After widget hook
212 | $widget .= $atts['after_widget'];
213 |
214 | wp_cache_set( $atts['cache_id'], $widget, 'widget', WEEK_IN_SECONDS );
215 |
216 | }
217 |
218 | return $widget;
219 | }
220 |
221 | /**
222 | * Update form values as they are saved.
223 | *
224 | * @param array $new_instance New settings for this instance as input by the user.
225 | * @param array $old_instance Old settings for this instance.
226 | * @return array Settings to save or bool false to cancel saving.
227 | */
228 | public function update( $new_instance, $old_instance ) {
229 | $this->flush_widget_cache();
230 | $sanitized = $this->cmb2( true )->get_sanitized_values( $new_instance );
231 | return $sanitized;
232 | }
233 | /**
234 | * Back-end widget form with defaults.
235 | *
236 | * @param array $instance Current settings.
237 | */
238 | public function form( $instance ) {
239 | // If there are no settings, set up defaults
240 | $this->_instance = wp_parse_args( (array) $instance, self::$defaults );
241 |
242 | $cmb2 = $this->cmb2();
243 |
244 | $cmb2->object_id( $this->option_name );
245 | CMB2_hookup::enqueue_cmb_css();
246 | CMB2_hookup::enqueue_cmb_js();
247 | $cmb2->show_form();
248 | }
249 |
250 | /**
251 | * Creates a new instance of CMB2 and adds some fields
252 | * @since 0.1.0
253 | * @return CMB2
254 | */
255 | public function cmb2( $saving = false ) {
256 |
257 | // Create a new box in the class
258 | $cmb2 = new CMB2( array(
259 | 'id' => $this->option_name .'_box', // Option name is taken from the WP_Widget class.
260 | 'hookup' => false,
261 | 'show_on' => array(
262 | 'key' => 'options-page', // Tells CMB2 to handle this as an option
263 | 'value' => array( $this->option_name )
264 | ),
265 | ), $this->option_name );
266 |
267 | foreach ( $this->cmb2_fields as $field ) {
268 |
269 | if ( ! $saving ) {
270 | $field['id'] = $this->get_field_name( $field['id'] );
271 | }
272 |
273 | $field['default_cb'] = array( $this, 'default_cb' );
274 |
275 | $cmb2->add_field( $field );
276 | }
277 |
278 | return $cmb2;
279 | }
280 |
281 | /**
282 | * Sets the field default, or the field value.
283 | *
284 | * @param array $field_args CMB2 field args array
285 | * @param CMB2_Field $field CMB2 Field object.
286 | *
287 | * @return mixed Field value.
288 | */
289 | public function default_cb( $field_args, $field ) {
290 | return isset( $this->_instance[ $field->args( 'id_key' ) ] )
291 | ? $this->_instance[ $field->args( 'id_key' ) ]
292 | : null;
293 | }
294 |
295 | }
296 |
297 | /**
298 | * Register this widget with WordPress.
299 | */
300 | function register_wds_widget_boilerplate() {
301 | register_widget( 'CMB2_Widget_Boilerplate' );
302 | }
303 | add_action( 'widgets_init', 'register_wds_widget_boilerplate' );
304 |
--------------------------------------------------------------------------------