Code

Build a custom meta box with proper output sanitization

An event-details meta box scenario covering nonce and autosave guards on save, per-field sanitization, and avoiding the classic recursive save_post loop.

Works with Claude / GPT1,050 uses 4.3

The prompt

code-custom-meta-box-sanitization
I need a meta box on the "Event" custom post type edit screen with three fields: event
date (date picker), ticket price (number), and an external registration URL.

CONTEXT: [a previous developer's version of this saved raw $_POST values directly with
no sanitization, and separately caused the edit screen to hang/error on autosave, which
is why I'm rebuilding it properly]

Build this the way a senior dev handles meta box save logic correctly, in order:
1. Show `add_meta_box()` registered on `add_meta_boxes`, and the render callback
   outputting a nonce field via `wp_nonce_field()` alongside the three inputs,
   populated from existing meta with `esc_attr( get_post_meta(...) )` so re-editing
   doesn't break on values containing quotes or special characters.
2. Show the `save_post` callback with the full guard sequence, explained not just
   listed: verify the nonce first, then check `current_user_can( 'edit_post', $post_id )`,
   then bail early on `wp_is_post_autosave()` and `wp_is_post_revision()`, since
   skipping any of these either creates a security hole or causes the exact autosave
   crash the previous version had (autosave requests don't include the same POST
   fields, so code that assumes they do can throw notices or overwrite data with
   empty values).
3. Sanitize each field with the correct function for its type, not a blanket
   `sanitize_text_field()` for everything: the date with a validated format check
   (reject anything that doesn't parse as a real date rather than silently storing
   garbage), the price with `absint()` or a float-safe equivalent with a minimum of
   zero, and the URL with `esc_url_raw()` before saving, `esc_url()` only on output.
4. Avoid the classic recursive loop: since `save_post` fires on every save including
   the one your own `update_post_meta()` calls might trigger indirectly through other
   hooked code, show the pattern of removing and re-adding the action inside the
   callback if there's any risk of `wp_update_post()` being called from within it.
5. Flag the edge case: if this event post type supports Gutenberg, confirm the meta
   box still renders (older-style `add_meta_box()` boxes show in a "Advanced" panel
   collapsed by default in the block editor), and consider whether these fields should
   actually be registered via `register_post_meta()` with `show_in_rest` and a proper
   sidebar panel instead, for a cleaner editing experience.

Replace the fields and post type with your actual meta box needs.

Sanitizing on save and escaping again on output are both required, doing only one leaves either a stored-XSS risk or a broken display for legitimately tricky input like an ampersand in a URL. Treat them as two separate steps, not one.