Meta box controls — checkbox and radio buttons

I already made a tutorial about meta boxes. In the tutorial I covered color picker control, and a cross between repeater field and related pages control. It was pointed out to me that I should cover as much of the controls that can be placed in a meta box as possible. So I wrote some of them down and thought to myself — here are nice 3 or 4 articles I can write! Cool. And then I was swamped with other stuff I have going on and I just couldn’t get myself to sit down and write an article.
 But I finally found some time so here we are :)

The first article in the series will cover radio boxes and check boxes. They might seem like an easy thing to add, but they can be tricky. I’ll also put a simple input field in, for a good measure. Let’s get started.

Prerequisites

I’ll be placing my code in functions.php file, because of the convenience. But you can easily add the code in a separate php file that you’ll include through your functions.php file. First we need to use the add_meta_box() function. We are going to hook to add_meta_boxes action

add_action( 'add_meta_boxes', 'mytheme_add_meta_box' );

if ( ! function_exists( 'mytheme_add_meta_box' ) ) {
/**
* Add meta box to page screen
*
* This function handles the addition of variuos meta boxes to your page or post screens.
* You can add as many meta boxes as you want, but as a rule of thumb it's better to add
* only what you need. If you can logically fit everything in a single metabox then add
* it in a single meta box, rather than putting each control in a separate meta box.
*
* @since 1.0.0
*/
function mytheme_add_meta_box() {
add_meta_box( 'additional-page-metabox-options', esc_html__( 'Metabox Controls', 'mytheme' ), 'mytheme_metabox_controls', 'page', 'normal', 'low' );
}
}

As a precaution, we are wrapping it all up in a function_exists() check. Inside the function you can add as many meta boxes as you want to. In the function you’ll add the unique meta box id (additional-page-metabox-options), the name of the meta box (esc_html__( ‘Metabox Controls’, ‘mytheme’ )), the callback function that will actually render the meta box (mytheme_metabox_controls), whether you’ll like to put the metabox on the page or post screen (here we are adding one on the page screen), the context and priority of it (normal and low).

Now that we have that we can add the callback function.

Adding the controls

In the callback function that we defined in the add_meta_box() function we will add our HTML that will render the controls. In our case these will be simple input types — text, radio box and checkbox. We can also style them as we see fit. But where are we actually saving these settings? Well since everything in WordPress is based around post types — the post is just post post type, page is a different post type, navigation as well and we can make our own custom post types, we are ‘binding’ our meta box controls to every single post. So every post can have different controls checked out or not. We can add an input field, or a textarea in the same manner, that will show some small intro or info of our posts or pages. Every post or page will have its own different info text. This is done by creating a post meta. So every control is a certain post meta data that we attach to our posts or pages.

This is why we will define variables that will check if the post data, for a certain control, exists or not. That way when we save the post data, we can immediately see it selected (or written) in our custom fields in the meta box.

if ( ! function_exists( 'mytheme_metabox_controls' ) ) {
/**
* Meta box render function
*
* @param object $post Post object.
* @since 1.0.0
*/
function mytheme_metabox_controls( $post ) {
$meta = get_post_meta( $post->ID );
$mytheme_input_field = ( isset( $meta['mytheme_input_field'][0] ) && '' !== $meta['mytheme_input_field'][0] ) ? $meta['mytheme_input_field'][0] : '';
$mytheme_radio_value = ( isset( $meta['mytheme_radio_value'][0] ) && '' !== $meta['mytheme_radio_value'][0] ) ? $meta['mytheme_radio_value'][0] : '';
$mytheme_checkbox_value = ( isset( $meta['mytheme_checkbox_value'][0] ) && '1' === $meta['mytheme_checkbox_value'][0] ) ? 1 : 0;
wp_nonce_field( 'mytheme_control_meta_box', 'mytheme_control_meta_box_nonce' ); // Always add nonce to your meta boxes!
?>
<style type="text/css">
.post_meta_extras p{margin: 20px;}
.post_meta_extras label{display:block; margin-bottom: 10px;}
</style>
<div class="post_meta_extras">
<p>
<label><?php esc_attr_e( 'Input text', 'mytheme' ); ?></label>
<input type="text" name="mytheme_input_field" value="<?php echo esc_attr( $mytheme_input_field ); ?>">
</p>
<p>
<label>
<input type="radio" name="mytheme_radio_value" value="value_1" <?php checked( $mytheme_radio_value, 'value_1' ); ?>>
<?php esc_attr_e( 'Radio value 1', 'mytheme' ); ?>
</label>
<label>
<input type="radio" name="mytheme_radio_value" value="value_2" <?php checked( $mytheme_radio_value, 'value_2' ); ?>>
<?php esc_attr_e( 'Radio value 2', 'mytheme' ); ?>
</label>
<label>
<input type="radio" name="mytheme_radio_value" value="value_3" <?php checked( $mytheme_radio_value, 'value_3' ); ?>>
<?php esc_attr_e( 'Radio value 3', 'mytheme' ); ?>
</label>
</p>
<p>
<label><input type="checkbox" name="mytheme_checkbox_value" value="1" <?php checked( $mytheme_checkbox_value, 1 ); ?> /><?php esc_attr_e( 'Checkbox value', 'mytheme' ); ?></label>
</p>
<?php
}
}

First we need to fetch all the post meta values for the current post. Then we define our variables that we’ll use in our HTML below. And remember: every time you create a meta box, you need to include a nonce. They are security measure that will prevent any possible malicious tempering with the fields. Next we create our controls. You can see the previously defined variables — in the input field I’ve escaped the text using esc_attr() function, if you wish to include any kind of HTML, I recommend the wp_kses_post() function, since esc_attr() strips all the html out.

For the radio boxes and checkbox we are using WordPress built in checked function.

Saving the meta boxes

We have our meta boxes ready, but we still need to save the values within our inputs. For that we need to hook into save_post hook. This hook fires any time a post or a page is saved, so we are using that to our advantage.

add_action( 'save_post', 'mytheme_save_metaboxes' );

if ( ! function_exists( 'mytheme_save_metaboxes' ) ) {
/**
* Save controls from the meta boxes
*
* @param int $post_id Current post id.
* @since 1.0.0
*/
function mytheme_save_metaboxes( $post_id ) {
/*
* We need to verify this came from the our screen and with proper authorization,
* because save_post can be triggered at other times. Add as many nonces, as you
* have metaboxes.
*/
if ( ! isset( $_POST['mytheme_control_meta_box_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['mytheme_control_meta_box_nonce'] ), 'mytheme_control_meta_box' ) ) { // Input var okay.
return $post_id;
}

// Check the user's permissions.
if ( isset( $_POST['post_type'] ) && 'page' === $_POST['post_type'] ) { // Input var okay.
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}

/*
* If this is an autosave, our form has not been submitted,
* so we don't want to do anything.
*/
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}

/* Ok to save */

if ( isset( $_POST['mytheme_input_field'] ) ) { // Input var okay.
update_post_meta( $post_id, 'mytheme_input_field', sanitize_text_field( wp_unslash( $_POST['mytheme_input_field'] ) ) ); // Input var okay.
}

if ( isset( $_POST['mytheme_radio_value'] ) ) { // Input var okay.
update_post_meta( $post_id, 'mytheme_radio_value', sanitize_text_field( wp_unslash( $_POST['mytheme_radio_value'] ) ) ); // Input var okay.
}

$mytheme_checkbox_value = ( isset( $_POST['mytheme_checkbox_value'] ) && '1' === $_POST['mytheme_checkbox_value'] ) ? 1 : 0; // Input var okay.
update_post_meta( $post_id, 'mytheme_checkbox_value', esc_attr( $mytheme_checkbox_value ) );

}
}

First we need to check our nonce. If the nonce check fails, we won’t save the meta data. The //Input var okay. comment at the end is for code sniffer purposes. After that we are checking if the user has permissions to save the post (page). Also we do not want to save our meta data on auto save. WordPress will periodically, unless we disable it, make an auto save of our post (for recovery purposes). The DOING_AUTOSAVE constant will be defined true within the wp_autosave() function.
 After all the checks have passed we can save our post meta. Always sanitize your input values — post meta gets written to the post_meta table in our database, so we want to make sure no malicious code can get in there. Likewise we are always escaping on the output — to prevent any malicious code being outputted on our page.
 For the checkbox we first need to see if the POST variable is defined and set to 1, so that we can put that in the variable that will be placed as a value of our post meta for the checkbox. Checkboxes are a bit different because if the checkbox input isn’t checked, on the form submit it looks like it doesn’t exist. That’s why we are using this intermediate step with our variable — we want to put either 0 or 1 in the post meta for the checkbox control so that we can use it in our theme.

With the minimal amount of styling our meta box looks like this

Meta box custom controls

Our custom defined meta box controls ready to be used

Using the controls

We have our controls, they can be saved, so we want to use them, right?

Well it’s actually really easy. All you need to use is the function get_post_meta(). In it you need to specify the post id from which you want to get the saved meta data, you can specify the exact post meta to fetch, and you can choose if you want to return the single value or not

get_post_meta( int $post_id, string $key = '', bool $single = false )

The post meta is usually fetched within the loop, so all you need to use is the built in get_the_ID() function. In the case of our input field the correct code will be

$input_text = get_post_meta( get_the_ID(), 'mytheme_input_field', true );

Mind you that we are within the loop. You can use it outside of it, but you’ll need to fetch the post ID somehow. So to actually use the text the best thing to do is to make a check if it’s not empty and if it’s set

if ( isset( $input_text ) && '' !== $input_text ) {
echo esc_attr( $input_text );
}

The same would apply to our radio and checkbox fields, with the exception that you’d be checking if the value of the checkbox meta data is not 0 (or is equal to 1).

And that is it for the start of the meta box controls tutorial, I hope you find it useful. If you have any questions feel free to ask it in the comments below, and as always, happy coding :)


Originally published at Made by Denis.