Use WordPress’s add_meta_box() API to add a custom field panel to the edit screen for posts, pages, or a custom post type. Then load saved values in the panel’s callback and persist submitted values through a guarded save handler. A meta box provides the editing interface; register the metadata separately when you need a schema or REST and Block Editor access.
Choose the right editing interface
A PHP meta box is a practical fit when a field is post-specific and a conventional form in the post editor is all you need. WordPress continues to document and support PHP meta boxes. For a more integrated Block Editor experience, consider a block or a plugin sidebar instead: WordPress’s Block Editor Handbook says porting PHP meta boxes to blocks or sidebar plugins is “highly encouraged.” That is guidance, not a claim that meta boxes have been removed.
As an Amazon Associate I earn from qualifying purchases.
The choice depends on how editors should use the field, whether its value needs to be exposed through the REST API or bound to a block attribute, and which WordPress versions the site supports. The APIs have distinct version requirements: the Block Bindings API is available from WordPress 6.5, while the documented core/post-data and core/term-data sources are marked as available since WordPress 6.9.
Recommended Free Tools
Register a meta box for the correct screen
Register the interface on the add_meta_boxes action. Supply a unique ID, a title, a rendering callback, and the screen or screens where it belongs. Use post for standard posts, page for pages, or the custom post type’s slug. The screen argument can also be an array.
#1 Best Overall
add_action( 'add_meta_boxes', 'myplugin_add_book_meta_box' );
function myplugin_add_book_meta_box() {
add_meta_box(
'myplugin_book_details',
__( 'Book details', 'myplugin' ),
'myplugin_render_book_meta_box',
'book'
);
}
For a box that belongs only to one post type, WordPress also provides a type-specific action. For the book type, use add_meta_boxes_book; its callback receives the post object. The general add_meta_boxes action receives the current object type and object. WordPress’s example registers a box for both post and a custom type, wporg_cpt.
Render fields and load saved values
The callback outputs the controls. Read an existing value with get_post_meta( $post->ID, $meta_key, true ) so the field is prepopulated when an editor reopens a saved post. Use a clear label and a metadata key that describes the value. The following example renders a single-line ISBN field:
function myplugin_render_book_meta_box( $post ) {
$isbn = get_post_meta( $post->ID, '_myplugin_isbn', true );
?>
<label for="myplugin-isbn">
<?php esc_html_e( 'ISBN', 'myplugin' ); ?>
</label>
<input
type="text"
id="myplugin-isbn"
name="myplugin_isbn"
value="<?php echo esc_attr( $isbn ); ?>"
/>
<?php
}
Meta-box fields are inside the post editor’s form, so WordPress submits them with the post when the user publishes or updates it. You do not need a second submit button. If a panel would contain many unrelated fields, separate them into focused boxes to keep the editor easier to scan.
Save metadata safely
A save callback should not treat every request as an authorized edit. Include a nonce in the rendered panel, verify it on save, check the current user’s capability for that post, skip autosaves and revisions where appropriate, confirm the expected field was submitted, and sanitize or validate according to the field’s type. Escape the stored value when rendering it. Also make the handler safe to run more than once: WordPress notes that save_post can fire multiple times for one update event.
Rank #3
This example shows the main protections for a text field. Adapt the sanitization and validation to the actual data type rather than using text sanitization for every kind of value.
function myplugin_render_book_meta_box( $post ) {
$isbn = get_post_meta( $post->ID, '_myplugin_isbn', true );
wp_nonce_field( 'myplugin_save_book_details', 'myplugin_book_nonce' );
?>
<label for="myplugin-isbn">
<?php esc_html_e( 'ISBN', 'myplugin' ); ?>
</label>
<input
type="text"
id="myplugin-isbn"
name="myplugin_isbn"
value="<?php echo esc_attr( $isbn ); ?>"
/>
<?php
}
add_action( 'save_post_book', 'myplugin_save_book_details' );
function myplugin_save_book_details( $post_id ) {
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return;
}
if ( wp_is_post_revision( $post_id ) ) {
return;
}
if ( ! isset( $_POST['myplugin_book_nonce'] ) ) {
return;
}
$nonce = sanitize_text_field(
wp_unslash( $_POST['myplugin_book_nonce'] )
);
if ( ! wp_verify_nonce( $nonce, 'myplugin_save_book_details' ) ) {
return;
}
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return;
}
if ( ! isset( $_POST['myplugin_isbn'] ) ) {
return;
}
$isbn = sanitize_text_field(
wp_unslash( $_POST['myplugin_isbn'] )
);
update_post_meta( $post_id, '_myplugin_isbn', $isbn );
}
The post-type-specific save hook keeps this handler focused on books. For a handler attached to the general save_post action, account for the post type in the callback as well. WordPress’s handbook examples illustrate the APIs but explicitly warn that their examples are not production-ready and omit protections such as input security, capability checks, nonces, and internationalization.
Rank #4
Register metadata when its schema or editor exposure matters
add_meta_box() creates the editing UI; it does not define the metadata key’s schema or make it available through the REST API. Use register_meta() when you need to declare details such as the value’s type, whether it is single-valued, a default, a sanitizer, an authorization callback, or REST visibility. Register a key against the specific object subtype when applicable.
For registered metadata on a custom post type to be exposed through the REST API, that post type must support custom-fields. If the metadata does not appear as expected in the Block Editor, check both REST visibility and the post type’s support settings. The Plugin Sidebar documentation likewise notes that metadata must be REST-visible for Block Editor access.
Best Value
Use post metadata with Block Bindings
WordPress’s core/post-meta Block Bindings source can connect a block attribute to registered post metadata. For this source, the key must be registered with show_in_rest => true and must not begin with an underscore. That restriction matters if a key such as _myplugin_isbn is used for the PHP form: it is protected from this Block Bindings source. Choose the key and interface based on how the value needs to be edited and exposed.
Check the site’s WordPress version before building around a binding source. The Block Bindings API is documented as available from WordPress 6.5; core/post-data and core/term-data are marked as available since WordPress 6.9. Do not assume those later sources exist on installations that run older versions.
Quick Recap
Official WordPress references
- Plugin Handbook: Custom Meta Boxes
- Function reference: add_meta_box()
- Hook reference: add_meta_boxes
- Function reference: register_meta()
- Block Editor Handbook: Meta Boxes
- Block Editor Handbook: Plugin Sidebar
- Block Editor Handbook: Block Bindings
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Do these 3 things before closing this tab:
1Fix the driver behind crashes, sound loss and screen glitches2Clear out junk files and repair common Windows errors3Scan for outdated or missing drivers - takes under a minute




