search ]

Creating Custom Meta Boxes with CMB2 in WordPress

Not long ago, I was asked to create an FAQ page for one of my clients. My first thought was to create this FAQ’s page using the beloved ACF plugin, but I remembered that one of the commenters on the blog had once suggested that I check out the CMB2 plugin to create custom fields and meta boxes. So I decided it was time to try CMB2 and give a few words about it – it definitely deserves it…

What is CMB2?

The word CMB stands for Custom Meta Boxes, as you probably guessed from the post title. The CMB2 plugin provides WordPress developers with a toolkit for building meta boxes, custom fields, and forms in WordPress.

With CMB2, you can easily manage meta fields for posts, taxonomy terms, users, comments, and even create a settings page for your theme. If you take a look at the plugin page, you’ll find the following definition:

“CMB2 is a meta box, custom fields, and forms library for WordPress that will blow your mind”

The plugin was developed by WebDevStudios and now has over 200,000 active installations and a five-star rating. However, somewhat controversially, there are those who argue that it does not belong in the plugin library and should not be approved by the WordPress Repository.

Why, you ask?

Because in most cases, you can perform some action with WordPress plugins immediately after installation. In most cases, there is a settings screen that comes with the plugin or it performs some functionality behind the scenes. Not so with the CMB2 plugin, and it can be said that CMB2 is actually a framework, not a plugin.

If you install CMB2, nothing will happen – you won’t find a settings screen or user interface for this plugin. To use CMB2, you will have to write code and add it to your functions.php file. That’s why this plugin is actually not a plugin…

But the good news is that it has been approved by the WordPress Repository so you can download and update it like any other plugin. Let’s see how to use it.

Creating a Custom Meta Box Using CMB2

As mentioned, CMB2 allows you to create metaboxes through code. But before we create the first metabox, we need to create a function that we will attach to the action hook named cmb2_init that the plugin provides:

add_action( 'cmb2_init', 'cmb2_add_metabox' );
function cmb2_add_metabox() {

    $prefix = '_yourprefix_';

}

As you can see, we also defined a variable named prefix that needs to be unique.

The reason for using a prefix is to avoid the risk that other plugins or themes will use the same ID to create the same metaboxes.

Then, creating the metabox will be simple like creating a new variable and is done in the following way:

add_action( 'cmb2_init', 'cmb2_add_metabox' );
function cmb2_add_metabox() {

    $prefix = '_yourprefix_';

    $cmb = new_cmb2_box( array(
        'id'           => $prefix . 'metabox',
        'title'        => __( 'Metabox Title', 'cmb2' ),
        'object_types' => array( 'page', 'post' ),
        'context'      => 'normal',
        'priority'     => 'default',
    ) );

}

Notice two important points related to the parameters of the Custom Meta Box we created:

  • In line 7, we used the prefix so that the ID of the metabox would be unique.
  • In line 9, we defined that this metabox would appear in the content types pages and posts using the parameter object_types.

There are many features that you can use when creating a metabox with CMB2. I won’t even try to explain them here but you are invited to take a look at the plugin’s documentation to understand what it’s about.

Adding New Fields to the Custom Meta Box We Created

After creating the first Meta Box, we’ll make it useful by adding a number of fields. The CMB2 plugin allows a wide variety of different fields and the way to add them is quite simple:

$cmb->add_field( array(
    'name' => __( 'My First Text Field', 'cmb2' ),
    'id' => $prefix . 'text_field',
    'type' => 'text',
    'desc' => __( 'My First Text Field Description', 'cmb2' ),
) );

In this case, we added a simple text field to the metabox. However, be aware that the CMB2 plugin has more than 30 types of fields that can be added. Here is the complete code along with several types of field examples (Example A.):

add_action( 'cmb2_init', 'cmb2_sample_metaboxes' );
/**
 * Define the metabox and field configurations.
 */
function cmb2_sample_metaboxes() {

    // Start with an underscore to hide fields from custom fields list
    $prefix = '_yourprefix_';

    /**
     * Initiate the metabox
     */
    $cmb = new_cmb2_box( array(
        'id'            => 'test_metabox',
        'title'         => __( 'Test Metabox', 'cmb2' ),
        'object_types'  => array( 'page', ), // Post type
        'context'       => 'normal',
        'priority'      => 'high',
        'show_names'    => true, // Show field names on the left
        // 'cmb_styles' => false, // false to disable the CMB stylesheet
        // 'closed'     => true, // Keep the metabox closed by default
    ) );

    // Regular text field
    $cmb->add_field( array(
        'name'       => __( 'Test Text', 'cmb2' ),
        'desc'       => __( 'field description (optional)', 'cmb2' ),
        'id'         => $prefix . 'text',
        'type'       => 'text',
        'show_on_cb' => 'cmb2_hide_if_no_cats', // function should return a bool value
        // 'sanitization_cb' => 'my_custom_sanitization', // custom sanitization callback parameter
        // 'escape_cb'       => 'my_custom_escaping',  // custom escaping callback parameter
        // 'on_front'        => false, // Optionally designate a field to wp-admin only
        // 'repeatable'      => true,
    ) );

    // URL text field
    $cmb->add_field( array(
        'name' => __( 'Website URL', 'cmb2' ),
        'desc' => __( 'field description (optional)', 'cmb2' ),
        'id'   => $prefix . 'url',
        'type' => 'text_url',
        // 'protocols' => array('http', 'https', 'ftp', 'ftps', 'mailto', 'news', 'irc', 'gopher', 'nntp', 'feed', 'telnet'), // Array of allowed protocols
        // 'repeatable' => true,
    ) );

    // Email text field
    $cmb->add_field( array(
        'name' => __( 'Test Text Email', 'cmb2' ),
        'desc' => __( 'field description (optional)', 'cmb2' ),
        'id'   => $prefix . 'email',
        'type' => 'text_email',
        // 'repeatable' => true,
    ) );

    // Add other metaboxes as needed

}

There are many more types of fields, and you can find them all on the CMB2 GitHub page. In this context, it should be noted that in the main folder of the plugin there is a file named example-functions.php(you can also find it here) where you can take a look and use it to understand how to create each type of field and even how to use a prefix for them.

You can also use the CMB2 Metabox Code Generator which generates CMB2 metaboxes and fields for you and greatly simplifies the work. In addition, for the fields we create using CMB2, there are many additional parameters that you can use as we previously showed for the metabox itself.

Displaying CMB2 Fields in the Frontend

After we’ve created the new metaboxes and fields within them, we’ll likely want to display them in our theme or plugin. To do this, we must use the get_post_meta() function which will display that metadata we entered in the WordPress admin interface.

To do this, we need to pass the post ID where the fields we created exist, as in the following example:

<?php
// Grab the metadata from the database
$text = get_post_meta( get_the_ID(), '_yourprefix_text', true );

// Echo the metadata
echo esc_html( $text );
?>

Let’s say you want to create a specific single page template that displays all the fields we showed previously (Example A. in the previous section), you can do it in the following way:

<?php
/**
 * Example for Single Page Template that shows CMB2 Fields in your Theme.
**/
get_header(); ?>

        <div id="primary">
            <div id="content" role="main">

                <?php while ( have_posts() ) : the_post(); ?>

                    <?php get_template_part( 'content', 'page' ); ?>

                    <?php
                    $text  = get_post_meta( get_the_ID(), '_yourprefix_text', true );
                    $email = get_post_meta( get_the_ID(), '_yourprefix_email', true );
                    $url   = get_post_meta( get_the_ID(), '_yourprefix_url', true );
                    echo esc_html( $text );
                    echo is_email( $email );
                    echo esc_url( $url );
                    ?>

                    <?php comments_template( '', true ); ?>

                <?php endwhile; // end of the loop. ?>

            </div><!-- #content -->
        </div><!-- #primary -->

<?php get_footer(); ?>

ACF vs CMB2 – Which is Better?

There are advantages and disadvantages to using both plugins. Advanced Custom Fields, for example, comes with many built-in functions such as get_field to retrieve the information. However, these functions make more database calls than using WordPress core functions like get_post_meta.

Moreover, if you disable or remove the ACF plugin (which I really like, don’t get me wrong), there will likely be an error on your site, and the information – which is still in the database, will not appear to the visitor. These issues can be resolved in several ways as I wrote in the following articles:

On the other hand, the CMB2 plugin does not present this problem. It stores the information in the same tables exactly as WordPress core functions do. It does not perform “redundant” database operations, and the information will appear on the site even if you disable the plugin.

Yet, having said all this, we cannot ignore the fact that ACF provides a very convenient interface for us and for the user and also offers very interesting options such as Flexible Content that are not available in CMB2. The percentage of users using ACF is higher than CMB2, and you will find more information online about it and how to use it, which is definitely something to consider.

So to summarize this section – The choice of whether to use Advanced Custom Fields or CMB2 is up to you, depending on the nature of the project and your work habits. Personally – my aspiration is to gradually move to using CMB2 exclusively in new projects.

Tips and Tricks for CMB2

Before we finish the post, and if you haven’t seen enough code in front of your eyes yet – here are several tips that can be useful when using the CMB2 plugin:

1. Overriding Text Strings in Fields – OVERRIDE TEXT STRINGS IN FIELD

Several of the fields in CMB2 include some text and the plugin allows you to override this text with text of your choice. For example, in a field of type file, there is a button with the default text “Add or Upload file”. Here’s how to change this text using the field’s parameters:

$cmb->add_field( array(
    'name'    => 'PDF',
    'id'      => $prefix . 'pdf',
    'type'    => 'file',
    'options' => array(
        'add_upload_file_text' => 'Upload PDF',
    ),
    'query_args' => array(
        'type' => 'application/pdf', // Make library only display PDFs.
    ),
) );

Note the use of the options parameter in line 5.

2. Adding Static Content in a Field – INJECT STATIC CONTENT IN A FIELD

There are several field properties you can use to add content to fields. These parameters are:

  • before_field
  • before_row
  • before
  • after
  • after_row
  • after_field

Using these parameters in the fields you create looks like this:

$cmb->add_field( array(
    'name'         => 'Testing Field Parameters',
    'id'           => $prefix . 'test_parameters',
    'type'         => 'text',
    'before_row'   => '<p>Testing <b>"before_row"</b> parameter</p>',
    'before'       => '<p>Testing <b>"before"</b> parameter</p>',
    'before_field' => '<p>Testing <b>"before_field"</b> parameter</p>',
    'after_field'  => '<p>Testing <b>"after_field"</b> parameter</p>',
    'after'        => '<p>Testing <b>"after"</b> parameter</p>',
    'after_row'    => '<p>Testing <b>"after_row"</b> parameter</p>',
) );

In this case, the result would look like the following image:

Static Content to CMB2 Fields

3. Limiting a Text Field to Numbers Only – LIMIT TEXT FIELD TO NUMBERS ONLY

The functionality is quite understood from the title in this case and there is no need to expand:

$cmb_demo->add_field( array(
    'name' => __( 'My Number Field', 'theme-domain' ),
    'desc' => __( 'Numbers only', 'theme-domain' ),
    'id'   => $prefix . 'number',
    'type' => 'text',
    'attributes' => array(
        'type' => 'number',
        'pattern' => '\d*',
    ),
) );

Summary

That’s it. If you are interested in getting more information about using CMB2, about the types of fields and their parameters, as well as about the features of CMB2 Metaboxes, you are invited to take a look at the following documentation.

I believe I will soon write more about using the plugin, about its Repeater Field and more. I would be very happy if you share your experiences with the plugin in the comments below and don’t forget to give a small like or share that we will go crazy for 😉

Roee Yossef
Roee Yossef

I develop pixel-perfect custom WordPress themes, delivering high-performance, SEO-optimized websites. Have a project in mind? need assistance? Feel free to contact me!

0 Comments...

Leave a Comment

To add code, use the buttons below. For instance, click the PHP button to insert PHP code within the shortcode. If you notice any typos, please let us know!