搜索全站
插件 13 分钟阅读

从零写一个 WordPress 插件(Hello World 完整步骤)

不用框架、不用脚手架,从新建目录到后台启用,一步步写出第一个 WordPress 插件。本文包含完整可运行代码、激活验证、短代码输出与安全转义,以及常见的第一步失败原因。

U
UFO_PF 2018-03-14 · 阅读 13 分钟
从零 插件
阅读提示
本文约 4,948 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:第一个插件应该小到什么程度

学 WordPress 插件开发最常见的障碍不是概念难,而是起步太重。很多人一开始就去看大型插件的源码,看到几十个目录、一堆类和接口,直接劝退。

实际上一个能被 WordPress 识别、能在前台输出内容的插件,只需要一个 PHP 文件、十几行代码。剩下的所有复杂度——设置页面、数据库表、REST 接口、后台列表——都是在这十几行的基础上长出来的。先把最小闭环跑通,你会对「插件到底是什么」有一个具体而非抽象的理解。

本文做的就是这个最小闭环:创建一个目录、写一个主文件、加一个短代码、在文章里输出一段文本、从后台启用、验证生效。全程不需要任何构建工具,一个文本编辑器和一个能跑 WordPress 的环境就够。

原理分析:一个插件跑起来要经过哪几步

理解流程比记住代码更重要。从文件出现到内容输出,一共五步:

第一步:WordPress 扫描目录。 后台进入插件页(或执行 wp plugin list)时,WordPress 会用 get_plugins() 扫描 wp-content/plugins/ 下的 PHP 文件,读取头部注释,生成插件清单。此时插件处于「已发现但未激活」状态。

第二步:激活。 你点「启用」,WordPress 把插件的主文件路径写进 wp_options 表的 active_plugins 数组。这是一个序列化的数组,顺序即加载顺序。

第三步:加载。 之后的每个请求,WordPress 读取 active_plugins,依次 include 每个主文件。注意是每个请求都 include 一次,前台、后台、AJAX、REST 请求全部如此(可通过条件判断跳过)。

第四步:注册。 主文件被执行时,你的代码调用 add_action() / add_shortcode() 等函数,把回调注册进全局的钩子数组 $wp_filter。这一步只是「登记」,还没有真正执行。

第五步:触发。 WordPress 执行到对应的时机(比如渲染文章内容时执行 the_content 过滤器),从 $wp_filter 里找出已注册的回调并执行。你的代码此时才真正运行,输出内容。

理解了这个流程,就能明白插件开发里最重要的两个习惯:主文件只做注册,不做重活;任何耗时逻辑都要判断当前请求是不是真的需要它。

另外要注意短代码的工作方式:短代码 [hello_world] 写在文章正文里,WordPress 在输出 the_content 时会用正则扫描方括号,把匹配到的名字交给 add_shortcode() 注册的回调处理,回调的返回值替换掉原文里的短代码。所以短代码回调必须返回值,不能直接 echo。这是新手最常踩的坑——直接 echo 的话,内容会出现在页面最顶部而不是短代码所在位置。

保姆级实操

第一步:创建插件目录与主文件

cd wp-content/plugins
mkdir mmf-hello
cd mmf-hello

目录名用小写字母加连字符,加上你自己的前缀避免与他人冲突。主文件名与目录名保持一致。

第二步:写主文件

<?php
/**
 * Plugin Name:       MMF Hello World
 * Description:       第一个 WordPress 插件:注册一个短代码并输出问候语。
 * Version:           1.0.0
 * Requires at least: 6.0
 * Requires PHP:      7.4
 * Author:            mimangfei
 * License:           GPL-2.0-or-later
 * License URI:       https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain:       mmf-hello
 */

defined( 'ABSPATH' ) || exit;

/**
 * 短代码回调:返回内容,不要 echo。
 *
 * 用法:[mmf_hello name="张三"]
 */
function mmf_hello_shortcode( $atts ) {

    $atts = shortcode_atts(
        array(
            'name' => '世界',
            'size' => '16',
        ),
        $atts,
        'mmf_hello'
    );

    $name = sanitize_text_field( $atts['name'] );
    $size = absint( $atts['size'] );

    if ( $size < 8 ) {
        $size = 8;
    }
    if ( $size > 72 ) {
        $size = 72;
    }

    return sprintf(
        '<p class="mmf-hello" style="font-size:%dpx">%s</p>',
        $size,
        sprintf(
            /* translators: %s 是访客的名字 */
            esc_html__( '你好,%s!这是你的第一个插件输出的内容。', 'mmf-hello' ),
            esc_html( $name )
        )
    );
}
add_shortcode( 'mmf_hello', 'mmf_hello_shortcode' );

这段代码里有三个值得注意的点:

  • shortcode_atts() 把用户传入的属性与默认值合并,同时过滤掉未声明的属性;
  • sanitize_text_field() 与 absint() 做输入净化,这是插件安全的底线(相关函数的完整对照见 数据验证与转义函数);
  • esc_html() 与 esc_html__() 做输出转义,避免用户传入的名字里带 HTML 造成 XSS。

第三步:验证语法

php -l wp-content/plugins/mmf-hello/mmf-hello.php

输出 No syntax errors detected 才继续。这一步能拦住绝大多数低级错误。

第四步:从后台或命令行启用

# 确认 WordPress 已识别到插件
wp plugin list --status=inactive

# 启用
wp plugin activate mmf-hello

# 确认状态
wp plugin list --status=active --fields=name,version,status

也可以在后台「插件 → 已安装插件」里找到「MMF Hello World」点启用。

第五步:在文章里使用并验证

新建一篇文章,正文写入:

[mmf_hello name="李四" size="20"]

保存后访问前台,应该看到一句带样式的问候语。如果看到的是方括号原文,说明插件没启用或短代码名写错。

第六步:加一个启用时的初始化动作

真实插件通常需要在启用时写默认配置。用 register_activation_hook():

register_activation_hook( __FILE__, 'mmf_hello_activate' );

function mmf_hello_activate() {
    if ( ! get_option( 'mmf_hello_options' ) ) {
        add_option(
            'mmf_hello_options',
            array(
                'default_name' => '世界',
                'default_size' => 16,
            )
        );
    }
    // 刷新重写规则,若插件注册了自定义文章类型则必须做
    flush_rewrite_rules();
}

register_activation_hook() 的第一个参数必须是插件主文件的路径,因此传 __FILE__。它在启用时只执行一次。

第七步:加一个后台提示,确认插件在工作

调试阶段最常用的手段:

add_action( 'admin_notices', function () {
    if ( ! current_user_can( 'manage_options' ) ) {
        return;
    }
    printf(
        '<div class="notice notice-success"><p>%s</p></div>',
        esc_html__( 'MMF Hello World 插件已启用。', 'mmf-hello' )
    );
} );

第八步:停用与删除

wp plugin deactivate mmf-hello
wp plugin delete mmf-hello

删除会触发 uninstall.php(如果存在)。本例还没有,实际项目里应该补上,规范写法见 uninstall.php 清理数据。

常见踩坑

  1. 短代码回调里用 echo 而不是 return:内容会跑到页面顶部。短代码必须返回字符串。

  2. 函数命名没有前缀:function hello() 这种名字极容易与其他插件冲突,触发 Cannot redeclare function。所有全局函数、类、常量都要加你的前缀。

  3. 忘记 defined( 'ABSPATH' ) || exit;:意味着这个文件可以被直接通过 URL 访问,是个信息泄露点。

  4. 不转义输出:用户传 name="<script>alert(1)</script>" 就会被原样输出。

  5. 在启用钩子里直接 echo:激活钩子执行时会发生重定向,echo 的内容会导致 headers already sent 错误。

  6. 案例: 一个新手把插件主文件保存成了 UTF-8 with BOM,PHP 能跑,但 WordPress 读取头部时把 BOM 当成了文件开头,导致 Plugin Name 解析不到,后台插件列表里永远看不到它。排查了一整天才发现是编辑器的编码设置问题。教训是:插件不被识别时,第一件事是检查文件编码与头部注释格式,而不是怀疑代码逻辑。

  7. 把整个插件写在一个文件里越写越长:超过 300 行就该拆到 includes/ 目录。

总结

一个插件的最小闭环是:目录 → 主文件头部 → 注册钩子或短代码 → 激活 → 验证输出。五步走通,剩下的都是在这之上加东西。

必须养成四个习惯:主文件开头加 ABSPATH 检查;所有全局标识符加前缀;输入用 sanitize_*、输出用 esc_*;短代码回调 return 不 echo。

下一步的学习路径:想让插件能被配置,看 创建自定义设置页面;想真正理解钩子机制,看 add_action 与 add_filter 区别——那是插件开发的地基。

U
UFO_PF作者

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

留下你的想法

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