wp_insert_post
Fires after a new post is saved or an existing post is updated.
It fires after the save_post_{$post_type} and save_post actions, but before wp_after_insert_post.
The action does not fire for attachments saved through wp_insert_post().
To handle only a specific post type, use the save_post_{$post_type} action, for example save_post_product.
Calling wp_update_post() or wp_insert_post() inside the callback can recursively trigger this same action.
wp_insert_post() cleans post_content, post_excerpt, and post_content_filtered with wp_filter_post_kses() if the current user does not have the unfiltered_html capability. The title is additionally cleaned with wp_filter_kses().
This matters when running through WP-CLI, WP-Cron, an unauthenticated REST request, or a separate script that includes wp-load.php. In these cases, get_current_user_id() usually returns 0, so potentially unsafe HTML, including <script>, <iframe>, and disallowed attributes, may be removed without warning. The post is still saved successfully, and the function does not return an error.
Before saving, set a user with the unfiltered_html capability, then restore the original user:
$original_user_id = get_current_user_id();
wp_set_current_user( 1 );
try {
$post_id = wp_insert_post(
[
'post_title' => 'Imported post',
'post_content' => $html_content,
'post_status' => 'publish',
],
true
);
} finally {
wp_set_current_user( $original_user_id );
}
Multisite
On multisite, only super admins have the unfiltered_html capability. A regular site administrator does not. The DISALLOW_UNFILTERED_HTML constant, when set to true, denies this capability to all users, including administrators and super admins.
Usage
add_action( 'wp_insert_post', 'wp_kama_insert_post_action', 10, 3 );
/**
* Function for `wp_insert_post` action-hook.
*
* @param int $post_id Post ID.
* @param WP_Post $post Post object.
* @param bool $update Whether this is an existing post being updated.
*
* @return void
*/
function wp_kama_insert_post_action( $post_id, $post, $update ){
// action...
}
- $post_id(int)
- ID of the saved post.
- $post(WP_Post)
- Object for the saved post.
- $update(bool)
trueif an existing post was updated.falseif a new post was created.
Examples
#1 Perform an action after saving a post
Save the update time of a regular post in a meta-field. Revisions and autosaves are skipped.
add_action( 'wp_insert_post', 'wp_kama_after_insert_post', 10, 3 );
function wp_kama_after_insert_post( $post_id, $post, $update ) {
if (
'post' !== $post->post_type
|| wp_is_post_revision( $post_id )
|| wp_is_post_autosave( $post_id )
) {
return;
}
update_post_meta( $post_id, '_last_processed', time() );
}
#2 Update a post without recursively calling the callback
Temporarily disable the callback before calling wp_update_post().
add_action( 'wp_insert_post', 'wp_kama_update_post_slug', 10, 3 );
function wp_kama_update_post_slug( $post_id, $post, $update ) {
if ( ! $update || 'product' !== $post->post_type ) {
return;
}
remove_action( 'wp_insert_post', 'wp_kama_update_post_slug', 10 );
wp_update_post(
[
'ID' => $post_id,
'post_name' => sanitize_title( $post->post_title ),
]
);
add_action( 'wp_insert_post', 'wp_kama_update_post_slug', 10, 3 );
}Changelog
| Since 2.0.0 | Introduced. |
Where the hook is called
do_action( 'wp_insert_post', $post_id, $post, $update );
do_action( 'wp_insert_post', $post->ID, $post, true );
do_action( 'wp_insert_post', $post->ID, $post, true );