
本文详解如何在 wordpress 插件中安全、规范地使用 ajax 提交表单并持久化数据到自定义数据库表,规避因直接引入核心文件导致的 json 解析错误、wpdb 未初始化及跨域/路径问题。
本文详解如何在 wordpress 插件中安全、规范地使用 ajax 提交表单并持久化数据到自定义数据库表,规避因直接引入核心文件导致的 json 解析错误、wpdb 未初始化及跨域/路径问题。
在 WordPress 插件开发中,绕过 WordPress 标准 AJAX 机制(如 admin-ajax.php)而直接调用独立 PHP 文件(如 sendmail.php),是引发「SyntaxError: Unexpected token
✅ 正确做法:使用 WordPress 原生 AJAX 流程
WordPress 提供了健壮、安全且可扩展的 AJAX 机制,所有插件应严格遵循此模式,禁止手动 require wp-db.php 或其他核心文件(如你代码中的 require_once('../../../../../wp-includes/wp-db.php'))。该写法不仅路径脆弱、易失效,更会导致 WordPress 环境(如 hooks、constants、authentication)完全缺失,使 $wpdb->insert() 内部调用失败,并可能输出 PHP 警告/错误 HTML,污染 JSON 输出。
1. 前端:注册并本地化 AJAX URL
在插件主文件或 functions.php 中,使用 wp_enqueue_script 和 wp_localize_script 安全传递 admin-ajax.php 地址:
// 在插件初始化钩子中(如 'plugins_loaded' 或 'wp_enqueue_scripts')
function verde_enqueue_subscribe_script() {
wp_enqueue_script('verde-subscribe', plugin_dir_url(__FILE__) . 'js/subscribe.js', ['jquery'], '1.0', true);
wp_localize_script('verde-subscribe', 'verde_ajax', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('verde_subscribe_nonce')
]);
}
add_action('wp_enqueue_scripts', 'verde_enqueue_subscribe_script');
2. 前端 JS:使用标准 AJAX 请求
更新你的 subscribe.js(注意选择器修正为 .subscribe-database,与 HTML class 一致):
需要创建、读取、编辑或处理 Word 文档(.docx / .dotx)时使用。触发词:'Word'、'word 文档'、'.docx'、'生成报告'、'制作合同/简历/方案/说明书'、'提取 word 内容'、'在文档里查找替换'、'给文档加页眉页脚/目录/表格'。也用于把任意内容排版成一份正式的 Word 文件。不要用它处理 PDF、Excel 或无关编程任务。中文创作场景尤其适合:小说大纲稿、投稿文档、合同、简历、工作总结。
jQuery(document).ready(function($) {
$('.subscribe-database').on('submit', function(e) {
e.preventDefault();
const formData = $(this).serialize();
const url = verde_ajax.ajax_url;
$.ajax({
type: 'POST',
url: url,
data: {
action: 'verde_save_email', // 必须匹配 PHP 中的 hook 名称
nonce: verde_ajax.nonce,
...JSON.parse('{"' + decodeURI(formData).replace(/"/g, '\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}') // 或直接用 new FormData(this)
},
dataType: 'json',
success: function(response) {
if (response.success) {
console.log('Success:', response.data.message);
// 可在此处清空表单、显示成功提示等
} else {
console.error('Error:', response.data.message);
}
},
error: function(xhr, status, error) {
console.error('AJAX Error:', status, error);
}
});
});
});
? 提示:更推荐使用 FormData 处理表单(兼容文件上传),但需确保 sendmail.php 已被完全移除——我们不再需要它。
3. 后端 PHP:在插件中注册 AJAX 处理函数
在插件主文件中添加以下逻辑(务必区分前台/后台权限):
// 前台用户可提交(无需登录)
add_action('wp_ajax_nopriv_verde_save_email', 'verde_handle_save_email');
add_action('wp_ajax_verde_save_email', 'verde_handle_save_email'); // 登录用户也支持
function verde_handle_save_email() {
// 验证 nonce(防 CSRF)
if (!isset($_POST['nonce']) || !wp_verify_nonce($_POST['nonce'], 'verde_subscribe_nonce')) {
wp_send_json_error(['message' => __('Invalid request.', 'verde')]);
}
// 获取并过滤输入
$email = sanitize_email(trim($_POST['email'] ?? ''));
$language = sanitize_text_field($_POST['language'] ?? 'english');
// 邮箱验证(使用 WordPress 内置函数更可靠)
if (empty($email) || !is_email($email)) {
$messages = [
'english' => 'Insert a valid email address',
'spanish' => 'Escribe un email válido',
'french' => 'Insérez une adresse e-mail valide',
'german' => 'Legen Sie eine gültige E-Mail-Adresse ein',
'italian' => 'Inserire un indirizzo email valido',
'portuguese'=> 'Insira um email válido'
];
$error_msg = $messages[$language] ?? $messages['english'];
wp_send_json_error(['message' => $error_msg]);
}
global $wpdb;
$table_name = $wpdb->prefix . 'verde_emails';
// 创建表(仅首次运行,生产环境建议用 dbDelta 在插件激活时执行)
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
option_email varchar(100) NOT NULL,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 插入数据
$result = $wpdb->insert($table_name, [
'option_email' => $email
]);
if (false === $result) {
wp_send_json_error(['message' => __('Database error. Please try again.', 'verde')]);
}
$success_msgs = [
'english' => 'Thanks for your subscription!',
'spanish' => '¡Gracias por tu suscripción!',
'french' => 'Merci pour votre abonnement!',
'german' => 'Vielen Dank für Ihr Abonnement!',
'italian' => 'Grazie per il vostro abbonamento!',
'portuguese'=> 'Obrigado pela sua inscrição!'
];
$success_msg = $success_msgs[$language] ?? $success_msgs['english'];
wp_send_json_success(['message' => $success_msg]);
}
⚠️ 关键注意事项
- 彻底删除 sendmail.php:该文件脱离 WordPress 环境,无法访问 $wpdb、wp_die()、wp_send_json_* 等核心功能,是错误根源。
- 永远使用 wp_send_json_success() / wp_send_json_error():它们会自动设置 Content-Type: application/json 并 exit(),杜绝意外输出。
- 必须校验 Nonce:防止跨站请求伪造(CSRF),这是 WordPress AJAX 的强制安全要求。
- 不要硬编码数据库前缀:使用 $wpdb->prefix,并在 SQL 操作中始终引用 $wpdb 对象。
- 前端 JS 中避免 return false + .submit() 绑定冲突:改用 e.preventDefault() 更清晰可靠。
遵循以上结构,你的表单将真正融入 WordPress 生态,实现安全、稳定、可维护的数据提交与存储。










