Contact Form 7是一款好用的表单插件,由来已久,口碑甚好。使用Contact Form 7时,通常是在后台创建两套模版:表单模版和邮件模版,模版可以使用HTML和shortcode。本文介绍如何借助这些功能动态的生成表单元素和邮件模版,让用户填写表单时可以动态增加数据,而不仅限于模版预定义的数据。

本文将描述如何在Contact Form 7页面

  • 引入自定义javascript
  • 引入自定义样式
  • 通过clone方法克隆部分表单,动态产生数据,这里以学校为例,用户点击添加学校按钮就可以输入多组学校信息,比如小学、中学、大学。
  • 动态修改email模版,将动态产生的数据一起发送
  • 如何借助WP-Mail-SMTP插件进行本地发送邮件测试

安装插件就不用介绍了,假设已经装好Contact Form 7和WP Mail SMTP插件,如果用服务器测试,则无需安装后者。

使用默认主题TwentyEleven主题测试。

最终效果

Final

源代码下载

Contact Form 7 定制实例 已下载 499 次

下载后,启用twentyeleven主题,文件放在主题主题根目录下,form_fun.php中的代码拷贝到主题的functions.php中,按照下面的方法创建form模版进行测试。

创建Contact From 7表单和邮件模版

打开Contact选项卡,会看到默认的表单Contact form 1,就以该表单为基础,添加一个可重复出现的学校字段

Form模版

<p>Your Name (required)<br />
    [text* your-name] </p>

<p>Your Email (required)<br />
    [email* your-email] </p>

<p>Subject<br />
    [text your-subject] </p>

<p>Your Message<br />
    [textarea your-message] </p>

<div class="repeater">

<p>毕业院校<br />
    [text your-school_1] </p>

<p>毕业时间<br />
    [text your-graduation-time_1] </p>

</div>

<div class="more-rows"></div>

<p class="add-more"><a href="#" id="add-new">添加学校</a></p>
<input type="hidden" value="1" name="rownum" id="rownum">

<p>[submit "Send"]</p>

在默认表单结构上添加了下面的内容

<!-- 位于该div下的所有内容,可以通过点击添加学校按钮产生更多组 -->
<div class="repeater">

<p>毕业院校<br />
    [text your-school_1] </p>

<p>毕业时间<br />
    [text your-graduation-time_1] </p>

</div>

<!-- 新产生的表单元素会放在这个div中 -->
<div class="more-rows"></div>

<!-- 复制表单的按钮和记录复制个数的隐藏域-->
<p class="add-more"><a href="#" id="add-new">添加学校</a></p>
<input type="hidden" value="1" name="rownum" id="rownum">

Message Body模版

From: [your-name] <[your-email]>
Subject: [your-subject]

Message Body:
[your-message]

学校信息:
[UserSchool]
--

[UserSchool]将会被程序动态替换成学校信息

创建一个page模版

复制page.php为page-contact.php,修改头部注释信息为

<?php
/**
 * Template Name: Custom Contact Form
 */

这样就创建了一个名为Custom Contact From的page模版

创建表单页面

点击页面->新建页面,创建一个新的页面,名字随便起,但要在页面属性中选则使用我们刚刚创建的page模版,也就是Custom Contact Form

选择模版

在编辑器中输入刚刚创建的表单的shortcode

[contact-form-7 id="21" title="Contact form 1"]

保存页面并查看,我们刚刚创建的表单就出现了,这是由Contact Form 7表单模版产生的表单结构,只是展示了预定义的内容,还不能动态生成新的表单元素。

由Contact Form 7表单模版产生的表单结构

增加动态产生表单的功能(js)

主要通过jquery实现,所以首先确保jquery正确引入。

在page-contact.php引入jquery,下面所述所有代码都要放在get_header()之前,因为引入脚本的wp_enqueue_script()函数是在wp_head()执行时运行的,而wp_head()在get_header()中执行,所以要在执行前加入。

//确保jquery加载,且不会重复加载
wp_enqueue_script('jquery');

接下来,引入克隆表单的javascript代码,希望把这段代码放在页面底部,所以挂载到wp_footer上

add_action('wp_footer', 'custom_form_script');
function custom_form_script(){
    ?>
    <script type="text/javascript">
        jQuery(document).ready( function($) {
           var cur_num = 1;
           $('#add-new').click(function(){
               $('#rownum').val(parseInt($('#rownum').val())+1);
                var cloned = $(".repeater").clone(true, true).get(0);
                ++cur_num;            
                cloned.className = "cloned"; 
                cloned.id = "cloned_" + cur_num;// Change the div itself.
                $(cloned).find("input").each(function(index, element) {   // And all inner elements.
                    element.value='';
                    if(element.id)
                    {
                        var matches = element.id.match(/(.+)_\d+/);
                        if(matches && matches.length >= 2)            // Captures start at [1].
                            element.id = matches[1] + "_" + cur_num;
                    }
                    if(element.name)
                    {
                        var matches = element.name.match(/(.+)_\d+/);
                        if(matches && matches.length >= 2)            // Captures start at [1].
                            element.name = matches[1] + "_" + cur_num;
                    }
                    
                });
                $(cloned).find("span.wpcf7-form-control-wrap").each(function(index, element) {
                    var matches = element.className.match(/(.+)_\d+/);
                    if(matches && matches.length >= 2)            // Captures start at [1].
                        element.className = matches[1] + "_" + cur_num;
                });
                $(cloned).appendTo($(".more-rows"));
                return false;
            });
       });
    </script>
    <?php
}

流程如下:

  • 给”添加学校“按钮(id是add-new)绑定click事件
  • 这个click事件首先复制一份被包围在<div class="repeater"></div>中的内容,任何内容,如果你想重复更多的元素,尽管在Form模版中向这个div中添加内容,命名规则为[fieldname_1]
  • 替换被克隆的表单元素的id和name,因为后面会POST数据,如果name相同就无法区分是哪一组数据了。用自增方式修改,这样第二组表单的命名会是[fieldname_2],第三组是[fieldname_3]等等。
  • 找到存放动态产生的表单元素的div <div class="more-rows"></div>,改变这个div在模版中的位置可以更改新元素出现的地方,我希望新元素位于”添加学校“按钮之前

让可重复的部分更明显

毕业院校和毕业时间是可重复产生的,为了让它们与其它元素区分开来,加一些css样式,代码依然要写在get_header()之前

add_action('wp_head', 'custom_form_styles');
function custom_form_styles(){
    ?>
    <style type="text/css">
        .cloned,.repeater{ background:#E6E6E6; padding:1em;-webkit-border-radius: 10px;-moz-border-radius: 10px;border-radius: 10px; }
        .cloned{margin-top:2em;}
        .add-more{padding:1em 0; text-align:right}
    </style>
    <?php
}

这样可重复的部分就与其它部分区分开了

可动态产生的区域

现在提交表单,模版中预定义的内容可以发送,但点击添加学校按钮产生的内容无法发送,接下来用程序修改发送模版

动态修改Contact Form7 邮件模版

下面的代码放在functions.php中

add_action("wpcf7_before_send_mail", "wpcf7_custom_email_template");  
function wpcf7_custom_email_template(&$wpcf7_data) {
    if ($wpcf7_data->id == 21) {
        $total_repeated = $wpcf7_data->posted_data['rownum'];
        $has_school = $wpcf7_data->posted_data['your-school_1'] ? true : false;
        if ($total_repeated > 0 && $has_school) {
            for ($i = 1; $i <= $total_repeated; $i++) {
                $more_fields .= "学校: [your-school_$i]\n毕业时间: [your-graduation-time_$i]\n\n";
            }
            $wpcf7_data->mail = str_replace('[UserSchool]', $more_fields, $wpcf7_data->mail);
        } else {
            $wpcf7_data->mail = str_replace('[UserSchool]', '无', $wpcf7_data->mail);
        }
    }
}

代码流程:

  • 先判断一下提交的表单的id,这段代码应该仅修改我们自定义的表单,对其它正常的表单不产生影响,表单的id可以从shortcode中获得
    [contact-form-7 id="21" title="Contact form 1"]
  • $wpcf7_data->posted_data包含所有post的数据,动态产生的那些也在里面
  • 为了让contact form 7发送动态数据,只需要将这些动态数据的名字用contact form 7的shortcode格式加到$wpcf7_data->mail变量中即可,用str_replace替换邮件模版中预定义的[UserSchool]达到目的。

这样,就可以接收到动态产生的表单信息了。

本地测试

想本地测试的话需要配置SMTP,用WP-Mail-SMTP插件完成,例如通过gmail发送邮件,需要你有gmail的邮箱。

wp-smtp配置

填写好后,就可以在本地测试发送邮件了,在表单中填写数据,测试一下结果吧。

结语

本文介绍了在Contact Form 7中用javascript动态产生表单数据,并在邮件中发送的方法。可重复的表单元素只是其中一种,还可以添加任意Form和Mail模版中未定义的表单,只要使用action wpcf7_before_send_mail定制化发送过程就可以正确发送数据了。

18条留言

  1. 博主你好,怎样修改contact form 7生成的表单样式,我想修改一下表单的外观

    1. 直接在主题样式表里写css就行,用浏览器的审查工具看一下最终生成的表单的html代码,就能找到需要的css selector

      1. 其实我想修改文本框的样式,但是文本框是短代码,我无法引用CSS,要引用就要自己重新写一个input,怎样直接修改短代码生成的模板?谢谢博主的回复

  2. sola, 晕死了,这几天有人不停的在网站上恶意发消息,通过contact form 7,ip每次不一样。这怎么办呀?

    1. 是机器人spam可以装Contact Form 7 Honeypot,是人工的这个就没办法了,你的表单用akismet过滤了吗?

  3. 美女,你有没有试过收件人改为腾讯企业邮箱,我试过2个腾讯企业邮箱就是收不到邮件,而Gmail或者QQ什么的都能收到..
    这个Contact Form 7发送的邮件再哪可以看到记录

    1. 没有记录。你可以装插件http://wordpress.org/plugins/contact-form-7-to-database-extension/
      这个插件能把发送的邮件记录到数据库里,但我感觉它解决不了你的问题。
      contact form7的邮件肯定是发出去了,qq为什么没收到,不好说。
      你可以先用你服务器上的webmail程序向qq邮箱发邮件,确认不是服务器的问题。
      如果服务器没事,contact form 7就是发不过去,可以装smtp插件,用服务器smtp发送,或者用第三方的smtp,比如163或者google

    2. 还有,要注意from地址,最好别用wordpress默认的,在服务器上创建一个email账户,把from地址改成这个。

      1. 搞定了,装了个smtp插件插件。
        再问个问题:
        我使用Advanced Custom Fields创建了一个自定义字段(summary-info),想自定义控制summary-info输出内容的字节个数,找了些资料都不行,请教下,谢谢

        1. 试过PHP的mb_strimwidth或者css的text-overflow ellipsis吗?

  4. SOLA,请问如何在contact page的页面中添加一个指定的widget呢?

  5. <?php
    $category_id = get_cat_ID( $cat_name='%1$s');
    $q = 'cat=' . $category_id;

    if (have_posts()) : $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $args=array(
    'cat' => '$q',
    'meta_key' => 'wpfp_favorites',
    'orderby' => 'meta_value_num',
    'paged' => $paged,
    'order' => DESC
    );
    query_posts($args);
    while (have_posts())
    : the_post(); update_post_caches($posts); ?>
    这个方法应该可以实现,但我不知道哪里出错了?

    1. 感觉你在兜圈子,既然已经在archive页面了,为啥还要通过category name来获取id?使用get_query_var(‘cat’)就可以了。

      进一步讲,你只是改变一下orderby之类的参数,没必要把cat id这种重新查询一遍吧,只需要增加你要变的参数,其它的保持不变就行了,也就是说根本没必要知道cat id是什么。

      参考一下官方文档

      global $wp_query;
      $args = array_merge( $wp_query->query_vars, array( 'post_type' => 'product' ) );
      query_posts( $args );

      这是只改变需要改变的,保留不需要改变的

      看一下http://codex.wordpress.org/Function_Reference/query_posts

      在functions.php中改的话,看一下http://codex.wordpress.org/Plugin_API/Action_Reference/pre_get_posts

  6. 这个问题研究了十几天星期,现在文章排序是:
    <?php if (have_posts()) : $paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
    $args=array(
    'cat' => '7',
    'meta_key' => 'wpfp_favorites',
    'orderby' => 'meta_value_num',
    'paged' => $paged,
    'order' => DESC
    );
    query_posts($args);
    while (have_posts())
    : the_post(); update_post_caches($posts); ?>

    这个比方说就是现实分类ID为7的,按wpfp_favorites值来排序,可以实现。
    但是一直都想不通,怎么样可以让用户点击任何一个分类或子类后进入的archive.php页面,也能够实现按wpfp_favorites来排序。

    怎么让cat后面的7变为一个变量就不懂了。后来我看到在进入archive.php页面时候,发现顶部有怎么一句:
    if (is_category()) {
    printf( __('Archive for the ‘%1$s’Category', 'inove'), single_cat_title('', false) );
    // If this is a tag archive
    } elseif (is_tag()) {
    printf( __('Posts Tagged ‘%1$s’', 'inove'), single_tag_title('', false) );

    这句话可以显示类别名称,比如ID为7的分类叫“影视原声”,那顶部就会显示Archive for the ‘影视原声’。但这只是个类别名字啊,怎么让这个类别名字变成ID号,成1个替代'cat' => '7'当中7的变量,好久好久了 太难了

      1. 如果改变了全局排序,其他按最新排序的好像也变了。

        1. 改变全局排序的时候,写上条件判断不就行了,比如is_tag(), is_category()之类的

评论功能已关闭