Site icon WP Smith

How to Create a Custom Form Field in Gravity Forms with a Terms of Service Form Field Example

First and foremost, RocketGenius has, in my opinion, the best form creation plugin in the WordPress market, GravityForms. It seriously is worth every penny and probably is the best money I've spent. I see so much potential with Gravity Forms that has yet to be tapped, and I am excited to see new things from GravityForms and the GravityForms community.

GravityForms has made major strides this past year in their documentation. With their recent and ever-expanding hooks and filters, the ability to expand Gravity Forms is becoming limitless. If it doesn't do something that you want, with its current set of filters and hooks, you can easily code it to make it possible.

So recently, I needed to create a Terms of Service custom Gravity Forms field. This TOS field would be a read-only input box with a scrollbar disabling the submit button (as an option, even), so when the user scrolled to the bottom, it would enable the submit button.

Here are the steps that I've taken:

  1. Add the Button
  2. Add the Field Title
  3. Add the Input Field
  4. Add the Editor Form JS
  5. Add a Placement Custom Setting
  6. Add a ToolTip
  7. Add my Custom External JS
  8. Optional: Add the Appropriate CSS Classes

Add the Button

You will first need to hook into the gform_add_field_buttons. There are three Field Groups where you can add your button:

  1. Standard Fields
  2. Advanced Fields
  3. Post Fields

Also each button will need three things:

  1. Class
  2. Value (or Name)
  3. Onclick Action

So let's look at the function:

[php]
// Add a custom field button to the advanced to the field editor
add_filter( 'gform_add_field_buttons', 'wps_add_tos_field' );
function wps_add_tos_field( $field_groups ) {
foreach( $field_groups as &$group ){
if( $group["name"] == "advanced_fields" ){ // to add to the Advanced Fields
//if( $group["name"] == "standard_fields" ){ // to add to the Standard Fields
//if( $group["name"] == "post_fields" ){ // to add to the Standard Fields
$group["fields"][] = array(
"class"=>"button",
"value" => __("Terms of Service", "gravityforms"),
"onclick" => "StartAddField('tos');"
);
break;
}
}
return $field_groups;
}
[/php]

In the $group['fields'] array, in value, I used the 'gravityforms' text domain. Right? Wrong? or Indifferent? This can easily be changed to your theme's or child theme's text domain, since Gravity Forms more than likely won't have that string translated.

The most important thing here for me, and the things I changed are the value "Terms of Service" in the value key and the arg in the js command StartAddField, 'tos'.

Add the Field Title

Now that we have our button, we can click on it and a field box with the word Untitled will appear.

However, if you hover over it, only the slug, or the ID, or the type that was given will appear. In my previous bit of code, I gave it the ID, tos.

However, I do not want the type or the slug to appear, so I want to give it a title. To do this, I will need to hook into the filter gform_field_type_title, which is new in Gravity Forms 1.6. The code is fairly straight forward. I check to see if I have the correct type and then I apply a title.

[php]
// Adds title to GF custom field
add_filter( 'gform_field_type_title' , 'wps_tos_title' );
function wps_tos_title( $type ) {
if ( $type == 'tos' )
return __( 'Terms of Service' , 'gravityforms' );
}
[/php]

Add the Input Field

This may be one of the most important pieces of adding new Gravity Forms custom fields. To edit the input field, you will need to hook into the gform_field_input (or possibly even the gform_field_content hook). gform_field_input allows you to modify the field's input tag to create custom field types. gform_field_content allows users to completely modify the way the field is rendered including both the input field and label.

This hook has 5 parameters:

  1. $input: The input tag string to be filtered. Will be passed to the hook an empty string value. Return an empty string to bypass the filtering, or change its value to specify a new input tag
  2. $field: This is the Field Object, which contains all the values for the various field settings. The most important key in this object is the $field['type'], which allows you to filter and ensure that you are editing the correct input field.
  3. $value: The pre-populated default/initial value of the field
  4. $lead_id: When executed from the entry detail screen, $lead_id will be populated with the Entry ID. Otherwise, it will be 0
  5. $form_id: The Current Form ID, which will allow you to edit on a form by form basis

[php]
// Adds the input area to the external side
add_action( "gform_field_input" , "wps_tos_field_input", 10, 5 );
function wps_tos_field_input ( $input, $field, $value, $lead_id, $form_id ){

if ( $field["type"] == "tos" ) {
$max_chars = "";
if(!IS_ADMIN && !empty($field["maxLength"]) && is_numeric($field["maxLength"]))
$max_chars = self::get_counter_script($form_id, $field_id, $field["maxLength"]);

$input_name = $form_id .'_' . $field["id"];
$tabindex = GFCommon::get_tabindex();
$css = isset( $field['cssClass'] ) ? $field['cssClass'] : '';
return sprintf("<div class='ginput_container'><textarea readonly name='input_%s' id='%s' class='textarea gform_tos %s' $tabindex rows='10' cols='50'>%s</textarea></div>{$max_chars}", $field["id"], 'tos-'.$field['id'] , $field["type"] . ' ' . esc_attr( $css ) . ' ' . $field['size'] , esc_html($value));

}

return $input;
}
[/php]

First I am checking to make sure I am editing the display of the correct field type. Once that's been determined, I work on the max characters and tab index. Then I added the readonly and the CSS Classes from any custom entered CSS Classes (via cssClass) as well as the Size selection. However, again, this is fairly straightforward. For your custom fields, this will look vastly different. Once complete, your input/checkbox, etc, will appear.

Add the Editor Form JS

Now, probably one of the most important hooks for any new custom field. Without this hook, you won't see anything.

So to see the various placement settings under Properties and Advanced you will need to hook into gform_editor_js. This hook will allow you to inject JS into the form editor page.

[php]
// Now we execute some javascript technicalitites for the field to load correctly
add_action( "gform_editor_js", "wps_gform_editor_js" );
function wps_gform_editor_js(){
?>

<script type='text/javascript'>

jQuery(document).ready(function($) {
//Add all textarea settings to the "TOS" field plus custom "tos_setting"
// fieldSettings["tos"] = fieldSettings["textarea"] + ", .tos_setting"; // this will show all fields that Paragraph Text field shows plus my custom setting

// from forms.js; can add custom "tos_setting" as well
fieldSettings["tos"] = ".label_setting, .description_setting, .admin_label_setting, .size_setting, .default_value_textarea_setting, .error_message_setting, .css_class_setting, .visibility_setting, .tos_setting"; //this will show all the fields of the Paragraph Text field minus a couple that I didn't want to appear.

//binding to the load field settings event to initialize the checkbox
$(document).bind("gform_load_field_settings", function(event, field, form){
jQuery("#field_tos").attr("checked", field["field_tos"] == true);
$("#field_tos_value").val(field["tos"]);
});
});

</script>
<?php
}
[/php]

I don't claim to be a jQuery/javascript person. Never have and probably never will. However, I do know from what this bit of code does, two things: (1) You must set your custom settings (i.e., fieldSettings["tos"]), or nothing appears. This can take all the fields of another setting or a comma-separated string of settings. Also note that these are class names. and (2) You want to hook into gform_load_field_settings for any custom placement fields. The documentation for gform_editor_js isn't that great but if you look at gform_field_advanced_settings or gform_field_standard_settings you will see other examples of this hook in action.

Add a Placement Custom Setting

Now, with custom settings, you will want, even need, to add custom placement input fields. To do this you will need to hook into one of two hooks (gform_field_advanced_settings or gform_field_standard_settings), depending on where you want the custom placement input field.

Since I wanted to add my custom placement field to the Advanced Settings, I am hooking into gform_field_advanced_settings. In this example, I am adding a checkbox placement.

[php]
// Add a custom setting to the tos advanced field
add_action( "gform_field_advanced_settings" , "wps_tos_settings" , 10, 2 );
function wps_tos_settings( $position, $form_id ){

// Create settings on position 50 (right after Field Label)
if( $position == 50 ){
?>

<li class="tos_setting field_setting">

<input type="checkbox" id="field_tos" onclick="SetFieldProperty('field_tos', this.checked);" />
<label for="field_tos" class="inline">
<?php _e("Disable Submit Button", "gravityforms"); ?>
<?php gform_tooltip("form_field_tos"); ?>
</label>

</li>
<?php
}
}
[/php]

While I did not use this, here is another example of

Now both gform_field_standard_settings and gform_field_advanced_settings have various positions to hook into, which will determine the placement of the custom setting. So you can use various positions to determine which position you should place yours. For your information, here is the order/position for the [expand title="Standard Settings"]

  1. label_setting
  2. product_field_setting
  3. shipping_field_type_setting
  4. base_price_setting
  5. disable_quantity_setting
  6. option_field_type_setting
  7. donation_field_type_setting
  8. quantity_field_type_setting
  9. content_setting
  10. next_button_setting
  11. previous_button_setting
  12. disable_margins_setting
  13. post_custom_field_type_setting
  14. post_tage_type_setting
  15. captcha_theme_setting
  16. post_custom_field_setting
  17. post_status_setting
  18. post_author_setting
  19. post_category_setting
  20. post_category_checkbox_setting
  21. post_category_initial_item_setting
  22. gfield_post_category_initial_item_containter
  23. post_content_template_setting
  24. post_tite_template_setting
  25. customfield_content_template_setting
  26. post_image_setting
  27. post_image_featured_image
  28. address_setting
  29. name_format_setting
  30. date_input_type_setting
  31. date_format_setting
  32. file_extensions_setting
  33. columns_setting
  34. max_rows_setting
  35. time_format_setting
  36. phone_format_setting
  37. choices_setting
  38. other_choice_setting
  39. email_confirm_setting
  40. password_strength_setting
  41. enable_enhanced_ui_setting
  42. gfield_min_strength_containter
  43. number_format_setting
  44. description_setting
  45. credit_card_setting
  46. credit_card_style_setting
  47. input_mask_setting
  48. maxlen_setting
  49. range_setting
  50. rules_setting

[/expand]

For your information, here is the order for the [expand title="Advanced Settings"]

  1. admin_label_setting
  2. size_setting
  3. default_value_setting
  4. default_value_textarea_setting
  5. error_message_setting
  6. credit_card_icon_style_setting
  7. captcha_language_setting
  8. css_class_setting
  9. add_icon_url_setting
  10. delete_icon_url_setting
  11. password_field_setting
  12. force_ssl_field_setting
  13. visibility_setting
  14. prepopulate_field_setting
  15. conditional_logic_field_setting
  16. conditional_logic_page_setting
  17. conditional_logic_nextbutton_setting

[/expand]

Add a ToolTip

Next is to add a tooltip, so you will need to hook into gform_tooltips.

ToolTips are fairly straight forward. Simply edit the tooltips. In to code below, I add a tooltip to my newly placed placement field and edit a tooltip of an existing placement field and tooltip.

[php]
//Filter to add a new tooltip
add_filter('gform_tooltips', 'wps_add_tos_tooltips');
function wps_add_tos_tooltips($tooltips){
$tooltips["form_field_tos"] = "<h6>Disable Submit Button</h6>Check the box if you would like to disable the submit button.";
$tooltips["form_field_default_value"] = "<h6>Default Value</h6>Enter the Terms of Service here.";
return $tooltips;
}
[/php]

Now, here are all the [expand title="ToolTips"]

[/expand]

Add my Custom External JS

Now my Advanced Custom Field would not be advanced or very custom if all I did was duplicate the Paragraph Text (textarea) field and add my custom placement field. Right now, the submit button does not disable for any reason.

So, I need to make some further modifications to achieve my goal. This included my own custom external JS. So I needed to hook into gform_enqueue_scripts, which would allow me to properly enqueue scripts Gravity Forms would like.

[php]
// Add a script to the display of the particular form only if tos field is being used
add_action( 'gform_enqueue_scripts' , 'wps_gform_enqueue_scripts' , 10 , 2 );
function wps_gform_enqueue_scripts( $form, $ajax ) {
// cycle through fields to see if tos is being used
foreach ( $form['fields'] as $field ) {
if ( ( $field['type'] == 'tos' ) && ( isset( $field['field_tos'] ) ) ) {
$url = plugins_url( 'gform_tos.js' , __FILE__ );
wp_enqueue_script( "gform_tos_script", $url , array("jquery"), '1.0' ); // Note WPS_JS is a constant I've set for all my child theme's custom JS.
break;
}
}
}
[/php]

Here is my JS, which is really simple (if I can understand it).

[javascript]
jQuery(document).ready(function($) {
$(".gform_footer input[type='submit']").prop("disabled",true);

$(".gform_body textarea.gform_tos").scroll(function(){
if($(this).scrollTop()+$(this).height() >= $(this)[0].scrollHeight-10){
$(".gform_footer input[type='submit']").prop("disabled",false);
}
});

});
[/javascript]

Add the Appropriate CSS Classes

Finally, in order to ease form display styling of the Terms of Service, I needed to make sure that I included a class. Now this could have been added with the gform_input_field hook, but I just wanted to display how it would work using this hook.

So I could hook into gform_field_css_class, which would allow me to add/change the CSS of the external fields. This hook is also great for all those designers who *cough*hate*cough* I mean love to style Gravity Forms CSS. Two little know documentation pages by Gravity Forms are its styling pages: CSS Ready Classes and CSS Targeting Samples. The interesting thing is that CSS Ready Classes gives an example of a Terms of Service, which requires a HTML box and a checkbox to state that you've read the TOS.

[php]
// Add a custom class to the field li
add_action("gform_field_css_class", "custom_class", 10, 3);
function custom_class($classes, $field, $form){

if( $field["type"] == "tos" ){
$classes .= " gform_tos";
}

return $classes;
}
[/php]

Here is a list of all the Gravity Forms [expand title="ready-to-use CSS classes."]

Halves

Thirds

Inline

List Classes

List Height Classes

Other Classes

[/expand]

Note: the classes are added to the parent

Download the Code

[download id="18"]

Here is the full code:

[php]
<?php
/**
* Plugin Name: Gravity Forms Terms of Service Field
* Terms of Service Gravity Forms Custom Form Field
* Plugin URI: https://wpsmith.net/2011/plugins/how-to-create-a-custom-form-field-in-gravity-forms-with-a-terms-of-service-form-field-example/
* Donate link: https://wpsmith.net/donation
* Description: The first generation of this plugin will set a default image for post thumbnails for the Genesis framework.
* Version: 0.2 beta
* Author: Travis Smith
* Author URI: http://www.wpsmith.net/
* License: GPLv2
*
* Copyright 2012 Travis Smith (email : http://www.wpsmith.net/contact)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2, as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
*
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/

// Add a custom field button to the advanced to the field editor
add_filter( 'gform_add_field_buttons', 'wps_add_tos_field' );
function wps_add_tos_field( $field_groups ) {
foreach( $field_groups as &$group ){
if( $group["name"] == "advanced_fields" ){ // to add to the Advanced Fields
//if( $group["name"] == "standard_fields" ){ // to add to the Standard Fields
//if( $group["name"] == "post_fields" ){ // to add to the Standard Fields
$group["fields"][] = array(
"class"=>"button",
"value" => __("Terms of Service", "gravityforms"),
"onclick" => "StartAddField('tos');"
);
break;
}
}
return $field_groups;
}

// Adds title to GF custom field
add_filter( 'gform_field_type_title' , 'wps_tos_title' );
function wps_tos_title( $type ) {
if ( $type == 'tos' )
return __( 'Terms of Service' , 'gravityforms' );
}

// Adds the input area to the external side
add_action( "gform_field_input" , "wps_tos_field_input", 10, 5 );
function wps_tos_field_input ( $input, $field, $value, $lead_id, $form_id ){

if ( $field["type"] == "tos" ) {
$max_chars = "";
if(!IS_ADMIN && !empty($field["maxLength"]) && is_numeric($field["maxLength"]))
$max_chars = self::get_counter_script($form_id, $field_id, $field["maxLength"]);

$input_name = $form_id .'_' . $field["id"];
$tabindex = GFCommon::get_tabindex();
$css = isset( $field['cssClass'] ) ? $field['cssClass'] : '';
return sprintf("<div class='ginput_container'><textarea readonly name='input_%s' id='%s' class='textarea gform_tos %s' $tabindex rows='10' cols='50'>%s</textarea></div>{$max_chars}", $field["id"], 'tos-'.$field['id'] , $field["type"] . ' ' . esc_attr($css) . ' ' . $field['size'] , esc_html($value));

}

return $input;
}

// Now we execute some javascript technicalitites for the field to load correctly
add_action( "gform_editor_js", "wps_gform_editor_js" );
function wps_gform_editor_js(){
?>

<script type='text/javascript'>

jQuery(document).ready(function($) {
//Add all textarea settings to the "TOS" field plus custom "tos_setting"
// fieldSettings["tos"] = fieldSettings["textarea"] + ", .tos_setting"; // this will show all fields that Paragraph Text field shows plus my custom setting

// from forms.js; can add custom "tos_setting" as well
fieldSettings["tos"] = ".label_setting, .description_setting, .admin_label_setting, .size_setting, .default_value_textarea_setting, .error_message_setting, .css_class_setting, .visibility_setting, .tos_setting"; //this will show all the fields of the Paragraph Text field minus a couple that I didn't want to appear.

//binding to the load field settings event to initialize the checkbox
$(document).bind("gform_load_field_settings", function(event, field, form){
jQuery("#field_tos").attr("checked", field["field_tos"] == true);
$("#field_tos_value").val(field["tos"]);
});
});

</script>
<?php
}

// Add a custom setting to the tos advanced field
add_action( "gform_field_advanced_settings" , "wps_tos_settings" , 10, 2 );
function wps_tos_settings( $position, $form_id ){

// Create settings on position 50 (right after Field Label)
if( $position == 50 ){
?>

<li class="tos_setting field_setting">

<input type="checkbox" id="field_tos" onclick="SetFieldProperty('field_tos', this.checked);" />
<label for="field_tos" class="inline">
<?php _e("Disable Submit Button", "gravityforms"); ?>
<?php gform_tooltip("form_field_tos"); ?>
</label>

</li>
<?php
}
}

//Filter to add a new tooltip
add_filter('gform_tooltips', 'wps_add_tos_tooltips');
function wps_add_tos_tooltips($tooltips){
$tooltips["form_field_tos"] = "<h6>Disable Submit Button</h6>Check the box if you would like to disable the submit button.";
$tooltips["form_field_default_value"] = "<h6>Default Value</h6>Enter the Terms of Service here.";
return $tooltips;
}

// Add a script to the display of the particular form only if tos field is being used
add_action( 'gform_enqueue_scripts' , 'wps_gform_enqueue_scripts' , 10 , 2 );
function wps_gform_enqueue_scripts( $form, $ajax ) {
// cycle through fields to see if tos is being used
foreach ( $form['fields'] as $field ) {
if ( ( $field['type'] == 'tos' ) && ( isset( $field['field_tos'] ) ) ) {
$url = plugins_url( 'gform_tos.js' , __FILE__ );
wp_enqueue_script( "gform_tos_script", $url , array("jquery"), '1.0' );
break;
}
}
}

// Add a custom class to the field li
add_action("gform_field_css_class", "custom_class", 10, 3);
function custom_class($classes, $field, $form){

if( $field["type"] == "tos" ){
$classes .= " gform_tos";
}

return $classes;
}
[/php]