Action Hook since 4.7.0

rest_insert_post

Fires after a post is created or updated through the REST API

Description

rest_insert_post is the REST-specific counterpart to save_post — it fires inside the Posts controller with the actual REST request object available, which save_post alone doesn't give you.

When it runs

Inside WP_REST_Posts_Controller, after the post is saved via the REST API — save_post also fires for the same request, but without direct access to the REST request object.

Signature

do_action( 'rest_insert_post', WP_Post $post, WP_REST_Request $request, bool $creating );

Parameters

  • post WP_Post — The post object that was inserted or updated.
  • request WP_REST_Request — The REST request that triggered the insert.
  • creating bool — True when a new post was created, false when an existing post was updated.

Examples

Basic

add_action( 'rest_insert_post', function( $post, $request, $creating ) {
    error_log( ( $creating ? 'Created' : 'Updated' ) . ' post via REST: ' . $post->ID );
}, 10, 3 );

Log whether a REST call created or updated a post.

Real case

add_action( 'rest_insert_post', function( $post, $request, $creating ) {
    $client_id = $request->get_header( 'X-Client-App' );
    if ( $client_id ) {
        update_post_meta( $post->ID, '_created_via', sanitize_text_field( $client_id ) );
    }
}, 10, 3 );

Tag posts with which headless client created them, using a custom request header.

Edge case

add_action( 'rest_insert_post', function( $post, $request, $creating ) {
    // save_post fires too for this same request —
    // guard against running duplicate logic in both places.
}, 10, 3 );

save_post and rest_insert_post both fire for the same REST-created post — avoid double-running side effects.

Common Use Cases

  • Read the REST request (headers, client info) at save time
  • Tag content created by a headless front-end or external app
  • Run REST-specific validation after the write
  • Trigger a webhook only for API-originated changes

Common mistakes

  • Duplicating logic that already runs on save_post — both fire for the same REST write, so pick one or guard against running twice
  • Assuming $creating always reflects the intent of the API client — it reflects whether the post row was inserted or updated, not the client's stated intent

Related hooks

FAQ

Do I need this if I already hook save_post?

Only if you need the REST request object itself — headers, route, or client-specific data that save_post doesn't expose.

Does rest_insert_post replace save_post for REST-created posts?

No — both fire. rest_insert_post adds the request context on top of what save_post already gives you.

Source: wp-includes/rest-api/endpoints/class-wp-rest-posts-controller.php

Group wizard

One session: this hook, then each related_hooks entry. Walk it and tell us what to change.

rest_insert_post → save_post → rest_api_init

functions.php — rest_insert_post
functions.php
PHP rest_insert_post · Hook 1 of 3 · Step 1 of 6

Practice the rest_insert_post WordPress action hook in our interactive sandbox — a VS Code-style editor with a step-by-step rest_insert_post tutorial, add_action exercises, and instant feedback. No local WordPress install required.