检查JavaScript代码的状态

在 JavaScript 开发过程中,在代码的不同位置进行调试以了解运行情况会非常有帮助。

我们来看看几种检查 JavaScript 代码状态的方法。

服务端 vs 客户端

调试 PHP 和 JavaScript 的主要区别之一在于,PHP 是一种服务端语言,因此你可以将消息记录到服务器上的文件中。

而 JavaScript 是一种客户端语言,因此你不能像 PHP 那样轻松地将消息记录到文件中。

幸运的是,我们可以使用浏览器的开发者工具(特别是控制台选项卡)来检查 JavaScript 代码的状态。

打开浏览器的开发者工具

大多数现代浏览器都内置了开发者工具,允许你检查和调试网页元素。

根据你使用的浏览器和操作系统,通常可以通过按下特定键来打开开发者工具,例如 F12Ctrl+Shift+ICmd+Option+I

如果你不确定如何在浏览器中打开开发者工具,可以在 MDN Web Docs 网站上找到便捷的说明,路径为:指南 > 常见问题 > 工具与设置 > 什么是浏览器开发者工具?。

[注意:引导用户完成导航路径,找到该页面]

打开开发者工具后,切换到“控制台”选项卡,页面上的所有错误都会记录在这里。

同时,你也可以在这里从 JavaScript 代码中记录消息,以帮助调试。

console 对象

console 对象允许你将消息记录到浏览器的控制台。它提供了多种方法,用于记录不同类型的消息。

以下是一些最常用的方法:

console.log() 方法是最常用的,因为它几乎可以记录任何内容到控制台。你可以向它传递各种数据类型,例如字符串、数字、数组或对象。

下面是一个将简单字符串变量记录到控制台的示例。

(function() {
    let hello = 'Hello, World!';
    console.log(hello)
})(); 

如果你打开开发者工具并选择“控制台”选项卡,变量的内容就会被记录到控制台中。

控制台输出还包含一个指向源文件中代码位置的链接,这有助于追踪消息是从哪里记录的。

你还可以记录更复杂的数据类型,例如数组或对象。

(function() {
    let fruits = [ 'apple', 'banana', 'orange' ];
    console.log( fruits );

    let person = {
        firstName: "Jane",
        lastName: "Smith",
        age: 30,
        eyeColor: "brown"
    }
    console.log( person );
})();

在控制台中查看时,你会看到数组和对象按预期被记录。你还可以展开数组或对象以查看其属性,以及该数据类型可用的任何 JavaScript 方法。

还有许多其他方法可用于将消息记录到控制台,例如 console.error()console.warn()console.info()

其中一个最被低估的方法是 console.table(),它可以将数组或对象以表格形式记录,使其更易于阅读。

(function() {
    let people = [
        { name: 'Jane', age: 30 },
        { name: 'John', age: 40 },
        { name: 'Alice', age: 25 }
    ];
    console.table( people );
})();

当你有一个对象数组,并且希望以更易读的格式查看数据时,这个方法尤其有用。

延伸阅读

要了解更多关于浏览器 console 对象及其方法的信息,请务必访问 MDN Web Docs 页面。该页面包含了所有 console 方法的完整列表以及有用的示例。

检查PHP代码状态

在调试 PHP 代码时,检查代码在特定时间点的状态会很有帮助。这可以帮助你理解代码中正在发生的事情,并识别可能导致问题的任何错误。

让我们看看一些使用内置 PHP 函数检查 PHP 代码状态的方法。

使用 error_log() 记录消息

正如在关于内置 WordPress 调试选项的课程中所讨论的,你可以使用 error_log() 函数将消息记录到 WordPress 的 debug.log 文件中。

这对于调试目的非常有用,因为它允许你查看代码中正在发生的事情,而无需在屏幕上显示。

error_log() 函数并非 WordPress 特有,它是一个 PHP 函数,你可以在任何 PHP 代码中使用它,将消息记录到服务器上配置的 PHP 错误日志文件中。

但是,一旦你在 wp-config.php 文件中启用了 WordPress 特定的调试选项,传递给 error_log() 的任何内容都将被记录到 WordPressdebug.log 文件中。

<?php
error_log( $some_variable );
?>

这会将 $some_variable 的值记录到 debug.log 文件中,这样你就可以看到它在代码中该点的内容。

使用 error_log() 的好处是,它允许你将消息记录到文件,而无需在屏幕上显示。如果你在屏幕上显示它们,尤其是在生产环境中,你可能会面临向用户暴露敏感信息的风险。

有时,在日志文件中查看输出也比在屏幕上搜索一长串输出更快。

使用 print_r()

另一个用于检查 PHP 代码状态的有用函数是 print_r()。此函数以人类可读的格式输出变量、数组或对象的值,以便你可以查看其内容。

看看这个 PHP 代码示例。

<?php
$some_array = array(
    'name' => 'John',
    'age'  => 30,
    'city' => 'New York'
);
print_r( $some_array );
?>

这段代码将在屏幕上输出以下内容:

Array
(
    [name] => John
    [age] => 30
    [city] => New York
)

开发者通常会将 print_r() 包裹在 <pre> 标签中,以使输出更易于阅读。

<pre>
    <?php print_r( $some_array ); ?>
</pre>

这将在屏幕上输出以下内容:

Array
(
    [name] => John
    [age] => 30
    [city] => New York
)

请注意,默认情况下 print_r() 会输出变量的值,但不会返回它。如果你想将 print_r() 的输出与 error_log() 一起使用,需要将第二个参数设置为 true

<?php
error_log( print_r( $some_array, true ) );
?>

这会将 print_r 调用的输出记录到 debug.log 文件中,这样你就可以看到 $some_array 在代码中该点的内容。

使用 var_dump()

var_dump() 函数是另一个用于检查 PHP 代码状态的有用函数。此函数以人类可读的格式输出变量、数组或对象的值,同时提供关于变量类型和长度的额外信息。

看看这个 PHP 代码示例。

<?php
$some_array = array(
    'name' => 'John',
    'age'  => 30,
    'city' => 'New York'
);
var_dump( $some_array );
?>

这段代码将在屏幕上输出以下内容:

array(3) {
  ["name"]=>
  string(4) "John"
  ["age"]=>
  int(30)
  ["city"]=>
  string(8) "New York"
}

请注意,var_dump() 会输出变量的值,以及关于变量类型和长度的额外信息。这对于调试目的非常有用,因为它提供了比 print_r() 更详细的变量信息。

print_r() 不同,var_dump() 没有将输出返回给变量的选项,因此你不能直接将其与 error_log() 一起使用。

但是,你可以使用一种称为输出缓冲的技术来捕获 var_dump() 的输出,然后将其记录到 debug.log 文件中。

<?php
ob_start();
var_dump( $some_array );
$output = ob_get_clean();
error_log( $output );
?>

开发者通常会将这种代码用于一个特殊的日志记录函数,以便能够同时使用 var_dumperror_log

<?php
if ( ! function_exists( 'var_log' ) ) {
    function var_log( $log ) {
        ob_start();
        var_dump( $log );
        $output = ob_get_clean();
        error_log( $output );
    }
}
?>

进一步阅读

有关本课程中提到的函数的更多信息,请查看 PHP 文档中的以下页面:

PHP var_dump() 函数

PHP error_log() 函数

PHP print_r() 函数

WordPress 内置调试选项

随着你对 WordPress 开发越来越熟练,你会发现有时事情并不像预期那样工作,你需要找出原因。

在本课中,你将了解 WordPress 内置的调试选项。

首先,你将学习调试代码的含义。然后,你将了解默认 WordPress 安装中可用的一些内置调试选项,以及如何启用和使用它们。

什么是调试?

调试是查找并修复代码中错误的过程。

由于 WordPress 的两种主要编程语言是 PHP 和 JavaScript,你需要能够调试这两种语言。

对于在浏览器中执行的 JavaScript 代码,使用 console.log() 向浏览器控制台写入消息以进行测试和调试是相当直接的。

另一方面,PHP 在服务器上执行,因此你需要一些方法来找出问题发生时的情况。

有一些第三方工具可用于高级调试,例如 Xdebug 或 Ray。

然而,就本课而言,你将学习 WordPress 特有的选项,并且不需要额外的软件。

调试 PHP

在 WordPress 中,在任何 WordPress 请求生命周期内,都会运行 wp_debug_mode() 函数来设置调试环境。此函数位于 wp-includes/load.php 文件中。

如果你查看这段代码,你会发现如果 WP_DEBUG 常量设置为 true,那么它会将 PHP 错误报告级别设置为 E_ALL,这意味着开启所有错误报告。

此外,如果 WP_DEBUG_DISPLAY 设置为 true,那么它会将 PHP 的 display_errors 设置设为 1,这意味着在屏幕上显示这些错误。

最后,如果 WP_DEBUG_LOG 设置为 true,那么它会将 PHP 的 error_log 设置设为 wp-content/debug.log 文件。也可以配置自定义的 debug.log 文件位置,而不是默认位置。

如果启用了此日志文件,它会将 PHP 的 log_errors 设置设为 1,并将 error_log 设置设为日志文件的路径,这意味着所有错误都将记录到此文件中。

利用这些知识,你可以配置 wp-config.php 文件来启用 WordPress 调试。

启用调试

要启用调试,请打开 wp-config.php 文件并向下滚动到设置 WP_DEBUG 常量的位置。

你可以将该部分更新为如下所示:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'WP_DEBUG_LOG', true );

此配置将:

  1. 启用调试
  2. 禁止在屏幕上显示错误
  3. 启用将错误记录到 wp-content/debug.log 文件

根据你的个人偏好,你可以启用屏幕上显示错误,但这可能导致错误被忽略或覆盖屏幕上的其他重要内容,这并不理想。

此外,如果你曾经在生产站点上调试问题,你不希望将错误显示在屏幕上,因为这可能导致敏感信息向用户显示。

为了实际查看效果,让我们看一个例子。

假设你开发了一个包含以下代码的插件:

<?php
/**
 * Plugin Name: WP Learn Debugging
 * Plugin Description: A plugin to learn about debugging in WordPress.
 * Plugin URI: https://learn.wordpress.org
 * Version: 1.0.0
 */

/**
 * Set up the required form submissions table
 */
register_activation_hook( __FILE__, 'wp_learn_setup_table' );
function wp_learn_setup_table() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'form_submissions';

    $sql = "CREATE TABLE $table_name (
      id mediumint(9) NOT NULL AUTO_INCREMENT,
      name varchar (100) NOT NULL,
      email varchar (100) NOT NULL,
      PRIMARY KEY  (id)
    )";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
}

/**
 * Register the REST API GET route
 */
add_action( 'init', 'wp_learn_register_routes' );
function wp_learn_register_routes() {
    register_rest_route(
        'wp-learn-form-submissions-api/v1',
        '/form-submissions/',
        array(
            'methods'             => 'GET',
            'callback'            => 'wp_learn_get_form_submissions',
            'permission_callback' => '__return_true'
        )
    );
}

/**
 * Fetch the form submissions for the REST API GET Route
 *
 * @return array|object|stdClass[]|null
 */
function wp_learn_get_form_submissions() {
    global $wpdb;
    $table_name = $wpdb->prefix . 'form_submission';

    $results = $wpdb->get_results( "SELECT * FROM $table_name" );

    return $results;
}

这个插件在激活时会在数据库中创建一个表单提交表,然后注册一个 REST API GET 路由来从数据库中获取表单提交。

出于测试目的,你手动在 form_submissions 表中插入了几条记录。

但是,如果你访问 REST API GET 路由,你看不到任何表单提交,因此你需要开始查找代码中的错误。

只需启用调试,代码中的任何错误都会自动记录到 wp-content/debug.log 文件中。所以如果你查看一下,你会看到一些错误已被记录。

[02-Jun-2023 13:51:41 UTC] PHP Notice:  Function register_rest_route was called <strong>incorrectly</strong>. REST API routes must be registered on the <code>rest_api_init action. Please see Debugging in WordPress for more information. (This message was added in version 5.1.0.) in /home/ubuntu/wp-local-env/sites/learnpress/wp-includes/functions.php on line 5865

在这种情况下,报告了两个错误。首先是由 WordPress 触发的 PHP 通知,这是由于将 wp_learn_register_routes 函数挂载到了错误的操作上。其次是与用于获取表单提交的数据库查询相关的错误。

看起来它查询的是 form_submission 表,而不是 form_submissions 表。

一旦你修复了这些错误,并访问 REST API GET 路由,你就会看到表单提交被返回了。

使用 error_log 进行调试

除了将错误记录到 debug.log 文件之外,你还可以使用 PHP 的 error_log 函数将消息或变量记录到 debug.log 文件。

此函数接受一个字符串参数。

例如,如果你想将正在运行的 SQL 查询记录到 debug.log 文件中,可以使用以下代码:

error_log( $wpdb->last_query );

如果你刷新请求并查看 debug.log 文件,就会看到查询被记录到该文件中。

[02-Jun-2023 13:55:35 UTC] SELECT * FROM wp_form_submissions

使用 SAVEQUERIES 常量

除了记录最后一条查询,你还可以记录 WordPress 请求生命周期中运行的所有查询。

要实现这一点,你可以在 wp-config.php 文件中启用 SAVEQUERIES 常量。

define( 'SAVEQUERIES', true );

启用此常量后,你可以使用以下代码记录所有查询:

error_log( print_r( $wpdb->queries, true ) );

这段代码结合使用了 error_log() 函数和 PHP 的 print_r() 函数,将 $wpdb->queries 数组记录到 debug.log 文件中。

该数组包含了 WordPress 请求生命周期中运行的所有查询,并且仅在启用 SAVEQUERIES 常量时才可用。

进一步阅读

有关 WordPress 调试的更多信息,请查看 WordPress 开发者文档中高级管理区域的“WordPress 调试”部分。

构建支持多站点的插件和主题

在为 WordPress 多站点网络开发主题或插件时,需要考虑一些与为单站点 WordPress 安装开发略有不同的事项。

在本课中,你将了解一些需要考虑的差异,以及如何确保你的插件和主题支持多站点。

开发主题和子主题

通常,主题和子主题在多站点网络上的工作方式与在单站点上完全相同。一旦主题或子主题被网络激活,它就可以在网络上的任何单个站点上激活。

你可能想要编码到 functions.php 文件中的所有特定功能都将在当前主题的范围内工作。例如,如果你想要在主题的页脚中显示站点名称,你可以使用标准的 get_bloginfo 函数来检索站点名称。

if ( ! function_exists( 'tt3c_get_site_name' ) ) {
    function tt3c_get_site_name() {
        return get_bloginfo( 'name' );
    }
}

然而,假设你想要在主题的页脚中包含主站点的名称,无论当前正在查看哪个站点。你可以使用 switch_to_blog 函数切换到主站点,检索站点名称,然后恢复当前站点。

if ( ! function_exists( 'tt3c_get_site_name' ) ) {
    function tt3c_get_site_name() {
        $site_name = get_bloginfo( 'name' );
        switch_to_blog( 1 );
        $main_site_name = get_bloginfo( 'name' );
        restore_current_blog();

        return $site_name . ' (part of the ' . $main_site_name . ' network)';
    }
}

更进一步,也许你想要仅将主站点排除在此自定义功能之外。你可以使用 is_main_site 函数来检查当前站点是否为主站点,如果是,则直接返回站点名称。

if ( ! function_exists( 'tt3c_get_site_name' ) ) {
    function tt3c_get_site_name() {
        if ( is_main_site() ) {
            return get_bloginfo( 'name' );
        }

        $current_site = get_bloginfo( 'name' );
        switch_to_blog( 1 );
        $main_site_name = get_bloginfo( 'name' );
        restore_current_blog();
        return $current_site . ' (part of the ' . $main_site_name . ' network)';
    }
}

所有这些都可以通过单个子主题中的一个 functions.php 文件实现。

开发插件

如前所述,大多数插件功能在单站点和多站点上的工作方式相同。像 register_post_typeget_posts 这样的函数将以相同的方式运行,只是在特定站点的范围内。

然而,在为多站点开发插件时,需要考虑两件事。

插件通常有一个设置页面,通常可以从管理仪表板访问。这对于单站点插件来说没问题,但在多站点网络上,你需要考虑设置页面应该位于何处。它应该位于网络管理仪表板上,还是位于单个站点仪表板上?

如果你需要在网络管理仪表板上有一个设置页面,你可以使用 network_admin_menu 钩子向网络管理仪表板添加一个菜单项。如果你需要在单个站点仪表板上有一个设置页面,你可以使用 admin_menu 钩子向单个站点仪表板添加一个菜单项。

插件可能必须添加自定义表来存储自定义数据。如果你使用像 $wpdb->prefix 这样的变量来为你的表名添加前缀,你最终会得到一个以站点 ID 为前缀的表名。因此,如果你需要为每个站点提供此功能的自定义表,你需要提前规划。

让我们看一个例子。

这里我们有来自《安全开发插件入门》教程的示例插件。它有一个在插件激活时创建的 form_submissions 表,用于存储表单提交数据。如果你查看代码,你会看到表名以全局 $wpdb 对象的前缀属性为前缀。

在单站点安装中,这意味着它将使用 wp-config.php 文件中定义的前缀创建一个表,在此示例中为 wp_form_submissions

然而,在多站点网络上,根据插件的安装方式,它将创建不同的表。

如果它在网络上的单个站点上激活,表前缀将包含站点 ID。

因此,对于站点 2,表名将是 wp_2_form_submissions

然而,如果插件是网络激活的,激活过程将在主站点的范围内运行,并且它会创建与在单站点安装上激活时相同的表。

因此,对于网络激活,表名将是 wp_form_submissions

问题出现在你查看存储表单提交数据的代码时。

因为这也使用了全局 $wpdb 对象中的相同前缀属性,当此代码在主站点的范围内运行时,它将查找 wp_form_submissions 表来存储数据,但是,例如,当它在网络上的站点 2 的范围内运行时,它将查找 wp_2_form_submissions 来存储数据,而该表并不存在。

为了解决这个问题,我们需要更新插件激活例程,以考虑到这一点:

首先,将表创建代码移动到一个单独的函数中,然后从激活钩子调用此函数。

function wp_learn_create_table(){
    global $wpdb;
    $table_name = $wpdb->prefix . 'form_submissions';

    $sql = "CREATE TABLE $table_name (
      id mediumint(9) NOT NULL AUTO_INCREMENT,
      name varchar (100) NOT NULL,
      email varchar (100) NOT NULL,
      PRIMARY KEY  (id)
    )";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
}

在 register_activation_hook 钩子的文档中,你会注意到回调函数接受一个 $network_wide 参数。这是一个布尔值,传递给激活钩子回调,指示插件是否正在网络范围内激活。

然后,你可以更新回调函数,首先检查站点是否为多站点网络,以及插件是否正在网络范围内激活。

如果是,则获取并遍历网络中的所有站点,依次切换到每个站点,并为每个站点创建数据表。

或者,如果插件未在网络范围内激活,则只需为当前站点创建数据表即可。

register_activation_hook( __FILE__, 'wp_learn_setup_table' );
function wp_learn_setup_table( $network_wide ) {
    if ( is_multisite() && $network_wide ) {
        $sites = get_sites();
        foreach ( $sites as $site ) {
            switch_to_blog( $site->blog_id );
            wp_learn_create_table();
            restore_current_blog();
        }
    } else {
        wp_learn_create_table();
    }
}

通过在网络上激活插件来测试此功能,您应该会看到所有正确的数据表都已创建。

但是,当创建新站点时会发生什么?在这种情况下,您需要使用像 wp_initialize_site 这样的钩子,为新站点创建数据表。

add_action( 'wp_initialize_site', 'wp_learn_setup_newsite_table' );
function wp_learn_setup_newsite_table( $site ) {
    switch_to_blog( $site->id );
    wp_learn_create_table();
    restore_current_blog();
}

通过创建一个新站点来测试这一点。它应该会在数据库中为该站点的表单提交创建新的数据表。

通过这种方式,您可以让插件在多站点网络上正常工作,无论是在网络上首次激活时(考虑到所有现有站点),还是为将来可能创建的新站点做好准备。

在哪里获取更多信息

除了关于创建网络以及创建网络前需考虑事项的文档外,针对多站点开发的开发者专用文档并不多。

不过,您可以通过浏览 WordPress 代码参考中的多站点包部分,查看所有与多站点相关的功能列表。

开发多站点网络

WordPress 核心包含一组函数和钩子,用于控制网络的某些方面或网络中的单个站点。

在本课中,你将了解需要注意的多站点特定函数命名约定,然后深入探讨一些有用的多站点特定函数和钩子。最后,你将学习如何为网络中的单个站点进行开发,以及在哪里可以获取关于多站点函数和钩子的更多信息。

关于命名约定的说明

WordPress 代码库中,关于多站点存在几种不同的命名约定。

WordPress 多站点最初被称为 WordPress MU(或 WordPress 多用户),许多与多站点相关的函数和钩子都使用 wpmu_ 前缀。

此外,一些函数基于旧术语命名,这些旧术语描述了一个“站点”上的多个“博客”。现在这已被更新为描述一个“网络”上的多个“站点”,但一些旧术语仍然存在于某些函数名称中。

有用的函数

当你开发一个支持多站点网络的产品时,了解一些有用的内部函数是值得的。

第一个是 is_multsite 函数。如果启用了多站点,此函数将返回 true,并且可能是与多站点相关的最广泛使用的函数。如果你在 WordPress 代码库中搜索 is_multsite 函数的使用情况,你会看到它在许多地方被使用,要么是在多站点网络上下文中执行特定任务,要么是将功能限制为仅适用于多站点网络。

还有一些常用函数在开发多站点网络的管理界面时非常有用:

  • is_super_admin 可用于检查当前登录用户是否为网络上的网络管理员。
  • is_network_admin 是 is_admin 函数的多站点等效项,用于确定当前请求是否针对网络管理界面。
  • network_admin_url 是 admin_url 函数的多站点等效项,允许你创建相对于网络管理区域的 URL。这对于重定向到网络管理仪表板的不同区域非常有用。

在处理站点内容时,有一些广泛使用的函数。

is_main_site 确定当前站点是否是当前网络的主站点。

接下来是 get_sites 函数,它将返回与请求参数匹配的站点列表。

然后是 switch_to_blog,它允许你切换到网络中的不同站点,restore_current_blog 在你切换到不同站点后恢复当前站点,以及 get_current_blog_id,它返回当前站点的 ID。

使用这些函数,你可以在整个网络中执行操作。

例如,假设你想创建一个函数来更新网络中特定站点上的一个选项。

function update_site_option( $site_id,  $option_name, $option_value ) {
    switch_to_blog( $site_id );
    update_option(  $option_name, $option_value );
    restore_current_blog();
}

但是,如果你想扩展该功能以在所有站点上更新相同的选项,你可以使用 get_sites 函数,并遍历网络中的所有站点。

function update_option_on_all_sites( $option_name, $option_value ) {
    $sites = get_sites();
    foreach ( $sites as $site ) {
        switch_to_blog( $site->blog_id );
        update_option( 'my_option', 'my_value' );
        restore_current_blog();
    }
}

你也可以使用 update_blog_option 函数来更新特定站点上的选项,而无需切换到该站点。

function update_option_on_all_sites( $option_name, $option_value ) {
    $sites = get_sites();
    foreach ( $sites as $site ) {
        update_blog_option( $site->blog_id, $option_name, $option_value );
    }
}

在开发多站点插件时,有 is_network_only_plugin 函数。这是一个特定于插件的函数,用于检查插件头部中的“Network: true”,以确定是否应仅作为网络范围的插件激活。如果你想限制一个插件只能在整个网络上激活,而不能在单个站点上激活,这将非常有用。

有用的钩子

在开发多站点时,还有一些有用的钩子可以使用。

第一个是 network_admin_menu 钩子,它允许你向网络管理仪表板添加菜单项。如果你想向网络管理仪表板添加自定义菜单项,这将非常有用。

第二个是 network_admin_notices 钩子,它允许你向网络管理仪表板添加通知。这可用于向网络管理员显示通知,就像 admin_notices 用于单站点通知一样。

signup_blogform 是一个过滤器,允许你修改新站点的注册表单。你可以使用它向注册表单添加额外的字段。

wp_initialize_site 是一个动作,在创建新站点时触发。如果你想在创建新站点时执行操作,例如为子站点分配自定义顶级域名,这将非常有用。

为网络中的单个站点进行开发

当你在网络中单个站点的范围内渲染任何内容时,WordPress 核心足够智能,能够知道你正在该站点的范围内工作。

这意味着你用来检索信息的任何函数,例如 get_bloginfo、get_option、get_posts 或 get_post_meta,以及你用来添加或更新信息的任何函数,比如 update_option、wp_insert_post 或 update_post_meta,都会针对你当前正在操作的站点获取、添加或更新正确的数据表。

此外,如果你使用像 register_post_typeregister_taxonomy 这样的函数,它们将仅为当前站点注册。

进一步阅读

要查看所有 WordPress 多站点相关函数和钩子的完整列表,请查阅 WordPress 开发者参考中的多站点包类别。

高级多站点管理

掌握了多站点网络管理的基础知识后,是时候了解一些更高级的多站点管理任务了。

让我们深入了解不同的站点状态选项、删除站点时会发生什么、如何将多站点网络中的单个站点导出为独立安装,以及如何将多站点网络安装恢复为单站点安装。

站点状态 (0:25)

网络管理员可以使用一些站点状态选项,了解这些选项很有用。

停用站点会将站点状态更新为已删除,并向访问该站点的任何人显示一条消息。此外,当站点被停用时,有一个 deactivate_blog 操作钩子;当站点被激活时,有一个 activate_blog 操作钩子,可用于在站点激活或停用时运行额外功能。

归档站点会将站点状态更新为已归档,并向访问该站点 URL 的任何人显示一条归档消息。

将站点标记为垃圾会将站点状态更新为垃圾,并显示与归档相同的消息,但不会触发额外的钩子。

从网络中删除站点

从网络中删除站点将移除与该站点关联的所有内容,包括文章、页面、评论以及任何其他自定义内容类型。它还会删除数据库中用于存放站点内容的任何表。与将文章或页面放入回收站不同,一旦删除站点,就无法撤销此操作。

将站点导出为单站点安装

在某些情况下,您可能希望将其中一个子站点提取出来,作为独立的单站点 WordPress 安装。这是可行的,但需要一些手动步骤。有几种方法可以做到这一点,这里只介绍一种可能性。

首先,登录子站点,然后浏览到 工具 > 导出 页面。

您可以使用 WordPress 导出工具将内容导出为 WordPress eXtended RSS 或 WXR 格式。

然后创建新的单站点和关联的用户。

确保安装子站点上使用的任何插件和主题。

然后浏览到工具 -> 导入,使用 WordPress 导入器将数据导入新站点。您可能需要点击 WordPress 选项下的“立即安装”来安装导入器,安装完成后点击“运行导入器”。

别忘了将数据分配给新站点上的相关用户。

数据导入后,手动将子站点的上传目录复制到新的单站点安装中。

您可以在多站点安装的 wp-content/uploads/sites/ 目录中找到子站点的上传目录,该目录位于一个以子站点 ID 命名的文件夹中。

最后但同样重要的是,运行一个搜索替换工具,例如 Better Search Replace,来更新数据库中的任何 URL。

您需要将子站点 URL(子域名或子目录版本)替换为新的单站点 URL。如果您将顶级域名指向了子站点,这一步可能不是必需的。

最后,全面测试一切,确保其按预期工作。

WordPress 数据导出选项的替代方法是手动将子站点的数据库表复制到新站点。但是,如果内容未与正确的用户关联,这可能会导致进一步的问题。

注意事项

如果您有任何创建自定义数据库表的插件,您可能需要手动将这些表复制到新安装中。

在这种情况下,依赖具有多站点扩展的付费第三方备份解决方案可能更容易,这些扩展会为您处理这些操作。

将多站点转换回单站点安装

也可以将多站点转换回单站点安装。如果您不再需要多站点功能,但希望保留原始站点,这将非常有用。

如果您有其他子站点,最好先将它们导出为单站点安装,因为这会删除子站点的内容表。此外,删除为子站点创建的任何用户。

要恢复为单站点,您首先需要移除 wp-config.php 中所有与多站点相关的常量。

完成此操作后,您的仪表盘将恢复为单站点仪表盘。

然后,如果您之前更新了 .htaccess 文件,您需要将其恢复为原始的 .htaccess 文件。

您可以通过将固定链接重置为您想要的任何格式来实现这一点。

最后,删除多站点安装期间专门创建的任何表,即:

wp_blogs
wp_blog_versions
wp_registration_log
wp_signups
wp_site
wp_sitemeta
wp_usermeta
wp_users

如果一切顺利,您现在应该拥有一个正常工作的主站点单站点安装。

进一步阅读

如需查看所有多站点管理功能的完整列表,请查阅 WordPress 开发者手册中“高级管理”下的“多站点”部分。

管理WordPress多站点网络

管理 WordPress 多站点网络与管理单站点 WordPress 安装略有不同。

在本课中,你将学习如何管理 WordPress 多站点网络。

你将了解网络管理仪表板、网络设置页面中的可用选项,以及在网络上创建和管理子站点的不同方法。

网络管理仪表板

一旦启用了多站点网络,你的管理员用户将变为超级管理员,并可以访问网络管理仪表板。在这里,你可以管理网络中的站点、用户、主题、插件和设置。

网络设置页面

网络设置页面是管理多站点网络的地方。

操作设置允许你设置网络标题和管理员邮箱。

注册设置允许你设置网络的注册选项。

例如,如果你想允许用户在网络中注册新站点,可以启用“站点和用户账户都可以注册”选项。

你还可以设置新站点的禁用名称、限制特定电子邮件域名的注册,以及禁止特定电子邮件域名的注册。

新站点设置控制着在网络中创建新站点时发送的电子邮件和创建的内容。

上传设置控制文件上传,包括文件大小限制和允许的文件类型。

语言设置允许你控制网络中新建站点的默认语言。

最后,菜单设置允许你控制站点管理员可以访问哪些菜单。

创建站点

你可能想做的第一件事就是创建一个子站点。为此,请转到站点页面,并点击“添加新站点”按钮。系统会要求你输入站点地址(子域名或子目录)、站点标题、站点语言和站点管理员邮箱地址。如果你使用现有用户的邮箱地址,该用户将被添加为站点管理员。否则,将创建一个新用户并设为新站点的管理员。

站点创建后,你可以通过点击站点列表中的“编辑”按钮来编辑该站点。

信息选项卡管理站点地址,显示站点的注册时间和最后更新时间,并管理站点属性。

用户选项卡允许你将现有用户添加到站点,或向站点添加新用户。

主题选项卡允许你为站点激活一个主题。这里可用的主题是那些未在整个网络中激活的主题。这意味着你可以为网络中的特定站点设置专属主题。

设置选项卡包含你可以管理的所有其他站点设置。

为站点分配顶级域名

还可以为网络中的站点设置顶级域名或根域名。如果你或站点管理员想为网络中的某个站点使用不同的域名,这将非常有用。

要实现这一点,你需要在域名注册商处注册该域名,并将其指向与多站点安装相同的位置。

在这种情况下,你可以看到新的顶级域名指向与多站点安装相同的位置,因为它会重定向到多站点的 URL。

然后,在网络管理中,编辑相关站点,并将站点地址字段更改为新的顶级域名。

现在,当你浏览该域名时,将被重定向到网络中关联的站点。

允许用户注册自己的站点

根据你计划如何使用多站点网络,你可能希望用户能够注册自己的子站点。为此,请转到网络设置页面,并启用“站点和用户账户都可以注册”选项。

现在,如果用户浏览默认的 WordPress 注册 URL,他们将看到还可以在网络中注册站点的选项。

// 示例代码块,内容保持不变

输入用户名和邮箱地址后,系统会询问他们是想要创建站点,还是仅在网络中注册用户账户。

如果他们选择创建站点,则需要设置站点名称和标题。

一旦他们点击注册,站点将被创建,用户将收到一封激活新站点的电子邮件,之后他们就可以登录到该子站点。

进一步阅读

有关管理多站点网络的更多详细信息,请查看 WordPress 开发者文档中的网络管理和网络设置页面。

搭建WordPress多站点网络

WordPress 多站点网络是一种在单个 WordPress 安装中托管多个 WordPress 站点的方式。

在本课中,你将进一步了解 WordPress 多站点、为何要考虑设置多站点网络,以及创建多站点网络需要遵循的步骤。

什么是 WordPress 多站点网络?

WordPress 多站点网络是一组共享单个 WordPress 安装的 WordPress 站点。通过多站点网络,可以允许用户创建自己的站点,或者将网络配置为仅允许管理员创建站点。这些站点在网络中被称为“子站点”或“独立站点”。

多站点网络中的所有站点都使用相同的 WordPress 安装文件,并共享相同的插件和主题。插件和主题在网络级别安装,然后在各个独立站点上激活。

每个独立站点在共享安装中都有独立的媒体上传目录,并在数据库中有独立的表来存储站点内容。

需要注意的是,虽然它们共享相同的 WordPress 核心文件,但多站点网络中的各个站点是相互独立的。它们不像其他类型的网络那样相互连接。如果你计划创建紧密互联、共享数据或共享用户的站点,那么多站点网络可能不是最佳解决方案。

为何要使用 WordPress 多站点网络?

当你拥有多个性质相似但需要相互独立的站点时,多站点网络是一个很好的解决方案。

这方面的例子包括高等教育网站、非营利组织和开源项目。

一个活跃多站点网络最典型的例子就是 Make WordPress。

在这里,每个参与 WordPress 开源项目的贡献者团队都拥有自己的子站点,这些子站点是 Make WordPress 网络的一部分。这意味着,如果你是核心团队的成员,你只能登录到核心子站点,并为该团队创建内容。

多站点网络支持

你使用的网络主机或本地开发环境将决定你如何在本地或在线服务器上创建多站点网络。两种常见的选择是:要么在新安装过程中提供一个设置选项,将新安装设置为多站点网络;要么在 WordPress 安装完成后,按照手动步骤设置多站点网络。

使用 Apache 网络服务器的网络主机和本地开发环境通常允许你使用手动方法将现有的 WordPress 安装转换为多站点网络。使用 Nginx 的环境通常要求你在创建新站点的过程中创建多站点网络。这是因为默认情况下,nginx 不支持用于手动启用多站点的 .htaccess 文件。

无论你使用的是自动还是手动启用多站点的网络主机或本地开发环境,了解从 WordPress 安装创建多站点网络所需的额外步骤都是一个好主意,这也是本课的重点。

如何创建多站点网络

在创建多站点网络之前,请务必阅读开发者文档中的“在创建网络之前”页面,因为它涵盖了一些你在创建多站点网络之前需要了解的重要注意事项。

接下来,你应该备份当前站点的文件和数据库。这不是绝对必要的,特别是如果你创建了一个全新的 WordPress 安装,但如果你已经在要转换为多站点网络的站点上创建了一些内容,那么备份是个好主意。

此外,如果你有站点文件的备份,那么在创建多站点网络过程中如果出现任何问题,你可以快速撤销所做的任何更改。

同时,你应该确保站点上的固定链接正常工作,并且已停用所有已安装的插件。

最后,如果你希望将 WordPress 安装运行在其自己的目录中,请确保在创建多站点网络之前完成此操作。

启用多站点

要启用多站点,你需要编辑 WordPress 安装根目录下的 wp-config.php 文件,并将 PHP 常量 WP_ALLOW_MULTISITE 定义为 true

/* 多站点 */
define( 'WP_ALLOW_MULTISITE', true );

然后,刷新你的 WordPress 仪表盘。通过设置此常量,你现在会在仪表盘的“工具”菜单下看到一个新的菜单项,名为“网络设置”。

安装网络

“网络设置”页面将引导你完成创建多站点网络的步骤。

首先,你需要选择是使用顶级域名的子域名还是子目录作为网络上站点的地址。子目录更简单,因为你不需要任何额外的 DNS 配置,但子域名能让站点拥有更专业的 URL。要使用子域名,你需要为你的顶级域名设置一个通配符 DNS 记录。

在本课中,我们将使用子目录。

您可以保留其余设置不变,或根据自己的喜好进行更改。

准备好后,点击“安装”按钮。

WordPress 现在将运行网络安装,创建所需的任何数据库表,并向这些表添加所需的特定数据。

启用网络

安装完成后,您需要启用网络。这需要做两处更改:

  1. 再次编辑 wp-config.php 文件,并添加仪表盘中“启用网络”页面第一步描述的常量。
  2. 编辑 WordPress 安装根目录中的 .htaccess 文件,并添加仪表盘中“启用网络”页面第二步描述的规则。

完成这些更改后,刷新您的 WordPress 仪表盘,系统会要求您重新登录。

您将被重定向回“网络设置”页面,但会注意到您现在已作为网络管理员登录,并且新创建的多站点网络为您提供了一组不同的菜单选项。

进一步阅读

有关如何创建多站点网络的更多详细信息,请务必阅读官方 WordPress 文档中的“创建网络”页面。

常用的国际化函数

要开始对代码进行国际化,您需要了解 WordPress 提供的用于帮助您完成此过程的函数。

在本课中,您将学习 WordPress 中最常用的国际化函数,以及如何在代码中使用它们。

如何对代码进行国际化 (0:18)

每当您编写一段将显示给用户的文本字符串时,都应使用 WordPress 的 i18n 函数,以确保它可以被翻译。

有许多可用的 i18n 函数,每个函数都执行与国际化相关的不同任务。

最常用的 i18n 函数是 __() 函数。此函数接收一个文本字符串,并返回该字符串的翻译版本。如果没有可用的翻译,则返回原始字符串。

您还会注意到,此函数以及大多数其他 i18n 函数都接受第二个参数。此参数用于指定文本域。

文本域是您的插件或主题的唯一标识符。它用于确保使用正确的翻译。

主题和插件在其头部都有一个“文本域”字段。这用于指定主题或插件的文本域。

每当您使用翻译函数时,都应始终将文本域作为第二个参数包含在内。

__( 'Some Text', 'my-textdomain' );

要了解其工作原理,让我们看一个示例:

首先,浏览到 GitHub 上的“初学者开发者学习路径”仓库,并下载“国际化主题”zip 文件。

然后,在您的 WordPress 网站上安装该主题,并在代码编辑器中浏览它。

functions.php 文件中,一个 JavaScript 文件在 WordPress 仪表盘的上下文中被入队。它还在“外观”菜单中注册了一个子菜单项,用于渲染主题设置页面。

<?php
/**
 * Enqueue theme.js file in the dashboard.
 */
add_action( 'admin_enqueue_scripts', 'internationalization_enqueue_scripts' );
function internationalization_enqueue_scripts() {
    wp_enqueue_script(
        'internationalization-theme-js',
        get_stylesheet_directory_uri() . '/assets/theme.js',
        array(),
        '1.0.0',
        true
    );
}

/**
 * Create a submenu item under the "Appearance" menu.
 */
add_action( 'admin_menu', 'internationalization_add_submenu_page' );
function internationalization_add_submenu_page() {
    add_submenu_page(
        'themes.php',
        'Internationalization',
        'Internationalization',
        'manage_options',
        'internationalization',
        'internationalization_display_page'
    );
}

/**
 * Render the page for the submenu item.
 */
function internationalization_display_page() {
    ?>
    <div class="wrap">
        <h1>Internationalization Settings</h1>
        <p>This is a settings page for the Internationalization theme</p>
        <button id="internationalization-settings-button" class="button button-primary">Alert</button>
    </div>
    <?php
}

如果您浏览到设置页面,它会包含一个按钮,点击该按钮会显示一个警告框。

此警告框由主题的 JavaScript 文件处理。

/**
 * Add event listener to the button
 */
document.querySelector( '#internationalization-settings-button' ).addEventListener( 'click', function(){
    alert( 'Settings button clicked' );
} );

在这段代码中,您有许多需要国际化的英文字符串。

第一步是国际化 PHP 代码中的文本字符串。为此,您可以将文本字符串包裹在 __() 函数中,并指定文本域。

首先检查主题的文本域。对于主题,这位于 style.css 文件中;对于插件,则位于主插件文件中。

在这种情况下,文本域是 internationalization。如果此主题没有文本域,您需要指定一个。

然后,更新 internationalization_add_submenu_page() 函数中的文本字符串。

/**
 * Create an admin submenu item under the "Appearance" menu.
 */
add_action( 'admin_menu', 'internationalization_add_submenu_page' );
function internationalization_add_submenu_page() {
    add_submenu_page(
        'themes.php',
        __( 'Internationalization', 'internationalization' ),
        __( 'Internationalization', 'internationalization' ),
        'manage_options',
        'internationalization',
        'internationalization_display_page'
    );
}

您可以为 internationalization_display_page() 函数中的文本字符串执行相同操作。

/**
 * Render the page for the submenu item.
 */
function internationalization_display_page() {
    ?>
    <div class="wrap">
        <h1><?php echo __( 'Internationalization Settings', 'internationalization' ); ?></h1>
        <p><?php echo __( 'This is a settings page for the Internationalization theme', 'internationalization' ); ?></p>
        <button id="internationalization-settings-button" class="button button-primary"><?php echo __( 'Alert', 'internationalization' ); ?></button>
    </div>
    <?php
}

WordPress 还包含一个用于直接输出可翻译字符串的简写函数。此函数是 _e() 函数。它既进行国际化,又直接输出字符串。您可以使用此函数来简化代码。

/**
 * Render the page for the submenu item.
 */
function internationalization_display_page() {
    ?>
    <div class="wrap">
        <h1><?php _e( 'Internationalization Settings', 'internationalization' ); ?></h1>
        <p><?php _e( 'This is a settings page for the Internationalization theme', 'internationalization' ); ?></p>
        <button id="internationalization-settings-button" class="button button-primary"><?php echo __( 'Alert', 'internationalization' ); ?></button>
    </div>
    <?php
}

接下来,您需要国际化 JavaScript 文件中的文本字符串。

为此,有一个与 PHP 的 __() 函数等效的 JavaScript 版本,它在 WordPress 前端的 wp.i18n 对象中可用。

为了确保您可以使用此函数,您需要更新您的 internationalization_enqueue_scripts() 函数,以将 wp-i18n 包作为依赖项。这将确保您的 JavaScript 代码仅在 wp-i18n 包加载且 wp.i18n 对象可用时才会被加载。

/**
 * Enqueue theme.js file in the dashboard.
 */
add_action( 'admin_enqueue_scripts', 'internationalization_enqueue_scripts' );
function internationalization_enqueue_scripts() {
    wp_enqueue_script(
        'internationalization-theme-js',
        get_stylesheet_directory_uri() . '/assets/theme.js',
        array( 'wp-i18n' ),
        '1.0.0',
        true
    );
}

然后,您需要为您想要翻译的脚本调用 wp_set_script_translations 函数。此函数接受脚本的句柄和文本域作为参数。这将加载脚本的翻译。

wp_set_script_translations( 'internationalization-theme-js', 'internationalization' );

完成此操作后,您就可以设置并使用来自 wp.i18n 对象的 __() 函数来翻译 JavaScript 文件中的文本字符串。

const __ = wp.i18n.__;
/**
 * Add event listener to the button
 */
document.querySelector( '#internationalization-settings-button' ).addEventListener( 'click', function(){
    alert( wp.i18n.__( 'Settings button clicked', 'internationalization' ) );
} );

如果您刷新页面,不会立即看到任何变化,所有功能仍将按预期工作。

但是,如果有人愿意,他们可以基于所有国际化的文本字符串为主题生成英文语言文件,以便进行翻译。

块开发中的国际化函数

如果您正在为块编辑器开发一个块,您也可以在块的 JavaScript 中使用 JavaScript 翻译函数来国际化块中的文本字符串。

您需要做的就是从 @wordpress/i18n 包中导入相关函数。

/**
 * Retrieves the translation of text.
 *
 * @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
 */
import { __ } from '@wordpress/i18n';

进一步阅读

本课程仅涵盖部分可用的国际化函数。如需了解所有可用函数的更多信息,请查阅 WordPress 开发者资源中通用 API 手册的国际化章节。

什么是国际化?

国际化是指开发软件时,使其能够在不修改源代码的情况下轻松翻译成其他语言的过程。

让我们了解在 WordPress 中什么是国际化、为什么它很重要,并学习在哪里可以找到更多关于如何在 WordPress 开发中实现国际化的信息。

什么是国际化?

WordPress 被全球使用,用户使用多种语言。

因此,WordPress 中的任何文本字符串都需要进行编码,以便它们可以轻松翻译成其他语言。

让我们看一个例子:

当你第一次登录 WordPress 仪表盘时,页面顶部会出现“仪表盘”这个标题。

你可以在 wp-admin/index.php 文件的第 33 行找到生成这个标题的代码。

$title       = __( 'Dashboard' );

这里 $title 变量被设置为“仪表盘”。

注意文本字符串是如何被包裹在 __() 函数中的。这是一个 WordPress 函数,用于使文本字符串可翻译。

如果你访问用户的个人资料并将其更新为另一种语言,文本字符串将被翻译成该语言。

例如,如果我将我的用户个人资料更改为西班牙语,标题将被翻译为“Escritorio”。

但底层的代码保持不变。

这是可能的,因为西班牙语的语言文件已安装在网站上,并且包含了文本字符串“仪表盘”的翻译。

#. translators: Network menu item.
#: wp-includes/admin-bar.php:431 wp-includes/admin-bar.php:596
#: wp-includes/admin-bar.php:716 wp-includes/deprecated.php:2822
#: wp-includes/deprecated.php:2824 wp-admin/index.php:33 wp-admin/menu.php:24
#: wp-admin/my-sites.php:142 wp-admin/user/menu.php:10
#: wp-admin/includes/class-wp-ms-sites-list-table.php:746
#: wp-admin/network/index.php:21 wp-admin/network/menu.php:11
#: wp-admin/network/site-info.php:138 wp-admin/network/site-settings.php:95
#: wp-admin/network/site-themes.php:181 wp-admin/network/site-users.php:226
msgid "Dashboard"
msgstr "Escritorio"

由于使用了翻译函数,一旦为用户设置了语言,WordPress 将在相关语言文件中搜索该词的翻译,并根据上下文显示或存储翻译。

国际化是编写代码的过程,通过将可能显示给用户的任何文本字符串包裹在正确的翻译函数中,使其可翻译。

国际化通常缩写为 i18n(因为字母 i 和 n 之间有 18 个字母)。

将国际化的文本字符串翻译并适应特定区域或语言的过程称为本地化。

虽然本地化不在本课程范围内,但你可以在 WordPress 开发者资源中通用 API 手册的本地化部分阅读更多相关内容。

国际化不是什么

国际化并不等同于确保你网站前端的内容以多种语言提供。

这通常被称为确保你的内容是多语言或已翻译的。

由于这些内容存储在数据库中,最好为每种你想要支持的语言准备一个完全翻译的网站副本。

这可以通过使用 TranslatePress、Polylang 或 WeGlot 等插件来实现。

在哪里找到更多信息

WordPress 开发者资源在通用 API 手册中有一个关于国际化的优秀部分。它包括一个过程概述,以及一个列出 WordPress 中常用于国际化的函数的页面。它还包含一个关于国际化指南的部分,对于任何希望使其 WordPress 插件或主题可翻译的开发者来说,这都是必读内容。