深入理解 WordPress `get_bloginfo()` 函数的源码:如何从数据库或常量中获取站点信息。

嘿!大家好!我是你们今天的 WordPress 信息侦探,代号“InfoHound”。咱们今天来聊聊 WordPress 里那个神通广大的 get_bloginfo() 函数,看看它到底是如何从数据库和常量里挖出各种站点信息的。准备好了吗?咱们开始探险!

第一部分:get_bloginfo() 是个啥?

首先,让我们给 get_bloginfo() 来个官方定义:它是一个 WordPress 内置函数,用于检索关于 WordPress 站点的信息,比如站点的名称、描述、URL 等等。你可以把它想象成一个信息检索器,只要告诉它你想知道什么,它就会尽力去找出来。

但是,它可不是像搜索引擎那样瞎搜一气,而是有明确的目标和路径。它主要从两个地方寻找信息:

  • 数据库: WordPress 站点的大部分信息都存储在数据库里,比如站点名称、描述、管理员邮箱等等。
  • 常量: 有些信息在 WordPress 的配置文件 wp-config.php 中定义为常量,比如 WordPress 的版本号、调试模式等等。

第二部分:get_bloginfo() 的庐山真面目:源码解读

好了,理论知识铺垫完毕,咱们直接上代码,看看 get_bloginfo() 的源码是如何运作的。

function get_bloginfo( string $show = '', string $filter = 'raw' ): string {
    global $wpdb, $blog_id, $site_id;

    $output = '';

    switch ( $show ) {
        case 'name':
            $output = get_option( 'blogname' );
            break;
        case 'description':
            $output = get_option( 'blogdescription' );
            break;
        case 'wpurl':
        case 'url':
            $output = get_option( 'siteurl' );
            break;
        case 'home':
            $output = home_url();
            break;
        case 'siteurl':
            $output = site_url();
            break;
        case 'admin_email':
            $output = get_option( 'admin_email' );
            break;
        case 'charset':
            $output = get_option( 'blog_charset' );
            break;
        case 'version':
            $output = get_blog_version();
            break;
        case 'html_type':
            $output = get_option( 'html_type' );
            break;
        case 'text_direction':
            $output = get_option( 'text_direction' );
            break;
        case 'language':
            $output = get_locale();
            break;
        case 'stylesheet_url':
            $output = get_stylesheet_uri();
            break;
        case 'stylesheet_directory':
            $output = get_stylesheet_directory_uri();
            break;
        case 'template_url':
        case 'template_directory':
            $output = get_template_directory_uri();
            break;
        case 'pingback_url':
            $output = get_option( 'pingback_url' );
            break;
        case 'rss_url':
            $output = get_feed_link( 'rss' );
            break;
        case 'rss2_url':
            $output = get_feed_link( 'rss2' );
            break;
        case 'atom_url':
            $output = get_feed_link( 'atom' );
            break;
        case 'rdf_url':
            $output = get_feed_link( 'rdf' );
            break;
        case 'comments_rss2_url':
            $output = get_feed_link( 'comments_rss2' );
            break;
        default:
            $output = '';
            break;
    }

    $output = apply_filters( 'pre_option_' . $show, $output );
    $output = apply_filters( 'option_' . $show, $output );

    if ( 'raw' === $filter ) {
        return $output;
    }

    return sanitize_text_field( $output );
}

别被这段代码吓到,咱们一步一步来分析。

  1. 函数签名:

    function get_bloginfo( string $show = '', string $filter = 'raw' ): string {
    • $show: 这是最重要的参数,它告诉 get_bloginfo() 你想获取什么信息。比如,你想获取站点名称,就把 $show 设置为 'name'
    • $filter: 这个参数用来控制输出结果的过滤方式。默认值是 'raw',表示不进行任何过滤。如果设置为其他值,可能会对输出结果进行转义或清理。通常情况下,保持默认值就够了。
    • : string:表示此函数返回一个字符串。
  2. 全局变量:

    global $wpdb, $blog_id, $site_id;
    • $wpdb:这是一个全局对象,代表 WordPress 的数据库连接。通过它可以执行 SQL 查询,从数据库中获取数据。
    • $blog_id$site_id:这两个变量在多站点 WordPress 中使用,分别代表当前博客和站点的 ID。
  3. switch 语句:

    switch ( $show ) {
        case 'name':
            $output = get_option( 'blogname' );
            break;
        // ... 其他 case ...
        default:
            $output = '';
            break;
    }

    这是 get_bloginfo() 的核心部分。它使用 switch 语句来判断 $show 参数的值,并根据不同的值执行不同的操作。

    • case 'name' 如果 $show'name',就调用 get_option( 'blogname' ) 函数来获取站点名称。get_option() 函数是 WordPress 用来从 wp_options 表中获取选项值的函数。'blogname' 是存储站点名称的选项名。
    • case 'description' 类似地,如果 $show'description',就调用 get_option( 'blogdescription' ) 来获取站点描述。
    • case 'wpurl''url' 这两个 case 获取的是站点的 URL,它们都调用 get_option( 'siteurl' )
    • case 'home' 这个比较特殊,它调用 home_url() 函数来获取站点的首页 URL。home_url() 函数会考虑多站点的情况,并返回正确的首页 URL。
    • case 'siteurl' 调用 site_url() 函数来获取站点的 URL,它和home_url()类似,会考虑多站点的情况
    • case 'version' 这个 case 调用 get_blog_version() 函数来获取 WordPress 的版本号。get_blog_version() 函数通常是从 wp-includes/version.php 文件中读取版本号常量。
    • default 如果 $show 的值不在任何一个 case 中,就将 $output 设置为空字符串。
  4. 各种URL的获取:

    • stylesheet_url: 获取样式表URL,通过get_stylesheet_uri()获取。
    • stylesheet_directory: 获取样式表目录的URL,通过get_stylesheet_directory_uri()获取。
    • template_url / template_directory: 获取模板目录URL,通过get_template_directory_uri()获取。
    • pingback_url: 获取Pingback URL,通过get_option( 'pingback_url' )获取。
    • rss_url, rss2_url, atom_url, rdf_url, comments_rss2_url: 获取各种RSS Feed URL, 通过 get_feed_link()获取。
  5. 过滤器(Filters):

    $output = apply_filters( 'pre_option_' . $show, $output );
    $output = apply_filters( 'option_' . $show, $output );

    WordPress 提供了强大的过滤器机制,允许开发者在函数执行过程中修改数据。

    • apply_filters( 'pre_option_' . $show, $output ):这个过滤器允许在从数据库中获取选项值之前修改 $output
    • apply_filters( 'option_' . $show, $output ):这个过滤器允许在从数据库中获取选项值之后修改 $output

    通过这些过滤器,你可以轻松地自定义 get_bloginfo() 的输出结果。

  6. Sanitization:

    if ( 'raw' === $filter ) {
        return $output;
    }
    
    return sanitize_text_field( $output );

    如果 $filter 不是 'raw',就调用 sanitize_text_field() 函数来清理 $outputsanitize_text_field() 函数会移除字符串中的 HTML 标签和特殊字符,以防止 XSS 攻击。

第三部分:get_option() 函数:数据库里的寻宝之旅

既然 get_bloginfo() 频繁地使用 get_option() 函数来从数据库中获取信息,那么咱们就来深入了解一下 get_option()

function get_option( string $option, mixed $default = false ): mixed {
    global $wpdb;

    /**
     * Filters the value of an existing option before it is retrieved.
     *
     * The dynamic portion of the hook name, `$option`, refers to the option name.
     *
     * @since 2.2.0
     *
     * @param mixed $pre_option The value to return instead of the option value.
     *                           Default null to bypass this filter.
     * @param string $option     Option name.
     */
    $pre = apply_filters( 'pre_option_' . $option, false, $option );
    if ( false !== $pre ) {
        return $pre;
    }

    $alloptions = wp_load_alloptions();

    if ( isset( $alloptions[ $option ] ) ) {
        $value = $alloptions[ $option ];
    } else {
        $value = wp_cache_get( $option, 'options' );

        if ( false === $value ) {
            $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );

            // Has to be get_row rather than get_var because of funkiness with 0, false, null values.
            if ( is_object( $row ) ) {
                $value = $row->option_value;
            } else {
                $value = $default;
            }

            wp_cache_add( $option, $value, 'options' );
        }
    }

    /**
     * Filters the value of an option.
     *
     * The dynamic portion of the hook name, `$option`, refers to the option name.
     *
     * @since 2.0.0
     *
     * @param mixed $value  Value of the option. If using an object, it will be passed by reference.
     * @param string $option Option name.
     */
    return apply_filters( 'option_' . $option, $value, $option );
}
  1. 函数签名:

    function get_option( string $option, mixed $default = false ): mixed {
    • $option: 这是要获取的选项名。比如,要获取站点名称,就把 $option 设置为 'blogname'
    • $default: 这是可选参数,用于指定当选项不存在时返回的默认值。默认值是 false
    • : mixed:表示此函数返回混合类型的数据。
  2. 过滤器(Filters):

    $pre = apply_filters( 'pre_option_' . $option, false, $option );
    if ( false !== $pre ) {
        return $pre;
    }

    类似于 get_bloginfo()get_option() 也使用了过滤器。'pre_option_' . $option 过滤器允许在从数据库中获取选项值之前直接返回一个值,跳过数据库查询。

  3. wp_load_alloptions()

    $alloptions = wp_load_alloptions();

    wp_load_alloptions() 函数会从数据库的 wp_options 表中加载所有自动加载的选项(autoload 字段设置为 'yes' 的选项),并将它们存储在一个数组中。这样可以减少数据库查询次数,提高性能。

  4. 缓存(Cache):

    if ( isset( $alloptions[ $option ] ) ) {
        $value = $alloptions[ $option ];
    } else {
        $value = wp_cache_get( $option, 'options' );
    
        if ( false === $value ) {
            // ... 从数据库中获取选项值 ...
            wp_cache_add( $option, $value, 'options' );
        }
    }

    get_option() 使用 WordPress 的对象缓存来存储选项值。

    • 首先,它检查选项是否在 $alloptions 数组中。如果在,就直接从数组中获取选项值。
    • 如果不在,就尝试从缓存中获取选项值。wp_cache_get( $option, 'options' ) 函数会从 'options' 组中获取 $option 的值。
    • 如果缓存中也没有,就执行 SQL 查询,从 wp_options 表中获取选项值。
    • 最后,将获取到的选项值添加到缓存中,以便下次使用。
  5. 数据库查询:

    $row = $wpdb->get_row( $wpdb->prepare( "SELECT option_value FROM $wpdb->options WHERE option_name = %s LIMIT 1", $option ) );
    
    if ( is_object( $row ) ) {
        $value = $row->option_value;
    } else {
        $value = $default;
    }

    如果缓存中没有找到选项值,get_option() 就会执行 SQL 查询来从数据库中获取。

    • $wpdb->prepare() 函数用于预处理 SQL 查询,以防止 SQL 注入攻击。
    • $wpdb->get_row() 函数执行 SQL 查询,并返回结果集的第一行作为一个对象。
    • 如果查询成功,就从对象中获取 option_value 字段的值。
    • 如果查询失败(例如,选项不存在),就返回 $default 参数指定的值。
  6. 最后的过滤器:

    return apply_filters( 'option_' . $option, $value, $option );

    在返回选项值之前,get_option() 还会应用 'option_' . $option 过滤器,允许开发者修改最终的选项值。

第四部分:get_blog_version():常量里的秘密

get_bloginfo()$show'version' 时,会调用 get_blog_version() 函数来获取 WordPress 的版本号。咱们来看看 get_blog_version() 的源码:

function get_blog_version() {
    include ABSPATH . WPINC . '/version.php';
    return $wp_version;
}

这段代码非常简单:

  1. 包含 version.php

    include ABSPATH . WPINC . '/version.php';

    它包含了 wp-includes/version.php 文件。这个文件定义了 WordPress 的版本号常量 $wp_version

  2. 返回 $wp_version

    return $wp_version;

    它直接返回 $wp_version 常量的值。

第五部分:实战演练:用 get_bloginfo() 获取站点信息

好了,理论知识讲了一大堆,现在咱们来做一些实战演练,看看如何使用 get_bloginfo() 函数来获取站点信息。

$show 参数 描述 示例输出
'name' 站点名称 '我的博客'
'description' 站点描述 '分享我的想法和经验'
'url' 站点 URL 'https://example.com'
'home' 站点首页 URL 'https://example.com'
'admin_email' 管理员邮箱 '[email protected]'
'version' WordPress 版本号 '6.3.1'
'stylesheet_url' 主题样式表URL 'https://example.com/wp-content/themes/my-theme/style.css'

示例代码:

<?php
$site_name = get_bloginfo( 'name' );
$site_description = get_bloginfo( 'description' );
$site_url = get_bloginfo( 'url' );
$wp_version = get_bloginfo( 'version' );

echo '站点名称:' . $site_name . '<br>';
echo '站点描述:' . $site_description . '<br>';
echo '站点 URL:' . $site_url . '<br>';
echo 'WordPress 版本:' . $wp_version . '<br>';
?>

这段代码会输出站点的名称、描述、URL 和 WordPress 版本号。

第六部分:高级技巧:使用过滤器自定义 get_bloginfo() 的输出

WordPress 的过滤器机制非常强大,可以让你轻松地自定义 get_bloginfo() 的输出结果。

示例:修改站点名称

function my_custom_blogname( $blogname ) {
    return '我的超级博客';
}
add_filter( 'option_blogname', 'my_custom_blogname' );

这段代码使用 option_blogname 过滤器来修改站点名称。它定义了一个名为 my_custom_blogname 的函数,该函数接受站点名称作为参数,并返回修改后的站点名称。add_filter() 函数将 my_custom_blogname 函数添加到 option_blogname 过滤器中。

现在,当你调用 get_bloginfo( 'name' ) 时,它会返回 '我的超级博客',而不是数据库中存储的站点名称。

第七部分:注意事项

  • 性能: 尽量避免在循环中调用 get_bloginfo(),因为它可能会导致多次数据库查询,影响性能。可以将结果缓存起来,然后在循环中使用缓存的值。
  • 安全性: 注意对 get_bloginfo() 的输出进行适当的转义,以防止 XSS 攻击。
  • 多站点: 在多站点 WordPress 中,get_bloginfo() 会返回当前站点的相关信息。

总结

get_bloginfo() 函数是 WordPress 中一个非常重要的函数,它可以帮助你轻松地获取站点的各种信息。通过深入了解它的源码,你可以更好地理解 WordPress 的工作原理,并使用过滤器来自定义它的输出结果。希望今天的探险之旅对你有所帮助!下次再见!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注