wp_update_post( array|object $postarr = array(), bool $wp_error = false )

Update a post with new post data.

Description Description

The date does not have to be set for drafts. You can set the date and it will not be overridden.

Parameters Parameters


(array|object) (Optional) Post data. Arrays are expected to be escaped, objects are not. Default array.

Default value: array()


(bool) (Optional) Allow return of WP_Error on failure.

Default value: false

Top ↑

Return Return

(int|WP_Error) The value 0 or WP_Error on failure. The post ID on success.

Top ↑

Source Source

File: wp-includes/post.php

function wp_update_post( $postarr = array(), $wp_error = false ) {
	if ( is_object( $postarr ) ) {
		// Non-escaped post was passed.
		$postarr = get_object_vars( $postarr );
		$postarr = wp_slash( $postarr );

	// First, get all of the original fields.
	$post = get_post( $postarr['ID'], ARRAY_A );

	if ( is_null( $post ) ) {
		if ( $wp_error ) {
			return new WP_Error( 'invalid_post', __( 'Invalid post ID.' ) );
		return 0;

	// Escape data pulled from DB.
	$post = wp_slash( $post );

	// Passed post category list overwrites existing category list if not empty.
	if ( isset( $postarr['post_category'] ) && is_array( $postarr['post_category'] )
			&& 0 != count( $postarr['post_category'] ) ) {
		$post_cats = $postarr['post_category'];
	} else {
		$post_cats = $post['post_category'];

	// Drafts shouldn't be assigned a date unless explicitly done so by the user.
	if ( isset( $post['post_status'] ) && in_array( $post['post_status'], array( 'draft', 'pending', 'auto-draft' ) ) && empty( $postarr['edit_date'] ) &&
			( '0000-00-00 00:00:00' == $post['post_date_gmt'] ) ) {
		$clear_date = true;
	} else {
		$clear_date = false;

	// Merge old and new fields with new fields overwriting old ones.
	$postarr                  = array_merge( $post, $postarr );
	$postarr['post_category'] = $post_cats;
	if ( $clear_date ) {
		$postarr['post_date']     = current_time( 'mysql' );
		$postarr['post_date_gmt'] = '';

	if ( $postarr['post_type'] == 'attachment' ) {
		return wp_insert_attachment( $postarr, false, 0, $wp_error );

	return wp_insert_post( $postarr, $wp_error );

Top ↑

Changelog Changelog

Version Description
1.0.0 Introduced.

Top ↑

User Contributed Notes User Contributed Notes

  1. Skip to note 1 content
    Contributed by Codex


    Before calling wp_update_post() it is necessary to create an array to pass the necessary elements. Unlike wp_insert_post(), it is only necessary to pass the ID of the post to be updated and the elements to be updated. The names of the elements should match those in the database.

    // Update post 37
      $my_post = array(
          'ID'           => 37,
          'post_title'   => 'This is the post title.',
          'post_content' => 'This is the updated content.',
    // Update the post into the database
      wp_update_post( $my_post );
    Processing $wp_error

    If your updates are not working, there could be an error. It is a good idea to set $wp_error to true and display the error immediately after.

    // Of course, this should be done in an development environment only and commented out or removed after deploying to your production site.
    wp_update_post( $current_item, true );						  
    if (is_wp_error($post_id)) {
    	$errors = $post_id->get_error_messages();
    	foreach ($errors as $error) {
    		echo $error;

    Categories need to be passed as an array of integers that match the category IDs in the database. This is the case even where only one category is assigned to the post.

    Caution – Infinite loop
    When executed by an action hooked into save_post (e.g. a custom metabox), wp_update_post() has the potential to create an infinite loop. This happens because (1) wp_update_post() results in save_post being fired and (2) save_post is called twice when revisions are enabled (first when creating the revision, then when updating the original post—resulting in the creation of endless revisions).

    If you must update a post from code called by save_post, make sure to verify the post_type is not set to ‘revision’ and that the $post object does indeed need to be updated.

    Likewise, an action hooked into edit_attachment can cause an infinite loop if it contains a function call to wp_update_post passing an array parameter with a key value of “ID” and an associated value that corresponds to an Attachment.

    Note you will need to remove then add the hook, code sample modified from the API/Action reference: save_post

    function my_function( $post_id ){
    	if ( ! wp_is_post_revision( $post_id ) ){
    		// unhook this function so it doesn't loop infinitely
    		remove_action('save_post', 'my_function');
    		// update the post, which calls save_post again
    		wp_update_post( $my_args );
    		// re-hook this function
    		add_action('save_post', 'my_function');
    add_action('save_post', 'my_function');
  2. Skip to note 2 content
    Contributed by PJ Brunet

    If you’re importing and then applying some updates with this function, it doesn’t recognize ‘import_id’ so remember to also use ‘ID’ too.

    In any case, if you “import” with wp_insert_post and then use wp_update_post, you’re going to lose all your featured images and any additional categories you added between import/update will be lost. (The plugin “Featured Image From URL” solves the featured images problem, if it’s activated.)

    Also, some of the documentation suggests that you can use an author’s name or a category’s name, but as far as I can tell, you can only use the id numbers for authors and categories when importing/updating content.

  3. Skip to note 4 content
    Contributed by ztvmark
    //Example with acf https://advancedcustomfields.com
    add_action( 'acf/save_post', 'add_category_acf', 20 );
    function add_category_acf( $post_id ) {
        //uncomment if a specific post is required example post 490
        //$post_id = 490;
        $post_type = get_post_type( $post_id );
        if ( 'post' == $post_type ) {
            //add the default category with id 3
            $data = array(
                'post_category' => [3],
            wp_update_post( $data );

You must log in before being able to contribute a note or feedback.