2026 年维护说明:本文末尾的日期明确档案中保留了 2019 年的完整正文,仅规范化了行尾空白。旧文写了“Code Sinppets”,却没有 URL、厂商、版本、代码或恢复方法,因此不能据此识别或推荐现在的某个插件。维护版把每个代码片段都视为可执行的应用程序代码。先备份或使用预发布环境,准备回滚路径,不要把未经评审的 PHP 粘贴到生产环境。
Table of Contents
2019 年旧文说明了什么,又缺少什么
旧文意识到一个有价值的架构原则:网站自定义功能不必混进主题源代码。但它的具体建议过于简略,今天不能作为安全的操作步骤。
| 旧文观点 | 2026 年分类 | 维护版处理方式 |
|---|---|---|
编辑 functions.php 或其他源文件 | 依赖上下文,而且往往与主题耦合 | 只有依赖该主题的表现层行为才放入子主题;绝不直接修改父主题或 WordPress 核心 |
| 把小修改“插件化” | 方向通常合理 | 需要在切换主题后继续生效的行为,优先放入受版本控制的小型站点专用插件 |
| 安装一个插件并粘贴代码 | 依赖上下文 | 代码片段管理器会改变存储和启用方式,却不会自动让未知代码变得兼容、安全或可回滚 |
| “Code Sinppets” | 未经核实的历史标签 | 原样保留拼写作为证据;不据此推断当前产品、版本或安装链接 |
1. 先给修改分类,再选择容器
先考虑归属,再考虑方便:
| 修改 | 首选位置 | 原因 |
|---|---|---|
| 与某个主题绑定的模板、主题资源或表现层行为 | 子主题 | 修改与可更新的父主题分离,同时明确承认它依赖该主题 |
| 切换主题后仍须存在的网站行为 | 小型站点专用插件 | 代码有明确身份、启用边界和受版本控制的文件 |
| 短期诊断实验 | 只放在本地或预发布环境,随后删除 | 调试辅助代码若长期启用,可能泄露数据、增加开销或改变行为 |
| 设置页面、数据写入、REST/AJAX 端点、定时任务或外部集成 | 有设计和测试的正式插件 | 这些功能需要授权、请求验证、生命周期、数据迁移和回滚决策 |
| WordPress 核心或父主题文件 | 永远不用作自定义位置 | 更新会覆盖修改,也会让来源和恢复更难追踪 |
对于小型、隔离的实验,如果已经核实代码片段管理器的准确版本、作用域规则、导出格式和紧急禁用步骤,可以考虑使用。本指南不假设所有管理器以同样方式存储、执行或恢复代码。
2. 首选基线:小型站点专用插件
对于网站行为,在开发检出中建立一个目录和一个 PHP 文件:
wp-content/plugins/lazyingart-site-tweaks/
└── lazyingart-site-tweaks.php
Plugin Name 文件头让 WordPress 能把该文件识别为插件。下面的例子只注册一个短代码,并有意避免数据库写入、管理员权限、远程请求和全局状态。
<?php
/**
* Plugin Name: LazyingArt Site Tweaks
* Description: Small, reviewed site-specific customizations.
* Version: 1.0.0
*/
defined( 'ABSPATH' ) || exit;
function lazyingart_1887_notice_shortcode( $attributes, $content = null ) {
$attributes = shortcode_atts(
array(
'type' => 'info',
),
(array) $attributes,
'lazyingart_notice'
);
$allowed_types = array( 'info', 'warning', 'success' );
$type = sanitize_key( $attributes['type'] );
if ( ! in_array( $type, $allowed_types, true ) ) {
$type = 'info';
}
$message = wp_kses_post( (string) $content );
return sprintf(
'<aside class="site-notice site-notice--%1$s">%2$s</aside>',
esc_attr( $type ),
$message
);
}
function lazyingart_1887_register_shortcodes() {
add_shortcode( 'lazyingart_notice', 'lazyingart_1887_notice_shortcode' );
}
add_action( 'init', 'lazyingart_1887_register_shortcodes' );
在内容中这样使用:
[lazyingart_notice type="warning"]Planned <strong>maintenance</strong> tonight.[/lazyingart_notice]
Shortcode API 要求回调返回而不是直接打印标记,本例正是如此。它规范化属性,把属性与一个很小的允许列表比较,只允许短代码内容中出现文章级安全 HTML,并在输出时转义 CSS 类值。唯一前缀可以减少命名冲突。
这个例子确实会产生生命周期成本:使用该短代码的文章依赖此插件。停用插件后,短代码文本会留在内容中。发布前要判断这种降级是否可以接受;对于长期功能,自定义区块或另一种经过设计的内容模型可能更合适。
3. 只有主题绑定行为才使用子主题
子主题把模板和表现层修改放在父主题之外,因此父主题更新不会覆盖它们。子主题的 functions.php 会在父主题文件之外额外加载,而不是替代父主题文件。把父主题的函数整体复制过去,很可能产生重复声明和致命错误。
修改依赖当前主题的模板、钩子、CSS 或设计约定时使用子主题;切换主题后仍须存在的行为则使用插件。无论放在哪里,都应把行为接到有文档的 action 和 filter 上,而不是修改 WordPress 核心。
区块主题和经典主题不会暴露完全相同的模板与样式接口。假设经典 PHP 模板、特定 HTML 选择器或主题专用钩子的片段是与主题耦合的,父主题每次变化后都必须重新测试。
4. 复制教程片段前先审计
检查完整回调及其执行上下文,不能只看似乎相关的那一行。
- 来源:记录来源 URL、获取日期、作者、已知许可证、目标 WordPress/PHP 版本和本地评审者。
- 钩子约定:在官方参考中确认 action 或 filter、参数、返回值、时序,以及它是否会在前台、后台、REST、AJAX、cron 或 CLI 请求中运行。
- 输入边界:列出每个短代码属性、请求值、选项、文章字段、远程响应和文件值。优先拒绝无效值;根据预定类型清理接受的输入。
- 输出边界:尽可能晚地针对准确上下文转义——HTML 文本、属性、URL、JavaScript 和允许的 HTML 不能互换。
- 权限:更改状态前检查适当的 capability。nonce 有助于确认请求意图、防止请求伪造;WordPress 明确说明 nonce 不是身份认证或权限授权。
- 名称与依赖:使用唯一前缀或命名空间,并记录所需插件、主题、PHP 扩展、选项和钩子优先级。
- 副作用:找出写入、外部请求、邮件、定时事件、缓存失效、隐私影响和最坏运行时间。
常见教程模式应这样处理:
| 模式 | 标签 | 决策 |
|---|---|---|
| 使用当前 Code Reference 中标为 deprecated 或已不存在的函数或钩子 | 过时 | 在弄清官方替代方案和迁移行为之前不要启用 |
| 依赖父主题 DOM、模板名或自定义钩子 | 与主题耦合 | 放入子主题,记录父主题版本,更新后重新测试 |
把 $_GET、$_POST、选项数据或远程响应直接打印进 HTML | 不安全 | 拒绝;使用验证/清理和与上下文对应的转义重新设计 |
| 没有 capability 和意图检查就修改选项、用户、文件或数据库行 | 不安全 | 拒绝;加入授权、适当的 nonce、验证和经过审计的 WordPress API |
| 宽泛回调运行时不检查请求或查询上下文 | 依赖上下文 | 添加明确的保护条件,并按需测试前台、后台、REST、AJAX、cron 和 CLI 路径 |
| 全局关闭更新、REST 访问、XML-RPC、认证行为或安全响应头 | 依赖上下文且涉及安全 | 必须提供威胁模型、兼容性评审、监控和回滚计划 |
“它修好了我的页面”不能证明一个片段在不同请求、角色、主题、插件或未来更新中仍然安全。
5. 以可复现方式预发布、语法检查、测试和部署
WordPress 调试手册要求修改前使用预发布环境或适当的备份。有用的备份同时覆盖文件和数据库,有已知位置和保留策略,而且已经在测试环境中恢复过,而不只是创建出来。
把站点插件目录纳入版本控制。记录预期的 WordPress 和 PHP 版本、当前主题、相关插件版本和准确测试用例。启用之前:
php -l wp-content/plugins/lazyingart-site-tweaks/lazyingart-site-tweaks.php
wp plugin activate lazyingart-site-tweaks
只在本地开发或预发布环境启用 WP_DEBUG 和日志,并隐藏页面上的错误输出。每次测试后检查日志,不要公开日志;其中可能包含路径、查询或其他运维数据。
在可丢弃的预发布副本上,可以用 WP-CLI 复现检查示例输出:
wp eval 'echo do_shortcode( "[lazyingart_notice type="warning"]Planned <strong>maintenance</strong> tonight.[/lazyingart_notice]" );'
预期输出:
<aside class="site-notice site-notice--warning">Planned <strong>maintenance</strong> tonight.</aside>
还要测试无效的 type、空内容、允许与拒绝的标记、未登录与高权限会话、相关模板和有代表性的缓存配置。命令行结果不能替代浏览器、可访问性、集成和授权测试。
6. 把回滚纳入启用流程
对于没有迁移的纯文件站点插件,第一步回滚是停用:
wp plugin deactivate lazyingart-site-tweaks
如果插件本身导致 WP-CLI 无法正常启动,可以使用全局 skip 选项,在停用时不加载该插件:
wp --skip-plugins=lazyingart-site-tweaks plugin deactivate lazyingart-site-tweaks
随后部署最后一个已知良好的文件版本,重新执行语法检查和预发布测试;只有查明原因后才再次启用。保存用于诊断的版本和错误证据之前,不要删除故障代码。
停用并不等于数据回滚。如果片段会写入选项、元数据、用户、文章、数据表、文件、队列或远程状态,部署前必须定义正向与反向迁移、备份恢复条件、负责人和可接受的维护窗口。
7. 使用可复现测试矩阵
| 用例 | 预期证据 |
|---|---|
| 插件未启用 | 网站能加载;已知依赖行为(例如显示短代码原文)有明确记录 |
| 插件启用 | 没有 PHP fatal、warning、notice 或意外数据库写入 |
| 有效短代码 | 出现准确的允许类名和允许标记 |
| 无效属性 | 值回退到 info;不会变成原始 HTML 或任意类名 |
| 不可信标记 | wp_kses_post() 删除不允许的标记 |
| 未登录和高权限请求 | 除非有明确角色设计,否则输出一致 |
| 后台、REST、AJAX、cron 和 CLI | 在适用上下文中没有意外输出或副作用 |
| 切换主题或更新父主题 | 站点插件行为仍存在;表现层依赖已有记录并经过检查 |
| 回滚演练 | 操作者能在约定时间内停用并恢复已知良好版本 |
把命令、预期结果、WordPress/PHP 版本和被测版本与修改一起保存。只有“手工检查过”,却没有用例与预期结果,不是可复现证据。
紧凑的决策与发布清单
- [ ] 修改已归类为主题表现、网站行为、诊断代码或较大型插件功能。
- [ ] 没有编辑 WordPress 核心或父主题文件。
- [ ] 来源、版本、钩子约定、依赖和评审者已有记录。
- [ ] 输入经过验证或清理;输出针对准确上下文转义。
- [ ] 状态更改会检查 capability、意图和失败路径。
- [ ] 函数/类名称使用唯一前缀或命名空间。
- [ ] 文件和数据库已经备份;恢复已在非生产基础设施演练。
- [ ] PHP 语法检查、预发布检查、日志、浏览器路径和适用请求上下文通过。
- [ ] 启用与回滚命令已写明并测试。
- [ ] 代码、测试证据和已知良好版本已纳入版本控制。
---
2019 年原始导出(来源档案)
档案边界:以下代码块内是
out/posts/2019-04-23-use-code-snippets-to-modify-your-wordpress-site-1887/index.md中 post 1887 的完整正文,导出内容日期为 2019 年 4 月 23 日。措辞、拼写、大小写和说法均未改变,仅规范化行尾空白。这是来源档案,不是当前推荐。
Sometimes, I found some tutorials for some wordpress problem. And it often ask you to change your functions.php or other source code.
I was wondering if there exists a method that I can pluginize those code. Actually, one can simply install a plugin to implement those modifications.
Code Sinppets
---
