Home › Forums › ACF PRO › have_rows causing infinite loop when getting repeater values from another page
There wasn’t enough space in the title to fully explain what I’m doing here, so here goes…
There are two pages, both using flexible content layouts (sections). One layout within sections allows you to get a section from another page based on a custom field in the layout itself (section_id).
That works nicely – I can get simple layouts from the target page as long as I don’t use have_rows().
I’ve simplified my code quite a bit for troubleshooting, so all it’ll do is spit out “Has Callouts”.
<?php
if( have_rows('sections') ) :
while ( have_rows('sections') ) : the_row();
if( $row_layout == 'layout_reference' ) :
// get the other page
$target_page = get_sub_field('target_page');
$target_section = get_sub_field('target_section');
if( have_rows('sections', $target_page) ) :
while ( have_rows('sections', $target_page) ) : the_row();
if ( get_sub_field('section_id') == $target_section ) {
if( have_rows('callout') ) : // this is where the infinite loop happens
echo 'Has Callouts';
endif;
}
endwhile;
endif; // have_rows
endif; // row_layout == layout_reference
endwhile;
endif;
?>
Commenting out the if( have_rows(‘callout’) ) block causes the page to load normally.
It seems that this last have_rows causes the while ( have_rows(‘sections’) ) to reset, and displays all of the flexible layouts again, triggering the loop.
Any thoughts?
I don’t know if this is a bug or it’s something else, but I don’t think I could can figure it out unless I see it in action. Can you export the field group or groups involved and attach them, you might need to put them into a .zip file. Then I can import them into a test site to see what happens.
Hi John,
Please see attached! I’ve re-created a simplified version of the field group, and have re-tested using updated code. It’s still doing the same – it resets the first loop, causing the page to keep spitting everything out again and again.
Thanks!
I love recursive code, but I have to tell you that this is recursive in a way the makes my head hurt just a bit.
While I was looking at it and trying to figure out how to make it into a single recursive function that would be easier to follow I noticed that the block_id
is a text field and it represents a post ID
and I’m pretty sure that it needs to be an integer. It’s a stab in the dark but try changing to this
$target_page = intval(get_sub_field('target_page'));
If that doesn’t do it I’d suggest trying to turn this into a recursive function, there could be a problem with using different template parts.
Also, I don’t see any way that it can stop if the pages reference each other back and forth, which is another reason I would suggest using a recursive function. It would make it easier to add a safety switch, some type of check to make sure you are not looping forever because of what’s been entered.
Hi John,
I’ve drawn up a little diagram to further explain what I’m doing here.
Here’s a point-by-point explanation:
All of this is working as long as the block that we’re trying to pull from Page 2 doesn’t include another have_rows() call. I’ve explored the plugin code a bit, and it looks like there’s a case where it breaks in api/api-template.php around line 489.
I’m going to do some more testing, but the main problem is that it’s resetting the have_rows() loop for Page 1, causing the entire page to be re-generated, which includes the item from Page 2 again, causing the infinite loop.
I’m aware of the potential for including another “block_reference” from another page, and have added some code to avoid this.
Thanks again for your help,
Scott
Okay, ultra simple version of this, with a temporary workaround.
The problem is that have_rows uses $post_id from the current page when you don’t specifically set it, even if it’s nested in a have_rows that has it specifically set.
The workaround is to setup_postdata before the third-level have_rows, and wp_reset_postdata it once we’re done with it.
Can this be updated to use the parent have_rows post if it’s been specifically set?
I’m not the developer, I just do my best to answer questions here. I can mark this thread for the developer to look at when he get time.
My suspicion is that it has something to do with a combination of not providing a post id for the repeater and the fact that you’re using get_template_part() which creates a disconnect.
get_template_part() includes a lot of global variable values so that the template part has access to them, like the current $post and $wp_query. This might have something to do with the post id being reset, this is likely the reason your post id value is being reset.
You could try using php include instead of get_template_part which would rule this out since the variables will transfer to the included file and won’t be overridden by the global calls in get_template_part.
But this causes another problem where $target_page and $target_section will be overwritten every time that _block_reference.php is included so you’ll end up with a different problem.
Like I said above, you’ll either need to do the work around that you outline or create a recursive function that would eliminate both problems.
Hi John,
We’ve tried it without get_template_part, and it still does the same thing. My first message in this thread included that code.
Yes, please pass this up – would be great to have a fix that doesn’t include setup_postdata.
Thanks!
I’ve done what i can do, and I also let it peculate in my head for a while.
The reason that I wasn’t seeing how to make this recursive was that I was over complicating it, trying to get your initial loop into the recursion and do the recursion at the same places that you were loading alternate files and also including a check for the target section, but all that really wasn’t needed. Instead the only place it really needs to recurse is when doing a nested block reference.
I haven’t tested this out 100%, but it looks like it should work.
Yeah, the whiles and ifs are nested a bit deep, but I couldn’t see a way to avoid that.
<?php
// start the blocks content
// this is the initial loop
if (have_rows('blocks')) {
while (have_rows('blocks')) {
the_row();
$layout = get_row_layout();
if ($layout == 'block_reference') {
$target_page = get_sub_field('target_page');
$target_section = get_sub_field('target_block_id');
flexible_block_reference($target_page, $target_section);
} else {
// flexible_repeater_block
if (have_rows('repeater_items')) {
while (have_rows('repeater_items')) {
the_row();
echo 'Item: ' . get_sub_field('title') . '<br />';
} // end while
} // end if
} // end if/else
} // end while
} // end if
function flexible_block_reference($post_id, $section) {
// recurstive function
if (have_rows('blocks', $post_id)) {
while (have_rows('blocks', $post_id)) {
the_row();
if (get_sub_field('block_id') == $section) {
$layout = get_row_layout();
if ($layout == 'block_reference') {
$target_page = get_sub_field('target_page');
$target_section = get_sub_field('target_block_id');
// recurse
flexible_block_reference($target_page, $target_section);
} else {
// flexible_repeater_block
if (have_rows('repeater_items')) {
while (have_rows('repeater_items')) {
the_row();
echo 'Item: ' . get_sub_field('title') . '<br />';
} // end while
} // end if
} // end if/else
} // end while
} // end if target section
} // end if
} // end function
?>
Hi John,
This is an interesting workaround, but in the end, all it’s doing is passing in the post_id to have_rows(). I’ve accomplished this in a simplified manner using setup_postdata() a few comments back. This method also avoids having to update all of the other templates I’m using for the large number of flexible content layouts included on each site.
I think we can call this one closed for now, but thanks for investigating it with me!
The topic ‘have_rows causing infinite loop when getting repeater values from another page’ is closed to new replies.
Welcome to the Advanced Custom Fields community forum.
Browse through ideas, snippets of code, questions and answers between fellow ACF users
Helping others is a great way to earn karma, gain badges and help ACF development!
We use cookies to offer you a better browsing experience, analyze site traffic and personalize content. Read about how we use cookies and how you can control them in our Privacy Policy. If you continue to use this site, you consent to our use of cookies.