Custom field merge tags for Gravity Forms

Gravity Forms custom merge tags

Being so overdue for a post, this isn’t the subject I planned on writing about next, but a little nudge from a reader has brought it to the top of the list.

Earlier this year I worked on a project for which I created a dynamic events sign-up page using Gravity Forms. I needed to make it as easy as possible for the client, so essentially the idea was that she never have to actually the edit the form itself in any way. The content would come from a custom post type that I created, allowing her to add events. The form would then be generated from a dynamic link from the events pages, telling it what information to display.

Most of it I had worked out. Using string variables I defined different events “types”, and then used Gravity Forms dynamic populate fields function. Based on the type, conditional logic allowed me to further adjust my form information to be appropriate to the type of event the user wanted to sign up for.

But something was missing, something not native to Gravity Forms (not yet in any case): I needed to be able to import specific data from custom fields defined in the custom post. I needed merge tags for my custom fields. I considered creating more string variables, which would have worked for the price field, but another custom field contained a large quantity of text. It would not have been practical by any means to carry over through the URL, and it was a requirement – the client had to be able to change that text for each event.

So I browsed around, and finally hit up David over at Gravity Wiz. His site had helped me with other projects in the past, and I kind of assumed he – or someone – would have come up with a solution. I couldn’t be the only one with these needs…

The idea had probably been mulled over before, but curiously had yet to be created. David graciously offered to write me up some code, for a small and very worth while fee. This was originally going to be posted on his site first, but busy as he is, it’s time we shared!

Paste the following into your theme’s functions.php

[pastacode lang=”php” message=”” highlight=”” provider=”manual”]

/**
* Advanced Merge Tags
* http://gravitywiz.com/
*/

class GWAdvancedMergeTags {

/**
* @TODO:
* - add support for validating based on the merge tag
* - add support for merge tags in dynamic population parameters
* - add merge tag builder
*
*/

function __construct() {

add_action( 'gform_pre_render', array( $this, 'support_default_value_and_html_content_merge_tags' ) );
add_action( 'gform_pre_render', array( $this, 'support_dynamic_population_merge_tags' ) );
add_action( 'gform_replace_merge_tags', array( $this, 'replace_merge_tags' ) );

}

function support_default_value_and_html_content_merge_tags( $form ) {

$current_page = isset( GFFormDisplay::$submission[$form['id']] ) ? GFFormDisplay::$submission[$form['id']]['page_number'] : 1;
$fields = array();

foreach( $form['fields'] as &$field ) {

$default_value = rgar( $field, 'defaultValue' );
preg_match_all( '/{.+}/', $default_value, $matches, PREG_SET_ORDER );
if( ! empty( $matches ) ) {
if( rgar( $field, 'pageNumber' ) != $current_page ) {
$field['defaultValue'] = '';
} else {
$field['defaultValue'] = self::replace_merge_tags( $default_value );
}
}

// only run 'content' filter for fields on the current page
if( rgar( $field, 'pageNumber' ) != $current_page )
continue;

$html_content = rgar( $field, 'content' );
preg_match_all( '/{.+}/', $html_content, $matches, PREG_SET_ORDER );
if( ! empty( $matches ) )
$field['content'] = self::replace_merge_tags( $html_content );

}

return $form;
}

function support_dynamic_population_merge_tags( $form ) {

$filter_names = array();

foreach($form['fields'] as &$field) {

if(!rgar($field, 'allowsPrepopulate'))
continue;

// complex fields store inputName in the "name" property of the inputs array
if(is_array(rgar($field, 'inputs')) && $field['type'] != 'checkbox') {
foreach($field['inputs'] as $input) {
if(rgar($input, 'name'))
$filter_names[] = array('type' => $field['type'], 'name' => rgar($input, 'name'));
}
} else {
$filter_names[] = array('type' => $field['type'], 'name' => rgar($field, 'inputName'));
}

}

foreach($filter_names as $filter_name) {

// do standard GF prepop replace first...
$filtered_name = GFCommon::replace_variables_prepopulate($filter_name['name']);

// if default prepop doesn't find anything, do our advanced replace
if( $filter_name['name'] == $filtered_name )
$filtered_name = self::replace_merge_tags( $filter_name['name'] );

if( $filter_name['name'] == $filtered_name )
continue;

add_filter("gform_field_value_{$filter_name['name']}", create_function("", "return '$filtered_name';"));
}

return $form;
}

public static function replace_merge_tags( $text ) {

//preg_match_all( '/{([a-z_]+):([a-z0-9&,_=-]+)}/mi', $text, $matches, PREG_SET_ORDER );
preg_match_all( '/{([a-z_]+):([a-z0-9&,_=)(\-]+)}/mi', $text, $matches, PREG_SET_ORDER );
if( empty( $matches ) )
return $text;

foreach( $matches as $match ) {

list( $tag, $type, $args ) = array_pad( $match, 3, false );
parse_str( $args, $args );

$args = array_map( array( __class__, 'check_for_value_modifiers' ), $args );
$value = '';

switch( $type ) {
case 'post':
$value = self::get_post_merge_tag_value( $args );
break;
case 'post_meta':
case 'custom_field':
$value = self::get_post_meta_merge_tag_value( $args );
break;
}

$text = str_replace( $tag, $value, $text );

}

return $text;
}

public static function check_for_value_modifiers( $text ) {

// modifier regex (i.e. "get(value)")
preg_match_all( '/([a-z]+)\(([a-z_\-]+)\)/mi', $text, $matches, PREG_SET_ORDER );
if( empty( $matches ) )
return $text;

foreach( $matches as $match ) {

list( $tag, $type, $arg ) = array_pad( $match, 3, false );
$value = '';

switch( $type ) {
case 'get':
$value = rgget( $arg );
break;
case 'post':
$value = rgpost( $arg );
break;
}

$text = str_replace( $tag, $value, $text );

}

return $text;
}

public static function get_post_merge_tag_value( $args ) {

extract( wp_parse_args( $args, array(
'id' => false,
'prop' => false
) ) );

if( !$id || !$prop )
return '';

$post = get_post( $id );
if( !$post )
return '';

return isset( $post->$prop ) ? $post->$prop : '';
}

public static function get_post_meta_merge_tag_value( $args ) {

extract( wp_parse_args( $args, array(
'id' => false,
'meta_key' => false
) ) );

if( !$id || !$meta_key )
return '';

$value = get_post_meta( $id, $meta_key, true );

return $value;
}

}

new GWAdvancedMergeTags();

[/pastacode]

Then, just insert the merge tag where you need it to show up on your form :

[pastacode lang=”php” message=”” highlight=”” provider=”manual”]

{post_meta:id=get(id)&meta_key=CUSTOM-FIELD} 

[/pastacode]

Where CUSTOM-FIELD is the name of your, well, custom field! smile

Et voilà ! Cool, huh? Enjoy!
And big thanks to Bea for the nudge wink

**EDIT**
I did forget one important step: it is necessary to pass the post ID to the form. In my example, I did this via the URL. My dynamic link looks like this:

[pastacode lang=”markup” message=”” highlight=”” provider=”manual”]

<a href="sign-up/?id=<?php echo $events->post->ID; ?>&type=<?php echo $term-slug; ?>">

[/pastacode]

Jenny Beaumont

Jenny Beaumont is an Agile Coach and the Director of Delivery at Human Made, makers of Altis DXP. She speaks at conferences around the world (ok, these days only on zoom), and is a former lead organizer of WordCamp Paris and WordCamp Europe.

Follow me on Twitter | Subscribe to my newsletter