Looping through meta box’s fields

Before 4.8, if you register the meta boxes using the old way (with admin_init hook), you could loop through the ['fields'] keys of the global variable $meta_boxes to get all fields registered for a meta box. Here is an example of the old way:

global $meta_boxes;
if ( isset( $meta_boxes['meta_box_id']['fields'] ) ) {
    foreach ( $meta_boxes['meta_box_id']['fields'] ) as $key ) {
        $value = rwmb_meta( $key['id'] );
        if ( ! empty($value) ) {
            echo '<label>' . $key['name'] . '</label> ' . $value;
        }
    }
}

This loop was very handy if your meta box has, say, 20 fields.

Since 4.8, the $meta_boxes is not used as a global variable anymore. You’re recommended to use rwmb_meta_boxes to register meta boxes and fields. But it’s still pretty easy to loop through the Meta-Box-only field keys using RWMB_Core::get_meta_boxes() function. The code is almost identical:

$meta_boxes = RWMB_Core::get_meta_boxes();
if ( isset( $meta_boxes['meta_box_id']['fields'] ) ) {
    foreach ( $meta_boxes['meta_box_id']['fields'] ) as $key ) {
        $value = rwmb_meta( $key['id'] );
        if ( ! empty($value) ) {
            echo '<label>' . $key['name'] . '</label> ' . $value;
        }
    }
}

Note: Without this function you would be trying to loop through ALL post meta, and there may be WordPress meta fields that are not part of your Meta Box, and you don’t want those. Without the core function, to retrieve only the values for your meta box with get_post_meta, you would have to know and re-list all the field keys separately in your code.

How to create nested array field with Meta Box Builder

Did you used some advanced fields like Post, Taxonomy, Date picker…? You can define these field easily with nested array but how to do it with Meta Box Builder?

Imagine you want to create a Post field like so:

https://gist.github.com/tanng/a776f381f5e44c0c2828

Prior to version 1.2, to create a nested array in Meta Box Builder, you can use JSON, encode the whole array of tax_query and paste to it value. Like so:

JSON value

From 1.2, you can use dot notation to define an array. For that tax_query above. We can define with dot notation like so:

Dot notation

Please note that I use tax_query.0.taxonomy, tax_query.0.field, and tax_query.0.terms because the taxonomy named category, the field named slug and the term named technology are belong to the first (and only one) array of tax_query, not directly belongs to tax_query.

How post meta is saved in the database?

Wondering how the Meta Box plugin stores meta values in the database? This documentation will explain how the plugin store custom fields’ values in the wp_postmeta table.

For non-cloneable fields

For non-cloneable fields, e.g. with no clone attribute or has it set to false, the plugin stores all meta data in the data base in a WordPress-compatible way as following:

  • If field has single value, it will be saved in single row of wp_postmeta table;
  • If field has multiple values (set by 'multiple' => true like select, checkbox_list, file, image, etc.), each value will be saved in single row of wp_postmeta table

This way you can use add_post_meta or update_post_meta to update meta values and get_post_meta to retrieve them. There’s nothing different from using these functions for Meta Box and for other custom fields at all.

For cloneable fields

For cloneable fields, cloned values are stored as a serialized array in a single row in the wp_postmeta table. The plugin does not to store cloned values in separated rows in the database because it’s confusing that we don’t know these are values of clones, or values of the field with 'multiple' => true. To make it work for all field types and for consistency, storing cloned values in a single row of the database is a better choice.

Due to this reason, you still can use get_post_meta function to retrieve meta value from the database (WordPress automatically unserializes string and returns an array). You will get an array of all cloned values.

Specific fields

For normal fields, the values saved in the database is the value entered or selected by users. But for some specific fields, the values store is not as obvious as that. The detail is listed below.

Field TypeValue stored in the database
file, file_advanced, image, image_select, plupload_image, thickbox_imageAttachment IDs. Note that these fields are always multiple.
mapA comma separated string of “latitude,longitude”.
passwordA hash of password since 4.8.0 using wp_hash_password() function. Previously it stores simple plan text password.
postPost ID
taxonomyNothing is stored in the database. This field only sets terms for the post.
taxonomy_advancedA comma separated string of term IDs.
userUser ID

Notes

Although you can use get_post_meta to retrieve meta value, it’s recommended to use plugin’s helper function to get the value and display it in the frontend. The helper function takes care of all the logic above and returns to you the needed data in a correct format.

To understand how the value is stored in the database, please use print_r function, like this:

$value = get_post_meta( get_the_ID(), 'field_id', true ); // Last param should be 'false' if field is multiple
print_r( $value );

How to create Columns in Meta Box Builder?

Did you know, Meta Box Builder has Custom Attribute feature can bring you a flexible way to create WordPress custom meta box fields and you can create columns also?

To apply columns style for your custom fields, on your field in Edit Meta Box page, click “Show Advanced” to show Custom Attribute section then click “Add Attribute”.

Meta Box Builder Custom Attributes

On the key textbox, enter columns which will add to columns attribute to that field, and on the value textarea, enter the column size. That’s based on 12 grids system. For example, if you enter 4 to value, then the column will has one third size of row.

After that step, don’t forget to Save Meta Box, see your results.

Note: Meta Box Columns extension is required to create columns.

Edit / remove meta boxes added by a parent theme / plugin?

When you use a WordPress theme or plugin which incorporates with Meta Box, all the information of fields and meta boxes are fixed, such as: meta box title, number of fields, fields’ names and descriptions, … It might be better in some situations when you want to change these texts or add/remove fields to a meta box or even remove a meta box.

Assuming we have 2 meta boxes registered in a WordPress parent theme or a plugin with this code below:

https://gist.github.com/rilwis/1c2738367e34bcf31922#file-register-meta-boxes-php

which are rendered as following:

meta boxes

Now we will:

  • Remove “Personal Information” meta box
  • Change title of “Address Info” meta box to “Address”
  • Add description for field “Street” in “Address” meta box
  • Add field “zip_code” (text field) to “Address” meta box

Our custom code will be put in functions.php file of the child theme (or in a custom plugin if we want).

The principle is simple as following:

  • We hook to rwmb_meta_boxes filter with higher priority than 10 to get all registered meta boxes
  • Then we check meta boxes by ID or title to get the meta boxes we want to edit / remove
  • Remove or change meta boxes information if needed (such as meta box title)
  • For that meta box, we loop through all custom fields and change fields’ info
  • And finally add more fields to that meta box if needed

The code is quite straight as following (with all necessary comments):

https://gist.github.com/rilwis/1c2738367e34bcf31922#file-functions-php

Here is the result:

edit remove meta boxes

Note: It’s always a good practice to set meta box ID (even when it’s optional). In the code above we check meta boxes by ID to get the ones we want to edit or remove. It’s fine to check by meta box title, but it will be harder if the website uses another language and the meta box title is translated.

Create your own field type

Overview

Meta Box plugin is so flexible that you can create your own field type easily. This documentation will show you how to create a new field type with Meta Box plugin.

Let’s create a field type phone which accepts the only phone in format xxx-xxxx.

Define a new field class

We have to create a class name RWMB_Phone_Field for phone field. Generally, if we want to create a new field type, we have to create a class name RWMB_{$field_type}_Field (make sure it has a correct case) extending RWMB_Field class.

if ( class_exists( 'RWMB_Field' ) )
{
    class RWMB_Phone_Field extends RWMB_Field
    {
    }
}

Save this class in a PHP file with any name, assuming field-phone.php. Then include that file in functions.php file of your theme or in plugin’s file:

add_action( 'init', 'prefix_load_phone_type', 1 );

function prefix_load_phone_type()
{
    require 'path/to/field-phone.php';
}
Note: we hook to init to make sure all files of Meta Box plugin is loaded and class RWMB_Field is defined. Priority 1 guarantees this code runs before meta boxes are registered.

Define field’s methods

The phone class inherits all method from RWMB_Field class. The full list of RWMB_Field methods and their description are described in this documentation.

For phone field, we have to define content of html method to define field HTML:

static public function html( $meta, $field )
{
    return sprintf(
        '<input type="tel" name="%s" id="%s" value="%s" pattern="d{3}-d{4}">',
        $field['field_name'],
        $field['id'],
        $meta
    );
}

Here we use new HTML5 input type tel with new attribute pattern to force users to enter correct phone number format xxx-xxxx.

For this field, we don’t need to handle saving or retrieving meta value or enqueueing scripts and styles. Everything is handled in default way (which can be understood like a text field).

The complete code for this class is the following:

https://gist.github.com/rilwis/0491dde925d20f9fff9b

Register fields with new field type

Now we can register fields with phone type, like this:

$meta_boxes[] = array(
    // Meta Box attributes
    'fields' => array(
        array(
            'name' => 'Phone',
            'id'   => 'prefix_phone',
            'type' => 'phone',
        ),
        // Other fields
    ),
);

Now when you go to edit post page, you’ll see a new field like this:

new field type
New field type

That’s all for this simple field type. If you want to create a more complicated field, just overwrite methods from RWMB_Field class. You might want to enqueue scripts and styles, sanitizing field value before saving in the database, etc. The RWMB_Field class has all methods for that you just need to overwrite necessary methods.