Skip to content

Instantly share code, notes, and snippets.

@Striffly
Last active July 3, 2024 15:35
Show Gist options
  • Save Striffly/fa79b85901dd6c98a8075a35d7dc45ee to your computer and use it in GitHub Desktop.
Save Striffly/fa79b85901dd6c98a8075a35d7dc45ee to your computer and use it in GitHub Desktop.
Gravity Forms with AJAX, conditional logic, pages transitions (compatible with Barba.js, Taxi.js, Highway.js, ...)

The following code enables the use of Gravity Forms (2.8.7 as of now) with the following features:

  • AJAX loading, 100% functional
  • Functional with page transitions (Barba.js, Taxi.js, Highway.js)
  • Enqueue Gravity Forms scripts used by each forms (including conditional logic scripts)
  • Works with recaptcha (with recent version of Gravity Forms reCAPTCHA Add-On, scripts are automaticaly enqueued)
  • Keep the form displayed after submission (optional)
  • Scripts moved to footer (optional)

The code was initially integrated into projects using roots/sage. I adapted the code for integration into "vanilla" WordPress projects but I have less feedback compared to the use I have with my stack, so feel free to let me know if there are any errors in the comments!

<div class="js-gravity-form" data-id="<?php echo $formId ?>">
<?php if (is_admin()) {
echo gravity_form($formId, false, false, false, false, false, 0, false);
}
?>
</div>
// import { ScrollTrigger } from 'gsap/ScrollTrigger';
class Forms {
constructor() {
if (typeof jQuery === 'undefined') return;
this.events();
this.loadForms();
}
events() {
document.addEventListener('gform_main_scripts_loaded', () => {
if (typeof gform === 'undefined') return;
gform.scriptsLoaded = !0;
this.loadForms();
});
// (optional) Hooks related to form display after form submit
jQuery(document).on('gform_post_render', (event, form_id, current_page) => {
const formEl = document.querySelector(`.js-gravity-form.loaded[data-id="${form_id}"]`);
if (formEl) {
// Remove confirmation messages after form submit
if (formEl.classList.contains('submitted')) {
formEl.classList.remove('submitted');
} else {
const confirmationMessagesContainer = formEl.querySelector('.gform_confirmation_wrapper');
if (confirmationMessagesContainer) {
confirmationMessagesContainer.remove();
}
}
// Remove empty divs after form submit
const emptyDivs = formEl.querySelectorAll('.gform_custom_empty_div');
emptyDivs.forEach((emptyDiv) => {
emptyDiv.remove();
});
}
});
// (optional) Show form again after form submit
jQuery(document).on('gform_confirmation_loaded', (event, formId) => {
const ev = new CustomEvent('gform_submitted', { detail: { event, formId } });
window.dispatchEvent(ev);
const formEl = document.querySelector(`.js-gravity-form.loaded[data-id="${formId}"]`);
if (formEl) {
formEl.classList.add('submitted');
const fields = formEl.querySelector('form').querySelectorAll('input:not([type=submit]):not([type=hidden]), textarea, select');
fields.forEach((input) => {
if (input.type === 'radio' || input.type === 'checkbox') {
input.checked = '';
} else {
input.value = '';
}
});
const wrapper = formEl.querySelector('.gform_wrapper');
wrapper.style.removeProperty('display');
this.loadFormHooks(formId);
}
});
}
loadForms() {
if (typeof gform === 'undefined' || !gform.scriptsLoaded || !gform.domLoaded) return;
const formContainers = document.querySelectorAll('.js-gravity-form');
for (const formContainer of formContainers) {
if (formContainer.classList.contains('loaded')) continue;
formContainer.classList.add('loaded');
const formId = formContainer.dataset.id;
fetch(`${wp_vars.adminAjax}?action=gf_get_form&form_id=${formId}`, {
method: 'GET',
credentials: 'same-origin',
})
.then((res) => res.json())
.then((datas) => {
const html = datas.data;
jQuery(formContainer).html(html);
this.loadFormHooks(formId);
// use it if you are using ScrollTrigger, ScrollSmoother, etc.
// ScrollTrigger.refresh();
const ev = new CustomEvent('gform_loaded', { detail: { formId } });
window.dispatchEvent(ev);
});
}
}
loadFormHooks(formId) {
jQuery(document).trigger('gform_post_render', [parseInt(formId), 0]);
if (window.gformInitDatepicker) {
window.gformInitDatepicker();
}
if (window.gformInitPriceFields) {
window.gformInitPriceFields();
}
}
}
document.addEventListener("DOMContentLoaded", function() {
gform.domLoaded = !0;
new Forms();
});
<?php
// [...]
/** GRAVITY FORMS RELATED FUNCTIONS & HOOKS **/
/**
* Open numeric keypad on mobile for number fields in gravity forms
* https://wire.gravityhopper.com/d/35-open-numeric-keypad-on-mobile-for-number-fields
*/
add_filter('gform_field_content', function ($content, $field, $value, $lead_id, $form_id) {
if (wp_is_mobile() && ($field instanceof GF_Field_Number || $field instanceof GF_Field_Quantity)) {
$content = str_replace("type='", "inputmode='decimal' type='", $content);
}
return $content;
}, 10, 5);
/**
* Disable the native auto-scroll feature on form errors
*/
add_filter('gform_confirmation_anchor', '__return_false');
/**
* Force add Gravity Forms hooks to all pages
*/
add_filter( 'gform_force_hooks_js_output', '__return_true' );
/**
* (optional) Allow the Gravity form to stay on the page when confirmation displays.
* Forked from https://gist.github.com/davidwolfpaw/0fa37230c9dbb197ed4a8bbc1c7e9547
*/
add_filter('gform_pre_submission_filter', 'gf_show_confirmation_and_form');
function gf_show_confirmation_and_form($form)
{
// Inserts a shortcode for the form without title or description
$shortcode = '[gravityform id="' . $form['id'] . '" title="false" description="false" ajax="true"]';
// Ensures that new lines are not added to HTML Markup
ob_start();
echo do_shortcode($shortcode);
$html = str_replace(array("\r", "\n"), '', trim(ob_get_clean()));
$html = preg_replace('#<script(.*?)>(.*?)</script>#is', '', $html);
$html = preg_replace('#<iframe(.*?)>(.*?)</iframe>#is', '', $html);
// Inserts the form into parent div
if (array_key_exists('confirmations', $form)) {
$lastKey = array_key_last($form['confirmations']);
$form['confirmations'][$lastKey]['message'] = $form['confirmations'][$lastKey]['message'] . '</div></div>' . $html . '<div class="gform_custom_empty_div"><div>';
}
return $form;
}
/**
* (optional) Move Gravity Forms scripts to footer
*/
add_filter('gform_init_scripts_footer', 'gform_init_scripts');
function gform_init_scripts() {
return true;
}
/** AJAX **/
add_action('wp_ajax_nopriv_gf_get_form', 'gf_ajax_get_form');
add_action('wp_ajax_gf_get_form', 'gf_ajax_get_form');
function gf_ajax_get_form()
{
if (!isset($_GET['form_id'])) {
wp_send_json_error();
exit;
}
$formId = absint($_GET['form_id']);
wp_send_json_success( gravity_form($formId, false, false, false, false, true, 0, false) );
exit;
}
/** ENQUEUE SCRIPTS */
function get_wp_variables() {
return [
'adminAjax' => admin_url('admin-ajax.php'),
];
}
wp_enqueue_script(
'forms',
get_stylesheet_directory_uri() . '/forms.js',
array( 'jquery' )
);
wp_localize_script( 'forms', 'wp_vars', $get_wp_variables );
@Striffly
Copy link
Author

Striffly commented May 13, 2024

I found this code in the form_display.php file of the Gravity Forms plugin.
What's quite surprising is that I don't see any place where the variable event is initialized. I might be mistaken (because it was a "quick" look), but it seems to me that the variable event is not initialized anywhere else.

It's also possible that this bug is caused by my use of hooks in the header/footer and/or in my JavaScript, and it may not be a case managed by Gravity Forms. I wouldn't be surprised if there are unhandled bugs related to this combination of using Gravity Forms via AJAX and the hooks called in my code. I haven't seen any documentation regarding the PHP hooks, I found them by myself.

Perhaps you could submit a bug report or contact Gravity Forms technical support about this code ? (https://www.gravityforms.com/open-support-ticket/technical/)

With this code, the bug will be resolved :

if (event && event.defaultPrevented)

@gonzalo-terrahq
Copy link

Exactly!!! That's what I had concluded, that event was not initialized anywhere, hence the error. I have modified the plugin file and it works correctly. Thanks for your help @Striffly , I will write to support because it is indeed a bug.

@Striffly
Copy link
Author

Exactly!!! That's what I had concluded, that event was not initialized anywhere, hence the error. I have modified the plugin file and it works correctly. Thanks for your help @Striffly , I will write to support because it is indeed a bug.

You welcome 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment