搜索全站
插件 11 分钟阅读

用代码替代 WordPress 插件的 10 个场景:一份能直接用的片段集

清 redirect、禁 Emoji、改邮件发信、关修订版本……很多功能其实几行代码就够了。本文整理 10 个可用代码替代插件的真实场景,附可直接粘贴的片段与适用边界说明。

U
UFO_PF 2016-03-29 · 阅读 11 分钟
用代 插件
阅读提示
本文约 4,210 字,预计阅读 11 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:为了一个小功能装一个插件,值不值

WordPress 插件生态的好处是“什么都有”,坏处也是“什么都有”——为了隐藏后台某个菜单、禁用 Emoji、发一封 SMTP 邮件,你可能已经装了三四个插件。每个插件都会带来额外的更新维护周期、潜在的安全面和一点点加载开销。

但这里有个必须说清的前提:代码替代插件不等于所有插件都该被替代。涉及数据表设计、第三方 API 交互、复杂 UI 的功能(表单构建器、备份、缓存规则、多语言),自己写的十几行代码往往是灾难的开始。真正适合用代码替代的,是那些 WordPress 核心已经提供了明确钩子或常量、逻辑不过十几行的场景(去掉一个插件后如何收敛它的 option 与 cron 残留,见插件停用卸载后的残留数据清理)。

本文挑出的 10 个场景都符合这个标准:原生钩子、逻辑简单、可逆性强。所有片段建议统一放在子主题的 functions.php 里,或者更推荐放在一个功能型小插件 / Code Snippets 这类管理界面里,避免主题切换后功能丢失。

原理分析:什么样的功能才适合“去插件化”

判断标准其实只有两条:命令式还是声明式,以及是否需要持久化数据。

声明式的配置型需求——比如“关闭某个功能模块”“把某个字符串替换掉”——核心早就留好了 filter 或常量(WP_POST_REVISIONS、AUTOSAVE_INTERVAL、DISABLE_WP_CRON),这类最适合代码化。命令式的、要记录数据的需求——比如表单提交记录、邮件发送日志——需要建表、需要考虑并发和清理,交给插件更稳。

还有一个常被忽略的点:替代码的长期成本是“你自己维护”。WordPress 每年三个大版本,钩子行为可能会有微调。代码片段写进站点后,最好在注释里注明用途和添加日期,方便日后排查。

保姆级实操

场景 1–2:关闭修订版本与自动保存间隔

// wp-config.php —— 放在 ABSPATH 定义之后
define( 'WP_POST_REVISIONS', 5 );   // 每篇文章最多保留 5 个修订版;设为 false 则完全关闭
define( 'AUTOSAVE_INTERVAL', 120 ); // 自动保存间隔改为 120 秒

场景 3:彻底移除 Emoji 相关资源

add_action( 'init', function () {
    remove_action( 'wp_head', 'print_emoji_detection_script', 7 );
    remove_action( 'admin_print_scripts', 'print_emoji_detection_script' );
    remove_action( 'wp_print_styles', 'print_emoji_styles' );
    remove_action( 'admin_print_styles', 'print_emoji_styles' );
    remove_filter( 'the_content_feed', 'wp_staticize_emoji' );
    remove_filter( 'comment_text_rss', 'wp_staticize_emoji' );
    remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
} );

场景 4:关闭 XML-RPC(不需要远程发布/App 时)

add_filter( 'xmlrpc_enabled', '__return_false' );

注意:Jetpack、WordPress 官方 App、部分第三方发布工具依赖 XML-RPC,确认用不到再关。

场景 5:隐藏登录页的具体错误提示

add_filter( 'login_errors', function () {
    return '用户名或密码不正确,请重试。';
} );

场景 6:通过 SMTP 发信(phpmailer_init 钩子)

add_action( 'phpmailer_init', function ( $phpmailer ) {
    $phpmailer->isSMTP();
    $phpmailer->Host       = 'smtp.example.com';
    $phpmailer->SMTPAuth   = true;
    $phpmailer->Port       = 587;
    $phpmailer->Username   = ''; // 留空由服务器环境变量提供
    $phpmailer->Password   = ''; // 不要把凭据硬编码进代码库
    $phpmailer->SMTPSecure = 'tls';
    $phpmailer->From       = 'no-reply@example.com';
    $phpmailer->FromName   = '站点名称';
} );

场景 7:给媒体库允许上传 SVG 之外的常用格式

add_filter( 'upload_mimes', function ( $mimes ) {
    $mimes['webp'] = 'image/webp';
    $mimes['json'] = 'application/json';
    return $mimes;
} );

场景 8:限制非管理员访问后台

add_action( 'admin_init', function () {
    if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
        return;
    }
    if ( current_user_can( 'subscriber' ) ) {
        wp_safe_redirect( home_url() );
        exit;
    }
} );

场景 9:让摘要结尾更自然

add_filter( 'excerpt_more', function () {
    return '…';
} );
add_filter( 'excerpt_length', function () {
    return 80;
} );

场景 10:移除前台加载的 dashicons/多余样式

add_action( 'wp_enqueue_scripts', function () {
    if ( ! is_user_logged_in() ) {
        wp_dequeue_style( 'dashicons' );
    }
} );

验证代码是否生效

# 用 evaluate 执行一次性检查,确认钩子已挂载
wp eval "echo has_filter('xmlrpc_enabled') ? 'xmlrpc 已关闭' : '未生效'; echo PHP_EOL;"

# 查看当前已定义的常量的实际值
wp eval "echo defined('WP_POST_REVISIONS') ? WP_POST_REVISIONS : '未定义'; echo PHP_EOL;"

清理站点外的调用:

# 检查主题是否还在引用已移除的能力(以 Emoji 为例)
grep -rn "print_emoji\|wp_staticize_emoji" wp-content/themes/ --include=*.php

常见踩坑

  1. 把片段写进父主题 functions.php。主题一更新就没了。用子主题,或者做成独立小插件。
  2. 在 phpmailer_init 里硬编码账号密码。代码进 Git 仓库等于凭据泄露。用环境变量或主机提供的 SMTP 免密通道(很多云主机自带邮件 relay)。
  3. 关了 XML-RPC 才发现 Jetpack 连不上。Jetpack 的早期连接方式依赖 xmlrpc.php,现代版本改用 REST,但仍有模块依赖。
  4. excerpt_length 对手动摘要无效。这个 filter 只作用于自动生成的摘要,编辑手动填写的“摘要”框内容不受影响。
  5. 多个片段重复注册同名匿名函数。匿名函数无法用 remove_action 精确移除,日后调试成本高。生产环境建议用具名函数并加 function_exists 保护。
  6. upload_mimes 放开 json 带来的风险。JSON 文件上传后若被 Web 服务器当作可执行内容处理存在风险,非必要不放行。
  7. 案例:某站点把 40 多个功能片段堆在一个 mu-plugin 里,某天后台白屏,日志显示 Cannot redeclare my_custom_login_logo()。排查半天才发现是主机提供的迁移脚本在新站点保留了旧 mu-plugin,而主题升级后又在 functions.php 里加了同名函数。修复方式是把所有片段改成 if ( ! function_exists( 'xxx' ) ) { ... } 包裹的具名函数,并在同一文件里用 add_action 统一注册。

总结

去插件化的收益是双重的:少了 N 个更新周期和安全面,也少了 N 份许可证兼容性的麻烦;代价是把维护责任转移到了你自己身上。

判断该不该写代码,就问三个问题(轻量选型的整体思路见轻量插件与万能插件的取舍方法):WordPress 核心有没有现成的钩子/常量?逻辑是不是二十行以内?这件事会不会产生需要留存的数据?三个答案都是“是”,那就动手;任何一个“否”,老实装插件。另外记得给每段代码写清楚注释和日期——三个月后的你会感谢现在的你。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。