Make Gravity Forms’ JavaScript load in the footer

Gravity Forms is not only THE way to create and manage forms in WordPress, but is also pretty awesome when it comes to extensibility and flexibility. However, as most software, it has its issues. One of those is how it outputs some of the JavaScript, which in certain cases will break your site. This is how to fix it.

This week I was helping out on a site that handled everything right when it comes to JavaScript: All of it was concatenated, minified and loaded in the footer. But this site also needed a form to be loaded programmatically with the gravity_form() function and using AJAX to handle the submission. To my horror, Gravity Forms outputs quite a lot of jQuery dependent JavaScript right after the form element. This is bad considering best practices for fast loading, but was a total failure considering that jQuery wouldn’t be loaded by the time and causing the form to malfunction.

Actually, as you can see from this screenshot, is that there are two blocks of JavaScript in the source: One that handles the form submission, and one that initializes the form:

Gravity Forms inline JavaScript

Luckily, as Gravity Forms have a lot of filter and action hooks available, the second block is easily moved to the footer with a single line:

add_filter('gform_init_scripts_footer', '__return_true');

But for the first block, we’re not so lucky. It is all part of the long concatenated HTML output that GF produces:

Gravity Forms concatenated $form_string

But if you look closely, there is in fact filter hooks both in the beginning and in the end of that JavaScript section. With a little clever trickery we can encapsulate that in a JS event callback that won’t run until after the content of the page have loaded:

add_filter( 'gform_cdata_open', 'wrap_gform_cdata_open' );
function wrap_gform_cdata_open( $content = '' ) {
	$content = 'document.addEventListener( "DOMContentLoaded", function() { ';
	return $content;
}
add_filter( 'gform_cdata_close', 'wrap_gform_cdata_close' );
function wrap_gform_cdata_close( $content = '' ) {
	$content = ' }, false );';
	return $content;
}

This won’t help us with the load speed issue (that JS should be run in the footer because the browser halts all loading whenever a <javascript> block is encountered), but at least the execution of the script block will be delayed until the DOMContentLoaded event is triggered – at which point jQuery will be loaded.

13 Comments

  1. Hi Bjørn,

    Thanks for this! I was searching for a fix like this for a long time.
    I do have a bugfix though! I noticed this when the forms redirects with ajax after submitting.

    The problem is with ajax. When doing ajax the event listener shouldn’t be added to the return values.
    Here is my full version:

    `
    add_filter( ‘gform_init_scripts_footer’, ‘__return_true’ );
    add_filter( ‘gform_cdata_open’, ‘wrap_gform_cdata_open’, 1 );
    function wrap_gform_cdata_open( $content = ” ) {
    if ( ( defined(‘DOING_AJAX’) && DOING_AJAX ) || isset( $_POST[‘gform_ajax’] ) ) {
    return $content;
    }
    $content = ‘document.addEventListener( “DOMContentLoaded”, function() { ‘;
    return $content;
    }
    add_filter( ‘gform_cdata_close’, ‘wrap_gform_cdata_close’, 99 );
    function wrap_gform_cdata_close( $content = ” ) {
    if ( ( defined(‘DOING_AJAX’) && DOING_AJAX ) || isset( $_POST[‘gform_ajax’] ) ) {
    return $content;
    }
    $content = ‘ }, false );’;
    return $content;
    }
    `

    Again, thanks!!

  2. I have been using Gravityforms for probably 4-5 years and early on purchased the developer license. Love love love it! At one point, I added the Gravityforms Nocaptcha Recaptcha – and it works fine except now that I’m fine tuning performance on my sites, I’m finding that the recaptcha__en.js that gets loaded takes almost 500ms. My pageload speed with pingdom is 1.5 seconds – so this would drop by a good deal if I can get the recaptcha js to load faster. Any advice?

  3. Please help me to put all of the script of gravity form in the footer. I copy and paste your code but there’s a inline script left at the bottom of the . I’am running google page speed and when i put the jquery library at the footer then the inline script left being error because there’s no library at the head.

    Thank in advance!

  4. Hi this code definitely sped up the load time but on submission the form did not redirect to the thankyou page and the spinny icon just stayed, it is an ajax form so I tried the amended code by Jory but the form did not even load? Any advice would be greatly appreciated using gravity forms Version 2.1.1.24

  5. Hello PPL.

    NB. UNFINISHED CODE NOT WORKING:

    Moves form script and iframe to bottom, I messed around with position with no luck. I’m posting this for somebody to finish. I sadly don’t have time to finish it :(

    add_filter( ‘gform_get_form_filter’, ‘gf_html_manipulate’, 99, 2); //
    function gf_html_manipulate( $form_string, $form ) {

    // Do better if performance issues
    if (strpos($form_string, ‘ajax’) !== false) {

    $gf_form_html_dom = new DOMDocument();
    $gf_form_html_dom->loadHTML(mb_convert_encoding($form_string, ‘HTML-ENTITIES’, ‘UTF-8’));

    // elements to varibles
    $gf_iframe = $gf_form_html_dom->getElementsByTagName( ‘iframe’ )->item(0);
    $gf_inline_scripts = $gf_form_html_dom->getElementsByTagName( ‘script’ )->item(0); // do your loop stuff if more // http://stackoverflow.com/questions/15272726/how-to-delete-element-with-domdocument

    //remove the node by telling the parent node to remove the child
    $gf_iframe->parentNode->removeChild($gf_iframe);
    $gf_inline_scripts->parentNode->removeChild($gf_inline_scripts);

    $str_gf_iframe = $gf_form_html_dom->saveHTML( $gf_iframe);;
    $str_gf_inline_scripts = $gf_form_html_dom->saveHTML( $gf_inline_scripts);

    add_action( ‘wp_footer’, function( $arg ) use ($str_gf_iframe, $str_gf_inline_scripts ) {
    echo $str_gf_iframe;
    echo $str_gf_inline_scripts;
    }, 10, 2); // 10, 2 is top , 99, 2 all bottom

    return $gf_form_html_dom->saveHTML(); // script and iframe removed.
    }
    else {
    return $form_string; // normal
    }

    }

Comments are closed.