如何使用Acorn构建自定义WP-CLI命令及自动化WordPress维护

如何使用Acorn构建自定义WP-CLI命令及自动化WordPress维护

文章目录

  • 如何安装Acorn并运行命令
  • 创建您的第一个Artisan命令
  • 如何构建3个实用的维护命令
  • 1. 清理孤立的文章元数据
  • 2. 删除过期的瞬态数据
  • 3. 审核自动加载选项
  • 如何通过命令访问WordPress数据
  • 使用Acorn和Artisan Console自定义WP-CLI命令

如何使用Acorn构建自定义WP-CLI命令及自动化WordPress维护

您可能有一些 PHP 脚本用于执行各种任务,例如清理孤立的文章元数据或删除过期的临时数据。随着时间的推移,这些脚本会不断增长,并分散在主题文件、插件文件夹或某个隐蔽的目录中。Acorn 通过将 Laravel 的 Artisan Console 引入 WordPress,帮助您摆脱这种混乱的局面。

这意味着您可以使用结构化的类文件构建自定义的 WP-CLI 命令,从而集中管理您的维护逻辑。这些命令会在开发、测试和生产环境中一致地运行,并提供进度指示器、格式化的表格输出、完善的错误处理等功能。您可以通过 SSH 触发这些命令,使用 cron 作业进行调度,或在部署期间执行它们。

如何安装Acorn并运行命令

第一步是安装所需的依赖项。Acorn 需要 PHP 8.2 或更高版本、用于管理依赖项的 Composer 以及运行在您的服务器上的 WP-CLI

您可以使用 Composer 在项目根目录下运行 composer require roots/acorn 命令来安装 Acorn。然后将引导代码添加到主题的 functions.php 文件或主插件文件中:

<?php
use Roots\Acorn\Application;
if (! class_exists(\Roots\Acorn\Application::class)) {
wp_die(
__('You need to install Acorn to use this site.', 'domain'),
'',
[
'link_url' => 'https://roots.io/acorn/docs/installation/',
'link_text' => __('Acorn Docs: Installation', 'domain'),
]
);
}
add_action('after_setup_theme', function () {
Application::configure()
->withProviders([
App\Providers\ThemeServiceProvider::class,
])
->boot();
}, 0);

零配置设置会将应用程序缓存和日志存储在 WordPress 缓存目录 [wp-content]/cache/acorn/ 中,而您的命令则位于主题的 app/ 目录中。

传统的结构遵循 Laravel 的约定,例如在项目根目录下分别设置 app/config/storage/, 和 resources/ 目录。您只需一行命令即可完成设置:

wp acorn acorn:init storage && wp acorn vendor:publish --tag=acorn

运行 wp acorn list 命令会验证您的 Acorn 安装,并显示所有可用的 Acorn 命令。从现在开始,您创建的所有自定义命令都将存储在 app/Console/Commands/ 目录中。Acorn 会自动发现此位置中的所有命令类,并将其注册到 WP-CLI。

注:您需要通过 SSH 连接到服务器,然后运行 ​​wp acorn 命令,后跟您的命令名称。

创建您的第一个Artisan命令

wp acorn make:command CleanupCommand Artisan 命令会生成具有您所需结构的文件。它包含每个 Artisan 命令都需要的三个关键元素:

  • $signature 属性,用于定义您的命令名称和选项。
  • $description 属性,用于显示帮助文本。
  • handle() 方法,用于存放您的命令逻辑。

在这种情况下,它会构建 app/Console/Commands/CleanupCommand.php 文件,其中包含一个基本的命令结构:

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CleanupCommand extends Command
{
protected $signature = 'app:cleanup';
protected $description = 'Command description';
public function handle()
{
//
}
}

$signature 属性使用特定的语法:

  • 基本命令只需要一个名称,例如 cleanup:run
  • 必需参数用花括号括起来(例如 cleanup:run {days})。
  • 可选参数用问号括起来:cleanup:run {days?}
  • 选项用双破折号括起来:cleanup:run {--force} {--limit=100}

接下来,添加命令描述和基本逻辑:

protected $signature = 'cleanup:test {--dry-run : Preview changes without executing}';
protected $description = 'Test cleanup command';
public function handle()
{
$dryRun = $this->option('dry-run');
if ($dryRun) {
$this->components->info('Running in dry-run mode');
}
$this->components->info('Cleanup command executed');
return 0;
}

您可以使用 wp acorn cleanup:test --dry-run 命令进行测试。该命令使用 Artisan 的组件系统输出格式化的消息。 $this->components->info() 方法会以绿色显示成功消息。您还可以使用 $this->components->error() 输出错误信息,$this->components->warn() 输出警告信息,以及使用 $this->line() 输出纯文本信息。

如何构建3个实用的维护命令

以下是一些示例,可帮助您处理许多 WordPress 网站都会遇到的数据库维护任务。

虽然每个命令都包含错误处理,并且基本遵循 WordPress 编码标准以确保数据安全,但您仍然应该将这些命令作为您自己项目的框架,而不是简单地复制粘贴。

1. 清理孤立的文章元数据

删除文章后,文章元数据仍然会保留。这是因为插件绕过了 WordPress 的删除钩子,留下了指向已不存在文章的元数据条目。随着时间的推移,这些冗余数据会降低数据库查询速度。

使用 wp acorn make:command CleanupOrphanedMeta 创建命令后,就可以开始设置命令类结构和签名了:

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CleanupOrphanedMeta extends Command
{
protected $signature = 'maintenance:cleanup-orphaned-meta 
{--dry-run : Preview orphans without deleting}';
protected $description = 'Remove orphaned post metadata from wp_postmeta';
public function handle()
{
global $wpdb;
$dryRun = $this->option('dry-run');
$this->components->info('Scanning for orphaned post metadata...');

该命令使用 LEFT JOIN 查询来查找这些孤立记录。该模式会检查 posts 表中是否存在 NULL 值。如果连接返回 NULL,则表示元数据属于已删除的帖子:

        // Find orphaned metadata
$orphans = $wpdb->get_results("
SELECT pm.meta_id, pm.post_id, pm.meta_key 
FROM {$wpdb->postmeta} pm
LEFT JOIN {$wpdb->posts} p ON pm.post_id = p.ID
WHERE p.ID IS NULL
LIMIT 1000
");
if (empty($orphans)) {
$this->components->info('No orphaned metadata found');
return 0;
}

当命令找到孤立记录时,如果处于试运行模式,它会显示记录数量并抽取一些记录作为样本。提交之前,您需要验证哪些记录被删除:

        $count = count($orphans);
$this->components->warn("Found {$count} orphaned metadata records");
if ($dryRun) {
$this->newLine();
$this->line('Sample orphaned records:');
foreach (array_slice($orphans, 0, 5) as $orphan) {
$this->line("  → Post ID {$orphan->post_id}: {$orphan->meta_key}");
}
return 0;
}

实际的删除操作使用 $wpdb->prepare() 来避免 SQL 注入攻击。该命令一次处理 1000 条记录,从而防止拥有数百万条元数据条目的站点出现内存问题:

        // Delete orphaned records
$metaIds = array_map(function($orphan) {
return $orphan->meta_id;
}, $orphans);
$placeholders = implode(',', array_fill(0, count($metaIds), '%d'));
$deleted = $wpdb->query(
$wpdb->prepare(
"DELETE FROM {$wpdb->postmeta} WHERE meta_id IN ({$placeholders})",
...$metaIds
)
);
if ($deleted === false) {
$this->components->error('Failed to delete orphaned metadata');
return 1;
}
$this->components->info("Deleted {$deleted} orphaned metadata records");
return 0;
}
}

要运行此命令,请使用 wp acorn maintenance:cleanup-orphaned-meta --dry-run

2. 删除过期的瞬态数据

WordPress 会将瞬态数据存储在 wp_options 表中,并设置过期日期。虽然每日定时任务会清理这些瞬态数据,但有时需要在维护窗口期间或瞬态数据过多造成问题时手动清理。

使用 wp acorn make:command CleanupTransients 生成命令后,您可以设置命令结构:

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class CleanupTransients extends Command
{
protected $signature = 'maintenance:cleanup-transients';
protected $description = 'Delete expired transients from wp_options';
public function handle()
{
global $wpdb;
$this->components->info('Deleting expired transients...');

此删除查询使用多表 DELETE 语法,一次性删除瞬态数据及其超时选项。该查询查找过期时间戳已过的超时记录:

        // Delete expired regular transients
$deleted = $wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
WHERE a.option_name LIKE %s
AND a.option_name NOT LIKE %s
AND b.option_name = CONCAT('_transient_timeout_', SUBSTRING(a.option_name, 12))
AND b.option_value < %d",
$wpdb->esc_like('_transient_') . '%',
$wpdb->esc_like('_transient_timeout_') . '%',
time()
)
);

同时检查错误并跟踪删除次数:

        if ($deleted === false) {
$this->components->error('Failed to delete transients');
return 1;
}
$transientCount = $deleted;

多站点部署中,该命令会运行第二个查询来获取站点瞬态数据。这些查询使用不同的表前缀,但遵循相同的删除模式:

        // Delete expired site transients (multisite)
if (is_multisite()) {
$siteDeleted = $wpdb->query(
$wpdb->prepare(
"DELETE a, b FROM {$wpdb->options} a, {$wpdb->options} b
WHERE a.option_name LIKE %s
AND a.option_name NOT LIKE %s
AND b.option_name = CONCAT('_site_transient_timeout_', SUBSTRING(a.option_name, 17))
AND b.option_value < %d",
$wpdb->esc_like('_site_transient_') . '%',
$wpdb->esc_like('_site_transient_timeout_') . '%',
time()
)
);
if ($siteDeleted !== false) {
$transientCount += $siteDeleted;
}
}
$this->components->info("Deleted {$transientCount} expired transients");
return 0;
}
}

要执行此命令,请运行 wp acorn maintenance:cleanup-transients

3. 审核自动加载选项

自动加载选项会在 WordPress 网站处理的每个请求中加载。当这些数据超过 1MB 时,您可能会开始看到网站速度变慢和内存消耗激增。此命令会查找最大的自动加载选项,以便您可以追踪哪些插件导致了数据膨胀。

首先,使用 wp acorn make:command AuditAutoload 创建审核命令。然后,定义带有可配置阈值的命令签名:

<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
class AuditAutoload extends Command
{
protected $signature = 'maintenance:audit-autoload 
{--threshold=1000000 : Size threshold in bytes}';
protected $description = 'Audit autoloaded options size';
public function handle()
{
global $wpdb;
$threshold = (int) $this->option('threshold');
$this->components->info('Calculating autoloaded options size...');

由此计算所有自动加载选项的总大小:

        // Get total autoload size
$result = $wpdb->get_row(
"SELECT 
SUM(LENGTH(option_value)) as total_bytes,
COUNT(*) as total_count
FROM {$wpdb->options}
WHERE autoload = 'yes'"
);
$totalBytes = (int) $result->total_bytes;
$totalCount = (int) $result->total_count;
$totalMb = round($totalBytes / 1024 / 1024, 2);
$this->newLine();
$this->line("Total autoloaded: {$totalMb} MB ({$totalCount} options)");

该命令会查询大于您设定阈值的选项,按大小排序,并将结果限制为最大的 20 个:

        // Get largest autoloaded options
$largeOptions = $wpdb->get_results(
$wpdb->prepare(
"SELECT option_name, LENGTH(option_value) as size_bytes
FROM {$wpdb->options}
WHERE autoload = 'yes'
AND LENGTH(option_value) > %d
ORDER BY size_bytes DESC
LIMIT 20",
$threshold
)
);
if (empty($largeOptions)) {
$this->components->info('No options exceed the threshold');
return 0;
}

Artisan 的 $this->table() 方法将这些结果格式化为 ASCII 表格:在终端中读取表格数据比解析原始查询输出要好得多:

        $this->newLine();
$this->components->warn('Large autoloaded options:');
$this->newLine();
$tableData = [];
foreach ($largeOptions as $option) {
$sizeKb = round($option->size_bytes / 1024, 2);
$tableData[] = [
$option->option_name,
$sizeKb . ' KB'
];
}
$this->table(
['Option Name', 'Size'],
$tableData
);

当自动加载的总大小超过 3MB 时,该命令会发出警告,这表明存在性能问题,需要解决:

        if ($totalBytes > 3000000) {
$this->newLine();
$this->components->error('Warning: Total autoload exceeds 3MB');
}
return 0;
}
}

要运行审计,请使用 wp acorn maintenance:audit-autoload --threshold=500000

如何通过命令访问WordPress数据

由于 Acorn 在 WordPress 生命周期内启动,因此 WordPress 函数可以在命令方法中运行。这意味着您可以调用一些函数,例如 get_posts() 或 get_option(),而无需任何特殊设置:

public function handle()
{
$posts = get_posts([
'post_type' => 'post',
'post_status' => 'publish',
'numberposts' => 10,
]);
foreach ($posts as $post) {
$this->line($post->post_title);
}
return 0;
}

对于直接数据库查询,请在方法开头声明全局变量 $wpdb

public function handle()
{
global $wpdb;   
$count = $wpdb->get_var(
"SELECT COUNT(*) FROM {$wpdb->posts} WHERE post_status = 'publish'"
);
$this->line("Published posts: {$count}");
return 0;
}

当您的查询包含变量或用户输入时,$wpdb->prepare()是理想的选择,因为它有助于防止 SQL 注入攻击:

$status = 'publish';
$postType = 'post';
$results = $wpdb->get_results(
$wpdb->prepare(
"SELECT ID, post_title FROM {$wpdb->posts} 
WHERE post_status = %s AND post_type = %s",
$status,
$postType
)
);

如果在任何数据库操作之后检查结果是否为 false,这应该可以帮助您捕获错误:

$updated = $wpdb->update(
$wpdb->posts,
['post_status' => 'draft'],
['ID' => 123],
['%s'],
['%d']
);
if ($updated === false) {
$this->components->error('Database update failed');
return 1;
}

自定义文章类型和分类法通过标准的 WordPress 功能实现:

$terms = get_terms([
'taxonomy' => 'category',
'hide_empty' => false,
]);
foreach ($terms as $term) {
wp_update_term($term->term_id, 'category', [
'description' => 'Updated via command',
]);
}

使用Acorn和Artisan Console自定义WP-CLI命令

Acorn 允许您访问 Laravel 的结构化命令类、格式化的输出组件、完善的错误处理等功能,同时让您完全访问 WordPress 的函数和数据。

您可以通过 SSH 访问和 cron 定时任务集成命令。您还可以将命令添加到部署脚本中以实现维护自动化,例如使用 GitHub Actions 工作流。

评论留言

闪电侠

(工作日 10:00 - 18:30 为您服务)

2026-04-16 02:40:54

您好,无论是售前、售后、意见建议……均可通过联系工单与我们取得联系。

您也可选择聊天工具与我们即时沟通或点击查看:

您的工单我们已经收到,我们将会尽快跟您联系!
取消
选择聊天工具: