各位观众老爷,大家好!今天咱们来聊聊WordPress里面一个挺不起眼,但关键时候能救命的函数——get_comment_meta()
。这玩意儿,专门负责从数据库里捞出评论的元数据,就像从评论的口袋里掏宝贝一样。
咱们今天就来扒一扒它的源码,看看它到底是怎么运作的,顺便也学点写代码的小技巧。准备好了吗?咱们开始!
一、Meta,何方神圣?评论为何需要Meta?
在深入代码之前,先得弄清楚“meta”是个什么东西。简单来说,meta就是“元数据”,是对数据进行描述的数据。对于评论来说,除了评论内容、作者、时间这些基本信息,我们还可能需要一些额外的、自定义的信息。
举个例子:
- 用户评分: 假设你想让用户对评论进行评分,这个评分数据就可以作为评论的meta。
- 管理员审核标记: 管理员可以给某些评论打上“已审核”、“待处理”之类的标记,这些标记也是meta。
- 评论来源: 标记评论来自哪个渠道(比如邮件回复、社交平台),这也能当meta。
如果没有 meta,这些额外的信息就没地方放,或者只能塞到评论内容里,想想都觉得乱。
二、get_comment_meta()
:你的取款机
get_comment_meta()
函数的作用,就是根据你提供的评论ID和meta key,从数据库里把对应的meta value取出来。它的基本用法是这样的:
<?php
$comment_id = 123; // 评论ID
$meta_key = 'rating'; // meta key,比如 'rating'(评分)
$single = true; // 是否只返回一个值,默认是 false 返回数组
$rating = get_comment_meta( $comment_id, $meta_key, $single );
if ( $rating ) {
echo '评论评分:' . $rating;
} else {
echo '该评论没有评分';
}
?>
$comment_id
: 不用多说,就是你要取meta的评论的ID。$meta_key
: 你要取的meta的名称。$single
: 决定返回单个值还是数组。如果$single
是true
,且找到了值,就直接返回这个值;如果是false
,或者有多个相同$meta_key
的值,就返回一个包含所有值的数组。
三、源码剖析:一步一步揭开它的面纱
好了,重头戏来了,咱们打开WordPress的源码,找到wp-includes/comment.php
文件,找到get_comment_meta()
函数。
function get_comment_meta( $comment_id, $key = '', $single = false ) {
return get_metadata( 'comment', $comment_id, $key, $single );
}
WTF?! 就这么一行? 没错,get_comment_meta()
自己啥也不干,直接把任务丢给了 get_metadata()
。 这是一种典型的“门面模式”,get_comment_meta()
只是一个门面,负责把请求转发给真正干活的 get_metadata()
。
这样做的好处是,代码更简洁,也更统一。WordPress用一套 *_metadata()
函数体系来处理各种类型的meta数据,比如文章meta、用户meta、评论meta等等。
接下来,我们继续追踪 get_metadata()
函数,它位于 wp-includes/meta.php
文件中。
function get_metadata( $meta_type, $object_id, $meta_key = '', $single = false ) {
global $wpdb;
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$meta_type = sanitize_key( $meta_type );
if ( ! in_array( $meta_type, array( 'post', 'comment', 'term', 'user' ), true ) ) {
return false;
}
$table_name = _get_meta_table( $meta_type );
if ( ! $table_name ) {
return false;
}
$cache_key = sanitize_key( $meta_type ) . '_' . $object_id;
$cache = wp_cache_get( $cache_key, 'meta' );
if ( ! isset( $cache[ $meta_key ] ) && '' !== $meta_key ) {
$cache = update_meta_cache( $meta_type, array( $object_id ) );
if ( isset( $cache[ $meta_key ] ) ) {
$cache = $cache[ $meta_key ];
} else {
$cache = false;
}
}
if ( isset( $cache[ $meta_key ] ) ) {
$values = array_map( 'maybe_unserialize', (array) $cache[ $meta_key ] );
if ( $single ) {
return reset( $values );
} else {
return $values;
}
}
if ( ! $meta_key ) {
$sql = "SELECT meta_key, meta_value FROM $table_name WHERE {$meta_type}_id = %d ORDER BY meta_key";
$values = $wpdb->get_results( $wpdb->prepare( $sql, $object_id ), OBJECT_K );
if ( empty( $values ) ) {
return false;
}
$cache = array();
foreach ( $values as $meta_key => $value ) {
$cache[ $meta_key ] = array( maybe_unserialize( $value->meta_value ) );
}
wp_cache_set( $cache_key, $cache, 'meta' );
if ( $single ) {
return reset( $cache[ $meta_key ] );
} else {
return $cache;
}
}
$sql = $wpdb->prepare( "SELECT meta_value FROM $table_name WHERE {$meta_type}_id = %d AND meta_key = %s", $object_id, $meta_key );
$values = $wpdb->get_col( $sql );
if ( empty( $values ) ) {
return false;
}
$values = array_map( 'maybe_unserialize', $values );
if ( $single ) {
return reset( $values );
} else {
return $values;
}
}
这段代码有点长,咱们分段来解读:
1. 参数校验和表名获取
global $wpdb;
$object_id = absint( $object_id );
if ( ! $object_id ) {
return false;
}
$meta_type = sanitize_key( $meta_type );
if ( ! in_array( $meta_type, array( 'post', 'comment', 'term', 'user' ), true ) ) {
return false;
}
$table_name = _get_meta_table( $meta_type );
if ( ! $table_name ) {
return false;
}
- 首先,引入全局的
$wpdb
对象,它是WordPress用来操作数据库的核心类。 - 然后,对传入的参数进行校验:
$object_id
必须是整数,并且大于0。$meta_type
必须是post
、comment
、term
、user
中的一个。
- 接着,通过
_get_meta_table()
函数获取存储meta数据的表名。对于评论meta,表名是wp_commentmeta
。
2. 缓存机制:能用缓存就不用数据库
$cache_key = sanitize_key( $meta_type ) . '_' . $object_id;
$cache = wp_cache_get( $cache_key, 'meta' );
if ( ! isset( $cache[ $meta_key ] ) && '' !== $meta_key ) {
$cache = update_meta_cache( $meta_type, array( $object_id ) );
if ( isset( $cache[ $meta_key ] ) ) {
$cache = $cache[ $meta_key ];
} else {
$cache = false;
}
}
if ( isset( $cache[ $meta_key ] ) ) {
$values = array_map( 'maybe_unserialize', (array) $cache[ $meta_key ] );
if ( $single ) {
return reset( $values );
} else {
return $values;
}
}
- WordPress使用了缓存来提高性能。它首先尝试从缓存中获取meta数据。
wp_cache_get( $cache_key, 'meta' )
从名为 ‘meta’ 的缓存组中获取键为$cache_key
的缓存数据。$cache_key
是由meta类型和对象ID组成的,比如comment_123
。- 如果缓存中没有找到指定
$meta_key
的数据,并且$meta_key
不为空,那么会调用update_meta_cache()
函数来更新缓存。update_meta_cache()
会批量从数据库中读取指定对象的所有meta数据,并存入缓存。 - 如果缓存中找到了数据,就直接返回,并根据
$single
参数决定返回单个值还是数组。maybe_unserialize()
函数用于反序列化从数据库中取出的数据。
3. 从数据库中读取数据
if ( ! $meta_key ) {
$sql = "SELECT meta_key, meta_value FROM $table_name WHERE {$meta_type}_id = %d ORDER BY meta_key";
$values = $wpdb->get_results( $wpdb->prepare( $sql, $object_id ), OBJECT_K );
if ( empty( $values ) ) {
return false;
}
$cache = array();
foreach ( $values as $meta_key => $value ) {
$cache[ $meta_key ] = array( maybe_unserialize( $value->meta_value ) );
}
wp_cache_set( $cache_key, $cache, 'meta' );
if ( $single ) {
return reset( $cache[ $meta_key ] );
} else {
return $cache;
}
}
$sql = $wpdb->prepare( "SELECT meta_value FROM $table_name WHERE {$meta_type}_id = %d AND meta_key = %s", $object_id, $meta_key );
$values = $wpdb->get_col( $sql );
if ( empty( $values ) ) {
return false;
}
$values = array_map( 'maybe_unserialize', $values );
if ( $single ) {
return reset( $values );
} else {
return $values;
}
- 如果缓存中没有找到数据,或者
$meta_key
为空(表示要获取所有meta数据),那么就需要从数据库中读取数据。 - 如果
$meta_key
为空,构造SQL语句,查询指定object_id
的所有meta_key
和meta_value
,并按照meta_key
排序。 然后将结果存入缓存,并根据$single
参数决定返回单个值还是数组。 - 如果
$meta_key
不为空,构造SQL语句,查询指定object_id
和meta_key
的meta_value
。然后根据$single
参数决定返回单个值还是数组。 $wpdb->prepare()
函数用于防止SQL注入。$wpdb->get_results()
、$wpdb->get_col()
是WordPress提供的数据库查询函数。maybe_unserialize()
函数用于反序列化从数据库中取出的数据。
四、wp_commentmeta
表结构
咱们来简单看看 wp_commentmeta
表的结构,这对理解meta数据的存储方式很有帮助。
字段名 | 数据类型 | 说明 |
---|---|---|
meta_id | bigint(20) UNSIGNED | 自增ID,主键 |
comment_id | bigint(20) UNSIGNED | 评论ID,外键,关联wp_comments 表的comment_ID 字段 |
meta_key | varchar(255) | meta的名称,比如 ‘rating’ |
meta_value | longtext | meta的值,可以存储字符串、数字、数组、对象等。 注意,数组和对象会先被序列化成字符串,再存入数据库。 |
五、update_meta_cache()
函数
前面提到,update_meta_cache()
函数用于批量更新缓存。 咱们简单看看这个函数。
function update_meta_cache( $meta_type, $object_ids ) {
global $wpdb;
if ( empty( $object_ids ) ) {
return false;
}
$meta_type = sanitize_key( $meta_type );
if ( ! in_array( $meta_type, array( 'post', 'comment', 'term', 'user' ), true ) ) {
return false;
}
$table_name = _get_meta_table( $meta_type );
if ( ! $table_name ) {
return false;
}
$object_ids = array_map( 'absint', (array) $object_ids );
$object_ids = array_unique( $object_ids );
$cache = array();
$non_cached_ids = array();
foreach ( $object_ids as $id ) {
$cache_key = sanitize_key( $meta_type ) . '_' . $id;
$cached_object = wp_cache_get( $cache_key, 'meta' );
if ( false === $cached_object ) {
$non_cached_ids[] = $id;
} else {
$cache[ $id ] = $cached_object;
}
}
if ( empty( $non_cached_ids ) ) {
return $cache;
}
$object_ids_string = implode( ',', $non_cached_ids );
$sql = "SELECT {$meta_type}_id, meta_key, meta_value FROM $table_name WHERE {$meta_type}_id IN ($object_ids_string) ORDER BY meta_key";
$meta_list = $wpdb->get_results( $sql, OBJECT );
if ( ! empty( $meta_list ) ) {
foreach ( $meta_list as $meta ) {
$id = (int) $meta->{$meta_type . '_id'};
$meta_key = $meta->meta_key;
$meta_value = maybe_unserialize( $meta->meta_value );
if ( ! isset( $cache[ $id ] ) ) {
$cache[ $id ] = array();
}
if ( ! isset( $cache[ $id ][ $meta_key ] ) ) {
$cache[ $id ][ $meta_key ] = array();
}
$cache[ $id ][ $meta_key ][] = $meta_value;
}
foreach ( $cache as $id => $object_cache ) {
$cache_key = sanitize_key( $meta_type ) . '_' . $id;
wp_cache_set( $cache_key, $object_cache, 'meta' );
}
}
return $cache;
}
- 这个函数接受一个 meta 类型和一个对象 ID 数组作为参数。
- 它首先检查哪些对象 ID 已经存在于缓存中,哪些不在。
- 然后,它从数据库中批量读取不在缓存中的对象 ID 的所有 meta 数据。
- 最后,它将读取到的 meta 数据存入缓存。
六、总结:get_comment_meta()
的工作流程
现在,我们来总结一下 get_comment_meta()
函数的工作流程:
- 接收评论ID、meta key和single参数。
- 调用
get_metadata()
函数。 get_metadata()
函数进行参数校验。get_metadata()
函数尝试从缓存中获取数据。- 如果缓存中没有数据,
get_metadata()
函数调用update_meta_cache()
函数更新缓存。 - 如果缓存中仍然没有数据,
get_metadata()
函数从数据库中读取数据。 get_metadata()
函数根据single参数决定返回单个值还是数组。get_metadata()
函数返回数据。get_comment_meta()
函数返回get_metadata()
函数返回的数据。
可以用表格来更清晰地表示:
步骤 | 函数 | 操作 |
---|---|---|
1 | get_comment_meta() |
接收参数,调用get_metadata() |
2 | get_metadata() |
参数校验,获取表名 |
3 | get_metadata() |
尝试从缓存中获取数据 (wp_cache_get() ) |
4 | get_metadata() |
如果缓存未命中,调用 update_meta_cache() 更新缓存 |
5 | update_meta_cache() |
批量查询数据库,将结果存入缓存 (wp_cache_set() ) |
6 | get_metadata() |
如果缓存仍然未命中(或者需要获取所有meta),则直接查询数据库 ($wpdb->get_results() 或 $wpdb->get_col() ) |
7 | get_metadata() |
根据 $single 参数,决定返回单个值还是数组 |
8 | get_comment_meta() |
返回结果 |
七、优化建议:用好缓存,避免滥用
- 批量获取: 如果你需要获取多个评论的meta数据,最好使用
update_meta_cache()
函数批量更新缓存,然后再从缓存中获取数据,这样可以减少数据库查询次数。 - 避免频繁更新: 频繁更新meta数据会导致缓存失效,影响性能。尽量减少不必要的更新操作。
- 考虑使用 Transients API: 对于一些不经常变化,但又需要持久存储的数据,可以考虑使用 WordPress 的 Transients API,它提供了更灵活的缓存机制。
八、总结:Meta,让评论更强大
get_comment_meta()
函数虽然简单,但它是WordPress评论系统的重要组成部分。它允许我们为评论添加自定义的元数据,从而扩展评论的功能,满足各种各样的需求。理解它的工作原理,可以帮助我们更好地使用它,并优化我们的WordPress站点。
好了,今天的讲座就到这里。希望大家有所收获!下次再见!