Multi-Instance Sync for Gravity Forms
by Smithfield · github.com/smithfield-studio/gravity-forms-multi-instance-sync · website
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/smithfield-studio/gravity-forms-multi-instance-sync/archive/refs/heads/main.zipPlace the same Gravity Form more than once on a page, for example at the top and bottom of a landing page, or in a mobile-only and a desktop-only block.
Gravity Forms doesn't support this on its own: every copy of a form shares the same element IDs, so the second copy's steps, validation, AJAX submission and conditional logic act on the first (Gravity Forms docs). Plugins that rename the copies' IDs depend on matching Gravity Forms' markup exactly and break as it changes.
How it works
- Each form renders once per page. Later placements render an empty slot with a link to the form.
- When a slot is about to scroll into view, the form moves into it: one form, so the visitor's answers, current step and conditional fields carry over.
- When a slot is revealed (a modal, tab, accordion or menu showing it), the form moves into it straight away. Reveals by
displayorvisibilityare picked up whether they come from a class or attribute, a transition, a breakpoint,:checked,:focus-within,:hoveror:target. - When the form's slot is hidden again (a modal closing), the form moves to a shown slot, wherever that is.
- The form stays put while its current slot is near the viewport or it's submitting, and the slot it leaves keeps its height so the page above doesn't jump. A reveal during a submission waits until the submission ends.
- If the form's first placement is hidden (say, a mobile-only block on desktop) and a later one shows, a small inline script moves it in as the page is parsed.
- Without JS, the slot's link jumps to the form.
Requirements
- WordPress 6.3+
- Gravity Forms 2.5+
- PHP 8.4+
Installation
composer require smithfield-studio/gravity-forms-multi-instance-sync
Or install it as a regular plugin and activate it. No settings.
The link
An empty slot shows a link to the form, "Go to the form", translated for da_DK, de_DE, es_ES, fi/fi_FI, fr_FR, it_IT, nb_NO, nl_NL, pt_BR, pt_PT and sv_SE (languages/, from gravity-forms-multi-instance-sync.pot). A translation in wp-content/languages/plugins/ takes precedence, and the link follows switch_to_locale().
To change its markup, copy templates/link.php to your theme as gravity-forms-multi-instance-sync/link.php. The plugin wraps the template in an element it shows and hides, so it can be any markup, such as your theme's full button markup. Keep $attributes (the link's href) on the link.
<div class="wp-block-buttons">
<div class="wp-block-button">
<a class="wp-block-button__link" <?php echo $attributes; ?>><?php esc_html_e('Book a demo', 'my-theme'); ?></a>
</div>
</div>
For themes that keep views elsewhere, gform_multi_instance_sync_link_template filters the template's path.
WP Rocket
The plugin excludes its scripts (the inline movers and assets/multi-instance-sync.js) from WP Rocket's Delay JavaScript Execution, so forms move before the visitor's first interaction, including into a modal opened by it.
Limitations
- Only one copy of each form exists on the page, so two placements can't show the form at the same time. If both are in view, the second one shows its link.
- Without JS, a link in a visible placement may point at a form in a hidden one.
- A placement hidden only with
opacity: 0counts as shown, since scroll animations fade sections in from 0.
Development
composer install && npm install
composer format # Mago
composer phpstan # PHPStan, level 10
composer rector # Rector, PHP 8.4 sets
npm run check # Oxfmt + Oxlint
npm run test:e2e # Playwright, against fixture pages rendered by the plugin's PHP (PLAYWRIGHT_CHANNEL=chrome for the installed Chrome)
bin/install-wp-tests.sh wordpress_test root '' 127.0.0.1 latest
composer test # PHPUnit, against the WordPress test suite
Translations: npm run translate:make-pot, update the .po files, then npm run translate:make-mo and npm run translate:make-php.
CI runs all of these on pull requests to main. Merging needs every check to pass and every review thread to be resolved, and Copilot reviews each pull request.