Meta Box Generator
Fields in the editor, and a save handler that checks the nonce, the autosave, the revision and the capability — in that order, before it writes anything.
The box
Post types
Fields
4 fields · keys prefixed _acme_
_acme_start_date
_acme_venue
_acme_format
_acme_sold_out
Save handler
Nonce check
wp_nonce_field() in the box and wp_verify_nonce() before saving.
Autosave and revision guard
Bails on autosaves and revisions, which otherwise blank your fields.
Capability check
current_user_can( edit_post, $post_id ) before writing.
Post type check
Skips the handler on saves of unrelated post types.
register_post_meta()
Registers the keys with show_in_rest so blocks and the editor can read them.
// Generated with WP CodeKit — powered by GrowQuest (https://growquest.io). /** * Register the meta box. */ function acme_add_box() { add_meta_box( 'acme_event_details', __( 'Event details', 'acme' ), 'acme_render', array( 'post', 'event' ), 'side', 'default' ); } add_action( 'add_meta_boxes', 'acme_add_box' ); /** * Print the box. * * @param WP_Post $post Post being edited. */ function acme_render( $post ) { wp_nonce_field( 'acme_save_meta', 'acme_meta_nonce' ); $start_date = get_post_meta( $post->ID, '_acme_start_date', true ); printf( '<p><label for="acme_start_date"><strong>%1$s</strong></label><br /><input type="date" id="acme_start_date" name="acme_start_date" value="%2$s" class="widefat" />%3$s</p>', esc_html( __( 'Start date', 'acme' ) ), esc_attr( $start_date ), '<span class="description">' . esc_html( __( 'When the event begins.', 'acme' ) ) . '</span>' ); $venue = get_post_meta( $post->ID, '_acme_venue', true ); printf( '<p><label for="acme_venue"><strong>%1$s</strong></label><br /><input type="text" id="acme_venue" name="acme_venue" value="%2$s" class="widefat" />%3$s</p>', esc_html( __( 'Venue', 'acme' ) ), esc_attr( $venue ), '' ); $format = get_post_meta( $post->ID, '_acme_format', true ); echo '<p><label for="acme_format"><strong>' . esc_html( __( 'Format', 'acme' ) ) . '</strong></label><br />'; echo '<select id="acme_format" name="acme_format">'; foreach ( array( 'online' => __( 'Online', 'acme' ), 'venue' => __( 'In person', 'acme' ), 'hybrid' => __( 'Hybrid', 'acme' ), ) as $value => $label ) { printf( '<option value="%1$s"%2$s>%3$s</option>', esc_attr( $value ), selected( $format, $value, false ), esc_html( $label ) ); } echo '</select></p>'; $sold_out = get_post_meta( $post->ID, '_acme_sold_out', true ); printf( '<p><label for="acme_sold_out"><input type="checkbox" id="acme_sold_out" name="acme_sold_out" value="1"%1$s /> %2$s</label>%3$s</p>', checked( (bool) $sold_out, true, false ), esc_html( __( 'Sold out', 'acme' ) ), '<span class="description">' . esc_html( __( 'Hides the booking button on the front end.', 'acme' ) ) . '</span>' ); } /** * Save the fields. * * @param int $post_id Post being saved. */ function acme_save( $post_id ) { if ( ! isset( $_POST['acme_meta_nonce'] ) || ! wp_verify_nonce( sanitize_key( $_POST['acme_meta_nonce'] ), 'acme_save_meta' ) ) { return; } if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) || ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) ) { return; } if ( ! current_user_can( 'edit_post', $post_id ) ) { return; } if ( ! in_array( get_post_type( $post_id ), array( 'post', 'event' ), true ) ) { return; } if ( isset( $_POST['acme_start_date'] ) ) { $value = sanitize_text_field( wp_unslash( $_POST['acme_start_date'] ) ); if ( '' === $value ) { delete_post_meta( $post_id, '_acme_start_date' ); } else { update_post_meta( $post_id, '_acme_start_date', $value ); } } if ( isset( $_POST['acme_venue'] ) ) { $value = sanitize_text_field( wp_unslash( $_POST['acme_venue'] ) ); if ( '' === $value ) { delete_post_meta( $post_id, '_acme_venue' ); } else { update_post_meta( $post_id, '_acme_venue', $value ); } } if ( isset( $_POST['acme_format'] ) && in_array( sanitize_key( $_POST['acme_format'] ), array( 'online', 'venue', 'hybrid' ), true ) ) { update_post_meta( $post_id, '_acme_format', sanitize_key( $_POST['acme_format'] ) ); } if ( ! empty( $_POST['acme_sold_out'] ) ) { update_post_meta( $post_id, '_acme_sold_out', 1 ); } else { delete_post_meta( $post_id, '_acme_sold_out' ); } } add_action( 'save_post', 'acme_save' ); /** * Expose the meta to the REST API so blocks and the editor can read it. */ function acme_register_meta() { register_post_meta( 'post', '_acme_start_date', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( 'post', '_acme_venue', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_text_field', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( 'post', '_acme_format', array( 'type' => 'string', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'sanitize_key', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); register_post_meta( 'post', '_acme_sold_out', array( 'type' => 'boolean', 'single' => true, 'show_in_rest' => true, 'sanitize_callback' => 'rest_sanitize_boolean', 'auth_callback' => function () { return current_user_can( 'edit_posts' ); }, ) ); } add_action( 'init', 'acme_register_meta' );