Paginating an Advanced Custom Fields Repeater
Hands down my favourite WordPress plugin is Elliot Condon’s Advanced Custom Fields, and it’s made even more powerful by the Repeater Field add-on. But a Repeater can get unwieldy when it contains a large number of items, and you might find yourself wanting to paginate the results when you display them to the user. Here’s a technique for doing that.
In this example we will paginate a Repeater image gallery mapped to a custom field named image_gallery
with a sub field named image
which contains an image object. Our Repeater will be displayed on a page at the URL /gallery
.
10 images will be displayed per page, and pagination links will allow the user to navigate between the gallery’s pages at pretty URLS such as /gallery/2/
, /gallery/3/
and so on.
If you’re wondering what special magic you need to perform to get those pretty permalinks working, the answer is… none! WordPress automagically converts URL segments such as /2/
into a query variable named "page"
. Very handy!
In your page template:
<?php
/*
* Paginate Advanced Custom Field repeater
*/
if( get_query_var('page') ) {
$page = get_query_var( 'page' );
} else {
$page = 1;
}
// Variables
$row = 0;
$images_per_page = 10; // How many images to display on each page
$images = get_field( 'image_gallery' );
$total = count( $images );
$pages = ceil( $total / $images_per_page );
$min = ( ( $page * $images_per_page ) - $images_per_page ) + 1;
$max = ( $min + $images_per_page ) - 1;
// ACF Loop
if( have_rows( 'image_gallery' ) ) : ?>
<?php while( have_rows( 'image_gallery' ) ): the_row();
$row++;
// Ignore this image if $row is lower than $min
if($row < $min) { continue; }
// Stop loop completely if $row is higher than $max
if($row > $max) { break; } ?>
<?php $img_obj = get_sub_field( 'image' ); ?>
<a href="<?php echo $img_obj['sizes']['large']; ?>">
<img src="<?php echo $img_obj['sizes']['thumbnail']; ?>" alt="">
</a>
<?php endwhile;
// Pagination
echo paginate_links( array(
'base' => get_permalink() . '%#%' . '/',
'format' => '?page=%#%',
'current' => $page,
'total' => $pages
) );
?>
<?php else: ?>
No images found
<?php endif; ?>
A note about Custom Post Types
This technique will also work on Custom Post Type single templates. Your pagination permalinks will have the format /post-type/post-slug/2/
.
Credits
My solution was inspired by Elliot Condon and Twansparent’s contributions to the Advanced Custom Fields forum.
33 thoughts on “Paginating an Advanced Custom Fields Repeater”
Comments are closed.
Hi, I found your post through the ACF post and I like your solution the best mainly because it is less code, but the pagination doesn’t seem to be working.
I see “1 2 Next »” and it says the URL for 2 is “domain.com/portfolio/post-name/page/2/”, but when I click on it, it reloads the parent page(“domain.com/portfolio/post-name/”).
What should I do?
(PS: the website is not open to public yet so I cant share the webpage)
Hey Jonathan,
I arrived to your blog reading a comment about the pagination on Elliot’s blog. Your solutions is much clean and leverage WP functionalities which is much better.
However, there is a bug. Your code doesn’t take in account the next page and keep loading records from number 1, thus making the pagination exercise useless.
I’m not sure whether this is the one above is the same code you run on your site though.
Best
Andrea
@Nils Sorry, I should have mentioned in my post that the technique as I originally described only worked on standard WordPress pages, not within a Custom Post Type. I’ve updated the post with a technique that should work with pages or with single custom post types. I have not tested this with standard posts.
Please note that the paginated permalinks have changed, and no longer include a
/page/
segment. Permalinks now look like this:/your-page-slug/2/
or for custom post types:
/post-type/post-slug/2/
The relevant code changes are:
The query variable referenced at the start of the code snippet becomes ‘page’ instead of ‘paged’:
if( get_query_var('page') ) {
$page = get_query_var( 'page' );
} else {
$page = 1;
}
And the base and format options passed to paginate_links become:
'base' => get_permalink() . '%#%' . '/',
'format' => '?page=%#%',
Let me know how you get on with this modified permalink structure.
@Andrea See my reply to Nils above. It probably applies in your situation too.
@Jonathan
It works great now! Thanks and I love your site here :]
Hi, thanks for that,
how is it possible to use the pagination links only with previous and next buttons in this case?
Thanks
Hi Jonathan,
thank you for the code, this works very well!
regards,
andi
@Oleg Probably the simplest solution is to use CSS to hide the number buttons, leaving only the prev and next buttons:
.page-numbers:not(.prev):not(.next) {
display: none;
}
@jonathan
it works – thanks
Hey Jonathan,
I’ve just found your blog via Advanced custom fields forum, Thanks for the developing the code, it is super useful.
I was thinking about having a “load more” button, With your code we’re almost there, do you have any thought to implement that?
@Amir Have a look at Paul Irish’s infinite scroll jQuery plugin https://github.com/paulirish/infinite-scroll
Infinite Scroll can be configured to work with a “load more” button. http://stackoverflow.com/questions/8770205/is-there-an-infinite-scroll-plugin-with-a-load-more-button
It works great! – Thank you very much Jonathan!
Hello,
I want a next, prev arrow functionality for testimonials.. means I want display one testimonial and other is next page..and previous page also.
I want a solution with ACF custom field plugin suitable code..If any one has code then plzzz help me quickly.
It will appreciated..
Thank You in advance..
@arpita See my reply to @oleg above.
Hello Jonathan,
Ya implement first that tutorial but its not works for me..
How to I link next prev button using testimonial.. display only one testimonial at a time.
Help me..
Thank you
Works wonderfully. Thanks a lot for sharing!
Can say i liked your solution, cleaner.. but your solution get me from page 2 to page 1 and leaves /1/ in link.. it will kinda look like duplicated content..
Hi Jonathan,
Brilliant post. Worked perfectly.
Cheers.
Jonathan,
That worked a treat for me, thank you.
Paudie
This works brilliantly. Thanks for sharing!
Is there a way to reverse the order of the rows, so that the most recently added repeater item would appear on the first page?
@Mark You could use this technique described in ACF’s documentation.
Hi, any idea on how to get this method to work with ACF Image Gallery?
This is awesome. The only thing I can’t figure out is why the
paginate_links()
doesn’t display. The only difference I can see that might be the culprit is I’m displaying a repeater on a page from an ACF Theme Options section.Here’s a link to see my code: http://www.codeshare.io/r1Hvp
Would love to hear your thoughts.
Cheers,
That worked a treat for me, thank you.
Awesome post man, thank you!
This is amazing – literally just worked perfectly. I had no idea how I was going to paginate my ACF repeater, so Googled it and this came up. Saved me a few hours work at least. Thanks!
Nice solution, so simple. Thanks for sharing. I guess after setting up a pagination it would be possible to send an ajax call. I am though not sure how to proceed. Do you/someone have any thoughts on that?
I like this solution to use and how it looks on the wordpress end and the user end, but unfortunately I can’t use it nor I would recommend anyone else of using it. this method is not passing through WordPress system such as in using tag.
by using this method WordPress has no knowledge of your paginated content
and it does not give a different Canonical tag for each page (for example if you are using some SEO plugin such as yoast).
as a result from all that, all numbered pages are has the same Canonical tag of the main first page which also get the address /1/ and thus duplicating the content on 2 different pages.
so, if I use this method all of the pages I create will be duplicated once and all numbers pages will canonical to them and will not be indexed in google or any other major search engine.
I wish I could find a way around it…. been looking for a long time but still can’t find any way to do this, if there is any way you can help me I would be very thankful, thanks for the post tough (:
Hi i looked at your article it works perfectly,
Thanks
Simply Superb. Hats off.
Hi. Your code is great, but the flaw Andrea spoke of above still occurs. It does not update the list but continually repeats pulling in rows. Your solution to Nils problem does not solve it, Johnathan. It needs to update the parameters for conditionals involving the row and max. Also, you cannot go back to first link as well. Do you have any solutions to these problems?
@Frederick I believe the problems Andrea and Nils identified were fixed in 2014 and no-one else has identified the same problem since then, so perhaps there is another factor at play which is stopping the code from working in your case? I am using this code on a production site to paginate an ACF repeater without the problems you have described.
@Jonathan May please see the link then so that I can see a live example of what it should be like then?