如何在WordPress中无需插件实现带PRG模式的自定义联系表单
WordPress无插件实现PRG模式的联系表单
嘿,我完全懂你在WordPress里折腾无插件联系表单的难处——既要避免插件臃肿,又要实现PRG模式防重复提交,用SESSION传递消息对吧?我给你整理了一套完整的可落地方案,直接照搬就能用:
1. 主题模板中的联系表单代码
把这段代码放到你的联系页面模板里(比如page-contact.php),表单样式可以根据自己的主题调整:
<?php // 先启动SESSION用于显示消息(要在输出HTML之前) if ( ! session_id() ) { session_start(); } ?> <!-- 显示消息的代码 --> <?php if ( isset( $_SESSION['contact_errors'] ) ) : ?> <div style="background: #f8d7da; color: #721c24; padding: 1rem; margin: 1rem auto; width: 500px; border-radius: 4px;"> <?php if ( is_array( $_SESSION['contact_errors'] ) ) : ?> <?php foreach ( $_SESSION['contact_errors'] as $error ) : ?> <p><?php echo esc_html( $error ); ?></p> <?php endforeach; ?> <?php else : ?> <p><?php echo esc_html( $_SESSION['contact_errors'] ); ?></p> <?php endif; ?> </div> <?php unset( $_SESSION['contact_errors'] ); ?> <?php endif; ?> <?php if ( isset( $_SESSION['contact_success'] ) ) : ?> <div style="background: #d4edda; color: #155724; padding: 1rem; margin: 1rem auto; width: 500px; border-radius: 4px;"> <p><?php echo esc_html( $_SESSION['contact_success'] ); ?></p> </div> <?php unset( $_SESSION['contact_success'] ); ?> <?php endif; ?> <!-- 联系表单 --> <form class="di-contact" method="post" action="<?php echo esc_url( get_template_directory_uri() . '/contact.php' ); ?>" style="width: 500px; margin: 2rem auto;"> <!-- WordPress安全验证Nonce,必须加! --> <?php wp_nonce_field( 'contact_form_submit', 'contact_nonce' ); ?> <div style="margin-bottom: 1rem;"> <label for="name" style="display: block; margin-bottom: 0.5rem;">姓名:</label> <input type="text" id="name" name="name" required style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;"> </div> <div style="margin-bottom: 1rem;"> <label for="email" style="display: block; margin-bottom: 0.5rem;">邮箱:</label> <input type="email" id="email" name="email" required style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;"> </div> <div style="margin-bottom: 1rem;"> <label for="message" style="display: block; margin-bottom: 0.5rem;">留言:</label> <textarea id="message" name="message" rows="5" required style="width: 100%; padding: 0.5rem; border: 1px solid #ddd; border-radius: 4px;"></textarea> </div> <button type="submit" style="padding: 0.5rem 1.5rem; background: #0073aa; color: white; border: none; border-radius: 4px; cursor: pointer;">提交</button> </form>
2. 表单处理程序 contact.php
在你的主题根目录下新建contact.php文件,写入以下代码——它负责处理表单提交、验证数据、发送邮件,然后重定向回表单页面(PRG模式核心):
<?php // 必须初始化WordPress环境,否则无法使用WP函数和SESSION require_once( dirname(__FILE__) . '/wp-load.php' ); // 启动SESSION if ( ! session_id() ) { session_start(); } // 验证请求合法性:POST请求 + Nonce验证 if ( $_SERVER['REQUEST_METHOD'] === 'POST' && isset( $_POST['contact_nonce'] ) && wp_verify_nonce( $_POST['contact_nonce'], 'contact_form_submit' ) ) { // 清理并获取表单数据 $name = sanitize_text_field( $_POST['name'] ); $email = sanitize_email( $_POST['email'] ); $message = sanitize_textarea_field( $_POST['message'] ); // 验证必填字段 $errors = []; if ( empty( $name ) ) { $errors[] = '请填写您的姓名'; } if ( ! is_email( $email ) ) { $errors[] = '请输入有效的邮箱地址'; } if ( empty( $message ) ) { $errors[] = '请填写留言内容'; } if ( empty( $errors ) ) { // 准备邮件内容,发送到站点管理员邮箱 $to = get_option( 'admin_email' ); $subject = '站点联系表单提交:' . $name; $body = "姓名:{$name}\n邮箱:{$email}\n\n留言内容:\n{$message}"; $headers = [ "From: {$name} <{$email}>" ]; // 发送邮件并设置SESSION消息 if ( wp_mail( $to, $subject, $body, $headers ) ) { $_SESSION['contact_success'] = '您的留言已成功提交,我们会尽快回复您!'; } else { $_SESSION['contact_errors'] = '邮件发送失败,请稍后再试'; } } else { // 把错误消息存入SESSION $_SESSION['contact_errors'] = $errors; } } else { // 非法请求处理 $_SESSION['contact_errors'] = '请求无效,请通过正常表单提交'; } // PRG模式:重定向回联系页面(这里假设页面slug是contact,根据实际修改) $contact_page_url = get_permalink( get_page_by_path( 'contact' ) ); wp_redirect( $contact_page_url ?: home_url() ); exit;
3. 关键注意事项
- 安全第一:Nonce验证是必须的,防止CSRF攻击;所有用户输入都用WP的
sanitize_*函数清理,避免XSS注入。 - SESSION启动时机:必须在输出任何HTML之前调用
session_start(),否则会报错。 - 邮件问题:如果邮件发送失败,检查主机的邮件服务是否正常,或者可以手动指定SMTP配置(不过你不想装插件的话,可能需要修改
wp_mail的底层实现,或者联系主机商)。 - 主题更新防护:建议用子主题存放这些自定义文件,避免主题更新时覆盖你的代码。
内容的提问来源于stack exchange,提问作者Marcos Di Paolo
相关产品推荐
相关产品推荐

