How to make multicheck for post/page meta box

The post metadata can store multiple values either as distinct entries in the postmeta table, or as one entry with the value as a serialized PHP array. The serialization may require less code, but the distinct entries allow faster querying later (“give me all posts that have at least option A of the multicheck checked”).

I took the code you linked to and made the following changes to allow a “multicheck”:

// in show():
// Line 254: replace it by:
$meta = get_post_meta($post->ID, $field['id'], 'multicheck' != $field['type'] /* If multicheck this can be multiple values */);
// Add the following to the switch:
case 'multicheck':
    foreach ( $field['options'] as $value => $name ) {
        // Append `[]` to the name to get multiple values
        // Use in_array() to check whether the current option should be checked
        echo '<input type="checkbox" name="', $field['id'], '[]" id="', $field['id'], '" value="', $value, '"', in_array( $value, $meta ) ? ' checked="checked"' : '', ' /> ', $name, '<br/>';
    }
    break;

// In save():
// Line 358: replace it by:
$old = get_post_meta($post_id, $name, 'multicheck' != $field['type'] /* If multicheck this can be multiple values */);
// Lines 409-413: Wrap them in an else-clause, and prepend them by:
if ( 'multicheck' == $field['type'] ) {
    // Do the saving in two steps: first get everything we don't have yet
    // Then get everything we should not have anymore
    if ( empty( $new ) ) {
        $new = array();
    }
    $aNewToAdd = array_diff( $new, $old );
    $aOldToDelete = array_diff( $old, $new );
    foreach ( $aNewToAdd as $newToAdd ) {
        add_post_meta( $post_id, $name, $newToAdd, false );
    }
    foreach ( $aOldToDelete as $oldToDelete ) {
        delete_post_meta( $post_id, $name, $oldToDelete );
    }
} else {
    // The original lines 409-413
}

Two extra changes to prevent PHP warnings when WP_DEBUG is enabled:

// Line 337:
if ( ! isset( $_POST['wp_meta_box_nonce'] ) || !wp_verify_nonce($_POST['wp_meta_box_nonce'], basename(__FILE__))) {
// Line 359:
$new = isset( $_POST[$field['id']] ) ? $_POST[$field['id']] : null;

With these changes, you can use a “multicheck” by defining it like this:

array(
    'name' => 'Multicheck',
    'id' => $prefix . 'multicheck',
    'type' => 'multicheck',
    'options' => array(
        'a' => 'Apple',
        'b' => 'Banana',
        'c' => 'Cherry',
    ),
)

Leave a Comment