求助:基于WordPress Contact Form 7实现邮件确认式表单提交流程
嘿,这个需求我帮很多人解决过——Contact Form 7本身确实没自带这种「用户确认后再发管理员」的双重验证功能,但咱们用几个钩子加自定义代码就能搞定,一步步来:
核心思路
咱们要做的是:拦截表单提交时的默认管理员邮件 → 暂存用户提交的数据并生成唯一确认令牌 → 给用户发带令牌链接的确认邮件 → 用户点击链接后,验证令牌并触发管理员邮件发送 → 清理暂存数据。
1. 拦截提交,暂存数据并发送确认邮件
用CF7的wpcf7_before_send_mail钩子,这个钩子会在邮件发送前触发,正好用来拦截默认的管理员邮件,同时生成令牌、暂存数据,再给用户发确认邮件。
把下面的代码加到你的主题functions.php里,记得替换注释里的表单ID和字段名:
add_action('wpcf7_before_send_mail', 'cf7_save_submission_for_verification'); function cf7_save_submission_for_verification($contact_form) { // 替换成你的目标表单ID(在CF7编辑页面看URL里的id参数) $target_form_id = 123; if ($contact_form->id() != $target_form_id) { return; } // 获取用户提交的所有数据 $submission = WPCF7_Submission::get_instance(); if (!$submission) return; $posted_data = $submission->get_posted_data(); // 生成唯一的确认令牌(WordPress自带的UUID生成函数,安全可靠) $token = wp_generate_uuid4(); // 把数据暂存在WordPress选项里,用令牌作为唯一标识 $temp_key = 'cf7_temp_submission_' . $token; update_option($temp_key, array( 'posted_data' => $posted_data, 'form_id' => $target_form_id, 'created_at' => current_time('mysql') ), false); // 拦截默认的管理员邮件,先不发 $contact_form->set_prop('mail', null); // 准备给用户的确认邮件 // 替换成你表单里的邮箱字段名(比如你的字段是[email* your-email],就用your-email) $user_email = $posted_data['your-email']; // 确认链接,后面我们会处理这个路由 $confirm_url = home_url('/cf7-verify?token=' . $token); // 配置用户邮件内容,支持纯文本或HTML $user_mail = array( 'subject' => '请确认你的表单提交', 'sender' => get_option('admin_email'), 'recipient' => $user_email, 'body' => '您好,感谢你的提交!请点击下面的链接完成确认:' . "\n\n" . $confirm_url . "\n\n" . '如果这不是你操作的,请忽略此邮件。', 'use_html' => false // 要发HTML邮件就改成true,body里写HTML代码 ); // 用CF7的mail_2发送用户邮件,不会覆盖你原来的表单设置 $contact_form->set_prop('mail_2', $user_mail); }
2. 处理确认链接的验证和邮件发送
接下来需要创建一个路由来处理用户点击确认链接的请求,用template_redirect钩子来捕获这个请求,验证令牌后触发管理员邮件发送:
同样加到主题functions.php里:
add_action('template_redirect', 'cf7_handle_verification'); function cf7_handle_verification() { // 检查是否是确认请求,没有token就直接跳过 if (!isset($_GET['token']) || empty($_GET['token'])) { return; } $token = sanitize_text_field($_GET['token']); $temp_key = 'cf7_temp_submission_' . $token; $temp_submission = get_option($temp_key); // 验证暂存数据是否存在(链接可能过期或无效) if (!$temp_submission) { wp_die('无效的确认链接,或该链接已过期'); } // 获取对应的表单和提交数据 $form_id = $temp_submission['form_id']; $posted_data = $temp_submission['posted_data']; $contact_form = wpcf7_contact_form($form_id); if (!$contact_form) { wp_die('对应的表单不存在'); } // 恢复表单原来的管理员邮件设置 $original_admin_mail = $contact_form->prop('mail'); if (!$original_admin_mail) { wp_die('表单未配置管理员邮件,请先在CF7里设置'); } // 重新填充提交数据,触发邮件发送 $submission = WPCF7_Submission::get_instance(); if ($submission) { $submission->set_posted_data($posted_data); } // 发送管理员邮件 $mailer = WPCF7_Mail::get_instance(); $mailer->send($contact_form, 'mail', $original_admin_mail); // 删除暂存的数据,避免用户重复点击发送 delete_option($temp_key); // 跳转到你的感谢页面,替换成实际的页面URL wp_redirect(home_url('/thank-you/')); exit; }
3. 额外优化:自动清理过期的暂存数据
为了避免数据库里堆积大量过期的暂存数据,我们可以加一个定时任务,每天清理超过24小时的暂存数据:
// 注册定时任务 add_action('wp', 'cf7_schedule_temp_submission_cleanup'); function cf7_schedule_temp_submission_cleanup() { if (!wp_next_scheduled('cf7_cleanup_temp_submissions')) { wp_schedule_event(time(), 'daily', 'cf7_cleanup_temp_submissions'); } } // 执行清理逻辑 add_action('cf7_cleanup_temp_submissions', 'cf7_cleanup_temp_submissions'); function cf7_cleanup_temp_submissions() { $expire_hours = 24; // 设置过期时间,比如24小时 $expire_timestamp = strtotime("-$expire_hours hours"); $all_options = wp_load_alloptions(); foreach ($all_options as $key => $value) { // 筛选出我们暂存的数据键名 if (strpos($key, 'cf7_temp_submission_') === 0) { $submission = get_option($key); // 如果创建时间早于过期时间,就删除 if (strtotime($submission['created_at']) < $expire_timestamp) { delete_option($key); } } } }
注意事项
- 替换代码里的表单ID:在CF7编辑页面的URL里可以找到,比如
wp-admin/admin.php?page=wpcf7&post=123&action=edit里的123就是表单ID。 - 替换字段名:比如你的邮箱字段是
[email* user-email],那代码里的$posted_data['your-email']要改成$posted_data['user-email']。 - 测试邮件发送:确保你的WordPress已经配置好邮件发送功能(可以用WP Mail SMTP之类的插件优化邮件送达率)。
内容的提问来源于stack exchange,提问作者Envi
相关产品推荐
相关产品推荐

