接入文档 / 实践

在 WordPress 中接入

用短代码显示表单,在 PHP 中校验。一个可以下载的小插件示例。

先接一张独立表单

下面是一个最小 WordPress 插件示例,提供 [cap_contact] 短代码。它不会自动保护登录、注册、评论,也不替代其他表单插件的提交钩子。

1. 配置公开 key 和私密 secret

在控制台加入 WordPress 页面实际使用的域名。在服务器的 wp-config.php 中配置下面两项,放在停止编辑的提示之前。不要把 secret 写入主题模板、网页脚本或浏览器公开的环境变量。

wp-config.php
define('CAP_SITEKEY', 'YOUR_SITEKEY');
define('CAP_SECRET', 'YOUR_SERVER_SECRET');

2. 安装示例并插入短代码

下载文件,放入 wp-content/plugins/cap-contact/cap-contact.php,在插件列表启用。编辑页面,加入短代码区块 [cap_contact]。

cap-contact.php下载文件 ↓
<?php
/**
 * Plugin Name: cap Contact Example
 * Description: A minimal shortcode form with server-side cap verification.
 */
if (!defined('ABSPATH')) { exit; }

add_shortcode('cap_contact', function () {
    if (!defined('CAP_SITEKEY')) { return '<p>请先配置 CAP_SITEKEY。</p>'; }
    wp_enqueue_script('cap-widget', 'https://cap.bug.im/v1.js', array(), null, true);
    ob_start(); ?>
    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
      <input type="hidden" name="action" value="cap_contact">
      <?php wp_nonce_field('cap_contact', 'cap_nonce'); ?>
      <label>留言 <textarea name="message" maxlength="2000" required></textarea></label>
      <div class="cap-captcha" data-sitekey="<?php echo esc_attr(CAP_SITEKEY); ?>"></div>
      <button type="submit">提交</button>
    </form>
    <?php return ob_get_clean();
});

add_action('admin_post_cap_contact', 'cap_contact_handle');
add_action('admin_post_nopriv_cap_contact', 'cap_contact_handle');
function cap_contact_handle() {
    if ($_SERVER['REQUEST_METHOD'] !== 'POST') { wp_die('仅接受 POST。', '', array('response' => 405)); }
    $nonce = isset($_POST['cap_nonce']) && is_string($_POST['cap_nonce']) ? sanitize_text_field(wp_unslash($_POST['cap_nonce'])) : '';
    if (!wp_verify_nonce($nonce, 'cap_contact')) { wp_die('表单已失效,请刷新。', '', array('response' => 403)); }
    if (!defined('CAP_SECRET')) { wp_die('服务端尚未配置。', '', array('response' => 503)); }
    $token = isset($_POST['cap-response']) && is_string($_POST['cap-response']) ? wp_unslash($_POST['cap-response']) : '';
    $message = isset($_POST['message']) && is_string($_POST['message']) ? sanitize_textarea_field(wp_unslash($_POST['message'])) : '';
    if (!$token || !$message || strlen($message) > 8000 || strlen($token) > 16384) { wp_die('请填写留言并完成验证。', '', array('response' => 400)); }
    $check = wp_remote_post('https://cap.bug.im/v1/siteverify', array(
      'timeout' => 8,
      'headers' => array('Content-Type' => 'application/json'),
      'body' => wp_json_encode(array('secret' => CAP_SECRET, 'response' => $token)),
    ));
    if (is_wp_error($check) || wp_remote_retrieve_response_code($check) !== 200) { wp_die('暂时无法校验,请重新验证。', '', array('response' => 503)); }
    $result = json_decode(wp_remote_retrieve_body($check), true);
    if (!is_array($result) || ($result['success'] ?? false) !== true || !empty($result['degraded'])) { wp_die('验证未通过,请重新验证。', '', array('response' => 403)); }
    // Persist the sanitized message here, before displaying success.
    wp_die('验证通过。此示例未保存留言。', '', array('response' => 200));
}

3. 在真正处理业务前校验

示例同时处理登录用户和未登录访客的提交,先检查 nonce 与输入,再由服务器请求验证接口。网络错误、失败结果或降级放行都会停止处理。成功响应只表示验证通过,示例不会发送邮件或保存留言。

使用页面缓存时,确认 nonce 不会因长时间缓存而失效。WordPress nonce 不能代替身份认证或限流。若要保护评论或现成表单插件,需要在它们各自的服务端提交钩子中校验,不能只插入控件。

相关接口:登录用户的提交钩子、访客提交钩子、wp_remote_post。

← 返回接入文档 · 体验验证