With WordPress, I'm using Advanced Custom Fields with a repeater field https://www.advancedcustomfields.com/resources/repeater/ and I'm trying to work out how to add some conditions to the repeater loop to conditionally display some repeater rows.
Right now, this works and displays all repeater fields:
if (have_rows('repeater')):
echo '<div class="container-fluid"><div class="row">';
while( have_rows('repeater') ): the_row();
echo '<div class="col">';
echo '<div class="title">';
the_sub_field('title');
echo '</div></div>';
endwhile;
echo '</div></div>';
endif;
And that outputs:
<div class="container-fluid">
<div class="row">
<div class="col">
<div class="title">
The title
</div>
</div>
<div class="col">
<div class="title">
Another title
</div>
</div>
</div>
</div>
// and on and on
But what I need to do is display some repeater rows, depending on two conditions: if the user is logged in, and if the repeater subfield show_only_to_logged_in_admins has the value of 1. After any/all of those conditional rows are displayed, I need to continue the repeater loop and display the rest of the repeater rows.
What I have right now, the code below, displays only the rows with the subfield show_only_to_logged_in_admins at the value of 1 to users who are logged-in administrators, and it displays no rwos to non-logged users and when show_only_to_logged_in_admins field value is 0.
if (have_rows('repeater')):
echo '<div class="container-fluid"><div class="row">';
while( have_rows('repeater') ): the_row();
$show_only = get_sub_field('show_only_to_logged_in_admins');
$current_user = wp_get_current_user();
if ((user_can( $current_user, 'administrator' )) & ($show_only == 1)) {
echo '<div class="col">';
echo '<div class="title">';
the_sub_field('title');
echo '</div></div>';
}
endwhile;
echo '</div></div>';
endif;
But what I need is this:
<div class="container-fluid">
<div class="row">
// the rows that are shown to logged users and when
// the repeater subfield show_only_to_logged_in_admins
// has the value of 1
<div class="col">
<div class="title">
The title
</div>
</div>
// and on and on
// and then the rest of the repeater rows
<div class="col">
<div class="title">
Another title
</div>
</div>
</div>
</div>
How can I display the conditional rows, and then continue the loop for all the rest of the rows?
Would I use a nested while or do-while loop for the conditionals? Nested inside the main repeater loop while( have_rows('repeater') ): the_row();
?
Update based on the comment:
I think your best shot is to use the PHP output buffers. So you don't have to repeat the mark up and you can implement what you want with a single while loop.
Example:
if (have_rows('repeater')):
$current_user = wp_get_current_user();
$adminOnlyContent = '';
$nonAdminContent = '';
while( have_rows('repeater') ): the_row();
$show_only = get_sub_field('show_only_to_logged_in_admins');
ob_start();
echo '<div class="col">';
echo '<div class="title">';
the_sub_field('title');
echo '</div></div>';
if ((user_can( $current_user, 'administrator' )) & ($show_only == 1)) {
$adminOnlyContent .= ob_get_clean();
} else {
$nonAdminContent .= ob_get_clean();
}
endwhile;
echo '<div class="container-fluid"><div class="row">';
echo $adminOnlyContent;
echo $nonAdminContent;
echo '</div></div>';
endif;
Another option is implement a separate function which will return the markup.
Original Answer:
You cannot use the_row()
twice within a loop. So you cannot use the nested loops here. But there are several ways to achieve what you want.
Here is one option: Store the content for both groups of fields in variables and echo them after the while loop.
$other_rows = [];
if (have_rows('repeater')):
$adminFields = '';
$nonAdminFields = '';
$current_user = wp_get_current_user();
while( have_rows('repeater') ): $row = the_row();
$show_only = get_sub_field('show_only_to_logged_in_admins');
if ((user_can( $current_user, 'administrator' )) & ($show_only == 1)) {
$adminFields .= '<div class="col"><div class="title">';
$adminFields .= the_sub_field('title');
$adminFields .= '</div></div>';
} else {
$nonAdminFields .= '<div class="col"><div class="title">';
$nonAdminFields .= the_sub_field('title');
$nonAdminFields .= '</div></div>';
}
endwhile;
echo '<div class="container-fluid"><div class="row">';
echo $adminFields;
echo $nonAdminFields;
echo '</div></div>';
endif;
Alternate solution:
The other options may require at least two loops. You need to use the loops one after the other instead of nested loops.
...
$current_user = wp_get_current_user();
while( have_rows('repeater') ): $row = the_row();
$show_only = get_sub_field('show_only_to_logged_in_admins');
if ((user_can( $current_user, 'administrator' )) && ($show_only == 1)) {
// Display content
}
endwhile;
while( have_rows('repeater') ): $row = the_row();
$show_only = get_sub_field('show_only_to_logged_in_admins');
if (! (user_can( $current_user, 'administrator' )) || ($show_only != 1)) {
// Display content
}
endwhile;
...
Alternate Solution 2
Here is another technique: Get all the repeater rows and segregate them to admin and non-admin rows. Then you can loop over them. Here also you need to use two loops.
// This is just a pseudo-code but you get the idea
$rows = get_field('repeater');
$current_user = wp_get_current_user();
$adminOnlyRows = array_filter($rows, function ($row) {
$show_only = $row['show_only_to_logged_in_admins'];
return (user_can( $current_user, 'administrator' )) && ($show_only == 1);
});
$nonAdminOnlyRows = array_filter($rows, function ($row) {
$show_only = $row['show_only_to_logged_in_admins'];
return ! (user_can( $current_user, 'administrator' )) || ($show_only != 1);
});
echo '<div class="container-fluid"><div class="row">';
foreach ($adminOnlyRows as $row) {
// Display content
}
foreach ($nonAdminOnlyRows as $row) {
// Display content
}
echo '</div></div>';