ACF Repeater Field to Multiple Posts via Advanced Forms

Screenshot of the advanced form interface example.

Origin Story

We have someone who wants to allow people to enter various numbers of items in a particular pattern. We want to keep this as easy as possible and they wanted to avoid having to repeatedly hit submit.

First Pass – Gravity Forms Repeater Field

I initially thought we could do this in Gravity Forms using the beta repeater field option. I used example #2 this time. It lets you reference another form as a repeater field inside the parent field. This example uses the form with ID 1 as the parent and ID 2 as the included repeater.

This worked great except it has issues with file uploads which canceled it out for our uses. This will work nicely for repeaters that aren’t dealing with those field types. And this pattern can be tossed in a plugin without modification with the idea that the first form you make will be the holder and the second form will be the repeater.

// Adjust your form ID
add_filter( 'gform_form_post_get_meta_1', 'add_fields_from_another_form' );
function add_fields_from_another_form( $form ) {
 
    $repeater = GF_Fields::create( array(
        'type'   => 'repeater',
        'id'     => 1000,
        'formId' => $form['id'],
        'label'  => 'My Repeater',
    ) );
 
    $another_form = GFAPI::get_form( 2 );
    foreach ( $another_form['fields'] as $field ) {
        $field->id = $field->id + 1000;
        $field->formId = $form['id'];
            if ( is_array( $field->inputs ) ) {
            foreach ( $field->inputs as &$input ) {
                $input['id'] = (string) ( $input['id'] + 1000 );
            }
        }  
    }
 
    $repeater->fields = $another_form['fields'];
    $form['fields'][] = $repeater;
 
    return $form;
}
// Remove the field before the form is saved. Adjust your form ID
add_filter( 'gform_form_update_meta_1', 'remove_my_field', 10, 3 );
function remove_my_field( $form_meta, $form_id, $meta_name ) {
 
    if ( $meta_name == 'display_meta' ) {
        // Remove the Repeater field: ID 1000
        $form_meta['fields'] = wp_list_filter( $form_meta['fields'], array( 'id' => 1000 ), 'NOT' );
    }
 
    return $form_meta;
}

Second Pass – ACF with Advanced Forms

After seeing that fail, I debated writing something to customize the file upload in Gravity Forms but figured I’d try ACF first. ACF has repeater fields and I recalled using acf_form() in a project a while back but wasn’t sure how it’d handle repeaters. Prior to doing it from scratch, I opted to google a bit for acf forms and repeaters. I found Advanced Forms which is a really easy way to stick ACF on the front of the site as a form.

Advanced Forms was really easy. Turn it on. Associate an ACF group with an Advanced Form and insert on a page via a shortcode. Repeater fields work out of the box. Image uploads are no problem. There is a pro version which offers additional functionality as well.

My goal was to have each repeater field entry create a new post. I wasn’t sure that the pro version would support that and figured I could give it a shot with the free version. They have good documentation.

The Trigger

Our first goal was to figure out how to trigger an event on submission of the form. The documentation makes that easy under processing form submissions. Their example is below.

function handle_form_submission( $form, $fields, $args ) {
    
    $email = af_get_field( 'email' );
    
}
add_action( 'af/form/submission', 'handle_form_submission', 10, 3 );

The Data

Because I have suffered so many times, I have finally wised up and want to see the data before I make any assumptions about what it looks like. That is where the logging function comes to play and the following bit shows how the two things interact to dump the data I want to the debugging log (wp-content/debug.log).

function handle_form_submission( $form, $fields, $args ) {
    $data = $fields;    
    
}

add_action( 'af/form/submission', 'handle_form_submission', 10, 3 );

//happy little logging function
if ( ! function_exists('write_log')) {
   function write_log ( $log )  {
      if ( is_array( $log ) || is_object( $log ) ) {
         error_log( print_r( $log, true ) );
      } else {
         error_log( $log );
      }
   }
}

That gives me data that looks like this for the demo setup. This is two repeater items and it looks scarier than it it.

Array
(
    [5d95e912a38fb] => Array
        (
            [title] => uno
            [image] => Array
                (
                    [ID] => 19
                    [id] => 19
                    [title] => 15353034428_cd94d1abc2_k
                    [filename] => 15353034428_cd94d1abc2_k.jpg
                    [filesize] => 871665
                    [url] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k.jpg
                    [link] => http://192.168.33.10/wordpress/one-two-repeater/15353034428_cd94d1abc2_k/
                    [alt] => 
                    [author] => 1
                    [description] => 
                     => 
                    [name] => 15353034428_cd94d1abc2_k
                    [status] => inherit
                    [uploaded_to] => 20
                    [date] => 2019-10-02 18:38:48
                    [modified] => 2019-10-02 18:39:06
                    [menu_order] => 0
                    [mime_type] => image/jpeg
                    [type] => image
                    [subtype] => jpeg
                    [icon] => http://192.168.33.10/wordpress/one-two-repeater/wp-includes/images/media/default.png
                    [width] => 1365
                    [height] => 2048
                    [sizes] => Array
                        (
                            [thumbnail] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k-150x150.jpg
                            [thumbnail-width] => 150
                            [thumbnail-height] => 150
                            [medium] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k-200x300.jpg
                            [medium-width] => 200
                            [medium-height] => 300
                            [medium_large] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k-768x1152.jpg
                            [medium_large-width] => 640
                            [medium_large-height] => 960
                            [large] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k-683x1024.jpg
                            [large-width] => 640
                            [large-height] => 960
                            [post-thumbnail] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/15353034428_cd94d1abc2_k.jpg
                            [post-thumbnail-width] => 1365
                            [post-thumbnail-height] => 2048
                        )

                )

            [pattern_type] => Array
                (
                    [0] => 3
                    [1] => 4
                )

        )

    [5d95e91ca38fc] => Array
        (
            [title] => Dos
            [image] => Array
                (
                    [ID] => 38
                    [id] => 38
                    [title] => implication12
                    [filename] => implication12.jpg
                    [filesize] => 54948
                    [url] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12.jpg
                    [link] => http://192.168.33.10/wordpress/one-two-repeater/implication12/
                    [alt] => 
                    [author] => 1
                    [description] => 
                     => 
                    [name] => implication12
                    [status] => inherit
                    [uploaded_to] => 0
                    [date] => 2019-10-03 12:27:26
                    [modified] => 2019-10-03 12:27:26
                    [menu_order] => 0
                    [mime_type] => image/jpeg
                    [type] => image
                    [subtype] => jpeg
                    [icon] => http://192.168.33.10/wordpress/one-two-repeater/wp-includes/images/media/default.png
                    [width] => 700
                    [height] => 526
                    [sizes] => Array
                        (
                            [thumbnail] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12-150x150.jpg
                            [thumbnail-width] => 150
                            [thumbnail-height] => 150
                            [medium] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12-300x225.jpg
                            [medium-width] => 300
                            [medium-height] => 225
                            [medium_large] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12.jpg
                            [medium_large-width] => 640
                            [medium_large-height] => 481
                            [large] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12.jpg
                            [large-width] => 640
                            [large-height] => 481
                            [post-thumbnail] => http://192.168.33.10/wordpress/one-two-repeater/wp-content/uploads/sites/61/2019/10/implication12.jpg
                            [post-thumbnail-width] => 700
                            [post-thumbnail-height] => 526
                        )

                )

            [pattern_type] => Array
                (
                    [0] => 4
                    [1] => 2
                )

        )

)

Processing the Data

We can move into the important part of the data with $fields[0][‘value’]. Once we are in the data, we can now loop through however many repeater entries we have.

The following code loops through the entries, gets the data, and then goes the extra step of using it to create a post for each repeater entry.

function handle_form_submission( $form, $fields, $args ) {
    $data = $fields[0]['value'];
    foreach ($data as $key => $item) {
//GET DATA
    	        $title = $item['title'];
		$image = $item['image']['ID'];
		$cats = $item['pattern_type'];
//MAKE POSTS
		$args = array(
			'post_title' => wp_strip_all_tags($title),
			'post_category' =>  $cats,
			'post_status'   => 'publish',
		);
		$post = wp_insert_post($args);
		set_post_thumbnail($post, $image);
    }
    
}

Comments on this post

  1. Cog.Dog said on October 3, 2019 at 2:11 pm

    I’m catching up, slowly with you. I’ve found ACF super powerful in 2 current projects, even just for extending / structuring the data with posts. The form plugin looks slick too, and maybe this is an alt way to think about SPLOT-like sites.

    Am I right that repeater fields are an $ add-on for ACF?

    • Tom Woodward said on October 3, 2019 at 7:34 pm

      ACF has really made things fast for us. I think you will find it increasingly useful.

      I like having multiple options for SPLOT-like creation. Between this and Gravity Forms, I feel like we can hit the customization sweet spot really quickly.

      Repeater fields are in the pro version but the price is reasonable and the license is the best I’ve seen in a long time- lifetime updates for unlimited sites for $100 and permissions to use it in plugins, themes etc. No recurring costs.

Leave a Reply to Tom Woodward Cancel reply

Trackbacks and Pingbacks on this post

No trackbacks.

TrackBack URL