<p>A form builder is a regular request for some clients when they are looking for a content management system. There aren’t that many CMS that have this kind of functionality built-in, and even if they do, the implementation is usually less than desirable.</p>
<p>If you follow along with what I’ve been up to, you can probably tell that I have been on a big <a href="http://expressionengine.com/">ExpressionEngine</a> kick. I’ve been using it on a ton of projects recently, and I love it for its flexibility. Although it does lack a true form builder, I figured out a simple way to build one.</p>
<p>If you are impatient and just want to get to the <a href="http://ee.trevor-davis.com/forms/contact-form/">demo</a>, go ahead. Although the form will look like nothing special, as I have just added some simple styling. The real magic of the form builder happens in the Control Panel.</p>
<h2>We Need Add-ons</h2>
<p>This form builder would not be possible without the use of some awesome add-ons:</p>
<ul><li><a href="http://devot-ee.com/add-ons/extensions/fieldframe/"><strong>FieldFrame</strong></a>
<p>This one is a no-brainer. I can’t even imagine building a site without it.</p></li>
 <li><a href="http://devot-ee.com/add-ons/modules/freeform/"><strong>Freeform</strong></a>
<p>If you need a form in EE, this is the way to do it.</p></li>
 <li><a href="http://devot-ee.com/add-ons/extensions/freeform-data-select/"><strong>Freeform Data Select</strong></a>
<p>A new fieldtype which pulls in templates and fields from the Freeform module.</p></li>
</ul>
<h2>Creating a Field Group</h2>
<p>I built a custom Field Group called Forms, which consisted of four fields:</p>
<ul><li>Template</li>
 <li>Notification Email Addresses</li>
 <li>Return Page</li>
 <li>Fields</li>
</ul>
<p>The first three are pretty simple, so I will just give a quick run through on the specifications for those fields and give a more detail review of the <strong>Fields</strong> field:</p>
<h3>Template</h3>
<p>This is where you select the Freeform template that will be used for the email. This field is not completely necessary, as just using the default template should be good enough, but I figured since it was an option, to throw it in.</p>
<ul><li><strong>Field Name</strong>: form_template</li>
 <li><strong>Field Type</strong>: Freeform Data Select</li>
 <li><strong>Populate drop-down with</strong>: Freeform Templates</li>
</ul>
<h3>Notification Email Addresses</h3>
<p>This is where you will enter the email address(es) that you want to email when the form is submitted. Since Freeform wants multiple email addresses separated by the | character, I added some help text describing that as well.</p>
<ul><li><strong>Field Name</strong>: form_notify</li>
 <li><strong>Field Type</strong>: Text Input</li>
 <li><strong>Default Text Formatting for This Field</strong>: None</li>
 <li><strong>Hide Formatting Menu</strong></li>
</ul>
<h3>Return Page</h3>
<p>This is where you enter the URL to the thank you page. Once a user successfully submits the form, they will be redirected here.</p>
<ul><li><strong>Field Name</strong>: form_return</li>
 <li><strong>Field Type</strong>: Text Input</li>
 <li><strong>Default Text Formatting for This Field</strong>: None</li>
 <li><strong>Hide Formatting Menu</strong></li>
</ul>
<h3>Fields</h3>
<p>This is where the magic happens. This field is a FF Matrix field type that consists of five other fields. Each row of the FF Matrix represents one field (or field group) in the form. I’ll give a brief description of each field of the FF Matrix and show you a screenshot so you can get a better picture:</p>
<ul><li><strong>Field Name</strong>: form_field</li>
 <li><strong>Field Type</strong>: FF Matrix</li>
</ul>
<h4>Label</h4>
<p>This is where you will enter the label for the form field:</p>
<ul><li><strong>Col Name</strong>: label</li>
 <li><strong>Cell Type</strong>: Text Input</li>
</ul>
<h4>Field</h4>
<p>This field pulls in all of the fields that have been entered into the Freeform module. So you are presented with a dropdown of all of the fields, and you just select the appropriate one:</p>
<ul><li><strong>Col Name</strong>: field</li>
 <li><strong>Cell Type</strong>: Freeform Data Select</li>
 <li><strong>Populate drop-down with</strong>: Freeform fields</li>
</ul>
<h4>Field Type</h4>
<p>This is where you select the type of form field you want to use. I put in a few different options, but this could be expanded upon too:</p>
<ul><li><strong>Col Name</strong>: type</li>
 <li><strong>Cell Type</strong>: FF Select</li>
 <li><strong>Select Options</strong>: Text Input<br>
  Textarea<br>
  Select<br>
  Multi-select<br>
  Checkbox<br>
  Checkbox Group<br>
  Radio Group
 </li>
</ul>
<h4>Is this field required?</h4>
<p>With most forms, there are some fields that are required and some that are not. If you want the field to be required, you just check the checkbox and the Freeform module will make sure it is filled in:</p>
<ul><li><strong>Col Name</strong>: required</li>
 <li><strong>Cell Type</strong>: FF Checkbox</li>
 <li><strong>Checkbox Label</strong>: Is this field required?</li>
</ul>
<h4>Options</h4>
<p>Finally, this field is used when you select a field type that has multiple options. For example, if you select a “Select” field type, you need to provide the options to populate it. So you enter the options separated by the | character:</p>
<ul><li><strong>Col Name</strong>: options</li>
 <li><strong>Cell Type</strong>: Text Input</li>
</ul>
<figure><a href="//assets.trevor-davis.com/uploads/images/content/2009/11/ff-matrix.png" title="FieldFrame Matrix Configuration"><img src="//assets.trevor-davis.com/uploads/images/content/2009/11/ff-matrix_thumb.png" alt="FieldFrame Matrix Configuration" width="570" height="203" class="pullLeft frame" data-image="b5js0bktz1as"></a></figure>
<p>So that is all you need for the Field Group, now go ahead and create a Forms Channel (or Weblog) and make sure to assign the Forms Field Group to it.</p>
<p>Now, when you go to publish a Forms entry, you should see something like this:</p>
<figure><a href="//assets.trevor-davis.com/uploads/images/content/2009/11/form-entry.png" title="New Forms Entry"><img src="//assets.trevor-davis.com/uploads/images/content/2009/11/form-entry_thumb.png" alt="New Forms Entry" width="570" height="258" class="pullLeft frame" data-image="yuyhw5avjb9u"></a></figure>
<p>I made a <a href="http://ee.trevor-davis.com/forms/contact-form/">demo form</a> showing off the various types of form fields. Here is what that entry looks like in the Control Panel:</p>
<figure><a href="//assets.trevor-davis.com/uploads/images/content/2009/11/demo-entry.png" title="Demo Form Entry in Control Panel"><img src="//assets.trevor-davis.com/uploads/images/content/2009/11/demo-entry_thumb.png" alt="Demo Form Entry in Control Panel" width="570" height="400" class="pullLeft frame" data-image="wu4yx2snnz46"></a></figure>
<h2>Template</h2>
<p>Now that we have our Channel and Field Group all setup, we need to deal with the template. You could really setup your template/template group in various ways, so I’m not going to get into those details. One detail that you need to know is that <strong>I enabled PHP for my template</strong>.</p>
<p>First, we just need to start with a simple <strong>exp:weblog:entries</strong> tag:</p>
<pre>{exp:weblog:entries weblog="forms" limit="1" disable="categories|category_fields|member_data|pagination|trackbacks"}
…
{/exp:weblog:entries} </pre>
<p>Next, we want to start the Freeform form tag:</p>
<pre>{exp:weblog:entries weblog="forms" limit="1" disable="categories|category_fields|member_data|pagination|trackbacks"}
 {exp:freeform:form form_name="{url_title}" form_id="{url_title}" template="{form_template}" notify="{form_notify}" return="{form_return}"}
 …
 {/exp:freeform:form}
{/exp:weblog:entries} </pre>
<p>Since we are inside of the exp:weblog:entries tag, we have access to everything that is being returned from that entry. If you have any questions about the various parameters, <a href="http://www.solspace.com/docs/detail/freeform_form/#parameters">refer to the Freeform Documentation</a>.</p>
<p>So far, the values that we are passing into the parameters are pretty straightforward, just custom fields from our entry. But, passing in the <a href="http://www.solspace.com/docs/detail/freeform_form/#required">required</a> parameter is a little more challenging, since we have to loop through all of the rows in our FF Matrix.</p>
<p>If we <a href="http://brandon-kelly.com/fieldframe/docs/ff-matrix">refer to the FF Matrix documentation</a>, we can see how to loop through the rows in the matrix. I only want to return rows that have the required checkbox checked, and I want to separate the names of the fields with the | character. Then, I use the backspace parameter to remove the last one:</p>
<pre>{exp:freeform:form form_name="{url_title}" form_id="{url_title}" template="{form_template}" notify="{form_notify}" return="{form_return}" &lt;strong&gt;required="{form_field search:required='y' backspace='1'}{field}|{/form_field}"&lt;/strong&gt;}
…
{/exp:freeform:form}</pre>
<p>Next, we want to add a title, ordered list that will contain the form fields, and the submit button:</p>
<pre>{exp:freeform:form form_name="{url_title}" form_id="{url_title}" template="{form_template}" notify="{form_notify}" return="{form_return}" required="{form_field search:required='y' backspace='1'}{field}|{/form_field}"}
 &lt;h1&gt;{title}&lt;/h1&gt;
 &lt;ol class="forms"&gt;
  …
  &lt;li class="buttons"&gt;&lt;input type="submit" name="submit" value="submit" /&gt;&lt;/li&gt;
 &lt;/ol&gt;
{/exp:freeform:form} </pre>
<p>Now here is where the code gets interesting. Just like we did with the required parameter, we want to loop through each row in the FF Matrix and display a list item for each one:</p>
<pre>{form_field}
 &lt;li&gt;
 …
 &lt;/li&gt;
{/form_field} </pre>
<p>First, let’s display the label, if there is one, and denote if the field is required or not:</p>
<pre>{if "{label}"}
 &lt;label for="{field}"&gt;{if "{required}" == "y"}&lt;em class="required"&gt;*&lt;/em&gt;{/if}{label}&lt;/label&gt;
{/if} </pre>
<p>The rest of the code is a big conditional statement which depends upon the Field Types that you specified in the FF Matrix. Let’s first take a look at the <strong>Text Input</strong>, <strong>Textarea</strong>, and <strong>Checkbox</strong> types since they are pretty straightforward:</p>
<pre>{if "{type}" == "Text Input"}
 &lt;input type="text" name="{field}" id="{field}" /&gt;
{if:elseif "{type}" == "Textarea"}
 &lt;textarea name="{field}" id="{field}"&gt;&lt;/textarea&gt;
{if:elseif "{type}" == "Checkbox"}
 &lt;input type="checkbox" class="checkbox" name="{field}" id="{field}" /&gt;
…
{/if} </pre>
<p>So we are just checking the type column in the FF Matrix, and then displaying the rest of the data from the row in the appropriate form field.</p>
<p>Next, let’s walk through what happens if you select the <strong>Select</strong> or <strong>Multi-select</strong> types:</p>
<pre>{if:elseif "{type}" == "Select" || "{type}" == "Multi-select" && "{options}"}
 &lt;select name="{field}{if "{type}" == "Multi-select"}[]{/if}" id="{field}"{if "{type}" == "Multi-select"} multiple="multiple" size="4"{/if}&gt;
  &lt;?php $items = explode("|", '{options}'); ?&gt;
  &lt;?php foreach ($items as $item) { ?&gt;
   &lt;option value="&lt;?php echo $item; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/option&gt;
  &lt;?php } ?&gt;
 &lt;/select&gt;
…
{/if} </pre>
<p>So first, we are displaying the <strong>select element</strong>, and if it is a <strong>Multi-select</strong>, we are adding <strong>[]</strong> to the name attribute, and adding the <strong>multiple</strong> and <strong>size</strong> attributes.</p>
<p>Next, we want to take the string of <strong>options</strong> that are separated by the | character, and create an array out of the string using the <a href="http://php.net/manual/en/function.explode.php">explode function</a>.</p>
<p>Then, we loop through the array, and display the options for each one.</p>
<p>Finally, we do virtually the same thing for the <strong>Radio Group</strong> and <strong>Checkbox Group</strong> field types:</p>
<pre>{if:elseif "{type}" == "Radio Group" && "{options}"}
 &lt;ul class="group"&gt;
  &lt;?php $items = explode("|", '{options}'); $count = 1; ?&gt;
  &lt;?php foreach ($items as $item) { ?&gt;
   &lt;li&gt;&lt;input type="radio" class="radio" name="{field}" id="{field}&lt;?php echo $count; ?&gt;" value="&lt;?php echo $item; ?&gt;" /&gt;
   &lt;label for="{field}&lt;?php echo $count; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/label&gt;&lt;/li&gt;
   &lt;?php $count++; ?&gt;
  &lt;?php } ?&gt;
 &lt;/ul&gt;
{if:elseif "{type}" == "Checkbox Group" && "{options}"}
 &lt;ul class="group"&gt;
  &lt;?php $items = explode("|", '{options}'); $count = 1; ?&gt;
  &lt;?php foreach ($items as $item) { ?&gt;
   &lt;li&gt;&lt;input type="checkbox" class="checkbox" name="{field}[]" id="{field}&lt;?php echo $count; ?&gt;" value="&lt;?php echo $item; ?&gt;" /&gt;
   &lt;label for="{field}&lt;?php echo $count; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/label&gt;&lt;/li&gt;
   &lt;?php $count++; ?&gt;
  &lt;?php } ?&gt;
 &lt;/ul&gt;
{/if} </pre>

<p>So that’s it really. Here is the full template:</p>
<pre>{exp:weblog:entries weblog="forms" limit="1" disable="categories|category_fields|member_data|pagination|trackbacks"}

 {exp:freeform:form form_name="{url_title}" form_id="{url_title}" template="{form_template}" notify="{form_notify}" return="{form_return}" required="{form_field search:required='y' backspace='1'}{field}|{/form_field}"}

  &lt;h1&gt;{title}&lt;/h1&gt;
  &lt;ol class="forms"&gt;
   {form_field}
    &lt;li&gt;
     {if "{label}"}
      &lt;label for="{field}"&gt;{if "{required}" == "y"}&lt;em class="required"&gt;*&lt;/em&gt;{/if}{label}&lt;/label&gt;
     {/if}
     {if "{type}" == "Text Input"}
      &lt;input type="text" name="{field}" id="{field}" /&gt;
     {if:elseif "{type}" == "Textarea"}
      &lt;textarea name="{field}" id="{field}"&gt;&lt;/textarea&gt;
     {if:elseif "{type}" == "Checkbox"}
      &lt;input type="checkbox" class="checkbox" name="{field}" id="{field}" /&gt;
     {if:elseif "{type}" == "Select" || "{type}" == "Multi-select" && "{options}"}
      &lt;select name="{field}{if "{type}" == "Multi-select"}[]{/if}" id="{field}"{if "{type}" == "Multi-select"} multiple="multiple" size="4"{/if}&gt;
       &lt;?php $items = explode("|", '{options}'); ?&gt;
       &lt;?php foreach ($items as $item) { ?&gt;
        &lt;option value="&lt;?php echo $item; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/option&gt;
       &lt;?php } ?&gt;
      &lt;/select&gt;
     {if:elseif "{type}" == "Radio Group" && "{options}"}
      &lt;ul class="group"&gt;
       &lt;?php $items = explode("|", '{options}'); $count = 1; ?&gt;
       &lt;?php foreach ($items as $item) { ?&gt;
        &lt;li&gt;&lt;input type="radio" class="radio" name="{field}" id="{field}&lt;?php echo $count; ?&gt;" value="&lt;?php echo $item; ?&gt;" /&gt;
        &lt;label for="{field}&lt;?php echo $count; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/label&gt;&lt;/li&gt;
        &lt;?php $count++; ?&gt;
       &lt;?php } ?&gt;
      &lt;/ul&gt;
     {if:elseif "{type}" == "Checkbox Group" && "{options}"}
      &lt;ul class="group"&gt;
       &lt;?php $items = explode("|", '{options}'); $count = 1; ?&gt;
       &lt;?php foreach ($items as $item) { ?&gt;
        &lt;li&gt;&lt;input type="checkbox" class="checkbox" name="{field}[]" id="{field}&lt;?php echo $count; ?&gt;" value="&lt;?php echo $item; ?&gt;" /&gt;
        &lt;label for="{field}&lt;?php echo $count; ?&gt;"&gt;&lt;?php echo $item; ?&gt;&lt;/label&gt;&lt;/li&gt;
        &lt;?php $count++; ?&gt;
       &lt;?php } ?&gt;
      &lt;/ul&gt;
     {/if}
    &lt;/li&gt;
   {/form_field}
   &lt;li class="buttons"&gt;&lt;input type="submit" name="submit" value="submit" /&gt;&lt;/li&gt;
  &lt;/ol&gt;
 {/exp:freeform:form}  
{/exp:weblog:entries} </pre>
<h2>Conclusion</h2>
<p>This is not meant to be an all-inclusive form builder, as you can see there are <a href="http://www.solspace.com/docs/detail/freeform_form/#parameters">many other parameters for the Freeform module</a>. But, this was meant to show a creative use of ExpressionEngine and EE add-ons to add functionality that is not directly built into the CMS.</p>
<p>So go forth and create.</p>