Support

Account

Home Forums Front-end Issues Nested Post Object Fields

Solved

Nested Post Object Fields

  • So, I’m building an Event listing using ACF, custom post types, and woocommerce.

    On my single event page I’m querying first a Post Object Repeater to select various products/tickets to associate with the event. I get the title of the product, and a couple of other ACF fields just fine. But then on that product/ticket page there is another post object field, referencing a venue custom post type. I’m trying to grab that post object field from my single event page, but not having any luck.

    Here’s my code. Hoping someone can assist. I feel like I’m close, but just missing something fairly obvious. It works up until the venue_object section.

    				if( have_rows('choose_dates')): // check for repeater fields 
    					if( have_rows('choose_dates') ):
    						while ( have_rows('choose_dates') ) : the_row();
    							$post_object = get_sub_field('pick_the_dates');
    								if( $post_object ):
    									$post = $post_object; setup_postdata( $post );
    				?>
    				<div class="container-fluid performances">
    					<div class="row">
    						<div class="col-md-1 col-sm-2 showtime">
    							<a href="<?php the_permalink(); ?>"><span class="list-ticket"><?php the_title(); ?></span></a>
    						</div>
    						
    						<div class="col-md-8 col-sm-8">
    							<?php $venue_object = get_field('event_location', $post_object->ID);
    								if( $venue_object ):
    									$venue = $venue_object;
    									
    									setup_postdata( $venue );
    							?>
    							
    							<p><?php the_field('showtime', $post_object->ID); the_field('am_pm', $post_object->ID); ?> <a href="<?php the_permalink($venue_object->ID); ?>"><?php the_title($venue_object->ID); ?></a>Venue name - City, State</p>
    							
    							<?php wp_reset_postdata( $venue );
    								endif;
    							?>
    							<h6><?php the_field('show_name', $post_object->ID); ?></h6>
    						</div>
    						
    						<div class="col-md-3 col-sm-2">
    							<a class="btn btn-default" href="<?php the_permalink($post_object->ID); ?>">Info & Tickets</a>
    						</div>
    					</div>
    				</div>
    				
    									<?php wp_reset_postdata();
    								endif;
    						endwhile;
    					endif;
    				endif; ?>
  • Try to persist your object->ID always, try something like:

    
    <?php
    if(have_rows('my-repeater', mypostfather->ID) :
    while(have_rows('my-repeater', mypostfather->ID) : the_row();
    $my-son-object = get_sub_field('my-relational-post-object-field'); //return your related-post 
    $my-son-values = get_field('my-son-acf-value', $my-son-object->ID);
    endwhile;endif;
    ?>
    

    I think that your wp_reset_postdata($venue) is causing the problem.
    I don’t use setup_post_data on custom-post-type-objects like $video, $venue, $etc

  • No, this doesn’t seem to be working. The section of the code in question (venue) that’s not working isn’t a repeater in this case. It’s simply a post_object.

  • I’m going to try to help you by explaining what the problem with your code is. This comes up often because most people don’t understand how wp_reset_post_data() really works.

    
     
      // this is inside the main WP query loop or "The Loop"
      
      // some time later
      
                  $post_object = get_sub_field('pick_the_dates');
                    if( $post_object ):
                      $post = $post_object; setup_postdata( $post );
                      
      // some time later
                    if( $venue_object ):
                      $venue = $venue_object;
                      
                      setup_postdata( $venue );
                      
      // some time later, 
      // this is the problem.
      // wp_reset_post_data does not take any arguments
      // this function, no matter how you call it will always
      // reset post data to "The Main Query"
      // once you do this, any reference to the post 
      // object returned by get_sub_field('pick_the_dates') 
      // will be looking at the post of the main query instead
      // of what you think you are looking at
      // in order to have multiple nestings you must use 
      // alternate means of getting values
      // other than using setup_postdata and wp_reset_postdata
                      
                      wp_reset_postdata( $venue );
                      
      // some time later
      // this next line actually does nothing 
      // because it was already done above
            
                      wp_reset_postdata();
    
  • Thank you. This actually helped a lot. I’ve got it working correctly now. Much appreciated 🙂

  • Hi @brotsky_pixie are you please able to detail how you fixed the issue?

    Thanks

  • I’m struggling with this as well.

  • Me too. I have a multiple Post Objects field, that then needs to display a single Post Object attached to each of those. @jamieics we are late to the party here, but did you get anywhere?!

  • @goto11 Unfortunately, I didn’t. I ended up moving the nested Post Object to a repeater instead. Not ideal for my situation, but timing was tight.

  • @jamieics no worries, I was starting to think I would need to do the same! Likewise time is tight, so I’ll crack on. Thanks for the reply

  • The examples on this site are for the simplest use of each field so do not cover the nuances of nested post loops. This all comes down to understanding what I explained above, that wp_reset_postdata() always resets the global $post variable to the main query’s post and not to the previous query’s post. This is something that is not explained well in the WP documentation. Every case of nested post queries will be a little different, however, the same principle applies. When you have nested queries you cannot use setup_postdata($posts) and wp_reset_postdata();

    Instead you must do the work yourself rather than relying on WP to do the work for you. A quick example of showing the title for posts in a relationship field.

    
    $related_posts = get_field('my-relationship-field');
    if ($related_posts) {
      foreach ($related_posts as $related_post) {
        ?><h1><?php echo get_the_title($related_post->ID); ?></h1><?php 
      }
    }
    

    This could also be done like this

    
    $related_posts = get_field('my-relationship-field');
    if ($related_posts) {
      foreach ($related_posts as $related_post) {
        ?><h1><?php echo $related_post->post_title ?></h1><?php 
      }
    }
    

    Getting fields from a related post

    
    $related_posts = get_field('my-relationship-field');
    if ($related_posts) {
      foreach ($related_posts as $related_post) {
        $some_value = get_field('some-field', $related_post->ID);
      }
    }
    
  • @hube2 Many thanks for the further input.

    At first glance I couldn’t see anything in your notes that I hadn’t tried. Then I noticed that you were referring to using a nested Relationship field instead of nested Post Object fields and the penny dropped for how I should be solving this. As Post Objects seem to only work using $post, your code was obviously not working. Switching to using a Relationship field instead, and using your suggested code is now working just great.

    I just need to remember for future instances that Relationship fields should be the way to go instead of Post Objects for most uses, as they are able to use their own separate query, without getting thrown by being forced to use the main setup_postdata($posts) query.

    I’ve probably worded all that horribly, but hopefully you get the idea! Thanks to all for the help!

  • Post object fields and relationship fields work the same way except for one difference. If a post object field only allows one selection then it will only return a single post, so you don’t need a loop.

    
    $related_post = get_field('my-post-object-field');
    if ($related_post) {
      ?><h1><?php echo get_the_title($related_post->ID); ?></h1><?php 
    }
    
  • I think it is possible to nest setup_postdata() while also avoiding multiple calls to wp_reset_postdata(). This can be achieved by storing the post object that you want to revert to in a variable, and later running setup_postdata() on it.

    Untested code to demonstrate:

    // Inside the main loop.
    
    // Setup outer post object.
    // Store it in $outer_post_object so that we can revert to it later.
    $outer_post_object = get_field('my_field');
    $post = $outer_post_object; // override $post
    setup_postdata($post);
    
    // Later on, setup an inner post object
    $inner_post_object = get_field('my_sub_field');
    $post = $inner_post_object; // override $post
    setup_postdata($post);
    
    // Later on, when you want to revert to $outer_post_object
    // Instead of wp_reset_postdata(), do this:
    $post = $outer_post_object;
    setup_postdata($post);

    Using this technique you can have as many nested setup_postdata() as you like.

  • I knew you’d be across it, John!

    Though I’m not sure I would call it a hack. It seems cleaner than having to explicitly pass an ID to every call to the_field/get_field?

    Speaking of which, I just ran across a similar problem when using ACF Post Objects inside ACF Gutenberg Block render templates:

    https://support.advancedcustomfields.com/forums/topic/post-objects-setup_postdata-and-get_field-in-acf-blocks/

    I am interested to know if this is something you’ve come across before John?

  • Going to be honest with you, I have no idea. I have made the decision that I will not be using the block editor for the foreseeable future. Frankly, it’s not what my clients want or need for various reasons. I am working towards not allowing the default editor and new themes that I’m building are replacing the default WP editor with an ACF WYSIWYG field in all cases. Having made this decision I have not even looked at ACF blocks. It also means that I may need to pull one of my plugins off of the WP repo.

  • I have a question on this topic. I have three post types. Notebooks -> Notebook Sections -> Notebook Pages. I have added two post object fields to the notebook pages. The first one picks the notebook the page goes into and I want the second one to only pull up the notebook sections that are children of the notebook selected. I also have a post object field on the notebook sections to choose the notebook parent to attach it to. This is the code I am using in my functions.php for that one.

    function my_acf_save_post( $post_id ) {
        
        // Get the selected post status
        $value = get_field('notebook_section_post_parent', $post_id);
        
        // Update current post
        $post = array(
          'ID'           => $post_id,
          'post_parent'   => $value,
        );
    
        // Remove the action to avoid infinite loop
        remove_action('acf/save_post', 'my_acf_save_post', 20);
        
        // Update the post into the database
        wp_update_post( $post );
        
        // Add the action back
        add_action('acf/save_post', 'my_acf_save_post', 20);
        
    }
    
    // run after ACF saves the $_POST['acf'] data
    add_action('acf/save_post', 'my_acf_save_post', 20);

    So, how do I make the notebook section field on the notebook pages only pull up the children of the notebook selected? I’m really new to coding, so I just can’t wrap my head around it and how to do it without it all getting so complicated. I appreciate ANY advice. Thanks!

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

The topic ‘Nested Post Object Fields’ is closed to new replies.