从零到可用:用 PHP 开发一个 WordPress 插件(含示例代码)

从零到可用:用 PHP 开发一个 WordPress 插件(含示例代码)

很多人第一次写 WP 插件,容易陷入两个误区:要么一上来就做“很大”的功能,结果代码越写越乱;要么只会把代码丢进 functions.php,后期换主题就全部丢失。更稳的做法是:先写一个“最小可用插件骨架”,把常用的钩子、菜单、设置页、短代码、AJAX、安全校验都串起来,再在这个骨架上扩展业务逻辑。

这篇文章我用一个小插件为例:后台提供一个设置项(保存一段文本),前台通过短代码输出,同时提供 AJAX 接口返回当前配置。重点不是功能,而是“开发思路 + 标准结构 + 安全习惯”。


1)插件目录与入口文件

wp-content/plugins/ 下新建目录:

my-wp-toolkit/
  my-wp-toolkit.php

入口文件 my-wp-toolkit.php 内容如下(可直接复制运行):

 'string',
                'sanitize_callback' => 'sanitize_text_field',
                'default' => ''
            ]
        );
    }

    public function render_settings_page() {
        if (!current_user_can('manage_options')) return;

        $val = get_option(self::OPTION_KEY, '');
        ?>
        <div class="wrap">
            <h1>My WP Toolkit 设置</h1>
            <form method="post" action="options.php">

                <table class="form-table" role="presentation">
                    <tr>
                        <th scope="row"><label for="mwt_message">前台展示文本</label></th>
                        <td>
                            <input type="text" id="mwt_message" name="<?php echo esc_attr(self::OPTION_KEY); ?>"
                                   value="<?php echo esc_attr($val); ?>" class="regular-text" />
                            &lt;p class="description"&gt;短代码:<code>[mwt_message]</code>&lt;/p&gt;
                        &lt;/td&gt;
                    &lt;/tr&gt;
                &lt;/table&gt;

            &lt;/form&gt;

            &lt;hr /&gt;
            &lt;h2&gt;AJAX 测试(返回 JSON)&lt;/h2&gt;
            &lt;p&gt;
                &lt;button class="button" id="mwt_ajax_btn"&gt;点击获取&lt;/button&gt;
                <code></code>
            &lt;/p&gt;
        &lt;/div&gt;

        &lt;script&gt;
        (function(){
            const btn = document.getElementById('mwt_ajax_btn');
            const out = document.getElementById('mwt_ajax_out');
            if(!btn) return;

            btn.addEventListener('click', async function(){
                out.textContent = 'loading...';
                const form = new FormData();
                form.append('action', 'mwt_get_message');
                form.append('_ajax_nonce', '');

                const res = await fetch('', {
                    method: 'POST',
                    body: form,
                    credentials: 'same-origin'
                });
                const json = await res.json();
                out.textContent = JSON.stringify(json);
            });
        })();
        &lt;/script&gt;
        '. esc_html($msg) .'&lt;/div&gt;';
    }

    public function ajax_get_message() {
        // 1) nonce 校验,防 CSRF
        check_ajax_referer('mwt_nonce');

        // 2) 返回 JSON(不要 echo html)
        $msg = get_option(self::OPTION_KEY, '');
        wp_send_json_success([
            'message' =&gt; $msg,
            'time'    =&gt; current_time('mysql')
        ]);
    }
}

new My_WP_Toolkit();


2)为什么要用 register_setting(而不是自己 update_option)

很多新手会在表单提交时自己 update_option(),看似简单,但会错过 WP 提供的“统一安全机制”:

  • 自动 nonce(settings_fields()
  • 统一的 sanitize 回调
  • 可控的 option 类型与默认值
  • 更清晰的权限边界(配合 manage_options

你会发现,当插件规模变大时,用 WP 的标准设置 API 能显著减少 bug。


3)安全要点:三件事必须形成肌肉记忆

  1. 防直连if (!defined('ABSPATH')) exit;
  2. 权限判断:后台页必须 current_user_can()
  3. 输出转义esc_html / esc_attr / esc_url 另外,AJAX 一定要做 check_ajax_referer(),否则容易被跨站请求滥用。

4)如何使用这个插件

  • 后台:设置 → My WP Toolkit,填入文本并保存
  • 前台任意页面插入短代码:[mwt_message]
  • 后台页里有 AJAX 测试按钮,会返回 JSON 数据

5)下一步怎么扩展成“真实插件”

这个骨架可以很自然地扩展:

  • 把功能拆成 includes/ 目录:Admin.php / Frontend.php / Ajax.php
  • 为 option 增加更多字段(checkbox、textarea、select)
  • 增加自定义表(dbDelta)存日志或数据
  • 用 REST API 替换 admin-ajax(更现代、易前后端分离)
  • 加入 WP Cron 定时任务做队列处理

评论 0