分析 WordPress `get_site_url()` 函数在多站点模式下的源码:如何生成站点的 URL。

各位代码界的吃瓜群众,大家好!我是今天的主讲人,咱们今天唠唠 WordPress 多站点模式下 get_site_url() 这个函数背后的故事,看看它是怎么变戏法儿,给你变出一个个站点的 URL 的。

开场白:get_site_url() 的自我介绍

首先,咱们得认识一下今天的主角 get_site_url()。简单来说,这个函数的作用就是获取站点的 URL。听起来很简单是不是?但如果你在多站点环境下,情况就稍微复杂一点了。因为它需要知道你想获取哪个站点的 URL。就像你去一家连锁店,总得告诉店员你想去哪家分店吧?

单站点与多站点的 URL 区别

在单站点环境下,get_site_url() 通常直接返回 WP_HOME 选项的值。这个选项的值在 WordPress 安装的时候就已经确定了,通常是你的网站域名。

// 单站点环境下的简化版 get_site_url() (仅为演示)
function my_get_site_url() {
  return get_option( 'home' ); // 实际上 WordPress 使用 WP_HOME 常量,但这里为了简化演示
}

但是,多站点环境下,每个站点都有自己的 URL,这些 URL 可能基于子域名或子目录。所以 get_site_url() 需要更智能地知道你想获取哪个站点的 URL。

多站点模式的两种类型:子域名和子目录

在 WordPress 多站点中,站点 URL 的生成方式取决于你选择了哪种模式:

  • 子域名 (Subdomain): 比如 site1.example.com, site2.example.com。每个站点都有自己的子域名。
  • 子目录 (Subdirectory): 比如 example.com/site1, example.com/site2。每个站点都在主站点的子目录下。

这两种模式直接影响 get_site_url() 的实现方式。

源码分析:get_site_url() 的庐山真面目

咱们现在直接扒开源码,看看 get_site_url() 到底是怎么工作的。因为 WordPress 源码比较庞大,这里提取了关键部分,并做了一些简化,方便大家理解。

// WordPress 源码 (简化版)

function get_site_url( $blog_id = null, $path = '', $scheme = null ) {
  global $current_site, $current_blog;

  // 1. 确定 Blog ID
  if ( null === $blog_id ) {
    if ( isset( $current_blog ) && is_object( $current_blog ) ) {
      $blog_id = $current_blog->blog_id;
    } else {
      $blog_id = get_current_blog_id();
    }
  }

  // 2. 获取站点的 Domain 和 Path
  $details = get_site( $blog_id );
  if ( ! $details ) {
    return false; // 如果站点不存在,返回 false
  }

  $domain = $details->domain;
  $path   = $details->path;

  // 3. 构建 URL
  $url = $scheme . '://' . $domain . $path;

  // 4. 拼接 path 参数
  if ( ! empty( $path ) ) {
    $url = trailingslashit( $url );
  }

  if ( ! empty( $path ) && is_string( $path ) && ( substr( $path, 0, 1 ) == '/' ) ) {
    $path = substr( $path, 1 );
  }

  if ( $path ) {
    $url .= $path;
  }

  return $url;
}

function get_site( $id = 0 ) {
    global $wpdb;

    if ( empty( $id ) ) {
        $id = get_current_network_id();
    }

    $key = $id . ':site';

    $cache = wp_cache_get( $key, 'site-details' );

    if ( false === $cache ) {
        $id = (int) $id;
        if ( ! $id ) {
            return false;
        }

        $cache = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->site} WHERE id = %d", $id ) );

        if ( empty( $cache ) ) {
            return false;
        }

        wp_cache_set( $key, $cache, 'site-details' );
    }

    return $cache;
}

function get_current_blog_id() {
    global $current_blog;

    if ( ! empty( $current_blog ) && is_object( $current_blog ) ) {
        return (int) $current_blog->blog_id;
    }

    if ( defined( 'SITE_ID_CURRENT_SITE' ) ) {
        return (int) SITE_ID_CURRENT_SITE;
    }

    return 1;
}

咱们一步一步地来解读这段代码:

  1. 确定 Blog ID ($blog_id):

    • 首先,get_site_url() 接受一个可选的 $blog_id 参数,用于指定你要获取哪个站点的 URL。如果没传这个参数,它会尝试从全局变量 $current_blog 中获取,或者使用 get_current_blog_id() 函数。
    • get_current_blog_id() 也很简单,也是优先从全局变量 $current_blog 获取,如果获取不到就返回 SITE_ID_CURRENT_SITE 常量。
  2. 获取站点的 Domain 和 Path:

    • 通过 get_site( $blog_id ) 函数,从数据库中获取指定 $blog_id 的站点的详细信息,包括 domain (域名) 和 path (路径)。
    • get_site() 函数内部会先尝试从缓存中获取站点信息,如果缓存没有,就从数据库的 wp_site 表中查询。
  3. 构建 URL:

    • $scheme (协议,比如 httphttps)、$domain (域名) 和 $path (路径) 拼接起来,构成基本的 URL。 协议的获取这里省略了,实际源码会根据情况选择 https 还是 http
  4. 处理 Path 参数:

    • 如果 $path 参数不为空,将它添加到 URL 的末尾。
    • 去除 $path 参数开头的斜杠,防止 URL 中出现多余的斜杠。

重点:wp_site 表长啥样?

wp_site 表存储了多站点网络中每个站点的基本信息,包括:

字段 类型 描述
id bigint(20) unsigned 站点 ID,唯一标识符
domain varchar(200) 站点的域名,比如 site1.example.comexample.com
path varchar(100) 站点的路径,比如 //site1。注意:必须以 / 开头,即使是根目录 /,也不能是空字符串。

案例分析:子域名模式下的 URL 生成

假设我们有一个多站点网络,使用子域名模式,并且有以下站点:

站点 ID 域名 路径
1 example.com /
2 site1.example.com /
3 site2.example.com /

如果我们调用 get_site_url(2),会发生什么?

  1. get_site_url(2) 会先确定 $blog_id 为 2。
  2. get_site(2) 会从 wp_site 表中查询 ID 为 2 的站点信息,得到域名为 site1.example.com,路径为 /
  3. get_site_url(2)https (假设我们使用 HTTPS) + :// + site1.example.com + / 拼接起来,得到 https://site1.example.com/

案例分析:子目录模式下的 URL 生成

假设我们有一个多站点网络,使用子目录模式,并且有以下站点:

站点 ID 域名 路径
1 example.com /
2 example.com /site1/
3 example.com /site2/

如果我们调用 get_site_url(2),会发生什么?

  1. get_site_url(2) 会先确定 $blog_id 为 2。
  2. get_site(2) 会从 wp_site 表中查询 ID 为 2 的站点信息,得到域名为 example.com,路径为 /site1/
  3. get_site_url(2)https (假设我们使用 HTTPS) + :// + example.com + /site1/ 拼接起来,得到 https://example.com/site1/

get_site_url()home_url() 的区别

很多同学可能会疑惑,get_site_url()home_url() 都是获取 URL 的,它们有什么区别呢?

  • get_site_url() 获取的是站点的 URL,也就是 wp_site 表中存储的域名和路径的组合。
  • home_url() 获取的是首页的 URL,它会考虑 WP_HOME 选项的值,并且可以添加额外的路径。

简单来说,get_site_url() 更底层,直接从数据库获取站点信息;home_url() 更灵活,可以根据需求添加路径。

network_site_url()

除了 get_site_url(),还有一个函数 network_site_url()。这个函数与 get_site_url() 的区别在于,network_site_url() 获取的是 网络 的 URL,而不是单个站点的 URL。它通常用于获取主站点的 URL。

总结:get_site_url() 的核心思想

get_site_url() 的核心思想是:

  1. 确定要获取哪个站点的 URL ($blog_id)。
  2. 从数据库中获取该站点的域名和路径。
  3. 将域名和路径拼接起来,构成完整的 URL。

一些注意事项

  • get_site_url() 返回的 URL 不包含尾部的斜杠。如果你需要尾部斜杠,可以使用 trailingslashit() 函数。
  • get_site_url() 可以接受第三个参数 $scheme,用于指定 URL 的协议 (http 或 https)。
  • 在多站点环境中,正确配置 wp-config.php 文件非常重要,包括 WP_ALLOW_MULTISITEMULTISITESUBDOMAIN_INSTALLDOMAIN_CURRENT_SITEPATH_CURRENT_SITESITE_ID_CURRENT_SITEBLOG_ID_CURRENT_SITE 等常量。

实战演练:在主题中使用 get_site_url()

假设我们想在主题中显示当前站点的 URL,可以这样写:

<?php
  $site_url = get_site_url();
  echo '<p>当前站点的 URL 是:' . esc_url( $site_url ) . '</p>';
?>

进阶:使用过滤器修改 get_site_url() 的行为

WordPress 提供了 site_url 过滤器,允许你修改 get_site_url() 的返回值。这在某些特殊情况下非常有用,比如你想根据用户的角色动态地修改站点的 URL。

add_filter( 'site_url', 'my_custom_site_url', 10, 3 );

function my_custom_site_url( $url, $path, $blog_id ) {
  // 在这里添加你的逻辑
  if ( is_user_logged_in() && current_user_can( 'administrator' ) ) {
    // 管理员访问时,添加一个特殊的参数
    $url = add_query_arg( 'admin_mode', 'true', $url );
  }
  return $url;
}

结束语:get_site_url() 的重要性

get_site_url() 是 WordPress 多站点中一个非常重要的函数,它负责生成站点的 URL,是多站点正常运行的基础。理解它的工作原理,可以帮助你更好地理解 WordPress 多站点的架构,并在开发主题和插件时更加得心应手。

好了,今天的讲座就到这里。希望通过今天的讲解,大家对 get_site_url() 有了更深入的了解。下次再遇到它,就不会觉得陌生了。记住,代码的世界充满了乐趣,只要你愿意探索,就能发现更多的惊喜!

感谢大家的收听,祝大家编码愉快!

发表回复

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