wp_update_post()
云策文档标注
概述
wp_update_post() 是 WordPress 核心函数,用于更新现有文章的数据。它基于 wp_insert_post() 实现,接受文章 ID 和要更新的字段数组作为参数,并返回文章 ID 或 WP_Error。
关键要点
- 函数签名:wp_update_post( $postarr = array(), $wp_error = false, $fire_after_hooks = true )
- 参数 $postarr 可以是数组或对象,数组需转义,对象会自动处理;必须包含 'ID' 字段以指定要更新的文章。
- 支持所有 wp_insert_post() 的参数,如 post_title、post_content、post_status、meta_input 等。
- 返回值为文章 ID(成功时)或 0/WP_Error(失败时),可通过 $wp_error 参数控制错误处理。
- 内部处理包括合并新旧字段、处理草稿日期、分类和标签覆盖、附件类型特殊处理等。
- 注意避免在 save_post 钩子中调用导致无限循环,需检查文章类型非 'revision'。
代码示例
// 更新文章 37
$my_post = array(
'ID' => 37,
'post_title' => 'This is the post title.',
'post_content' => 'This is the updated content.',
);
wp_update_post( $my_post );注意事项
- 分类需以整数数组形式传递(即使单个分类),标签可通过 tags_input 参数更新。
- 更新草稿时,日期不会自动设置,除非显式指定 edit_date 参数。
- 使用 meta_input 可同时更新文章元数据,注意数据转义以避免反斜杠丢失。
- 在 save_post 或 edit_attachment 钩子中调用时,需谨慎防止无限循环。
原文内容
Updates a post with new post data.
Description
The date does not have to be set for drafts. You can set the date and it will not be overridden.
Parameters
$postarrarray|objectoptional-
Post data. Arrays are expected to be escaped, objects are not. See wp_insert_post() for accepted arguments.
Default array.More Arguments from wp_insert_post( … $postarr )
An array of elements that make up a post to update or insert.
IDintThe post ID. If equal to something other than 0, the post with that ID will be updated. Default 0.post_authorintThe ID of the user who added the post. Default is the current user ID.post_datestringThe date of the post. Default is the current time.post_date_gmtstringThe date of the post in the GMT timezone. Default is the value of$post_date.post_contentstringThe post content. Default empty.post_content_filteredstringThe filtered post content. Default empty.post_titlestringThe post title. Default empty.post_excerptstringThe post excerpt. Default empty.post_statusstringThe post status. Default'draft'.post_typestringThe post type. Default'post'.comment_statusstringWhether the post can accept comments. Accepts'open'or'closed'.
Default is the value of'default_comment_status'option.ping_statusstringWhether the post can accept pings. Accepts'open'or'closed'.
Default is the value of'default_ping_status'option.post_passwordstringThe password to access the post. Default empty.post_namestringThe post name. Default is the sanitized post title when creating a new post.to_pingstringSpace or carriage return-separated list of URLs to ping.
Default empty.pingedstringSpace or carriage return-separated list of URLs that have been pinged. Default empty.post_parentintSet this for the post it belongs to, if any. Default 0.menu_orderintThe order the post should be displayed in. Default 0.post_mime_typestringThe mime type of the post. Default empty.guidstringGlobal Unique ID for referencing the post. Default empty.import_idintThe post ID to be used when inserting a new post.
If specified, must not match any existing post ID. Default 0.post_categoryint[]Array of category IDs.
Defaults to value of the'default_category'option.tags_inputarrayArray of tag names, slugs, or IDs. Default empty.tax_inputarrayAn array of taxonomy terms keyed by their taxonomy name.
If the taxonomy is hierarchical, the term list needs to be either an array of term IDs or a comma-separated string of IDs.
If the taxonomy is non-hierarchical, the term list can be an array that contains term names or slugs, or a comma-separated string of names or slugs. This is because, in hierarchical taxonomy, child terms can have the same names with different parent terms, so the only way to connect them is using ID. Default empty.meta_inputarrayArray of post meta values keyed by their post meta key. Default empty.page_templatestringPage template to use.
Default:
array() $wp_errorbooloptional-
Whether to return a WP_Error on failure.
Default:
false $fire_after_hooksbooloptional-
Whether to fire the after insert hooks.
Default:
true
Source
function wp_update_post( $postarr = array(), $wp_error = false, $fire_after_hooks = true ) {
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'] )
&& count( $postarr['post_category'] ) > 0
) {
$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' ), true )
&& 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 ( 'attachment' === $postarr['post_type'] ) {
return wp_insert_attachment( $postarr, false, 0, $wp_error );
}
// Discard 'tags_input' parameter if it's the same as existing post tags.
if ( isset( $postarr['tags_input'] ) && is_object_in_taxonomy( $postarr['post_type'], 'post_tag' ) ) {
$tags = get_the_terms( $postarr['ID'], 'post_tag' );
$tag_names = array();
if ( $tags && ! is_wp_error( $tags ) ) {
$tag_names = wp_list_pluck( $tags, 'name' );
}
if ( $postarr['tags_input'] === $tag_names ) {
unset( $postarr['tags_input'] );
}
}
return wp_insert_post( $postarr, $wp_error, $fire_after_hooks );
}
Skip to note 10 content
Codex
Examples
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_errorIf 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.
get_error_messages(); foreach ($errors as $error) { echo $error; } } ?>Categories
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
Skip to note 11 content
Chad Reitsma
You can also update the meta at the same time (if needed)
$data = array( 'ID' => $post_id, 'post_content' => $content, 'meta_input' => array( 'meta_key' => $meta_value, 'another_meta_key' => $another_meta_value ) ); wp_update_post( $data );Skip to note 12 content
Andrei Surdu
If you are losing backslashes from
post_contentfield, usewp_slashfunction to prepare the data:wp_update_post( wp_slash( array( 'ID' => $postId, 'post_content' => $newContent, ) ) );Skip to note 13 content
Azamat
Programmatically change “publish” (or “draft”) to “future” and schedule the post to be published tomorrow:
$time = strtotime( 'tomorrow' ); $my_post = array( 'ID' => 1, 'post_status' => 'future', 'post_date' => date( 'Y-m-d H:i:s', $time ), 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $time ), ); wp_update_post( $my_post );Skip to note 14 content
Irian
When setting the
post_date, make sure to also set thepost_date_gmt.// Change the post date on a post with a status other than 'draft', 'pending' or 'auto-draft' $arg = array( 'ID' => $post_id, 'post_date' => $post_date, 'post_date_gmt' => get_gmt_from_date( $post_date ), ); wp_update_post( $arg );When you are setting the post date on a ‘draft’, ‘pending’ or ‘auto-draft’ post status, also set
edit_dateto true, otherwise the post date won’t be changed.// Change the post date on a post with a status 'draft', 'pending' or 'auto-draft' $arg = array( 'ID' => $post_id, 'post_date' => $post_date, 'post_date_gmt' => get_gmt_from_date( $post_date ), 'edit_date' => true, ); wp_update_post( $arg );Skip to note 15 content
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.
Skip to note 16 content
mmacneil
If you are rescheduling a previously published post, you will be moving the post_status from ‘publish’ to ‘future’ – this seems to require both the
post_date_gmtand your local time (post_date) passed into the function though it executes without complaint if you pass onlypost_date:$args = array( 'ID' => $post_id, 'post_date' => $formattedDateBST, 'post_date_gmt' => $formattedDateGMT, 'post_status' => 'future', );If you neglect to specify the GMT date, the post will stay at ‘Published’ but the ‘Published’ date will be set to the future – yes, this really happens! There is a
get_gmt_from_date()function which works for theY-m-d H:i:sdate/time format only, so you have to be careful there.Some earlier posts include an
edit_date => trueparameter and suggest it is required to reschedule but I cannot find any information listed in the argument list about it on the related pages and I am running a task that runs rescheduling code without specifying it. I am using a custom post type so this might be one of those cases where things behave differently.Skip to note 17 content
Aurovrata Venet
programmatically publish a post,
// Puslish post 37 $my_post = array( 'ID' => 37, 'post_status' => 'publish', ); // Update the post into the database wp_update_post( $my_post );Skip to note 18 content
ztvmark
//Example with acf <a href="https://advancedcustomfields.com" rel="nofollow ugc">https://advancedcustomfields.com</a> 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 ); } }