To add a new meta box:
function fairways_upload_dates_box() {
$screens = [ 'post' ];
foreach ( $screens as $screen ) {
add_meta_box(
'fairways_upload_dates_box',
'Availability dates',
'fairways_upload_dates_box_html',
$screen
);
}
}
add_action( 'add_meta_boxes', 'fairways_upload_dates_box' );
function fairways_upload_dates_box_html( $post ) {
echo "Your form is here";
}
Parameters of add_meta_box()
add_meta_box( $id, $title, $callback, $post_type, $context, $priority, $args );
| Parameter | * | Description |
|---|---|---|
$id |
Required | The HTML id attribute that will be assigned to the meta box block. |
$title |
Required | The heading of the box. |
$callback |
Required | The function that fills the box. Passed as a string with the function name (or a callable). |
$post_type |
Required | The post type to show the box for. |
$context |
Which part of the page to place the box in (normal, side, advanced). Default — advanced. |
|
$priority |
The priority: the higher it is, the closer to the top of the page the box appears (high, core, default, low). Default — default. |
|
$args |
Arguments passed to the callback function. |
Example:
function add_meta_boxes() {
add_meta_box( 'settings', 'Settings', 'print_settings_box', 'post', 'normal', 'high' );
}
add_action( 'add_meta_boxes', 'add_meta_boxes' );
Printing the fields
The callback simply echoes the HTML — these are ordinary input elements. The only addition is a nonce field, which is needed to verify the request when the post is saved.
function print_settings_box() {
wp_nonce_field( plugin_basename( __FILE__ ), 'myplugin_noncename' );
echo '<label for="myplugin_new_field">' . __( "Description for this field", 'myplugin_textdomain' ) . '</label> ';
echo '<input type="text" id="myplugin_new_field" name="myplugin_new_field" value="whatever" size="25" />';
}
Saving the data
The values are saved on the save_post hook. This hook fires in a lot of situations, so all four checks
below matter:
add_action( 'save_post', 'myplugin_save_postdata' );
function myplugin_save_postdata( $post_id ) {
// Make sure the field is set.
if ( ! isset( $_POST['myplugin_new_field'] ) )
return;
// Verify the nonce of our page, because save_post can be triggered from somewhere else.
if ( ! wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename( __FILE__ ) ) )
return;
// Do nothing on autosave.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
// Check the user permissions.
if ( ! current_user_can( 'edit_post', $post_id ) )
return;
// Everything is fine. Sanitize the value of the input.
$my_data = sanitize_text_field( $_POST['myplugin_new_field'] );
// Update the data in the database.
update_post_meta( $post_id, '_my_meta_value_key', $my_data );
}
Reading the value in a template
$client_position = get_post_meta( get_the_ID(), 'team-member-position', true );
The third argument makes the function return a single value instead of an array.
A custom featured image box
Sometimes a post type needs a second image alongside the standard featured image. The approach is a meta box that stores an attachment ID and reuses the media library UI. The original write-up is open_in_new here .
Registering the box:
add_action( 'add_meta_boxes', 'add_banner_image_metabox' );
function add_banner_image_metabox() {
add_meta_box( 'bottom-image', 'Bottom image', 'print_bottom_image_metabox', 'success-story', 'side', 'low' );
}
Rendering it:
function print_bottom_image_metabox( $post ) {
global $content_width, $_wp_additional_image_sizes;
$image_id = get_post_meta( $post->ID, 'bottom_image_id', true );
$old_content_width = $content_width;
$content_width = 254;
if ( $image_id && get_post( $image_id ) ) {
if ( ! isset( $_wp_additional_image_sizes['post-thumbnail'] ) ) {
$thumbnail_html = wp_get_attachment_image( $image_id, array( $content_width, $content_width ) );
} else {
$thumbnail_html = wp_get_attachment_image( $image_id, 'post-thumbnail' );
}
if ( ! empty( $thumbnail_html ) ) {
$content = $thumbnail_html;
$content .= '<p class="hide-if-no-js"><a href="javascript:;" id="remove_listing_image_button" >' . esc_html__( 'Remove listing image', 'text-domain' ) . '</a></p>';
$content .= '<input type="hidden" id="upload_listing_image" name="_listing_cover_image" value="' . esc_attr( $image_id ) . '" />';
}
$content_width = $old_content_width;
} else {
$content = '<img src="" style="width:' . esc_attr( $content_width ) . 'px;height:auto;border:0;display:none;" />';
$content .= '<p class="hide-if-no-js"><a title="' . esc_attr__( 'Set listing image', 'text-domain' ) . '" href="javascript:;" id="upload_listing_image_button" data-uploader_title="' . esc_attr__( 'Choose an image', 'text-domain' ) . '" data-uploader_button_text="' . esc_attr__( 'Set listing image', 'text-domain' ) . '">' . esc_html__( 'Set listing image', 'text-domain' ) . '</a></p>';
$content .= '<input type="hidden" id="upload_listing_image" name="_listing_cover_image" value="" />';
}
echo $content;
}
Andrew Dorokhov