研究 WordPress 中的 query_vars 变量注册与路由匹配关系

WordPress Query Vars:注册、路由与匹配深度解析

大家好,今天我们要深入探讨 WordPress 中 query_vars 这个核心变量,以及它在 URL 路由和查询构建过程中扮演的关键角色。理解 query_vars 能让你更灵活地控制 WordPress 如何处理 URL 请求,并自定义内容检索逻辑。

什么是 Query Vars?

query_vars 本质上是一个全局数组(通常通过 $wp_query 对象访问),它包含了从 URL 中解析出来的查询参数。WordPress 使用这些参数来确定要显示的内容,例如文章、页面、分类目录等。可以把 query_vars 看作是 WordPress 理解用户请求意图的“语言”。

默认的 Query Vars

WordPress 预定义了一系列默认的 query_vars,用于处理常见的请求。以下是一些关键的默认 query_vars 及其作用:

Query Var 描述 示例 URL
p 文章 ID。用于直接访问特定 ID 的文章。 example.com/?p=123
page_id 页面 ID。用于直接访问特定 ID 的页面。 example.com/?page_id=456
name 文章别名(slug)。用于通过别名访问文章。 example.com/?name=my-awesome-post
pagename 页面别名(slug)。用于通过别名访问页面。 example.com/?pagename=about-us
category_name 分类目录别名(slug)。用于显示特定分类目录的文章列表。 example.com/?category_name=news
tag 标签别名(slug)。用于显示特定标签的文章列表。 example.com/?tag=featured
s 搜索关键词。用于执行搜索。 example.com/?s=WordPress+development
author 作者 ID 或别名(slug)。用于显示特定作者的文章列表。 example.com/?author=1example.com/?author=john-doe
post_type 文章类型。用于指定要查询的文章类型。 example.com/?post_type=book
posts_per_page 每页显示的文章数量。 example.com/?posts_per_page=10
paged 分页页码。用于显示分页结果。 example.com/?paged=2

这些默认的 query_vars 已经覆盖了大部分常见的 WordPress 使用场景。但有时,我们需要自定义 query_vars 来处理更复杂的 URL 结构和数据检索需求。

注册自定义 Query Vars

要注册自定义 query_vars,我们需要使用 query_vars 过滤器。这个过滤器允许我们在 WordPress 处理 URL 之前,向 query_vars 数组中添加新的变量。

以下是一个注册自定义 query_var 的示例:

/**
 * 注册自定义 query var
 *
 * @param array $query_vars 现有的 query vars 数组.
 * @return array 修改后的 query vars 数组.
 */
function register_custom_query_vars( $query_vars ) {
    $query_vars[] = 'my_custom_var';
    return $query_vars;
}
add_filter( 'query_vars', 'register_custom_query_vars' );

这段代码首先定义了一个名为 register_custom_query_vars 的函数,它接收一个 $query_vars 数组作为参数。然后在函数内部,我们将 'my_custom_var' 添加到 $query_vars 数组中,最后返回修改后的数组。

add_filter( 'query_vars', 'register_custom_query_vars' ) 这行代码将 register_custom_query_vars 函数挂载到 query_vars 过滤器上。这意味着每次 WordPress 处理 URL 时,都会调用 register_custom_query_vars 函数,并将返回的 $query_vars 数组用于后续的路由和查询构建过程。

注意: 注册自定义 query_vars 只是告诉 WordPress “我知道这个参数”,但它并没有告诉 WordPress 如何处理这个参数。我们需要在后续的步骤中,配置 URL 重写规则,并将 URL 中的参数映射到我们自定义的 query_vars 上。

URL 重写规则 (Rewrite Rules)

URL 重写规则是将“友好”的 URL 转换为 WordPress 可以理解的内部 URL 的机制。我们需要定义重写规则,将 URL 中的自定义参数映射到我们注册的 query_vars 上。

WordPress 提供了 add_rewrite_rule() 函数来添加自定义重写规则。这个函数需要两个参数:

  • $regex: 用于匹配 URL 的正则表达式。
  • $redirect: 将匹配的 URL 转换为内部 URL 的字符串。

以下是一个使用 add_rewrite_rule() 函数创建重写规则的示例:

/**
 * 添加自定义重写规则
 */
function add_custom_rewrite_rules() {
    add_rewrite_rule(
        '^my-custom-page/([^/]*)/?', // 正则表达式,匹配以 "my-custom-page/" 开头,后跟一个参数的 URL
        'index.php?pagename=my-custom-page&my_custom_var=$matches[1]', // 重定向到内部 URL
        'top' // 规则的优先级 (top, bottom)
    );
}
add_action( 'init', 'add_custom_rewrite_rules' );

/**
 * 刷新重写规则
 */
function flush_rewrite_rules_on_activation() {
    add_custom_rewrite_rules();
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'flush_rewrite_rules_on_activation' );

代码解释:

  1. add_custom_rewrite_rules() 函数:
    • add_rewrite_rule( '^my-custom-page/([^/]*)/?', 'index.php?pagename=my-custom-page&my_custom_var=$matches[1]', 'top' ): 这是添加重写规则的关键代码。
      • '^my-custom-page/([^/]*)/?': 这是一个正则表达式,用于匹配 URL。它匹配以 my-custom-page/ 开头,后跟任意字符(除了 /),然后是可选的 / 的 URL。 ([^/]*) 部分使用括号捕获匹配的字符,我们将在后续的重定向中使用它。
      • 'index.php?pagename=my-custom-page&my_custom_var=$matches[1]': 这是一个重定向字符串,它将匹配的 URL 转换为 WordPress 可以理解的内部 URL。
        • index.php?pagename=my-custom-page: 这部分指定了要显示的页面是 my-custom-pagepagename 是 WordPress 默认的 query_var,用于指定页面别名。
        • &my_custom_var=$matches[1]: 这部分将我们自定义的 query_var my_custom_var 设置为正则表达式中捕获的值。 $matches[1] 表示正则表达式中第一个括号捕获的内容,也就是 URL 中 my-custom-page/ 后面的参数。
      • 'top': 这指定了规则的优先级。'top' 表示这个规则具有最高的优先级,这意味着它会优先于其他规则进行匹配。
  2. add_action( 'init', 'add_custom_rewrite_rules' ): 这行代码将 add_custom_rewrite_rules() 函数挂载到 init 动作钩子上。 init 动作在 WordPress 初始化时触发,这意味着我们的重写规则将在 WordPress 加载时被添加。
  3. flush_rewrite_rules_on_activation() 函数:
    • 这个函数在插件激活时被调用,它负责刷新 WordPress 的重写规则。 刷新重写规则是必要的,因为当我们添加或修改重写规则时,WordPress 需要重新生成 .htaccess 文件(如果使用 Apache 服务器)或更新 Nginx 配置(如果使用 Nginx 服务器)。
    • add_custom_rewrite_rules(): 首先,我们调用 add_custom_rewrite_rules() 函数,确保我们的自定义重写规则被添加到 WordPress 的重写规则列表中。
    • flush_rewrite_rules(): 然后,我们调用 flush_rewrite_rules() 函数来刷新重写规则。 非常重要: 在生产环境中,避免每次页面加载都调用 flush_rewrite_rules(),因为它会影响性能。最好只在插件激活或主题切换时调用。
  4. register_activation_hook( __FILE__, 'flush_rewrite_rules_on_activation' ): 这行代码将 flush_rewrite_rules_on_activation() 函数注册为插件激活时的回调函数。 __FILE__ 是一个魔术常量,它表示当前文件的路径。

示例 URL:

假设我们有一个页面,其别名为 my-custom-page。 如果用户访问 example.com/my-custom-page/some-value/,那么我们的重写规则会将这个 URL 转换为 index.php?pagename=my-custom-page&my_custom_var=some-value。 WordPress 会解析这个内部 URL,并将其中的 pagenamemy_custom_var 设置到 $wp_query 对象的 query_vars 属性中。

关键点:

  • 正则表达式: 正则表达式是定义重写规则的关键。 你需要仔细设计正则表达式,以确保它能够匹配你想要处理的 URL 结构。
  • 重定向字符串: 重定向字符串定义了如何将匹配的 URL 转换为内部 URL。 你需要确保重定向字符串正确地设置了 WordPress 默认的 query_vars 和你自定义的 query_vars
  • flush_rewrite_rules() 在添加或修改重写规则后,必须刷新重写规则,以使更改生效。 但是,不要在每次页面加载时都刷新重写规则,因为它会影响性能。

使用自定义 Query Vars

现在我们已经注册了自定义 query_vars 并添加了重写规则,接下来就可以在 WordPress 模板中使用这些变量来控制内容显示。

我们可以使用 $wp_query 对象的 get() 方法来获取 query_vars 的值。

以下是一个在 WordPress 模板中使用自定义 query_var 的示例:

<?php
// 获取 $wp_query 对象
global $wp_query;

// 获取自定义 query var 的值
$my_custom_value = $wp_query->get( 'my_custom_var' );

// 检查 query var 是否存在且不为空
if ( ! empty( $my_custom_value ) ) {
    // 根据自定义 query var 的值执行不同的操作
    echo '<p>My Custom Value: ' . esc_html( $my_custom_value ) . '</p>';

    // 示例:根据值查询数据库或执行其他逻辑
    // ...
} else {
    echo '<p>My Custom Value is not set.</p>';
}
?>

代码解释:

  1. global $wp_query;: 这行代码声明 $wp_query 为全局变量。 $wp_query 对象包含了当前请求的所有信息,包括 query_vars、查询结果等等。
  2. $my_custom_value = $wp_query->get( 'my_custom_var' );: 这行代码使用 $wp_query 对象的 get() 方法来获取名为 my_custom_varquery_var 的值。 如果 my_custom_var 不存在,get() 方法将返回空字符串。
  3. if ( ! empty( $my_custom_value ) ) { ... }: 这行代码检查 my_custom_value 是否存在且不为空。 ! empty() 函数可以用来判断一个变量是否为空字符串、nullfalse0、或者一个空数组。
  4. echo '<p>My Custom Value: ' . esc_html( $my_custom_value ) . '</p>';: 这行代码输出 my_custom_value 的值。 esc_html() 函数用于对输出的 HTML 进行转义,以防止 XSS 攻击。
  5. // 示例:根据值查询数据库或执行其他逻辑: 这部分代码是一个示例,展示了如何根据 my_custom_value 的值来执行不同的操作。 你可以根据自己的需求,在这里编写自定义的逻辑,例如查询数据库、调用 API 等等。

示例:自定义文章查询

假设我们想要创建一个页面,允许用户通过 URL 指定要显示的特定作者的文章,并且指定每页显示的文章数量。 我们可以结合自定义 query_varsWP_Query 类来实现这个功能。

首先,注册两个自定义 query_vars: custom_authorcustom_posts_per_page

/**
 * 注册自定义 query vars
 *
 * @param array $query_vars 现有的 query vars 数组.
 * @return array 修改后的 query vars 数组.
 */
function register_custom_query_vars_author( $query_vars ) {
    $query_vars[] = 'custom_author';
    $query_vars[] = 'custom_posts_per_page';
    return $query_vars;
}
add_filter( 'query_vars', 'register_custom_query_vars_author' );

然后,添加重写规则:

/**
 * 添加自定义重写规则
 */
function add_custom_rewrite_rules_author() {
    add_rewrite_rule(
        '^custom-author/([^/]*)/posts/([0-9]*)/?',
        'index.php?pagename=custom-author-page&custom_author=$matches[1]&custom_posts_per_page=$matches[2]',
        'top'
    );
}
add_action( 'init', 'add_custom_rewrite_rules_author' );

/**
 * 刷新重写规则
 */
function flush_rewrite_rules_on_activation_author() {
    add_custom_rewrite_rules_author();
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'flush_rewrite_rules_on_activation_author' );

现在,如果用户访问 example.com/custom-author/john-doe/posts/5/,那么 custom_author 将会被设置为 john-doecustom_posts_per_page 将会被设置为 5

最后,在 custom-author-page 页面的模板中,我们可以使用这些 query_vars 来构建自定义的 WP_Query 对象:

<?php
global $wp_query;

$custom_author = $wp_query->get( 'custom_author' );
$custom_posts_per_page = intval( $wp_query->get( 'custom_posts_per_page' ) );

// 确保 posts_per_page 是一个正整数
if ( $custom_posts_per_page <= 0 ) {
    $custom_posts_per_page = 10; // 默认值
}

$args = array(
    'author_name'    => $custom_author,
    'posts_per_page' => $custom_posts_per_page,
    'paged'          => get_query_var( 'paged' ) ? get_query_var( 'paged' ) : 1, // 处理分页
);

$custom_query = new WP_Query( $args );

if ( $custom_query->have_posts() ) {
    while ( $custom_query->have_posts() ) {
        $custom_query->the_post();
        ?>
        <h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
        <p><?php the_excerpt(); ?></p>
        <?php
    }

    // 分页导航
    the_posts_pagination( array(
        'total'   => $custom_query->max_num_pages,
        'current' => max( 1, get_query_var('paged') ),
    ) );

    wp_reset_postdata(); // 恢复全局 $post 对象
} else {
    echo '<p>No posts found for author: ' . esc_html( $custom_author ) . '</p>';
}
?>

代码解释:

  1. 获取 query_vars 我们使用 $wp_query->get() 方法获取 custom_authorcustom_posts_per_page 的值。 intval() 函数用于将 custom_posts_per_page 转换为整数。
  2. 构建 WP_Query 对象: 我们使用 WP_Query 类创建一个新的查询对象,并将 author_name 设置为 custom_authorposts_per_page 设置为 custom_posts_per_pagepaged 参数用于处理分页。
  3. 循环显示文章: 我们使用 while 循环遍历查询结果,并显示每篇文章的标题和摘要。
  4. 分页导航: 我们使用 the_posts_pagination() 函数生成分页导航链接。 total 参数设置为 $custom_query->max_num_pages,表示总页数。 current 参数设置为 get_query_var('paged'),表示当前页码。
  5. wp_reset_postdata() 在循环结束后,我们调用 wp_reset_postdata() 函数来恢复全局 $post 对象。 这很重要,因为自定义查询会修改全局 $post 对象,如果不恢复,可能会影响其他部分的 WordPress 代码的运行。

调试重写规则

调试重写规则可能是一项挑战,但有一些工具和技巧可以帮助你:

  • query_vars 过滤器:query_vars 过滤器中,使用 var_dump()print_r() 函数来查看 $query_vars 数组的内容。 这可以帮助你确认自定义 query_vars 是否被正确注册。
  • rewrite_rules_array 过滤器: 使用 rewrite_rules_array 过滤器来查看 WordPress 的所有重写规则。 这可以帮助你确认你的自定义重写规则是否被正确添加,并且没有被其他规则覆盖。
  • global $wp_rewrite; var_dump($wp_rewrite) 打印 $wp_rewrite 对象可以查看当前 WordPress 的重写规则配置。
  • .htaccess 文件: 如果你的服务器使用 Apache,可以查看 .htaccess 文件,以确认 WordPress 生成的重写规则是否正确。
  • 插件: 有一些插件可以帮助你管理和调试重写规则,例如 "Rewrite Rules Inspector"。

总结核心要点

掌握 query_vars 注册和 URL 重写规则能够帮助你构建更灵活,更强大的 WordPress 网站。 注册自定义 query_vars 并正确配置 URL 重写规则后,就能在模板文件中使用这些变量来自定义内容显示,从而实现更复杂的业务逻辑。 理解这些核心概念,并熟练运用相关函数,你就能充分利用 WordPress 的强大功能,创建出满足各种需求的网站。

发表回复

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