- The Challenge
- The Solution
- Step 1. Configure the ACF Repeater
- Step 2. Add a Repeater Field to a Formidable Form
- Step 3. Configure the Create Post Form Action
- Step 4. Write the Custom PHP Code
Any Pro license includes a Create Post form action that provides you with the ability to allow users to create posts, pages, and custom post types from the front-end of your site. Your users may also manage and edit their posts through the Formidable form that was used to create the post.
If you're an Advanced Custom Fields user, it should excite you to know that another nice feature delivered with the Create Post form action is functionality that integrates your form's fields with the very popular ACF Pro plugin right out of the box. This feature raises questions though:
Is there a way to map a Formidable repeater to ACF repeater?Ben Rose—Formidable Slack Community #code-help Channel
This is a commonly asked question that Formidable's knowledge base documentation addresses this way:
…the more advanced field types like the repeater field, currently require custom code for integration.Formidable Knowledge base—Integrate with Advanced Custom Fields (ACF)
As you know, Formidable Pro includes a repeater field. So does ACF. But what custom code do you use to integrate the two field types with each other?
Sadly, there is no custom code example available in the knowledge base article to demonstrate how this integration should be handled. Hopefully, this article addresses Ben Rose's question.
Before we delve into writing code, one thing we're not going to address in this article is how the Formidable repeater field works on the front end. We've already covered that topic in detail in Repeaters and Complex jQuery Operations. If you haven't read the article or want to learn more about how Formidable's repeater field works, please take the time to visit the link.
There are four steps to integrating Formidable Pro's repeater field with ACF:
- Configure the ACF repeater
- Add a repeater field to a Formidable form
- Configure the Create Post form action
- Write the custom PHP code
Step 1. Configure the ACF Repeater
This section does not provide step-by-step instructions for configuring an ACF repeater. There's plenty of material, including a nicely done video, for learning about repeaters on the ACF web site. Click the link to learn more about repeaters.
For this tutorial, we've created an ACF field group consisting of a single repeater with three fields: name, city, and state. For simplicity's sake, they are all text fields.
We've assigned this field group to a custom post type called Repeater.
Step 2. Add a Repeater Field to a Formidable Form
The form is very simple with just three fields: title, post content, and the repeater. The repeater has three text fields that match the text fields in the ACF repeater: name, city, and state.
Step 3. Configure the Create Post Form Action
For the Create Post form action, we'll be creating a custom post type named Repeater so we can segregate these test posts from other types of content.
The Action Name is Create Repeater Field. The Post Title receives the content of the form's Title input and the Post Content gets the value of the Post Content input field.
Save your form, add it to a page or post, and test that a CPT is created as expected.
Step 4. Write the Custom PHP Code
Now that you've successfully tested your form and created a new post, it's time to write our custom code and apply it through a Formidable hook. The best hook to use for this is the frm_after_create_entry action. The reason will become clear shortly.
If you're not familiar with WordPress hooks (actions and filters), it's important that you spend a little time learning about them. Many of the tutorials and advanced courses on this site make prominent use of actions and filters. It's easy to get lost if you don't have a working understanding of them. The Hooks section of the WordPress Plugin Handbook is a good place to start.
Before we get into writing the actual code, it's important to understand a little about the way Formidable stores its entry content compared to how WordPress and ACF store their respective data elements because our custom code will be pulling data from Formidable and writing it directly to a WordPress table.
When a user creates a new form entry, Formidable stores all entry data in two tables: wp_frm_items and wp_frm_item_metas.
wp_frm_items is essentially a header record. wp_frm_item_metas contains the details of the form entry. In other words, the content for every field on your form is stored in a separate row in this table, one row per field. Each row is linked back to the header record.
If you're really a techno-geek, the structures of these tables as shown in PHPMyAdmin are:
WordPress and ACF on the other hand use different tables to store their content. These tables are wp_posts and wp_postmeta. These table structures are somewhat similar to Formidable's content tables in that wp_posts serves as a header record for custom field data that gets stored in wp_postmeta, one custom field per wp_postmeta row.
ACF Repeater Storage Schema
The ACF developers explain their repeater field storage schema this way:
The repeater field saves all its data in the wp_postmeta table. If your repeater field is called “gallery” and contains 2 sub fields called “image” and “description”, this would be the database structure of 2 rows of data:
The entire purpose of our custom code is to extract the data from Formidable in whatever format it is stored in, reformat it wp_postmeta, and write it to the wp_postmeta table as explain by the ACF developers.
The Basic Function
Earlier, we mentioned that we'll be using Formidable's frm_after_create_entry action hook to execute our custom code. The reason for this is because in order to write our repeater data to wp_postmeta, we have to use the WordPress add_post_meta function.
The add_post_meta function has three mandatory parameters and one optional parameter. We're going to ignore the optional parameter for this tutorial. The mandatory parameters are:
- $post_id—this is the id of the post created by the Create Post form action.
- $meta_key—the metadata name
- $meta_value—the metadata value. Must be serializable, if non-scalar.
If you're new to coding at this level, I'm sure that the third parameter is making your head spin. A scalar variable, or scalar field, is a variable that holds one value at a time. Basically, it's a standard input field.
Serializing is required if a field stores multiple values such as multi-select checkbox or dropdown may. We won't be serializing data in this lesson. To learn more about this visit the WordPress maybe_serialize function page.
Now back to the reason for using frm_after_create_entry. Since the first mandatory parameter for add_post_meta is $post_id and the post id doesn't exist until the post is created, the only hook that allows us to retrieve the post id from Formidable is frm_after_create_entry. It would be nice if there was a frm_after_create_post action, but that's just wishful thinking.
This first part of our custom function retrieves the post id.
Let's explain the code. The frm_after_create_entry action fires for every Formidable form on your site. The 30, 2 means our action runs at priority 30 and the associated function has 2 parameters. So the first step is to limit this action to the form that has our repeater. In the case of the form on our development site, the form id is 30. You have to change this id to the id of your form.
The second step is to retrieve the form entry. We're using Formidable's built-in FrmEntry::getOne( $entry_id ) function to do that. The parameter is the $entry_id passed to our function by the action.
Next is the retrieval of the post id and a sanity check to back out of the function if the entry doesn't have an associated post id. The getOne function returns an object that contains all of the fields from the wp_frm_items table for a specific from entry. To get a visual of this, we'll use the Kint debugger to display the content returned by getOne:
As you can see, the post_id for the newly created post is 509. Now let's get to the Formidable repeater field.
Retrieve the Form's Repeater Field Content
There are a couple of ways to retrieve to the repeater field content. The first is how we don't want you doing it. That is using PHP's $_POST array, an associative array of variables passed to the current script via the HTTP POST method. In other words, when you click submit PHP takes all of the fields from your form and creates this array to hold all of your form entry data. This is automatic and $_POST persists until Formidable finishes processing your form submission.
To explain why we don't like using the $_POST array for this operation requires a visual. Look at this Kint view of the $_POST array content for our test form.
The data for the form inputs are within the item_meta array. The array element referenced by the 237 key is the title field. Correspondingly, 238 is the post content field, and 232 is the repeater field. Then there are three associated arrays to the repeater field. You have an array for row_ids, then an array for each of the individual rows. The 234, 235, and 236 elements are the field ids and content for the row inputs.
You could easily extract the data you need to populate the ACF repeater from the $_POST array. (Well, maybe not so easily.) The reason we don't recommend this is because of the KEY vs. ID argument when writing transportable code. If you've ever taken one of our courses or read any of our other programming articles, we strongly advocate for referencing keys in your code rather than ids. To learn more, see Writing Transportable Code: Keys vs. IDs.
Now let's look at how Formidable stores repeater data in its wp_frm_item_metas table:
If you recall from our $_POST array examination, our repeater field has the field id of 232. Look at how Formidable stores the content of our repeater field. What is that unintelligible content stored as the repeater's meta_value?
Formidable treats repeaters as an individual form similar to an embedded form. In truth, it is an embedded form. Internally, it has it's own form id and key. If you were to look into our wp_forms table, the repeater has a form_id of 31. Yet, the form we are working with has a form_id of 30.
When saving our form's data, Formidable writes each row of a repeater field as a separate entry for the embedded repeater form, which displays as a field on its parent form. The rows are saved first, then the entry ids of each row of data is stored in an array and saved as the meta_value for the repeater field. The meta_value for field 232 is a serialized representation of the item ids for the two rows of data we added to our repeater field.
This is a little bit difficult to understand at first, so let's go a little deeper. We entered two rows of data into our repeater. The first row is John Doe, Raleigh, North Carolina. The second row is Mickey Mouse, Orlando, Florida.
In the table content above, the first row is associated with item_id 361 and the second row with item_id 362 and our repeater field is linked to item_id 363. Because these are all form entries, there is a corresponding header record with these ids in wp_frm_items.
To finish our custom function, we need to get the content of the repeater field, convert it back to an array we can work with in code, loop through the array, retrieve the row content, format it for ACF, and finally write the new values to wp_postmeta. Simple, right?
Format the Data and Write to ACF's Repeater
Here's your finished custom code:
We really hope this gets you pointed in the right direction. Obviously, this tutorial doesn't address what happens if you edit a form entry, but at least it will get you started integrating the Formidable repeater with the ACF repeater. We'll leave the editing for another tutorial someday.