Front-End Extensibility: Dynamic Content

In a previous post, I explained our decision to use Underscore templates when displaying the form on the front-end. The use of the phrase “templating” caused many of our collaborating developers, who customize their forms using the 2.9.x API, to ask some hard questions about customizing their form output without creating new templates. Like our advanced users, we love how easy it is to add custom content in our current approach though:

  1. add a WordPress action
  2. output stuff

If we moved strictly to a JS templating system on the front-end, how would our users inject dynamic content into their form display? Would they need to learn JS, backbone.js, and underscore.js? How would they enqueue that dynamic content?

We pondered possible solutions for a couple of days, and then I got sick. I had a sinus infection, and it knocked me out of commission for a day or two. Over those two sick days, however, I came up with what seemed like a novel solution. I couldn’t wait to explain it to our other developer, and sent out a cryptic Slack message:

@kjohnson remind me tomorrow to talk to you about templating. I’ve had a great idea that might make our jobs easier. Or it’s all the medicine. Not sure which!

Since I was pretty drugged-up on NyQuil, there was a good chance that the idea was total crap.

The next morning, Kyle listened to my NyQuil-fueled idea and stroked his stubble. (He’s growing a new beard for the 3.0 push.)

After about thirty minutes or so of discussion, he made some good suggestions and our solution to dynamic templating was born. This solution allows us to maintain the dynamic nature of our previous solution, while using templates to display field elements.

Let’s look at an example to help explain our solution. If you want to inject some dynamic content before your fields, currently do something like this:

function ninja_forms_custom_display( $form_id ) {
// Output text received from the database before our field output.
$text = get_stuff_from_somewhere_else( $form_id );
echo '<h4>'. $text . '</h4>';
add_action( 'ninja_forms_display_before_form', 'ninja_forms_custom_display' );

This is a very straightforward WordPress hook. That action is fired while the form is being output to the page, and so your content is echo’d during that process. Unfortunately, this kind of action/echo doesn’t work when the form is built from Underscore templates. Those templates can’t be customized with dynamic text because they need to be used for every like element on the page. This is where the NyQuil-induced fever dream idea comes in: we use WordPress filters to simulate the action hooks and output the resulting strings to the front-end for our JS to consume. There will be a new collection of WordPress filters available to those who want to inject content into their forms. These filters will be localized to the page so that they can be accessed by the JS that is building the form and output at the appropriate places.

Let’s recreate our dynamic “before fields” content using this new system. (Keep in mind that all the code examples here are subject to change.):

function ninja_forms_custom_display( $before_fields, $form_id ) {
// Output text received from the database before our field output.
$text = get_stuff_from_somewhere_else( $form_id );
$before_fields .= '<h4>'. $text . '</h4>';
return $before_fields;
add_filter( 'nf_frontend_before_form', 'ninja_forms_custom_display', 10, 2 );

As you can see, the only real difference is that we’re returning our string rather than just echoing out to the page.

When we display the form on the front-end, we get a variable that our JS can access that looks something like:

* This variable holds all of our custom strings for form display.
* It can be accessed and used by our JS code.
var nfDynamicContent = {
beforeForm: '',
beforeFields: '<h4>Please check your fields carefully!</h4>',
afterFields: '',
afterForm: ''

Using Backbone views, we display these strings in specific areas of the form if they exist. So the settings above that are empty strings, like ‘beforeForm’ wouldn’t be output to the page. This lets us recreate all of our current WordPress action hooks and still exclusively use Underscore templating. It gives us the best of both worlds.