Support

Account

Home Forums Backend Issues (wp-admin) Create Multiple Posts on Back End

Solved

Create Multiple Posts on Back End

  • I’m looking to setup a customized area in the WordPress back end that would allow an admin to create a series of posts using ACF repeater fields.

    You might think of it as first creating a post in WordPress that we might call “News for 6/15/16”. Then, the repeater fields would be a list of news items from that particular day. Almost like having a parent posts with children listed inside.

    For each post in the repeater, there would be:

    -A post title (text field)
    -Content (WYSIWYG)
    -Select or create tags for the post (taxonomy field)

    Has anyone done something like this before? Any advice for setting up? I did run across this https://support.advancedcustomfields.com/forums/topic/acf_form-create-one-or-multiple-posts-at-once/ and it was helpful. But I was curious if there’s anything else I should be aware of when creating this, or if it is even possible.

  • Hi @karks88

    I believe the thread you’ve shared is the best workaround for now. Is there something with that workaround that makes you think it won’t work for you?

    Thanks πŸ™‚

  • Thanks James! Good to know I’m on the right path πŸ™‚ Please excuse the questions, but I’m not an expert at PHP. The main things I’m wondering about at this point:

    -Do the field names have to be anything specific?

    -Any differences because I’m doing this on the back end, rather than the front end?

  • I’ve given this a shot (just testing it on the front end before I figure out how to add it on the back end) and I can create a single, untitled post with no content πŸ™‚

    Here’s what I’ve got in the front end template:

    <?php
    		
    		// Bail if not logged in or able to post
        if ( ! ( is_user_logged_in()|| current_user_can('publish_posts') ) ) {
            echo '<p>You must be a registered author to post.</p>';
            return;
        }
    		
    		 acf_form(array(
    					'post_id'		=> 'new_post',
    					'form'               => true,
    					'field_groups' => array(4),
    					'new_post'		=> array(
    						'post_type'		=> 'post',
    						'post_status'		=> 'publish'
    					),
    					'submit_value'		=> 'Save Posts',
    					'updated_message' => __("Post updated", 'acf')
    				));
    				
    				 ?>

    And in functions.php…

    // Special ACF Function for Creating Multiple Daily News Brief Posts
    // This function imports multiple posts at once
    function acf_import_multiple_posts( $post_id ) {
      // If the post_id is not equal to 'new', skip the entire function
      if( $post_id != 'new' ) {
        return $post_id;
      };
    
      $loop = $_POST['acf']['field_57614ac1e5179']; //ACF Repeater Field key
      $customMetaField = 'news_post_tags'; // Custom Meta Field
      $customContentField = 'news_post_content'; // Custom Content Field
      $customPostTitle = 'news_post_title'; // Custom Title
    
      $count = count($loop); // Get the number of rows in the Repeater Field
    
      for ($key = 0; $key < $count; ++$key) { // If $count is 5, run for loop till it reaches 5 times
        // Swap out $key for each row number
        $customMetaField = trim($_POST['acf']['field_5762b0a5ad19f'][$key]['field_5762b0a5ad19f']);
        $customContentField = trim($_POST['acf']['field_57614bf6c6b13'][$key]['field_57614bf6c6b13']);
        $customPostTitle = trim($_POST['acf']['field_57614baac6b12'][$key]['field_57614baac6b12']);
    
        // Create a new App Post from posts listed in the repeater field
        $post = array(
          'post_status'  => 'publish', // Set to draft because the user still needs to review
          'post_title' => $customPostTitle, // Actual Post Title
          'post_name' => sanitize_title( $customPostTitle ), // Actual Post Slug
    	  'post_content' => $customContentField, // Post Content
          'post_type'  => β€˜post’ // Post Type
        );
    
        $post_id = wp_insert_post( $post );     // Use the WordPress default wp_insert_post function
    
        // Set the Custom Meta Fields with the $customMetaField, $customContentField and $customPostTitle
        add_post_meta($post_id, 'customMetaField', $customMetaField, true);
    	add_post_meta($post_id, 'customContentField', $customContentField, true);
        add_post_meta($post_id, 'customPostTitle', $customPostTitle, true);
      }
    
      // update $_POST['return']
      $_POST['return'] = add_query_arg( array('post_id' => $post_id), $GLOBALS['acf_form']['return'] );
    
      // return the new ID
      return $post_id;
    }
    add_action('acf/pre_save_post', 'acf_import_multiple_posts', 20);

    I know I’m doing something very wrong, but I’m just not sure what. Anything in particular stand out? Thanks so much for your help!

  • Hi @karks88

    It looks great for me. Is there something wrong with the code?

    Also, because you use ‘new_post’, I believe ACF will create a new post with repeater you used for the multiple posts in it. If it is, then I believe you can use the acf/save_post and wp_delete_post() to delete the newly created post.

    I hope this makes sense πŸ™‚

  • Thanks James! It’s really weird, I’m starting to wonder if the functions.php code is firing at all. I’ve made changes and thought it looked good, but still no luck. All I get is a completely blank post that I can’t delete from the dashboard. I did update the code to the following…

    Template:

    <?php
    		
    		// Bail if not logged in or able to post
        if ( ! ( is_user_logged_in()|| current_user_can('publish_posts') ) ) {
            echo '<p>You must be a registered author to post.</p>';
            return;
        }
    		
    		 acf_form(array(
    					'post_id'		=> 'new_post',
    					'field_groups' => array(4)
    				));
    			
    				
    				 ?>

    Functions.php
    // Special ACF Function for Creating Multiple Daily News Brief Posts
    // This function imports multiple posts at once

    function acf_import_multiple_posts( $post_id ) {
    	
    	
      // If the post_id is not equal to 'new', skip the entire function
      if( $post_id != 'new_post' ) {
      return $post_id;
      };
    
      $loop = $_POST['acf']['field_57614ac1e5179']; //ACF Repeater Field key
      $customMetaField = 'news_post_tags'; // Custom Meta Field
      $customContentField = 'news_post_content'; // Custom Content Field
      $customPostTitle = 'news_post_title'; // Custom Title
    
      $count = count($loop); // Get the number of rows in the Repeater Field
    
      for ($key = 0; $key < $count; ++$key) { // If $count is 5, run for loop till it reaches 5 times
        // Swap out $key for each row number
        $customMetaField = trim($_POST['acf']['field_5762b0a5ad19f'][$key]['field_5762b0a5ad19f']);
        $customContentField = trim($_POST['acf']['field_57614bf6c6b13'][$key]['field_57614bf6c6b13']);
        $customPostTitle = trim($_POST['acf']['field_57614baac6b12'][$key]['field_57614baac6b12']);
    
        // Create a new App Post from posts listed in the repeater field
        $post = array(
          'post_status'  => 'publish', // Set to draft because the user still needs to review
          'post_title' => $customPostTitle, // Actual Post Title
          'post_name' => sanitize_title( $customPostTitle ), // Actual Post Slug
    	  'post_content' => $customContentField, // Post Content
          'post_type'  => 'post' // Post Type
        );
    
        $post_id = wp_insert_post( $post );     // Use the WordPress default wp_insert_post function
    
        // Set the Custom Meta Fields with the $customMetaField, $customContentField and $customPostTitle
        add_post_meta($post_id, 'news_post_tags', $customMetaField, true);
    	add_post_meta($post_id, 'news_post_content', $customContentField, true);
        add_post_meta($post_id, 'news_post_title', $customPostTitle, true);
      }
    
      // update $_POST['return']
      $_POST['return'] = add_query_arg( array('post_id' => $post_id), $GLOBALS['acf_form']['return'] );
    
      // return the new ID
      return $post_id;
    }
    
    add_action('acf/pre_save_post', 'acf_import_multiple_posts', 20);
  • Hi @karks88

    I’ve created another way to do it by using “acf/save_post” instead of “acf/pre_save_post” for you. Here’s the front end form:

    acf_form(array(
        'post_id' => 'new_post',
        'new_post' => array(
            'post_type'	=> 'post',
            'post_status'	=> 'publish'
        ),
    ));

    And here’s the functions.php:

    function my_acf_save_multiple_posts( $post_id ) {
        
        // get the repeater
        $values = get_field('new_posts', $post_id);
        
        // loop through the repeater
        foreach( $values as $value ) {
            
            // set the new post arguments
            $new_post = array(
                'post_title' => $value['post_title'],
                'post_content' => $value['post_content'],
                'post_type' => 'cpt',
            );
            
            // post it!
            $new_post_id = wp_insert_post($new_post);
            
            // add the custom fields if you have any (you need to use the field key!!!)
            update_field('field_1234567890abc', $value['post_meta_custom_fields'], $new_post_id);
            
        }
        
        // delete the unused post
        wp_delete_post($post_id);
        
    }
    
    // run after ACF saves the $_POST['acf'] data
    add_action('acf/save_post', 'my_acf_save_multiple_posts', 20);

    I’ve also attached the JSON export file (if you use the PRO version). If you use the free version, please examine the JSON file to see the options I’ve created instead.

    I hope this helps πŸ™‚

  • James, I can’t thank you enough! That worked perfectly πŸ™‚

    I am a loyal Pro user because it’s an amazing plugin and you provide such outstanding support. Thank you.

  • One thing I have noticed is that, when using this on the back end, it creates duplicates of each post. Any reason you can think of that this would happen? I’m not using acf_form on the back end but wasn’t sure if that was necessary since it does create the post.

  • Hi @karks88

    I think the ‘acf/save_post’ is executed when you use the wp_insert_post() function, so you get the infinite/double post issue. Could you please modify it like the following?

    // remove action to avoid infinite loop issue
    remove_action('acf/save_post', 'my_acf_save_multiple_posts', 20);
    
    // post it!
    $new_post_id = wp_insert_post($new_post);
    
    // add the action back
    add_action('acf/save_post', 'my_acf_save_multiple_posts', 20);

    This page should give you more idea about it: https://codex.wordpress.org/Function_Reference/wp_update_post#Caution_-_Infinite_loop.

    Thanks!

  • James, it worked! If we ever meet, you are getting an entire case of beer on me πŸ™‚

  • I think I’ve got just about everything down with this. Just one more thing I have to wrestle with (I think, I hope).

    The way I have this setup on the backend is that I have a custom post type called “Daily News Briefs”. The author can go in and write whatever they want in the standard WP content editor for that post, and then use the code we’ve been working on to create multiple “sub-posts” with the repeater fields. Those new posts are just saved as standard WP Posts.

    In the original code you so kindly fashioned, there is this:

    // delete the unused post
        wp_delete_post($post_id);

    I’ve commented that out because, in my case, I want to keep that post I’ve created in the custom post type.

    The only other issue I can find here is that, if I were to go into that custom post type and edit one of the custom fields and re-save, I’ll get a whole other set of duplicate posts created.

    What I’ve tried to do is write a conditional that says if the post_id exists, simply update it using wp_update_post, otherwise use wp_insert_post. Unfortunately, that just leads to a duplicate post when trying to update.

    Here’s what I’m working with:

    // Special ACF Function for Creating Multiple Daily News Brief Posts
    function my_acf_save_multiple_posts( $post_id ) {
        
        // get the repeater
        $values = get_field('new_daily_brief_posts', $post_id);
    
        
        // loop through the repeater
        foreach( $values as $value ) {
    		
    		// set the new post arguments
            $new_post_article = array(
                'post_title' => $value['post_title'],
                'post_content' => $value['post_content'],
                'post_type' => 'post',
    			'post_status'	=> 'publish',
    			'tags_input' => $value['post_tags']
            );
            
    		// remove action to avoid infinite loop issue
    		remove_action('acf/save_post', 'my_acf_save_multiple_posts', 20);
    		
    		// look to see if this post already exists
    		$exists =  get_post_status ( $ID ) == 'publish'; 
    		
    		// if this doesn't exist, create the post.
    		if( !$exists ){
    
     		// post it!
            $new_brief_post_id = wp_insert_post($new_post_article);
    		
    		}
    		
    		// Update the post if it already exists
    		else {
    			
    		// remove action to avoid infinite loop issue
    		
    	    $new_brief_post_id = wp_update_post($new_post_article);  }
    
    	}
        
        // delete the unused post
        //wp_delete_post($post_id);
    
    }
    
    // run after ACF saves the $_POST['acf'] data
    add_action('acf/save_post', 'my_acf_save_multiple_posts', 20);

    I would imagine that acf/safe_post would interfere with updating the post?

  • Hi @karks88

    If you want to keep the “Daily News Briefs” post and maintain the relation with its subfield, this will make things a bit more complicated πŸ™‚

    Because this is an advanced situation, I’m afraid I can only guide to do it. I’m sorry about that.

    To maintain the relationship, I suggest you add post object field type in the new post repeater. When you add new posts from the repeater, you don’t need to select the post object field as we will do it automatically in the acf/save_post hook.

    In the acf/save_post hook, you need to get the index key when looping through the repeater field like this:

    foreach( $values as $key => $value ) {

    After that, we need to update the post object field in the repeater values like this:

    // post it!
    $new_post_id = wp_insert_post($new_post);
    $values[$key]['post_object_field_name'] = $new_post_id;

    And after the loop, we need to update the repeater with the update_field() function like this:

    update_field( 'new_posts', $values, $post_id );

    This will add the newly created posts to the correct repeater rows. With this setup, you can check if the post object field is set or not like this:

    if( $value['post_object_field_name'] ) {

    If it’s set, get the ID and update it. If not, just insert a new post.

    I hope this makes sense πŸ™‚

  • Thanks James! I have gone through these steps but am still having a bit of trouble. I submitted a ticket (not sure if this issue can be handled further by an official ticket, but figured it was worth a shot).

    Seems like the issue I’m having at this point is that a post object isn’t assigned a value, thus the conditional for preexisting posts never fires.

Viewing 14 posts - 1 through 14 (of 14 total)

The topic ‘Create Multiple Posts on Back End’ is closed to new replies.