Howdy, Stranger!
It looks like you're new here. If you want to get involved, click one of these buttons!
Ability to reset has_sub_field
-
In the process of looping through a while Loop, I find the entry I want, to I trigger a 'break;' statement to jump out of the while loop, rather than continue through the rest of the unneeded entries (and have to do coding to ignore them).
The problem came about in the NEXT has_sub_field loop, because the first wasn't cleaned up properly, it wasn't finding the entries I needed.
I would like to be able to call a break statement and then something like a has_sub_field($fieldname, $post_id, true) where true means to reset the has_sub_field, probably simply bypassing the rest of the code in that function and going directly to the end:// no next row! Unset this array and return false to stop while loop
unset( $GLOBALS['acf_field'][$depth] );
$GLOBALS['acf_field'] = array_values($GLOBALS['acf_field']);
return false;
---OR (this is probably the right fix...maybe...it works for me anyway)----
Fix the detection for a new while loop to determine that a break was used and this is a new while loop that is not a child of a previous while loop. :)
maybe something like this in - api.php line 245 (Version 3.5) Added code in the ELSEIF// does the given $field_name match the current field?
if( $field_name != $name )
{
// is this a "new" while loop refering to a sub field?
if( isset($value[$row][$field_name]) )
{
$GLOBALS['acf_field'][] = array(
'name' => $field_name,
'value' => $value[$row][$field_name],
'row' => -1,
'post_id' => $post_id,
);
} elseif($depth == 0) //this is a break from a previous WHILE loop...reset.
{
// reset
$GLOBALS['acf_field'] = array();
return has_sub_field($field_name, $post_id);
}
// if someone used break; We should see if the parent value has this field_name as a value.
if( isset($GLOBALS['acf_field'][$depth-1]) && $GLOBALS['acf_field'][$depth-1]['name'] == $field_name )
{
unset( $GLOBALS['acf_field'][$depth] );
$GLOBALS['acf_field'] = array_values($GLOBALS['acf_field']);
}
} -
Hi @fancyfiber
I though my code would already look for a break by checking the 'field_name'...
Can I see your page template, to run some tests on?
Thanks -
I would share the page template if I were working in a page template for this. I am working in a custom plugin for a specific site (could have done the same stuff in functions.php, but planned on changing themes and was working in advance of the theme creation...long story...)
Site has the requirement to have multiple short bios, but only the first one will be shown publicly. Same for photos.
So, I set up a repeater field for each of these with only the one field under them (short_bio or photo) as you will see from the code. (my code at the bottom of this post) (p.s. I know I don't NEED the $postid in the get_sub_field, but I am training myself to put the post_id in all the time because I forget too often.)
The issue, as I saw it and I could be misunderstanding the code, with current ACF code is that it will detect a break in the while loop if you were at a $depth greater than 0, but when the $depth is 0 (zero) this code will not trigger the reset:if( isset($GLOBALS['acf_field'][$depth-1]) && $GLOBALS['acf_field'][$depth-1]['name'] == $field_name )
because $depth-1 will never be set.
You won't go to a new depth as this line would like to do:if( isset($value[$row][$field_name]) )
because this isn't a sub-field of the other one.
So, my solution was to reset the $GLOBALS['acf_field'] and try again, as you did in the code before when the $post_id changes, when the field name changes and we are at $depth == 0.
This fixed my issue.
My code that was having the issue:$short_bio = '';
if(get_field('short_bios', $postid)) {
while(has_sub_field('short_bios', $postid)) {
$t = get_sub_field('short_bio', $postid);
$short_bio = (strlen($t) >= 150) ? substr($t, 0, 150) . '...' : $t;
break;
}
}
$image = '';
if(get_field('photos', $postid)) {
while(has_sub_field('photos', $postid)) {
$photo = get_sub_field('photo', $postid);
$image = $photo['sizes']['our-team'];
break;
}
} -
Thanks @fancyfiber
Great description. I'll look over it shortly. From the top of my head, I think your onto something. I'll need to do some testing and get back to you
Cheers
Elliot -
Hi @fancyfiber
This is the patch I will be adding to the api.php in the next version
Thanks for outlining this issue. I don't know how I overlooked this, but here's the fix!function has_sub_field($field_name, $post_id = false)
{
// needs a post_id
global $post;
if( !$post_id )
{
$post_id = $post->ID;
}
// empty?
if( empty($GLOBALS['acf_field']) )
{
$GLOBALS['acf_field'][] = array(
'name' => $field_name,
'value' => get_field($field_name, $post_id),
'row' => -1,
'post_id' => $post_id,
);
}
// vars
$depth = count( $GLOBALS['acf_field'] ) - 1;
$name = $GLOBALS['acf_field'][$depth]['name'];
$value = $GLOBALS['acf_field'][$depth]['value'];
$row = $GLOBALS['acf_field'][$depth]['row'];
$id = $GLOBALS['acf_field'][$depth]['post_id'];
// if ID has changed, this is a new repeater / flexible field!
if( $post_id != $id )
{
// reset
$GLOBALS['acf_field'] = array();
return has_sub_field($field_name, $post_id);
}
// does the given $field_name match the current field?
if( $field_name != $name )
{
// is this a "new" while loop refering to a sub field?
if( isset($value[$row][$field_name]) )
{
$GLOBALS['acf_field'][] = array(
'name' => $field_name,
'value' => $value[$row][$field_name],
'row' => -1,
'post_id' => $post_id,
);
}
elseif( isset($GLOBALS['acf_field'][$depth-1]) && $GLOBALS['acf_field'][$depth-1]['name'] == $field_name )
{
// if someone used break; We should see if the parent value has this field_name as a value.
unset( $GLOBALS['acf_field'][$depth] );
$GLOBALS['acf_field'] = array_values($GLOBALS['acf_field']);
}
else
{
// this was a break; (probably to get the first row only). Clear the repeater
$GLOBALS['acf_field'] = array();
return has_sub_field($field_name, $post_id);
}
}
// update vars
$depth = count( $GLOBALS['acf_field'] ) - 1;
$value = $GLOBALS['acf_field'][$depth]['value'];
$row = $GLOBALS['acf_field'][$depth]['row'];
// increase row number
$GLOBALS['acf_field'][$depth]['row']++;
$row++;
if( isset($value[$row]) )
{
// next row exists
return true;
}
// no next row! Unset this array and return false to stop while loop
unset( $GLOBALS['acf_field'][$depth] );
$GLOBALS['acf_field'] = array_values($GLOBALS['acf_field']);
return false;
} -
Excellent! I agree that your solution is better than what I did quickly to solve my situation. I appreciate you taking the time to look at the issue. And I must say again, I love ACF.
Thanks again! -
Hi,@admin
I'm using the latest version 3.5.3.1, but I still have a wrong,if I use "break" through a while Loop.
I have a repeat field through While Loop traverse, but when certain conditions happened I need to break, terminate the While Loop. If only to traverse one time, the program is no problem. But if the second time I use While Loop to traverse the same repeat field , because there is no reset, I will not I want to record.
My code shown below:
$acf_user_ID = 'user_'.$user_ID;
if(get_field('shipping_address',$acf_user_ID)){
while (has_sub_field('shipping_address', $acf_user_ID)):
if(get_sub_field($condition)){
$address['shipping_address_firstname'] = get_sub_field('shipping_address_firstname');
$address['shipping_address_mi'] = get_sub_field('shipping_address_mi');
$address['shipping_address_lastname'] = get_sub_field('shipping_address_lastname');
$address['shipping_address_email'] = get_sub_field('shipping_address_email');
$address['shipping_address_areacode_tel'] = get_sub_field('shipping_address_areacode_tel');
$address['shipping_address_tel'] = get_sub_field('shipping_address_tel');
$address['shipping_address_areacode_cellphone'] = get_sub_field('shipping_address_areacode_cellphone');
$address['shipping_address_cellphone'] = get_sub_field('shipping_address_cellphone');
$address['shipping_address_address1'] = get_sub_field('shipping_address_address1');
$address['shipping_address_address2'] = get_sub_field('shipping_address_address2');
$address['shipping_address_city'] = get_sub_field('shipping_address_city');
$address['shipping_address_postcode'] = get_sub_field('shipping_address_postcode');
$address['shipping_address_state'] = get_sub_field('shipping_address_state');
$address['shipping_address_country'] = get_sub_field('shipping_address_country');
break;
}else{
continue;
}
endwhile;
}