阐述 `wp_get_document_title()` 函数的源码,它是如何生成页面标题的?

咳咳,各位,欢迎来到今天的“WordPress标题炼金术”讲座!我是你们的向导,今天咱们要一起扒开 wp_get_document_title() 这个小家伙的外衣,看看它到底是如何把各种零碎的信息,变成我们浏览器标签页上那闪闪发光的页面标题的。

准备好了吗?Let’s dive in!

1. 标题的诞生:wp_get_document_title() 的真面目

首先,让我们来看看 wp_get_document_title() 的庐山真面目。这个函数存在于 WordPress 的 wp-includes/general-template.php 文件中。它的主要职责就是根据当前页面的上下文环境,构建一个合适的 HTML 文档标题。

function wp_get_document_title() {
    /**
     * Filters the parts used to build the document title.
     *
     * @since 4.4.0
     *
     * @param string[] $title_array Array of strings used to put together the document title.
     */
    $title_array = apply_filters( 'document_title_parts', _wp_document_title_parts() );

    /**
     * Filters the separator used between the document title parts.
     *
     * @since 4.4.0
     *
     * @param string $sep Document title separator.
     */
    $title = implode( apply_filters( 'document_title_separator', _wp_document_title_separator() ), $title_array );

    /**
     * Filters the document title.
     *
     * @since 4.4.0
     *
     * @param string $title The document title.
     * @param string[] $title_array Array of strings used to put together the document title.
     */
    return apply_filters( 'document_title', $title, $title_array );
}

瞧见没?这个函数本身并没有多少“硬编码”,它主要依赖于三个过滤器:

  • document_title_parts: 这个过滤器负责提供标题的各个组成部分(比如文章标题、站点名称等等)。
  • document_title_separator: 这个过滤器负责定义标题各个部分之间的分隔符(比如 " – " 或 "|")。
  • document_title: 这个过滤器允许你对最终生成的完整标题进行最后的修改。

这种设计简直太妙了!它赋予了我们极大的灵活性,可以根据自己的需求定制页面的标题。

2. 标题零件的制造者:_wp_document_title_parts()

wp_get_document_title() 本身只是个组装工,真正负责提供标题零件的是 _wp_document_title_parts() 函数。这个函数才是真正的标题“侦探”,它会根据当前的页面类型,搜集各种信息,然后把它们整理成一个标题零件数组。

function _wp_document_title_parts() {
    global $wp_query, $wp_locale;

    $title = array();

    /*
     * The order in which these are added is important.
     *
     * They will be output in the order:
     *  1. Site name.
     *  2. Page description.
     *  3. Page/post title.
     */

    if ( is_front_page() ) {
        if ( is_home() ) {
            // If purely home, the front page is a blog, so use the site title.
            $title['title'] = get_bloginfo( 'name', 'display' );
        } else {
            // Front page is a page.
            $title['title'] = get_the_title();
        }
    } elseif ( is_home() ) {
        // If the front page is a page, the blog is the "home".
        $title['title'] = single_post_title( '', false );
    } elseif ( is_singular() ) {
        /*
         * Singular Post View.
         *
         * is_single() or is_page() or attachment page.
         */
        $title['title'] = single_post_title( '', false );
    } elseif ( is_category() ) {
        $title['title'] = single_cat_title( '', false );
    } elseif ( is_tag() ) {
        $title['title'] = single_tag_title( '', false );
    } elseif ( is_tax() ) {
        $term = get_queried_object();
        if ( $term ) {
            $title['title'] = $term->name;
        }
    } elseif ( is_author() ) {
        $author = get_queried_object();
        if ( $author ) {
            $title['title'] = $author->display_name;
        }
    } elseif ( is_post_type_archive() ) {
        $title['title'] = post_type_archive_title( '', false );
    } elseif ( is_date() ) {
        /*
         * Yearly archive: 2016
         * Monthly archive: March, 2016
         * Daily archive: March 8, 2016
         */
        if ( is_year() ) {
            $title['title'] = get_the_date( _x( 'Y', 'yearly archives date format' ) );
        } elseif ( is_month() ) {
            $title['title'] = get_the_date( _x( 'F, Y', 'monthly archives date format' ) );
        } elseif ( is_day() ) {
            $title['title'] = get_the_date( _x( 'F j, Y', 'daily archives date format' ) );
        }
    } elseif ( is_search() ) {
        /* translators: %s: search query. */
        $title['title'] = sprintf( __( 'Search Results for “%s”' ), get_search_query() );
    } elseif ( is_404() ) {
        $title['title'] = __( 'Page Not Found' );
    } else {
        $title['title'] = get_bloginfo( 'name' );
    }

    $title['site'] = get_bloginfo( 'name', 'display' );

    if ( ( is_home() || is_front_page() ) && ( $description = get_bloginfo( 'description', 'display' ) ) ) {
        $title['description'] = $description;
    }

    return $title;
}

这个函数利用了 WordPress 的各种条件判断函数(比如 is_front_page(), is_singular(), is_category() 等等),来确定当前页面的类型。然后,它会根据页面类型,调用相应的函数来获取标题信息。

  • get_bloginfo(): 用于获取站点信息,比如站点名称和描述。
  • single_post_title(): 用于获取文章或页面的标题。
  • single_cat_title(): 用于获取分类目录的标题。
  • single_tag_title(): 用于获取标签的标题。
  • get_the_date(): 用于获取日期存档页面的日期。
  • get_search_query(): 用于获取搜索关键词。

它将获取到的信息存入 $title 数组中,数组的键名包括 title (页面内容标题), site (站点名称), description (站点描述)。

3. 分隔符的秘密:_wp_document_title_separator()

接下来,我们来看看分隔符。_wp_document_title_separator() 函数非常简单,它只是返回一个默认的分隔符。

function _wp_document_title_separator() {
    /**
     * Filters the document title separator string.
     *
     * @since 4.4.0
     *
     * @param string $sep Document title separator.
     */
    return apply_filters( 'document_title_default_separator', ' » ' );
}

默认情况下,分隔符是 » (也就是 » 符号)。 当然,你可以使用 document_title_default_separator 过滤器来修改它。

4. 组装与润色:从零件到完整标题

现在,我们已经有了标题的各个组成部分,也有了分隔符。wp_get_document_title() 函数会使用 implode() 函数,将这些零件组装成一个完整的标题字符串。

$title = implode( apply_filters( 'document_title_separator', _wp_document_title_separator() ), $title_array );

在这里,apply_filters( 'document_title_separator', _wp_document_title_separator() ) 允许我们通过 document_title_separator 过滤器修改分隔符,然后再将修改后的分隔符传递给 implode() 函数。

最后,wp_get_document_title() 函数会使用 document_title 过滤器,允许我们对最终生成的标题进行最后的润色。

return apply_filters( 'document_title', $title, $title_array );

5. 实战演练:自定义页面标题

理论讲了这么多,不如来点实际的。假设我们想在所有文章页面的标题后面,都加上一个 " – Powered by My Awesome Theme" 的后缀。我们可以这样做:

add_filter( 'document_title_parts', 'my_awesome_theme_document_title_parts' );

function my_awesome_theme_document_title_parts( $title ) {
    if ( is_singular( 'post' ) ) {
        $title['powered_by'] = 'Powered by My Awesome Theme';
    }
    return $title;
}

add_filter( 'document_title_separator', 'my_awesome_theme_document_title_separator' );
function my_awesome_theme_document_title_separator( $sep ) {
    return '|'; // 更改分隔符为 |
}

这段代码首先使用 document_title_parts 过滤器,向标题零件数组中添加了一个新的元素 powered_by。 然后使用 document_title_separator 过滤器,更改了分隔符为竖线 |

再举个例子,假设我们想在所有分类目录页面的标题前面,加上 "Category: " 的前缀。我们可以这样做:

add_filter( 'document_title', 'my_awesome_theme_document_title' );

function my_awesome_theme_document_title( $title ) {
    if ( is_category() ) {
        $title = 'Category: ' . $title;
    }
    return $title;
}

这段代码直接使用 document_title 过滤器,修改了最终生成的标题字符串。

6. 总结:标题炼金术的精髓

让我们来总结一下,wp_get_document_title() 函数的精髓在于:

  • 灵活性: 它通过过滤器机制,赋予了我们极大的灵活性,可以根据自己的需求定制页面的标题。
  • 可扩展性: 我们可以通过添加新的过滤器,来扩展 wp_get_document_title() 函数的功能。
  • 模块化: 标题的各个组成部分都是独立的,我们可以单独修改它们。

7. 常见问题与解答

  • Q: 为什么我的页面标题没有生效?

    A: 请检查你的主题是否使用了 wp_head() 函数,以及是否正确地调用了 wp_get_document_title() 函数。 另外,检查你添加的过滤器是否正确,以及是否有其他插件或主题覆盖了你的设置。

  • Q: 如何禁用 WordPress 的默认标题生成?

    A: 你可以移除 wp_head() 函数中的 wp_enqueue_scripts 动作,或者使用一个空的标题字符串覆盖默认标题。 但是,不建议这样做,因为它可能会影响 SEO。

  • Q: 如何针对不同的文章类型,设置不同的标题格式?

    A: 你可以使用 is_singular() 函数,根据文章类型进行条件判断,然后设置不同的标题格式。

8. 深入探索:一些高级技巧

  • 使用 transients 缓存标题: 对于一些计算量较大的标题,可以使用 transients 缓存结果,以提高性能。

  • 利用 Yoast SEO 等插件: 这些插件通常提供了更高级的标题管理功能,可以让你更方便地控制页面标题。

  • 考虑 SEO 因素: 在设置页面标题时,要考虑 SEO 因素,选择合适的关键词,并确保标题的长度适中。

9. 代码示例:不同场景下的标题定制

为了让大家更直观地理解,我再提供一些代码示例,展示如何在不同的场景下定制页面标题。

场景 代码示例
在首页显示站点名称和描述,并使用 " – " 分隔符 phpphp

// 首页标题
add_filter( ‘document_title_parts’, ‘my_custom_home_title’ );
function my_custom_home_title( $title ) {
if ( is_front_page() && is_home() ) {
$title[‘title’] = ‘Welcome to My Awesome Website!’;
$title[‘description’] = ‘The best place on the internet.’;
}
return $title;
}

// 分类目录标题
add_filter( ‘document_title_parts’, ‘my_custom_category_title’ );
function my_custom_category_title( $title ) {
if ( is_category() ) {
$title[‘title’] = ‘Browsing Category: ‘ . single_cat_title( ”, false );
}
return $title;
}

// 文章页标题
add_filter( ‘document_title_parts’, ‘my_custom_post_title’ );
function my_custom_post_title( $title ) {
if ( is_singular( ‘post’ ) ) {
$

发表回复

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