各位观众老爷,今天咱们来聊聊WordPress里一个重量级的函数——wp_insert_post()
。这哥们儿负责往数据库里插文章,看着简单,实际上肚子里乾坤可大了,文章状态、分类法、自定义字段,它都得管。咱们今天就扒开它的源码,看看它到底是怎么运作的。
打个招呼: 嘿,各位!准备好接受一场源码的洗礼了吗? Let’s dive in!
一、wp_insert_post()
的基本流程
先来个宏观的视角,wp_insert_post()
的大致流程如下:
- 数据预处理: 接收你传进来的文章数据(数组),进行各种清理、验证、过滤,确保数据安全可靠。
- 检查文章是否存在: 根据文章ID判断是新建还是更新文章。
- 数据准备: 构建要插入或更新数据库的数据数组。
- 插入/更新文章主表: 使用
$wpdb
对象执行SQL语句,插入或更新wp_posts
表。 - 处理分类法: 更新文章的分类、标签等分类法信息。
- 处理自定义字段: 更新文章的自定义字段(meta数据)。
- 清理缓存: 清理相关的缓存,确保数据一致性。
- 触发钩子: 触发各种动作钩子,方便插件扩展。
二、文章状态的处理
文章状态决定了文章的可见性和发布状态,比如“已发布”、“草稿”、“待审核”等等。wp_insert_post()
对文章状态的处理也相当严谨。
// 源码片段 (简化)
function wp_insert_post( $postarr, $wp_error = false ) {
global $wpdb;
// 1. 默认值和数据类型转换
$defaults = array(
'post_status' => 'draft', // 默认状态是草稿
'post_type' => 'post', // 默认类型是文章
);
$postarr = wp_parse_args( $postarr, $defaults ); // 合并数组,如果 $postarr 里没有,就用默认值
// 2. 状态验证
$post_status = sanitize_key( $postarr['post_status'] ); // 清理状态,防止注入
if ( ! in_array( $post_status, get_post_statuses() ) ) {
$post_status = 'draft'; // 如果状态不合法,强制设为草稿
}
// ... (省略其他代码)
// 3. 构建插入/更新的数据数组
$post_data = array(
'post_status' => $post_status,
// ... 其他字段
);
// ... (省略其他代码)
// 4. 插入/更新数据库
if ( $update ) {
$result = $wpdb->update( $wpdb->posts, $post_data, array( 'ID' => $post_ID ) );
} else {
$result = $wpdb->insert( $wpdb->posts, $post_data );
$post_ID = $wpdb->insert_id;
}
return $post_ID;
}
关键点:
- 默认状态: 默认文章状态是
draft
(草稿),避免未经审核的文章直接发布。 - 状态验证:
sanitize_key()
清理状态,get_post_statuses()
获取所有允许的文章状态,确保状态的合法性。如果状态不合法,会被强制设置为draft
。 - 数据数组: 将验证后的状态放入
$post_data
数组,用于插入或更新数据库。 - SQL操作: 最后,通过
$wpdb->insert()
或$wpdb->update()
将状态写入wp_posts
表的post_status
字段。
简单来说,wp_insert_post()
会确保你传入的文章状态是合法有效的,如果不是,就用默认的草稿状态。
三、分类法的处理
分类法(Taxonomies)是 WordPress 用于组织文章的方式,包括分类(Categories)、标签(Tags)等。wp_insert_post()
需要处理文章和分类法之间的关联。
// 源码片段 (简化)
function wp_insert_post( $postarr, $wp_error = false ) {
global $wpdb;
// ... (省略前面的代码)
$tax_input = isset( $postarr['tax_input'] ) ? $postarr['tax_input'] : array();
// ... (省略其他代码)
// 处理分类法
wp_set_post_terms( $post_ID, $tax_input, $postarr['post_type'] );
// ... (省略后面的代码)
return $post_ID;
}
function wp_set_post_terms( $post_id, $terms, $taxonomy = 'category', $append = false ) {
$post_id = (int) $post_id;
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
if ( ! is_array( $terms ) ) {
$terms = array( $terms );
}
$terms = array_map( 'trim', $terms );
$term_ids = array();
foreach ( $terms as $term ) {
// 如果是 term_id, 则直接加入
if ( is_numeric( $term ) ) {
$term_ids[] = (int) $term;
} else {
// 如果是 term_name, 则先获取 term_id
$term_obj = term_exists( $term, $taxonomy );
if ( $term_obj ) {
$term_ids[] = (int) $term_obj['term_id'];
} else {
// 如果 term 不存在, 则创建 term
$term_info = wp_insert_term( $term, $taxonomy );
if ( ! is_wp_error( $term_info ) ) {
$term_ids[] = (int) $term_info['term_id'];
}
}
}
}
$term_ids = array_unique( $term_ids );
return wp_set_object_terms( $post_id, $term_ids, $taxonomy, $append );
}
function wp_set_object_terms( $object_id, $terms, $taxonomy, $append ) {
global $wpdb;
$object_id = (int) $object_id;
if ( ! taxonomy_exists( $taxonomy ) ) {
return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy.' ) );
}
if ( ! is_array( $terms ) ) {
$terms = array( $terms );
}
$terms = array_map( 'intval', $terms );
$terms = array_unique( $terms );
if ( empty( $terms ) ) {
$delete_callback = '_delete_empty_terms';
} else {
$delete_callback = null;
}
$current_terms = wp_get_object_terms( $object_id, $taxonomy, array( 'fields' => 'ids', 'orderby' => 'term_order' ) );
if ( ! is_wp_error( $current_terms ) ) {
$current_terms = array_map( 'intval', $current_terms );
}
if ( $append ) {
$terms = array_merge( $current_terms, $terms );
$terms = array_unique( $terms );
}
$terms_to_add = array_diff( $terms, $current_terms );
$terms_to_remove = array_diff( $current_terms, $terms );
if ( $terms_to_remove ) {
$query = "DELETE FROM {$wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id IN (" . implode( ',', $terms_to_remove ) . ")";
$result = $wpdb->query( $wpdb->prepare( $query, $object_id ) );
}
$values = array();
$query = "INSERT INTO {$wpdb->term_relationships} (object_id, term_taxonomy_id, term_order) VALUES ";
$i = 0;
foreach ( $terms_to_add as $term_id ) {
$values[] = $wpdb->prepare( "(%d, %d, %d)", $object_id, $term_id, $i );
$i++;
}
if ( $values ) {
$query .= implode( ',', $values );
$wpdb->query( $query );
}
wp_cache_delete( $object_id, $taxonomy . '_relationships' );
wp_update_term_count( $terms_to_add, $taxonomy );
wp_update_term_count( $terms_to_remove, $taxonomy );
do_action( 'set_object_terms', $object_id, $terms, $taxonomy, $append, $old_tt_ids = array() );
return $terms;
}
关键点:
-
tax_input
参数:wp_insert_post()
从$postarr
数组中获取tax_input
参数,这个参数是一个数组,包含了要设置的分类法信息。例如:$post_data = array( 'post_title' => '我的文章', 'post_content' => '文章内容', 'tax_input' => array( 'category' => array( 1, 3 ), // 分类ID为1和3 'post_tag' => array( 'wordpress', '技巧' ) // 标签名为 wordpress 和 技巧 ) ); wp_insert_post( $post_data );
-
wp_set_post_terms()
函数:wp_insert_post()
调用wp_set_post_terms()
来处理具体的分类法设置。这个函数负责:- 验证分类法是否存在:
taxonomy_exists()
检查分类法是否有效。 - 处理Term ID 和 Term Name: 如果传递的是 Term ID,则直接使用。 如果传递的是 Term Name,则先查找对应的Term ID,如果不存在,则创建对应的Term。
- 调用
wp_set_object_terms()
: 继续调用wp_set_object_terms()
来更新数据库。
- 验证分类法是否存在:
-
wp_set_object_terms()
函数:wp_set_object_terms()
主要负责将文章和分类法关联起来:- 计算需要添加和删除的关联: 比较当前文章的分类法关联和新的分类法关联,计算出需要添加和删除的关联。
- 删除旧的关联: 使用SQL语句从
wp_term_relationships
表中删除旧的关联。 - 添加新的关联: 使用SQL语句向
wp_term_relationships
表中添加新的关联。这个表是文章和分类法关联的核心。
简单来说,wp_insert_post()
通过 tax_input
参数接收分类法信息,然后调用 wp_set_post_terms()
和 wp_set_object_terms()
来更新 wp_term_relationships
表,从而实现文章和分类法的关联。
四、自定义字段的处理
自定义字段(Custom Fields),也叫Meta Data,是 WordPress 用于存储文章额外信息的一种方式。wp_insert_post()
也负责处理自定义字段的插入和更新。
// 源码片段 (简化)
function wp_insert_post( $postarr, $wp_error = false ) {
global $wpdb;
// ... (省略前面的代码)
$meta_input = isset( $postarr['meta_input'] ) ? $postarr['meta_input'] : array();
// ... (省略其他代码)
// 处理自定义字段
if ( ! empty( $meta_input ) ) {
foreach ( $meta_input as $meta_key => $meta_value ) {
update_post_meta( $post_ID, $meta_key, $meta_value );
}
}
// ... (省略后面的代码)
return $post_ID;
}
function update_post_meta( $post_id, $meta_key, $meta_value, $prev_value = '' ) {
return update_metadata( 'post', $post_id, $meta_key, $meta_value, $prev_value );
}
function update_metadata( $meta_type, $object_id, $meta_key, $meta_value, $prev_value = '' ) {
global $wpdb;
if ( ! $meta_type || ! is_string( $meta_type ) ) {
return false;
}
if ( ! $object_id || ! is_numeric( $object_id ) ) {
return false;
}
$object_id = absint( $object_id );
$table = _get_meta_table( $meta_type );
if ( ! $table ) {
return false;
}
$column = sanitize_key( $meta_type . '_id' );
if ( is_protected_meta( $meta_key, $meta_type ) ) {
return false;
}
$meta_key = wp_slash( $meta_key );
$meta_value = maybe_serialize( wp_slash( $meta_value ) );
$id = null;
$old_value = null;
if ( is_array( $meta_value ) || is_object( $meta_value ) ) {
$meta_value = wp_json_encode( $meta_value );
}
$check = apply_filters( "update_{$meta_type}_metadata_by_key", null, $object_id, $meta_key, $meta_value, $prev_value );
if ( null !== $check ) {
return (bool) $check;
}
$meta_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_id FROM $table WHERE meta_key = %s AND $column = %d", $meta_key, $object_id ) );
if ( empty( $meta_ids ) ) {
$wpdb->insert(
$table,
array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value,
),
array( '%d', '%s', '%s' )
);
$id = $wpdb->insert_id;
wp_cache_delete( $object_id, $meta_type . '_meta' );
do_action( "added_{$meta_type}_meta", $id, $object_id, $meta_key, $meta_value );
return $id;
} else {
foreach ( $meta_ids as $meta_id ) {
$cur_val = get_metadata_by_mid( $meta_type, $meta_id );
if ( $cur_val && ($prev_value === '' || $cur_val->meta_value == $prev_value) ) {
$id = $meta_id;
$old_value = $cur_val->meta_value;
break;
}
}
if ( ! $id ) {
$wpdb->insert(
$table,
array(
$column => $object_id,
'meta_key' => $meta_key,
'meta_value' => $meta_value,
),
array( '%d', '%s', '%s' )
);
$id = $wpdb->insert_id;
wp_cache_delete( $object_id, $meta_type . '_meta' );
do_action( "added_{$meta_type}_meta", $id, $object_id, $meta_key, $meta_value );
return $id;
} else {
$wpdb->update(
$table,
array( 'meta_value' => $meta_value ),
array( 'meta_id' => $id ),
array( '%s' ),
array( '%d' )
);
wp_cache_delete( $object_id, $meta_type . '_meta' );
do_action( "updated_{$meta_type}_meta", $id, $object_id, $meta_key, $meta_value, $old_value );
return true;
}
}
}
关键点:
-
meta_input
参数:wp_insert_post()
从$postarr
数组中获取meta_input
参数,这个参数是一个数组,包含了要设置的自定义字段信息。例如:$post_data = array( 'post_title' => '我的文章', 'post_content' => '文章内容', 'meta_input' => array( 'price' => '99.99', 'color' => 'red' ) ); wp_insert_post( $post_data );
-
循环处理:
wp_insert_post()
遍历$meta_input
数组,对每个自定义字段调用update_post_meta()
函数。 -
update_post_meta()
函数:update_post_meta()
函数主要负责更新wp_postmeta
表,这个表存储了文章的自定义字段信息。它实际上调用了update_metadata()
函数。 -
update_metadata()
函数: 这个函数是核心,它判断是插入还是更新自定义字段:- 判断是否存在: 先查询
wp_postmeta
表,看是否存在具有相同post_id
和meta_key
的记录。 - 插入或更新: 如果不存在,则插入一条新记录。如果存在,则更新现有记录。
- 判断是否存在: 先查询
简单来说,wp_insert_post()
通过 meta_input
参数接收自定义字段信息,然后循环调用 update_post_meta()
和 update_metadata()
来更新 wp_postmeta
表,从而实现自定义字段的存储。
五、总结
wp_insert_post()
真是个大忙人!它不仅负责创建和更新文章本身,还要处理文章状态、分类法和自定义字段。它的内部逻辑比较复杂,涉及到数据的验证、清理、SQL语句的构建和执行,以及缓存的清理。理解 wp_insert_post()
的源码,可以帮助我们更好地理解 WordPress 的运作机制,也可以让我们在开发插件和主题时更加得心应手。
功能 | 处理方式 |
---|---|
文章状态 | 1. 使用默认状态 draft 作为兜底。2. 验证状态的合法性 (get_post_statuses() ),不合法则强制设为 draft 。3. 将状态写入 wp_posts 表的 post_status 字段。 |
分类法 | 1. 从 tax_input 参数获取分类法信息。2. 调用 wp_set_post_terms() 处理分类法设置。3. wp_set_post_terms() 内部验证分类法是否存在,处理Term ID 和 Term Name,然后调用 wp_set_object_terms() 。4. wp_set_object_terms() 比较当前文章的分类法关联和新的关联,计算需要添加和删除的关联,然后更新 wp_term_relationships 表。 |
自定义字段 | 1. 从 meta_input 参数获取自定义字段信息。2. 循环调用 update_post_meta() 处理每个自定义字段。3. update_post_meta() 实际上调用 update_metadata() 。4. update_metadata() 查询 wp_postmeta 表,判断自定义字段是否存在,然后决定是插入新记录还是更新现有记录。 |
希望今天的讲座能让大家对 wp_insert_post()
有更深入的了解。下次再见!