各位同学,今天咱们来扒一扒 WordPress 里面一个非常重要的函数—— delete_post_meta()
。这货可是负责给文章(post)“瘦身”的,专门用来删除那些我们不再需要的自定义字段(meta data)。想象一下,你的文章本来穿了很多“衣服”(自定义字段),现在觉得太累赘了,想脱掉几件,那 delete_post_meta()
就是你的私人造型师,帮你把那些多余的“衣服”一件件脱下来。
好,废话不多说,直接上代码,然后咱们一点一点拆解它。
<?php
/**
* Deletes post meta data.
*
* @since 2.0.0
*
* @global wpdb $wpdb WordPress database abstraction object.
*
* @param int $post_id Post ID.
* @param string $meta_key Optional. Meta key to delete. By default, delete for all meta keys.
* @param mixed $meta_value Optional. Meta value to delete. Must be used with $meta_key. By default, delete for all meta values.
* @param bool $delete_all Optional. Whether to delete all matching meta entries,
* or just the first. Default is false.
* @return bool True on successful delete, false on failure.
*/
function delete_post_meta( $post_id, $meta_key = '', $meta_value = '', $delete_all = false ) {
global $wpdb;
$post_id = absint( $post_id );
if ( ! $post_id ) {
return false;
}
$meta_key = trim( $meta_key );
if ( empty( $meta_key ) ) {
return false;
}
$table = _get_meta_table( 'post' );
$id_column = 'meta_id';
$post_id_column = 'post_id';
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
$meta_ids = array();
do_action( 'delete_post_meta', $post_id, $meta_key, $meta_value, $delete_all );
$key_name = esc_sql( $meta_key );
if ( $delete_all ) {
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) {
$value_to_delete = wp_slash( $meta_value );
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s",
$post_id,
$meta_key,
$value_to_delete
);
} else {
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s",
$post_id,
$meta_key
);
}
$meta_ids = $wpdb->get_col( $query );
if ( ! empty( $meta_ids ) ) {
$meta_ids = array_map( 'intval', $meta_ids );
$sql = "DELETE FROM {$table} WHERE {$id_column} IN (" . implode( ',', $meta_ids ) . ')';
$count = $wpdb->query( $sql );
if ( $count ) {
wp_cache_delete_multiple( $meta_ids, 'post_meta' );
do_action( 'deleted_post_meta', $meta_ids, $post_id, $meta_key, $meta_value, $delete_all );
return true;
} else {
return false;
}
}
} else {
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) {
$value_to_delete = wp_slash( $meta_value );
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s LIMIT 1",
$post_id,
$meta_key,
$value_to_delete
);
} else {
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s LIMIT 1",
$post_id,
$meta_key
);
}
$meta_id = $wpdb->get_var( $query );
if ( $meta_id ) {
/**
* Fires immediately before post meta is deleted.
*
* @since 2.9.0
*
* @param int $meta_ids ID of the meta data being deleted.
*/
do_action( 'delete_post_meta_by_mid', $meta_id );
$result = $wpdb->delete( $table, array( $id_column => $meta_id ) );
if ( $result ) {
wp_cache_delete( $meta_id, 'post_meta' );
do_action( 'deleted_post_meta', array( $meta_id ), $post_id, $meta_key, $meta_value, $delete_all );
return true;
} else {
return false;
}
}
}
return false;
}
是不是感觉有点长?别怕,咱们把它分解成几个小模块,逐个击破。
1. 参数校验与准备阶段
global $wpdb;
$post_id = absint( $post_id );
if ( ! $post_id ) {
return false;
}
$meta_key = trim( $meta_key );
if ( empty( $meta_key ) ) {
return false;
}
$table = _get_meta_table( 'post' );
$id_column = 'meta_id';
$post_id_column = 'post_id';
$meta_key = wp_unslash( $meta_key );
$meta_value = wp_unslash( $meta_value );
$meta_ids = array();
do_action( 'delete_post_meta', $post_id, $meta_key, $meta_value, $delete_all );
global $wpdb;
: 这句是老朋友了,把全局的$wpdb
对象拿过来,这样我们才能操作数据库。$wpdb
就像一个数据库的遥控器,你想对数据库做什么,都得通过它。$post_id = absint( $post_id );
:absint()
函数确保$post_id
是一个正整数。如果$post_id
不是整数,或者小于等于 0,那就直接返回false
,说明文章 ID 不合法,没法删除。$meta_key = trim( $meta_key );
:trim()
函数去除$meta_key
首尾的空格,防止因为空格导致匹配失败。if ( empty( $meta_key ) ) { return false; }
: 如果$meta_key
是空的,那还删个啥?直接返回false
。$table = _get_meta_table( 'post' );
:_get_meta_table( 'post' )
函数获取存储 post meta 的表名。通常情况下,这个表名是wp_postmeta
。$id_column = 'meta_id'; $post_id_column = 'post_id';
: 定义了两个常量,分别代表 meta 表中的 ID 列(meta_id
)和 post ID 列(post_id
)。$meta_key = wp_unslash( $meta_key ); $meta_value = wp_unslash( $meta_value );
:wp_unslash()
函数移除$meta_key
和$meta_value
中的反斜杠。这个操作主要是为了还原数据,因为在保存到数据库时,可能会对某些特殊字符进行转义。$meta_ids = array();
: 初始化一个空数组,用来存储待删除的 meta ID。do_action( 'delete_post_meta', $post_id, $meta_key, $meta_value, $delete_all );
: 这是一个非常重要的钩子(hook),允许开发者在删除 meta 数据之前执行自定义操作。你可以在这里做一些权限验证、日志记录等等。
这部分代码主要做了两件事:一是验证输入参数的合法性,二是准备一些后面要用到的变量。
2. delete_all
为 true
的情况:删除所有匹配的 meta 数据
if ( $delete_all ) {
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) {
$value_to_delete = wp_slash( $meta_value );
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s",
$post_id,
$meta_key,
$value_to_delete
);
} else {
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s",
$post_id,
$meta_key
);
}
$meta_ids = $wpdb->get_col( $query );
if ( ! empty( $meta_ids ) ) {
$meta_ids = array_map( 'intval', $meta_ids );
$sql = "DELETE FROM {$table} WHERE {$id_column} IN (" . implode( ',', $meta_ids ) . ')';
$count = $wpdb->query( $sql );
if ( $count ) {
wp_cache_delete_multiple( $meta_ids, 'post_meta' );
do_action( 'deleted_post_meta', $meta_ids, $post_id, $meta_key, $meta_value, $delete_all );
return true;
} else {
return false;
}
}
}
这部分代码是核心逻辑之一,处理 $delete_all
为 true
的情况。
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) { ... } else { ... }
: 判断是否指定了$meta_value
。如果指定了$meta_value
,就需要精确匹配post_id
、meta_key
和meta_value
;如果没有指定$meta_value
,只需要匹配post_id
和meta_key
。$value_to_delete = wp_slash( $meta_value );
: 如果存在$meta_value
,使用wp_slash()
函数对$meta_value
进行转义,防止 SQL 注入。$query = $wpdb->prepare( ... );
: 使用$wpdb->prepare()
函数构造 SQL 查询语句。这个函数可以安全地处理用户输入,防止 SQL 注入。注意,这里使用了预处理语句,用%d
、%s
等占位符代替实际的值,然后再将值传递给$wpdb->prepare()
函数。"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s"
: 如果指定了$meta_value
,这个 SQL 语句会查找所有post_id
、meta_key
和meta_value
都匹配的 meta ID。"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s"
: 如果没有指定$meta_value
,这个 SQL 语句会查找所有post_id
和meta_key
都匹配的 meta ID。
$meta_ids = $wpdb->get_col( $query );
: 执行 SQL 查询,获取所有匹配的 meta ID,并将它们存储在$meta_ids
数组中。$wpdb->get_col()
函数只返回查询结果的第一列。if ( ! empty( $meta_ids ) ) { ... }
: 判断是否找到了匹配的 meta ID。如果没有找到,就直接跳过删除操作。$meta_ids = array_map( 'intval', $meta_ids );
: 将$meta_ids
数组中的所有元素转换为整数。$sql = "DELETE FROM {$table} WHERE {$id_column} IN (" . implode( ',', $meta_ids ) . ')';
: 构造 SQL 删除语句。这里使用了IN
子句,可以一次性删除多个 meta ID。implode( ',', $meta_ids )
函数将$meta_ids
数组转换为一个以逗号分隔的字符串。$count = $wpdb->query( $sql );
: 执行 SQL 删除语句。$wpdb->query()
函数返回受影响的行数。if ( $count ) { ... } else { ... }
: 判断是否成功删除了 meta 数据。如果$count
大于 0,说明成功删除了 meta 数据,就执行一些清理操作,并返回true
;否则,返回false
。wp_cache_delete_multiple( $meta_ids, 'post_meta' );
: 从 WordPress 对象缓存中删除已删除的 meta 数据。wp_cache_delete_multiple()
函数可以一次性删除多个缓存项。do_action( 'deleted_post_meta', $meta_ids, $post_id, $meta_key, $meta_value, $delete_all );
: 这是一个钩子,允许开发者在删除 meta 数据之后执行自定义操作。
3. delete_all
为 false
的情况:只删除第一个匹配的 meta 数据
else {
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) {
$value_to_delete = wp_slash( $meta_value );
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s LIMIT 1",
$post_id,
$meta_key,
$value_to_delete
);
} else {
$query = $wpdb->prepare(
"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s LIMIT 1",
$post_id,
$meta_key
);
}
$meta_id = $wpdb->get_var( $query );
if ( $meta_id ) {
/**
* Fires immediately before post meta is deleted.
*
* @since 2.9.0
*
* @param int $meta_ids ID of the meta data being deleted.
*/
do_action( 'delete_post_meta_by_mid', $meta_id );
$result = $wpdb->delete( $table, array( $id_column => $meta_id ) );
if ( $result ) {
wp_cache_delete( $meta_id, 'post_meta' );
do_action( 'deleted_post_meta', array( $meta_id ), $post_id, $meta_key, $meta_value, $delete_all );
return true;
} else {
return false;
}
}
}
这部分代码处理 $delete_all
为 false
的情况,也就是只删除第一个匹配的 meta 数据。
if ( ! empty( $meta_value ) || is_numeric( $meta_value ) ) { ... } else { ... }
: 和前面一样,判断是否指定了$meta_value
。$query = $wpdb->prepare( ... );
: 构造 SQL 查询语句。注意,这里使用了LIMIT 1
,表示只返回第一个匹配的结果。"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s AND meta_value = %s LIMIT 1"
: 如果指定了$meta_value
。"SELECT {$id_column} FROM {$table} WHERE {$post_id_column} = %d AND meta_key = %s LIMIT 1"
: 如果没有指定$meta_value
。
$meta_id = $wpdb->get_var( $query );
: 执行 SQL 查询,获取第一个匹配的 meta ID。$wpdb->get_var()
函数只返回查询结果的第一行第一列。if ( $meta_id ) { ... }
: 判断是否找到了匹配的 meta ID。do_action( 'delete_post_meta_by_mid', $meta_id );
: 这是一个钩子,允许开发者在通过 meta ID 删除 meta 数据之前执行自定义操作。$result = $wpdb->delete( $table, array( $id_column => $meta_id ) );
: 执行 SQL 删除语句。$wpdb->delete()
函数删除表中满足指定条件的行。if ( $result ) { ... } else { ... }
: 判断是否成功删除了 meta 数据。wp_cache_delete( $meta_id, 'post_meta' );
: 从 WordPress 对象缓存中删除已删除的 meta 数据。wp_cache_delete()
函数删除单个缓存项。do_action( 'deleted_post_meta', array( $meta_id ), $post_id, $meta_key, $meta_value, $delete_all );
: 这是一个钩子,允许开发者在删除 meta 数据之后执行自定义操作。
4. 兜底返回 false
return false;
}
如果前面的所有操作都没有成功删除 meta 数据,就返回 false
。
总结一下,delete_post_meta()
函数的执行流程如下:
- 参数校验: 检查
$post_id
和$meta_key
是否合法。 - 准备工作: 获取 meta 表名,定义 ID 列和 post ID 列,移除反斜杠,初始化 meta ID 数组。
- 钩子: 触发
delete_post_meta
钩子。 delete_all
为true
:- 构造 SQL 查询语句,查找所有匹配的 meta ID。
- 执行 SQL 查询,获取 meta ID 列表。
- 构造 SQL 删除语句,删除所有匹配的 meta ID。
- 执行 SQL 删除语句。
- 从对象缓存中删除已删除的 meta 数据。
- 触发
deleted_post_meta
钩子。
delete_all
为false
:- 构造 SQL 查询语句,查找第一个匹配的 meta ID。
- 执行 SQL 查询,获取 meta ID。
- 触发
delete_post_meta_by_mid
钩子。 - 执行 SQL 删除语句,删除该 meta ID。
- 从对象缓存中删除已删除的 meta 数据。
- 触发
deleted_post_meta
钩子。
- 返回结果: 如果成功删除了 meta 数据,返回
true
;否则,返回false
。
表格总结
步骤 | 描述 |
---|---|
参数校验 | 验证 $post_id 和 $meta_key 的有效性。 |
准备工作 | 获取 meta 表名,定义 ID 和 post ID 列,移除反斜杠。 |
delete_post_meta 钩子 |
允许在删除 meta 数据前执行自定义操作。 |
delete_all = true |
查找并删除所有匹配的 meta 数据: 1. 构建 SQL 查询,获取所有匹配的 meta ID。 2. 执行 SQL 删除,一次性删除所有 meta ID。 3. 从缓存中删除已删除的 meta 数据。 4. 触发 deleted_post_meta 钩子。 |
delete_all = false |
查找并删除第一个匹配的 meta 数据: 1. 构建 SQL 查询,获取第一个匹配的 meta ID。 2. 触发 delete_post_meta_by_mid 钩子。3. 执行 SQL 删除,删除该 meta ID。 4. 从缓存中删除已删除的 meta 数据。 5. 触发 deleted_post_meta 钩子。 |
返回结果 | 如果成功删除 meta 数据,返回 true ,否则返回 false 。 |
实际应用场景举例
假设你有一个文章类型是 "book",你想删除所有书的 "author" 这个自定义字段。
$args = array(
'post_type' => 'book',
'posts_per_page' => -1, // 获取所有 book 类型的文章
);
$books = get_posts( $args );
foreach ( $books as $book ) {
delete_post_meta( $book->ID, 'author', '', true ); // 删除所有 'author' 字段
}
这段代码会遍历所有 "book" 类型的文章,然后调用 delete_post_meta()
函数,将每本书的 "author" 字段都删除掉。delete_all
设置为 true
,确保所有 "author" 字段都被删除,不管有多少个。
注意事项
- 谨慎使用
delete_all = true
: 如果你的 meta key 使用不当,可能会误删一些不该删的数据。 - SQL 注入:
$wpdb->prepare()
函数可以防止 SQL 注入,但是在使用自定义 SQL 语句时,一定要注意对用户输入进行转义。 - 缓存: 删除 meta 数据后,一定要清理缓存,确保前台显示的数据是最新的。
好了,关于 delete_post_meta()
函数的讲解就到这里。希望通过今天的学习,大家对这个函数有了更深入的了解。记住,熟练掌握这些常用的函数,才能在 WordPress 开发的道路上越走越远!下课!