咳咳,麦克风试音… 1, 2, 3… 好嘞!各位好,我是你们今天的WordPress探秘向导,江湖人称代码小能手,今天咱们要一起扒一扒WordPress多站点里一个非常实用,但又容易被忽略的函数:get_blog_details()
。
大家有没有遇到过这样的情况:在一个WordPress多站点网络里,你需要在某个子站点里获取另一个子站点的各种信息,比如站点名称、域名、路径、管理邮箱等等。如果手动去数据库里捞,那可就太low了,效率低不说,还容易出错。这时候,get_blog_details()
函数就派上大用场了。
一、get_blog_details()
函数的前世今生
get_blog_details()
函数,顾名思义,就是“获取博客详情”的意思。它主要用于在WordPress多站点环境中获取指定站点的详细信息。它的定义位于 wp-includes/ms-functions.php
文件中(没错,多站点相关的核心函数都在这里)。
二、get_blog_details()
函数的语法和参数
先来看看 get_blog_details()
函数的基本语法:
get_blog_details( int $blog_id = 0, string $field = '' ) : WP_Site|stdClass|string|null
是不是有点眼花缭乱?别怕,我来给你分解一下:
-
$blog_id
(int, optional): 这是要获取信息的站点的ID。如果省略或者设置为0
,则默认获取当前站点的信息。记住,这里指的是 WordPress 多站点网络中的站点 ID,不是文章 ID 或者其他 ID。 -
$field
(string, optional): 这是一个可选参数,用于指定要获取的字段。如果不指定,则函数会返回一个包含所有站点信息的对象。如果指定了,则只会返回该字段的值。 常见的字段包括:'domain'
:站点域名。'path'
:站点路径。'blogname'
:站点名称。'siteurl'
:站点 URL。'postcount'
:站点文章数量。'admin_email'
:站点管理员邮箱。
-
返回值 (WP_Site|stdClass|string|null): 返回值类型取决于你传入的
$field
参数:- 如果
$field
为空,则返回一个WP_Site
对象 (WordPress 4.6 及以上版本) 或者一个stdClass
对象 (WordPress 4.6 之前版本),包含站点的所有信息。 - 如果
$field
被指定,则返回该字段的字符串值。 - 如果找不到指定的站点或者字段,则返回
null
。
- 如果
三、get_blog_details()
函数的源码剖析
源码是最好的老师,让我们一起深入 wp-includes/ms-functions.php
文件,看看 get_blog_details()
函数的真面目:
function get_blog_details( $blog_id = 0, $field = '' ) {
global $wpdb, $current_site;
if ( ! is_numeric( $blog_id ) ) {
_doing_it_wrong( __FUNCTION__, sprintf( __( 'Blog ID should be a number. Value: %s' ), esc_html( var_export( $blog_id, true ) ) ), '4.6.0' );
return null;
}
$blog_id = (int) $blog_id;
if ( empty( $blog_id ) ) {
$blog_id = get_current_blog_id();
}
if ( ! is_object( $current_site ) ) {
$current_site = new stdClass;
}
$details = wp_cache_get( $blog_id, 'blog-details' );
if ( ! is_object( $details ) ) {
switch_to_blog( $blog_id );
$details = new stdClass;
$details->blog_id = $blog_id;
$details->domain = $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM {$wpdb->blogs} WHERE blog_id = %d", $blog_id ) );
$details->path = $wpdb->get_var( $wpdb->prepare( "SELECT path FROM {$wpdb->blogs} WHERE blog_id = %d", $blog_id ) );
$scheme = is_ssl() ? 'https://' : 'http://';
$details->siteurl = $scheme . $details->domain . $details->path;
$name = get_option( 'blogname' );
if ( empty( $name ) ) {
$name = get_network()->site_name;
}
$details->blogname = $name;
$admin_email = get_option( 'admin_email' );
if ( empty( $admin_email ) ) {
$admin_email = get_site_option( 'admin_email' );
}
$details->admin_email = $admin_email;
$details->postcount = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = 'post'", '' ) );
restore_current_blog();
wp_cache_set( $blog_id, $details, 'blog-details' );
}
if ( version_compare( $GLOBALS['wp_version'], '4.6', '>=' ) ) {
$site = WP_Site::get_instance( $blog_id );
if ( $site ) {
$details->domain = $site->domain;
$details->path = $site->path;
}
}
if ( ! empty( $field ) ) {
if ( isset( $details->$field ) ) {
return $details->$field;
} else {
return null;
}
} else {
return $details;
}
}
这段代码看起来有点长,但其实逻辑很简单,我来给大家一行一行地解读:
global $wpdb, $current_site;
: 引入全局变量$wpdb
(数据库对象) 和$current_site
(当前站点对象)。if ( ! is_numeric( $blog_id ) ) { ... }
: 检查$blog_id
是否为数字,如果不是,则报错并返回null
。$blog_id = (int) $blog_id;
: 将$blog_id
强制转换为整数类型。if ( empty( $blog_id ) ) { ... }
: 如果$blog_id
为空,则获取当前站点的 ID。if ( ! is_object( $current_site ) ) { ... }
: 如果$current_site
不是对象,则创建一个新的stdClass
对象。$details = wp_cache_get( $blog_id, 'blog-details' );
: 尝试从缓存中获取站点信息。WordPress 使用缓存来提高性能,避免重复查询数据库。if ( ! is_object( $details ) ) { ... }
: 如果缓存中没有站点信息,则从数据库中查询:switch_to_blog( $blog_id );
: 切换到指定的站点。这个函数非常重要,它会改变全局状态,让后续的数据库查询操作针对指定的站点。$details = new stdClass;
: 创建一个新的stdClass
对象来存储站点信息。$details->blog_id = $blog_id;
: 设置站点 ID。$details->domain = $wpdb->get_var( $wpdb->prepare( "SELECT domain FROM {$wpdb->blogs} WHERE blog_id = %d", $blog_id ) );
: 从wp_blogs
表中查询站点域名。$wpdb->prepare()
函数用于防止 SQL 注入。$details->path = $wpdb->get_var( $wpdb->prepare( "SELECT path FROM {$wpdb->blogs} WHERE blog_id = %d", $blog_id ) );
: 从wp_blogs
表中查询站点路径。$scheme = is_ssl() ? 'https://' : 'http://';
: 判断当前是否使用 SSL,并设置协议。$details->siteurl = $scheme . $details->domain . $details->path;
: 拼接站点 URL。$name = get_option( 'blogname' ); ... $details->blogname = $name;
: 从wp_options
表中查询站点名称。如果站点名称为空,则使用网络名称。$admin_email = get_option( 'admin_email' ); ... $details->admin_email = $admin_email;
: 从wp_options
表中查询管理员邮箱。如果管理员邮箱为空,则使用站点管理员邮箱。$details->postcount = (int) $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM {$wpdb->posts} WHERE post_status = 'publish' AND post_type = 'post'", '' ) );
: 查询站点文章数量。restore_current_blog();
: 恢复到之前的站点。 这个函数和switch_to_blog()
配套使用,非常重要,否则可能会影响其他站点的操作。wp_cache_set( $blog_id, $details, 'blog-details' );
: 将站点信息保存到缓存中。
if ( version_compare( $GLOBALS['wp_version'], '4.6', '>=' ) ) { ... }
: 如果是 WordPress 4.6 及以上版本,则使用WP_Site
对象来获取站点域名和路径。if ( ! empty( $field ) ) { ... }
: 如果指定了$field
参数,则返回该字段的值。else { ... }
: 否则,返回包含所有站点信息的对象。
四、get_blog_details()
函数的使用示例
光说不练假把式,让我们来看一些实际的使用示例:
示例 1:获取指定站点的域名
$blog_id = 2; // 假设我们要获取 ID 为 2 的站点的域名
$domain = get_blog_details( $blog_id, 'domain' );
if ( $domain ) {
echo '站点 ID ' . $blog_id . ' 的域名是:' . $domain;
} else {
echo '找不到站点 ID ' . $blog_id . ' 的信息';
}
示例 2:获取当前站点的所有信息
$details = get_blog_details(); // 不传递任何参数,默认获取当前站点的信息
if ( is_object( $details ) ) {
echo '站点名称:' . $details->blogname . '<br>';
echo '站点域名:' . $details->domain . '<br>';
echo '站点路径:' . $details->path . '<br>';
echo '站点 URL:' . $details->siteurl . '<br>';
echo '站点管理员邮箱:' . $details->admin_email . '<br>';
echo '站点文章数量:' . $details->postcount . '<br>';
} else {
echo '获取站点信息失败';
}
示例 3:在循环中获取多个站点的名称
$blog_ids = [1, 2, 3]; // 假设我们要获取 ID 为 1, 2, 3 的站点的名称
foreach ( $blog_ids as $blog_id ) {
$blogname = get_blog_details( $blog_id, 'blogname' );
if ( $blogname ) {
echo '站点 ID ' . $blog_id . ' 的名称是:' . $blogname . '<br>';
} else {
echo '找不到站点 ID ' . $blog_id . ' 的信息<br>';
}
}
示例 4:配合 switch_to_blog()
和 restore_current_blog()
使用
这个示例展示了如何在不同的站点之间切换,并获取每个站点的文章数量:
$original_blog_id = get_current_blog_id(); // 保存当前站点的 ID
$blog_ids = [1, 2, 3]; // 假设我们要获取 ID 为 1, 2, 3 的站点的文章数量
foreach ( $blog_ids as $blog_id ) {
switch_to_blog( $blog_id ); // 切换到指定站点
$post_count = get_blog_details( null, 'postcount' ); // 获取当前站点的文章数量 (注意这里 $blog_id 传 null)
if ( $post_count !== null ) {
echo '站点 ID ' . $blog_id . ' 的文章数量是:' . $post_count . '<br>';
} else {
echo '找不到站点 ID ' . $blog_id . ' 的信息<br>';
}
restore_current_blog(); // 恢复到之前的站点
}
// 确保最后恢复到最初的站点
if ($original_blog_id != get_current_blog_id()) {
switch_to_blog($original_blog_id);
}
五、注意事项和最佳实践
- 缓存:
get_blog_details()
函数会使用 WordPress 的缓存机制,所以不必担心频繁调用会影响性能。但是,如果站点信息发生变化,可能需要清除缓存才能看到最新的信息。 switch_to_blog()
和restore_current_blog()
: 在使用switch_to_blog()
函数切换站点后,一定要记得使用restore_current_blog()
函数恢复到之前的站点,否则可能会导致不可预知的错误。- 安全性:
get_blog_details()
函数本身没有安全问题,但是在使用它获取站点信息时,要注意对输出进行转义,防止 XSS 攻击。 - 性能: 虽然
get_blog_details()
函数使用了缓存,但是频繁调用仍然会影响性能。如果需要在循环中获取多个站点的信息,建议一次性获取所有站点的信息,然后进行遍历。 - 错误处理: 在使用
get_blog_details()
函数时,要进行错误处理,判断是否成功获取了站点信息。 - WordPress 版本: 注意不同 WordPress 版本对
get_blog_details()
函数的返回值类型可能略有不同,特别是WP_Site
对象的引入。
六、get_blog_details()
函数的替代方案
虽然 get_blog_details()
函数非常方便,但在某些情况下,你可能需要考虑其他方案:
- 直接查询数据库: 如果你需要获取的站点信息不在
get_blog_details()
函数提供的字段范围内,或者你需要进行更复杂的查询,可以直接使用$wpdb
对象查询数据库。 - 使用
WP_Site
对象: 在 WordPress 4.6 及以上版本中,你可以使用WP_Site
对象来获取站点信息。WP_Site
对象提供了更多的方法来操作站点信息,例如获取站点的所有选项。 - 自定义函数: 如果你需要频繁获取特定的站点信息,可以编写自定义函数来封装
get_blog_details()
函数或者直接查询数据库。
七、总结
get_blog_details()
函数是WordPress多站点开发中一个非常实用的工具,它可以帮助你轻松获取指定站点的详细信息。掌握它的用法,可以大大提高你的开发效率。希望今天的讲解能帮助大家更好地理解和使用 get_blog_details()
函数。
最后,记住,代码的世界充满了乐趣,不断学习和探索才能成为真正的代码高手! 下次再见!