How to prepopulate metadata when creating a post with PHP in WordPress

Contents

Introduction

This article explains, in exhaustive detail, how to prepopulate post metadata when creating posts in WordPress using PHP (and when needed a bit of JavaScript for the admin UI). You will learn the common programmatic methods, how to expose metadata to the REST API, how to pre-fill metadata on the Add New post screen (both block editor and classic), and best practices including sanitization, capability checks and debugging tips. All sample code is ready to copy into plugins or theme functions and is clearly labelled.

Core concepts

  • Post meta (a.k.a. custom fields) is arbitrary key/value data attached to a post and is stored in the wp_postmeta table.
  • Metadata vs taxonomy: metadata is key/value, while taxonomy terms are separate relational entities (categories, tags, custom taxonomies).
  • Gutenberg (block editor) and REST: Gutenberg reads and writes meta exposed through register_post_meta(…, show_in_rest => true). For programmatic insertion you can use the REST API or PHP functions.
  • Admin prepopulation: The Add New post screen does not automatically accept meta URL parameters — you must inject defaults by hooking, enqueueing admin scripts, or by creating the post programmatically with meta already set.

Overview of approaches

  1. Programmatically create a post with metadata using wp_insert_post with the meta_input parameter.
  2. Create the post first then add or update metadata with add_post_meta() or update_post_meta().
  3. Register post meta for REST and create posts with metadata via the REST API (requires register_post_meta with show_in_rest).
  4. Prepopulate metadata on the admin Add New screen using an admin script for Gutenberg (via wp.data) or the classic editor (DOM/jQuery).

Method 1 — wp_insert_post with meta_input (recommended for programmatic creation)

When creating posts in PHP you can pass post meta in the wp_insert_post argument meta_input. This is simple and atomic — meta is saved as part of the post insert operation.

Example plugin/function using wp_insert_post meta_input:

lt?php
// Create a post with metadata
function my_create_post_with_meta() {
    post_data = array(
        post_title   =gt My programmatically created post,
        post_content =gt Content added with wp_insert_post,
        post_status  =gt publish,
        post_type    =gt post,
        // meta_input accepts an associative array of meta_key => meta_value
        meta_input   =gt array(
            my_meta_key =gt my meta value,
            another_key =gt 123,
        ),
    )

    post_id = wp_insert_post( post_data, true ) // true returns WP_Error on failure

    if ( is_wp_error( post_id ) ) {
        error_log( Failed to insert post:  . post_id-gtget_error_message() )
        return post_id
    }

    // post_id is the new post ID
    return post_id
}
?gt

Notes:

  • Always check for WP_Error when passing true as the second param.
  • meta_input will call add_post_meta or update automatically values are sanitized and stored as-is (you should sanitize before storing if necessary).

Method 2 — insert post then update_post_meta / add_post_meta

If you prefer separating concerns or need conditional meta writes after the post is created (for example you need the post ID to generate a meta value), insert the post first and then use update_post_meta(). This gives you more control for complex logic.

lt?php
post_id = wp_insert_post( array(
    post_title =gt Another post,
    post_status =gt draft,
) )

if ( ! is_wp_error( post_id ) ) {
    // Add or update metadata
    update_post_meta( post_id, my_meta_key, value-one )

    // If you need to add multiple meta entries:
    update_post_meta( post_id, numeric_meta, intval( some_value ) )
    update_post_meta( post_id, flag_meta, flag ? yes : no )
}
?gt
  • Use add_post_meta() if you want multiple values for the same meta key (multi-valued meta).
  • update_post_meta() updates an existing value or adds it if it does not exist.

Method 3 — Register meta for REST and create posts via REST API

If you want external systems or the block editor to set meta, register the meta key using register_post_meta() (or register_meta() with post type). Setting show_in_rest =gt true makes the meta available in the REST API and block editor (Gutenberg) as part of the post object.

lt?php
function my_register_post_meta() {
    register_post_meta( post, my_meta_key, array(
        type              =gt string,
        single            =gt true,
        sanitize_callback =gt sanitize_text_field,
        auth_callback     =gt function() {
            // Only allow users who can edit posts to change this meta
            return current_user_can( edit_posts )
        },
        show_in_rest      =gt true,
    ) )
}
add_action( init, my_register_post_meta )
?gt

Once registered with show_in_rest true, you can call the REST endpoint to create a post with the meta included:

# Example curl using basic auth (replace with your preferred auth)
curl -u username:application-password -X POST https://example.com/wp-json/wp/v2/posts 
  -H Content-Type: application/json 
  -d {
    title: REST-created post,
    content: Content set via REST,
    status: publish,
    meta: {
      my_meta_key: my rest meta value
    }
  }

Notes:

  • You need proper authentication (application passwords, OAuth, cookie authentication, JWT, etc.).
  • The meta key must be registered and permitted by auth_callback.
  • Gutenberg will show registered meta in the inspector if your meta is registered and configured in a compatible way (and your block or UI handles it).

Method 4 — Prepopulate metadata on the Add New admin screen

If you want the Add New post screen to start with metadata already filled, there are two main approaches:

  1. For Gutenberg (block editor): enqueue an admin script that runs a small JS snippet which sets post meta via wp.data.dispatch(core/editor).editPost(…). This works on the Add New screen and sets the editors state immediately.
  2. For Classic Editor or custom meta boxes: enqueue an admin script that reads URL query parameters (or localized script data) and sets the DOM field values for meta boxes.

How to pass defaults via URL

A common pattern is to add query args to the Add New screen URL, e.g.:

  • /wp-admin/post-new.php?post_type=postmy_meta_key=value

Server-side code should sanitize and validate these values before exposing them to admin scripts.

Gutenberg (block editor) example

Enqueue a small admin script on the post-new.php screen, pass defaults through wp_localize_script or inline script, and call wp.data.dispatch(core/editor).editPost({ meta: { … } }). This updates editor state so meta futures will be saved on publish.

lt?php
function my_enqueue_admin_prefill_script( hook ) {
    if ( hook !== post-new.php  hook !== post.php ) {
        return
    }

    screen = get_current_screen()
    if ( ! screen  screen-gtpost_type !== post ) {
        return
    }

    // Only for users who can edit posts
    if ( ! current_user_can( edit_posts ) ) {
        return
    }

    // Prepare defaults from URL query (sanitize)
    defaults = array()
    if ( isset( _GET[my_meta_key] ) ) {
        defaults[my_meta_key] = sanitize_text_field( wp_unslash( _GET[my_meta_key] ) )
    }

    if ( empty( defaults ) ) {
        return
    }

    // Enqueue an inline script that will use wp.data to set meta when the editor is ready
    wp_enqueue_script( my-admin-prefill, , array( wp-data, wp-edit-post ), false, true )

    script = window.__MY_PREFILL =  . wp_json_encode( defaults ) . 
    wp_add_inline_script( my-admin-prefill, script )

    // Inline JS to call wp.data (this could be in a separate JS file instead)
    inline = 
    ( function() {
        var defaults = window.__MY_PREFILL  {}
        if ( ! Object.keys( defaults ).length ) {
            return
        }
        // Wait for the editor store to be available
        var setMeta = function() {
            var editPost = wp.data  wp.data.dispatch  wp.data.dispatch(core/editor)
            if ( ! editPost  ! editPost.editPost ) {
                // Try again soon
                setTimeout( setMeta, 200 )
                return
            }
            var meta = {}
            Object.keys( defaults ).forEach( function(key) {
                meta[key] = defaults[key]
            } )
            editPost.editPost( { meta: meta } )
        }
        setMeta()
    } )()
    
    wp_add_inline_script( my-admin-prefill, inline )
}
add_action( admin_enqueue_scripts, my_enqueue_admin_prefill_script )
?gt

Explanation:

  • We collect sanitized values from _GET and expose them to the script via inline JS.
  • The JS waits until wp.data.dispatch(core/editor) is ready, then calls editPost({ meta: {…} }) to populate meta values in editor state. Those meta values will appear in the post object and be saved when the post is saved/published.

Classic editor or legacy meta boxes example

For the Classic Editor or custom meta box input fields, simply set the DOM value using jQuery/vanilla JS. This example reads the URL parameter and sets the value of a custom field named my_meta_key.

(function() {
    function getQueryParam(name) {
        var params = new URLSearchParams(window.location.search)
        return params.get(name)
    }

    var value = getQueryParam(my_meta_key)
    if (!value) {
        return
    }

    // Wait until DOM is ready and meta box inputs exist
    document.addEventListener(DOMContentLoaded, function() {
        // If you use the custom fields meta box (name=meta[my_meta_key]) you may target it directly
        var input = document.querySelector(input[name=my_meta_key], input[name=meta[my_meta_key]], textarea[name=my_meta_key])
        if (input) {
            input.value = value
        }

        // Or, if your meta box uses an input with an ID:
        var specific = document.getElementById(my_meta_key_field)
        if (specific) {
            specific.value = value
        }
    })
})()

Enqueue this script conditionally on post-new.php as shown in the Gutenberg example always sanitize the _GET value before echoing it into inline scripts.

Security, sanitization and capability checks

  • Sanitize before storing: Use appropriate sanitization callbacks (sanitize_text_field, intval, wp_strip_all_tags, wp_kses_post, etc.) depending on the content and register a sanitize_callback in register_post_meta when possible.
  • Authorization: Ensure only authorized users can set or change meta. For REST, use auth_callback in register_post_meta. For admin scripts only enqueue for users with proper capabilities and use current_user_can() server-side.
  • Nonces: For custom AJAX or forms that set meta on the server, validate a nonce with wp_verify_nonce.
  • Autosave revision handling: Be careful about autosaves and revisions writing partial meta. In save_post hooks check wp_is_post_autosave() and wp_is_post_revision() as needed before saving meta.

Best practices

  • Prefer register_post_meta with sanitize and auth callbacks for data integrity and REST compatibility.
  • Keep meta keys short, use a prefix to avoid collisions (e.g., myprefix_my_meta_key).
  • Store structured data as JSON only when necessary and consider separate meta keys for separate fields so they are queryable.
  • Use meta_input on insert when possible since it is simple and atomic.
  • When pre-filling admin screens, prefer the block editor approach (wp.data.editPost) for reliability with Gutenberg.

Edge cases and debugging tips

  • If meta is not saved, check server logs and call is_wp_error() for wp_insert_post errors.
  • Use error_log() or WP_DEBUG to surface PHP errors var_dump and die are okay for development but remove them for production.
  • If REST meta not accepted, confirm register_post_meta was called early (init) and show_in_rest is true and auth_callback allows the request user.
  • When meta appears in the block editor but does not persist, ensure meta keys are registered as single or array correctly and that editPost is setting the meta under the expected key.

Complete example: register meta, prefill add-new, and programmatically insert with meta

This example shows three moving parts together:

  • register_post_meta on init
  • admin enqueue to prefill add-new via URL
  • programmatic creation function that uses meta_input
lt?php
// 1) Register meta
function example_register_meta() {
    register_post_meta( post, example_prefill_meta, array(
        type              =gt string,
        single            =gt true,
        sanitize_callback =gt sanitize_text_field,
        auth_callback     =gt function() {
            return current_user_can( edit_posts )
        },
        show_in_rest      =gt true,
    ) )
}
add_action( init, example_register_meta )

// 2) Prefill admin add-new via URL param ?example_prefill_meta=value
function example_admin_prefill( hook ) {
    if ( hook !== post-new.php ) {
        return
    }

    / @var WP_Screen screen /
    screen = get_current_screen()
    if ( ! screen  screen-gtpost_type !== post ) {
        return
    }

    if ( ! current_user_can( edit_posts ) ) {
        return
    }

    defaults = array()
    if ( isset( _GET[example_prefill_meta] ) ) {
        defaults[example_prefill_meta] = sanitize_text_field( wp_unslash( _GET[example_prefill_meta] ) )
    }

    if ( empty( defaults ) ) {
        return
    }

    wp_enqueue_script( example-admin-prefill,  , array( wp-data ), false, true )

    wp_add_inline_script( example-admin-prefill, window.__EXAMPLE_PREFILL =  . wp_json_encode( defaults ) .  )

    inline_js = 
    ( function() {
        var defaults = window.__EXAMPLE_PREFILL  {}
        if ( ! Object.keys( defaults ).length ) {
            return
        }
        var setMeta = function() {
            var store = wp.data  wp.data.dispatch  wp.data.dispatch(core/editor)
            if ( ! store  ! store.editPost ) {
                setTimeout( setMeta, 200 )
                return
            }
            store.editPost( { meta: defaults } )
        }
        setMeta()
    } )()
    
    wp_add_inline_script( example-admin-prefill, inline_js )
}
add_action( admin_enqueue_scripts, example_admin_prefill )

// 3) Programmatic insertion using meta_input
function example_create_post_with_meta( title, meta_value ) {
    post_id = wp_insert_post( array(
        post_title   =gt title,
        post_status  =gt publish,
        post_type    =gt post,
        meta_input   =gt array(
            example_prefill_meta =gt sanitize_text_field( meta_value ),
        ),
    ), true )

    if ( is_wp_error( post_id ) ) {
        return post_id
    }

    return post_id
}
?gt

Summary

You can prepopulate post metadata when creating posts in multiple ways:

  • For programmatic creation use wp_insert_post with meta_input (atomic and simple).
  • Use update_post_meta/add_post_meta if you need to calculate meta after post creation.
  • Expose meta to the REST API via register_post_meta(…, show_in_rest =gt true) and create posts with meta through REST calls.
  • Pre-fill the admin Add New screen with query args and a small admin script: use wp.data.editPost for Gutenberg or DOM methods for the Classic Editor.

Follow security best practices: sanitize inputs, register meta with sanitize/auth callbacks, check capabilities, and avoid accidental writes from autosaves and revisions. These techniques cover most real-word scenarios for prepopulating post metadata with PHP and a small amount of admin-side JavaScript when needed.



Acepto donaciones de BAT's mediante el navegador Brave 🙂



Leave a Reply

Your email address will not be published. Required fields are marked *