Gravity Wiz

Magically enhanced tutorials, snippets and plugins for Gravity Forms!

  • Gravity Perks
    • Gravity Perks
    • Tutorials & Snippets
    • About
  • Support
    • Documentation
    • Support
    • Account

Customizing the Multi-File Merge Tag

A simple way to create custom templates for displaying files uploaded via a Multi-File Upload field. Image files can be displayed as images, video files can be loaded as playable videos, PDFs (and other text file types) can be stylized to indicate the file type. The possibilities are endless.

Last updated August 21, 2019 | Written by David Smith 120 Comments

  • November 22, 2018: Added support for applying markup to specific fields on a specific form.

  • January 19, 2017: Fixed typo. Thanks, Tanguy!

  • July 9, 2015: Updated to automatically integrate with GP Preview Submission.

  • February 19, 2015: Fixed issue with GF 1.9 where merge tag was being replaced prematurely and incorrectly

Show All Updates
gw-multi-file-merge-tag-postPost generated with this snippet
View DemoShow CodeDownload Code
<?php
/**
* Gravity Wiz // Multi-File Merge Tag for Post Content Templates
*
* Enhance the merge tag for multi-file upload fields by adding support for outputting markup that corresponds to the
* uploaded file. Example: image files will be wrapped in an <img> tag. Out of the box, this snippet only supports
* images and is limited to the 'jpg', 'png', and 'gif'.
*
* The default merge tag for the multi-file upload field will output the URL for each of the files.
*
* @version 1.4
* @author David Smith <david@gravitywiz.com>
* @license GPL-2.0+
* @link http://gravitywiz.com/...
* @copyright 2018 Gravity Wiz, LLC.
*/
class GW_Multi_File_Merge_Tag {
private static $instance = null;
/**
* Temporarily stores the values of the 'gform_merge_tag_filter' filter for use in the 'gform_replace_merge_tags' filter.
*
* @var array
*/
private $_merge_tag_args = array();
private $_settings = array();
private function __construct() {
add_filter( 'gform_pre_replace_merge_tags', array( $this, 'replace_merge_tag' ), 10, 7 );
}
public static function get_instance() {
if( null == self::$instance )
self::$instance = new self;
return self::$instance;
}
public function get_default_args() {
return array(
'form_id' => false,
'field_ids' => array(),
'exclude_forms' => array(),
'default_markup' => '<li><a href="{url}">{filename}.{ext}</a></li>',
'markup' => array(
array(
'file_types' => array( 'jpg', 'png', 'gif' ),
'markup' => '<img src="{url}" width="33%" />'
),
array(
'file_types' => array( 'mp4', 'ogg', 'webm' ),
'markup' => '<video width="320" height="240" controls>
<source src="{url}" type="video/{ext}">
Your browser does not support the video tag.
</video>'
),
array(
'file_types' => array( 'ogv' ),
'markup' => '<video width="320" height="240" controls>
<source src="{url}" type="video/ogg">
Your browser does not support the video tag.
</video>'
)
)
);
}
public function register_settings( $args = array() ) {
$args = wp_parse_args( $args, $this->get_default_args() );
if( ! $args['form_id'] ) {
$this->_settings['global'] = $args;
} else {
$this->_settings[$args['form_id']] = $args;
}
}
public function replace_merge_tag( $text, $form, $entry, $url_encode, $esc_html, $nl2br, $format ) {
preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $text, $matches, PREG_SET_ORDER );
foreach( $matches as $match ) {
$input_id = $match[1];
$field = GFFormsModel::get_field( $form, $input_id );
if( ! $this->is_applicable_field( $field ) ) {
continue;
}
if( $format != 'html' ) {
$value = $this->_merge_tag_args['value'];
} else {
if( $entry['id'] == null && is_callable( array( 'GWPreviewConfirmation', 'preview_image_value' ) ) ) {
$files = GWPreviewConfirmation::preview_image_value( 'input_' . $field->id, $field, $form, $entry );
} else {
$value = GFFormsModel::get_lead_field_value( $entry, $field );
$files = empty( $value ) ? array() : json_decode( $value, true );
}
$value = '';
if( $files ) {
foreach( $files as &$file ) {
$value .= $this->get_file_markup( $file, $form['id'] );
$value = str_replace( $file, $field->get_download_url( $file, false ), $value );
}
}
}
$has_value = ! empty( $value );
// Replace each instance of our merge tag individually so we can check if it is part of a [gf conditional]
// shortcode; if so, replace the value with 1 so it can correctly evaluate as having a value.
do {
$pos = strpos( $text, $match[0] );
if ( $pos !== false ) {
$replace = substr( $text, $pos - 11, 10 ) == 'merge_tag=' ? $has_value : $value;
$text = substr_replace( $text, $replace, $pos, strlen( $match[0] ));
}
} while( $pos !== false );
}
return $text;
}
public function get_file_markup( $file, $form_id ) {
$value = str_replace( " ", "%20", $file );
$file_info = pathinfo( $value );
extract( $file_info ); // gives us $dirname, $basename, $extension, $filename
if( ! $extension )
return $value;
$markup_settings = $this->get_markup_settings( $form_id );
if( empty( $markup_settings ) )
return $value;
$markup_found = false;
foreach( $markup_settings as $file_type_markup ) {
$file_types = array_map( 'strtolower', $file_type_markup['file_types'] );
if( ! in_array( strtolower( $extension ), $file_types ) )
continue;
$markup_found = true;
$markup = $file_type_markup['markup'];
$tags = array(
'{url}' => $file,
'{filename}' => $filename,
'{basename}' => $basename,
'{ext}' => $extension
);
foreach( $tags as $tag => $tag_value ) {
$markup = str_replace( $tag, $tag_value, $markup );
}
$value = $markup;
break;
}
if( ! $markup_found && $default_markup = $this->get_default_markup( $form_id ) ) {
$tags = array(
'{url}' => $file,
'{filename}' => $filename,
'{basename}' => $basename,
'{ext}' => $extension
);
foreach( $tags as $tag => $tag_value ) {
$default_markup = str_replace( $tag, $tag_value, $default_markup );
}
$value = $default_markup;
}
return $value;
}
public function get_markup_settings( $form_id ) {
$form_markup_settings = rgars( $this->_settings, "$form_id/markup" ) ? rgars( $this->_settings, "$form_id/markup" ) : array();
$global_markup_settings = rgars( $this->_settings, 'global/markup' ) ? rgars( $this->_settings, 'global/markup' ) : array();
return array_merge( $form_markup_settings, $global_markup_settings );
}
public function get_default_markup( $form_id ) {
$default_markup = rgars( $this->_settings, "$form_id/default_markup" );
if( ! $default_markup )
$default_markup = rgars( $this->_settings, 'global/default_markup' );
return $default_markup;
}
public function is_excluded_form( $form_id ) {
$has_global_settings = isset( $this->_settings['global'] );
$excluded_forms = (array) rgars( $this->_settings, 'global/exclude_forms' );
$explicity_excluded = $has_global_settings && in_array( $form_id, $excluded_forms );
$passively_excluded = ! $has_global_settings && ! isset( $this->_settings[$form_id] );
return $explicity_excluded || $passively_excluded;
}
public function is_applicable_field( $field ) {
$field_ids = rgars( $this->_settings, "{$field->formId}/field_ids" );
$is_valid_form = ! $this->is_excluded_form( $field['formId'] );
$is_matching_field_id = empty( $field_ids ) || in_array( $field->id, $field_ids );
$is_file_upload_filed = GFFormsModel::get_input_type( $field ) == 'fileupload';
$is_multi = rgar( $field, 'multipleFiles' );
return $is_valid_form && $is_matching_field_id && $is_file_upload_filed && $is_multi;
}
}
function gw_multi_file_merge_tag() {
return GW_Multi_File_Merge_Tag::get_instance();
}
# Usage
gw_multi_file_merge_tag()->register_settings();
view raw gw-gravity-forms-multi-file-merge-tag.php hosted with ❤ by GitHub

Gravity Forms v1.8 adds support for the much desired multi-file uploads field. Just add a File Upload field to your form, check the “Enable Multi-File Upload” setting on the field, and just like that, you’ll find yourself in multi-file upload heaven.

Like every other Gravity Forms field, the Multi-File Upload field has a merge tag that can be used in Notifications, Confirmations, Post Content Templates, and more. It looks something like {Files:2} (where “Files” is the field label and “2” is the ID of the field).

By default, this merge tag will output a simple list of the file URLs that were uploaded.

http://myurl.com/../Tulips8.jpg
http://myurl.com/../Penguins11.jpg
http://myurl.com/../Lighthouse11.jpg

This isn’t a very pretty (or useful) way to display these files for the end user.

This snippet provides a simple way to provide custom markup (HTML) templates for displaying these file URLs. Image URLs can be displayed as images, video URLs can be loaded as playable videos, PDFs (and other text file types) can be stylized more attractively to indicate the file type, and so on. The possibilities are endless.

How do I get started?

  1. Make sure you’re running Gravity Forms v1.8 or later.
    • Already have a license? Download Latest Gravity Forms
    • Need a license? Buy Gravity Forms
  2. Copy and paste the snippet into your theme’s functions.php file.
  3. Review the usage instructions below to configure the snippet for your needs.

Basic Usage

Applies default markup to all forms.

gw_multi_file_merge_tag()->register_settings();

Exclude Form(s)

Applies default markup to all forms excluding the specified forms.

gw_multi_file_merge_tag()->register_settings( array(
'exclude_forms' => 2 // multiple forms: array( 2, 4 )
) );

Specific Form

Applies default markup to a specific form.

gw_multi_file_merge_tag()->register_settings( array(
'form_id' => 402
) );

Specific Field(s) on a Specific Form

Applies default markup to a specific field on a specific form.

gw_multi_file_merge_tag()->register_settings( array(
'form_id' => 123,
'field_ids' => array( 1 ),
) );

Specific Form w/ Custom Markup

Applies custom markup to a specific form. If the snippet has also been configured to apply the default markup to all forms, the markup provided here will override the default markup for this form.

gw_multi_file_merge_tag()->register_settings( array(
'form_id' => 402,
'markup' => array(
array(
'file_types' => array( 'jpg', 'jpeg', 'png', 'gif' ),
'markup' => '<div class="gw-image"><a href="{url}" class="gw-image-link"><img src="{url}" width="100%" /></a><span>{filename}</span></div>'
),
array(
'file_types' => array( 'mp4', 'ogg', 'webm' ),
'markup' => '<video width="320" height="240" controls>
<source src="{url}" type="video/{ext}">
Your browser does not support the video tag.
</video>'
)
)
) );

Parameters

  • form_id (int) The ID of the form to which this snippet should be applied. Defaults to false. If you want to apply this snippet to all forms, do not pass this parameter.
  • field_ids (array) An array of field IDs (belonging to the passed form_id) to which the markup should be applied.
  • exclude_forms (int|array) A single form ID or array of form IDs that should be excluded from this snippet. Defaults to array().
  • markup (array) An array of arrays, with each child array having a ‘file_types’ and ‘markup’ property. See the Default Markup section for default values.
    • file_types (array) An array of file types for which this markup should apply.
    • markup (string) An HTML-based template for how the file type should be displayed. See Markup Merge Tags for a list of available merge tags that can be used in this template.

Default Markup

Here is a list of the default markup that comes packaged with the snippet. Default support is limited to images (“jpg”, “jpeg”, “png” and “gif”) and videos (“mp4”, “ogg”, “ogv”, “webm”). If you’d think there are more file types that should be supported, leave a comment with the file type and suggested markup.

'exclude_forms' => array(),
'default_markup' => '<li><a href="{url}">{filename}.{ext}</a></li>',
'markup' => array(
array(
'file_types' => array( 'jpg', 'png', 'gif' ),
'markup' => '<img src="{url}" width="33%" />'
),
array(
'file_types' => array( 'mp4', 'ogg', 'webm' ),
'markup' => '<video width="320" height="240" controls>
<source src="{url}" type="video/{ext}">
Your browser does not support the video tag.
</video>'
),
array(
'file_types' => array( 'ogv' ),
'markup' => '<video width="320" height="240" controls>
<source src="{url}" type="video/ogg">
Your browser does not support the video tag.
</video>'

Markup Merge Tags

The markup parameter supports the usage of the following merge tags which provide access to information about the uploaded file. See the Default Markup section and custom markup usage example for examples of usage.

http://myurl.com/.../Tulips8.jpg

  • {url} The URL of the file (i.e. “http://myurl.com/…/Tulips8.jpg”).
  • {filename} The name of the file (i.e. “Tulips8”).
  • {basename} The name of the file including the extension (i.e. “Tulips8.jpg”).
  • {ext} The extension of the file (i.e. “jpg”)

Summary

If there are more file types that should be supported, leave a comment with the file type and suggested markup. And if you use it and like it, let me know!

Demo Configuration & Styles — Want to use the configuration and styling from the demo? Here is the PHP and CSS.

Did this resource help you do something awesome with Gravity Forms? Then you'll absolutely love Gravity Perks; a suite of 31+ essential add-ons for Gravity Forms with support you can count on.

  • View All Perks
  • Buy Gravity Perks

Filed Under: Snippets

Comments

  1. Taylor Curry says

    February 12, 2018 at 10:14 pm

    Hello!

    Such cool code. I have been looking for a way to do this for a long time. I have one question though –

    Is there any way to have it use the Gravity Perks “Gravity Forms Media Library” to have the media upload directly to the media library and not to the gravity forms uploads area?

    Thank you!

    Reply
  2. Edi Michael says

    December 17, 2017 at 9:39 pm

    Hi David, If I have multiple forms and different field to configure, how should I configure the code?

    Reply
    • David Smith says

      December 17, 2017 at 9:58 pm

      Hi Edi, this will help: https://gravitywiz.com/documentation/apply-class-based-snippet-different-forms/

  3. BCI Media says

    October 27, 2017 at 2:04 pm

    Hey David,

    Big thanks for this snippet! Our team has taken it one step further to display all of the uploaded photos in a Slick Slider, works like a charm. The only caveat is that any portrait-oriented photos that are uploaded get flipped 90 degrees to be displayed in landscape orientation. Here’s an example using your demo: http://demos.gravitywiz.com/my-post-title-530/, you can see this happening to ‘1_Peak_Portrait’ and ‘2_Keyhole’. I am obviously experiencing the same issue when creating test posts on our site. I’ve confirmed that it’s not coming from camera settings, I’ve tested with photos from a DLSR and iPhone photos, no difference. What is really interesting is that even if I go into the Media Library where these photos get saved (I have the multi-file upload field set to save uploads to the Media Library) and flip them back to portrait and save them, they still display landscape in the post, and I have confirmed that this isn’t a caching issue. Any suggestions?

    Thanks for your time!

    Reply
    • BCI Media says

      October 27, 2017 at 3:49 pm

      David,

      We’ve figured out why altering the image in Media Library and saving provides no results, because WordPress creates an entirely new URL for edited images, which would then need to be updated in the post editor… Still looking for ideas on why portrait photos get uploaded sideways in landscape orientation in the first place, I’m 99% sure it’s not coming from EXIF settings. Thanks!

    • David Smith says

      October 28, 2017 at 9:11 am

      Hey BCI Media, I’m not sure on this one. This snippet doesn’t actually handling uploading the images; Gravity Forms does that. I’d ping the GF support team and see if they have a solution for this. :)

  4. Hosea says

    August 2, 2017 at 4:06 am

    David, first off thank you for this snippet as well as the wonderful support you have provided within these comments. I’m wondering how I could go about combining the multiple files uploaded by the user into a single archive. I understand if this is too much customization to get into here, but hoping you might have a direction to point me in, to get started. Thank you!

    Reply
    • David Smith says

      August 12, 2017 at 6:23 pm

      Hi Hosea, we actually have a snippet that will do this.

      https://gist.github.com/spivurno/4ef44d4d4bd62faf94ae

      If you’re a Gravity Perks customer, we’ll be happy to provide additional support for this snippet via the support form.

  5. will says

    June 11, 2017 at 9:57 am

    What about these extensions? array(“PDF”, “DOC”, “ZIP”, “RAR”)

    Reply
    • will says

      June 11, 2017 at 10:05 am

      I will just like to add that I’m trying to allow someone to use the Gravity Form to upload zip, rar, 7z and it shows on the post same as the images do. Therefore, if you’re a visitor you and not a user submitting content you can easily download the content via post.

    • David Smith says

      June 12, 2017 at 9:14 am

      Hi Will, this snippet is designed as a starting point and does not cover every file type. See the “Specific Form w/ Custom Markup” example for how you can add your own markup for different file types.

« Older Comments

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Categories

  • How To (34)
  • News (21)
  • Plugins (8)
  • Releases (7)
  • Resource (2)
  • Snippets (53)
  • Tutorials (42)
  • Updates (80)

Recent Posts

  • Complete Guide to Gravity Forms WooCommerce Integration
  • Gravity Wiz Weekly #80
  • Complete Guide to Gravity Forms Conditional Logic
  • Exporting with Nested Forms
  • Gravity Wiz Weekly #79

Meta

  • Log in
  • Entries RSS
  • Comments RSS
  • WordPress.org

Copyright © 2019 · Powered by WordPress · Gravity Wiz LLC · Log out

  • Support
  • Affiliates
  • About
  • Sitemap
  • Gravity Perks
    ▼
    • Gravity Perks
    • Tutorials & Snippets
    • About
  • Support
    ▼
    • Documentation
    • Support
    • Account