Skip to content

Instantly share code, notes, and snippets.

@FranciscoG
Last active April 18, 2024 00:00
Show Gist options
  • Star 31 You must be signed in to star a gist
  • Fork 15 You must be signed in to fork a gist
  • Save FranciscoG/c393d9bc6e0a89cd79d1fd531eccf627 to your computer and use it in GitHub Desktop.
Save FranciscoG/c393d9bc6e0a89cd79d1fd531eccf627 to your computer and use it in GitHub Desktop.
An Advanced Custom Fields shortcode that allows to loop through a field with a repeater. This only handles simple cases, it can't handle nested repeater fields
<?php
/**
* ACF Pro repeater field shortcode
*
* I created this shortcode function because it didn't exist and it was being requested by others
* I originally posted it here: https://support.advancedcustomfields.com/forums/topic/repeater-field-shortcode/
*
* @attr {string} field - (Required) the name of the field that contains a repeater sub group
* @attr {string} sub_fields - (Required) a comma separated list of sub field names that are part of the field repeater group
* @attr {string} post_id - (Optional) Specific post ID where your value was entered. Defaults to current post ID (not required). This can also be options / taxonomies / users / etc
*/
function my_acf_repeater($atts, $content='') {
extract(shortcode_atts(array(
"field" => null,
"sub_fields" => null,
"post_id" => null
), $atts));
if (empty($field) || empty($sub_fields)) {
// silently fail? is that the best option? idk
return "";
}
$sub_fields = explode(",", $sub_fields);
$_finalContent = '';
if( have_rows($field, $post_id) ):
while ( have_rows($field, $post_id) ) : the_row();
$_tmp = $content;
foreach ($sub_fields as $sub) {
$subValue = get_sub_field(trim($sub));
$_tmp = str_replace("%$sub%", $subValue, $_tmp);
}
$_finalContent .= do_shortcode( $_tmp );
endwhile;
else :
$_finalContent = "$field does not have any rows";
endif;
return $_finalContent;
}
add_shortcode("acf_repeater", "my_acf_repeater");

Shortcode for Advanced Custom Fields Repeater rows

Setup a repeater field, in this example we'll call it "example-row"

and you give it the following sub fields:

  • example-name, text
  • example-phone, text
  • example-image, image, returns URL

in your post content setup the shortcode like this:

[acf_repeater field="example-row" sub_fields="example-name, example-phone, example-image"]
  User: %example-name%
  Phone: %example-phone%
  profile pic: %example-image%
[/acf_repeater]

notice how the list of comma separated items within the sub_field attribute become %variables% accessible within the repeater shortcode. This allows you to create a template row for your repeater. These items get trimmed so spaces around the commas in the list are ok.

Important

You can NOT nest repeater shortcodes as library is right now. If you need to then I would recommend adding more shortcodes with different names but pointing to the same function like this:

add_shortcode("acf_repeater", "my_acf_repeater");
add_shortcode("acf_sub_repeater", "my_acf_repeater");

and now you can nest it.

[acf_repeater field="example-row" sub_fields="example-name,  example-phone"]
  <div class="user">User: %example-name%</div><div class="phone">Phone: %example-phone%</div>
  [acf_sub_repeater field="example-sub-row" sub_fields="sub-item1, sub-item2"]
    %sub-item1% %sub-item2%
  [/acf_sub_repeater]
   You can put nested repeaters adjacent to each other, you just can't nest it again. For that you'll need to make more shortcodes
  [acf_sub_repeater field="example-sister-row" sub_fields="sub-item1, sub-item2"]
    %sub-item1% %sub-item2%
  [/acf_sub_repeater]
[/acf_repeater]

TODO: Figure out a better way to handle nesting rows without having to create more copies of the shortcode.

@dkeys222
Copy link

dkeys222 commented May 4, 2018

How can i separate each repeater field value with a line?

@kubik101
Copy link

kubik101 commented May 7, 2018

FYI - I needed to remove the space after the comma for the comma separated sub_fields so that I had the following:
[acf_repeater field="example-row" sub_fields="example-name,example-phone,example-image"]

@dkeys222
Copy link

dkeys222 commented May 7, 2018

how can I display only certain rows of the custom fields?

@meugamer
Copy link

Say my friend. In its first version I was able to run without problems. Now I have a hard time making it work in this new version.

@notechup
Copy link

Hi! Thanks for sharing this. Could be just what I need to show some repeater fields on my page with Elementor, as it does not seemlike they support those fields for dynamic content yet.

I get a fatal error though when activating the plugin. because I am missing the post_id, I just left it at null (since it was optional), but that doesn't work :)

Let's say I want to show this field on the author archive, so it needs to load the field from the same user profile that is being viewed. Would I need to change the post_id all over? Any help will be appreciated :) Thanks

@ryanjmcdermott
Copy link

I can't seem to get this to work properly. :/ here's what my situation looks like.

I've got a repeater field called "hours" and a sub-field called "open_hours".

My shortcode looks like this:

[acf_repeater field="hours" sub_fields="open_hours"] %open_hours% [/acf_repeater]

If I could get some help on this, that'd be great! It's the exact solution I've been looking for. :)

@Kennyboy7
Copy link

FYI - I needed to remove the space after the comma for the comma separated sub_fields so that I had the following:
[acf_repeater field="example-row" sub_fields="example-name,example-phone,example-image"]

Legend this was driving me mad until I read your comment

@Kennyboy7
Copy link

This works perfectly with X Theme Pro in the various elements. It's been driving me mad of how to do this and I stumbled across your code and tried it and it works for repeater fields. Thank you

@speedfreakhorror
Copy link

speedfreakhorror commented Mar 20, 2019

This is my code https://nimb.ws/Cha8Yd
what I get in return as result is weirder.
https://nimb.ws/t8nNUK
Any way to get the taxonomy field to get the name instead of the ID.

@Asaf2eat
Copy link

Any way to control the post_id inside the shortcode?

@imdanmuse
Copy link

@speedfreakhorror Were you able to resolve this? I'm having the same issue.
In the field settings, I've asked it to return the term object instead of the term ID, but when I do so, this shortcode makes the content of the entire page disappear.
I also attempted to use get_sub_field_object on line 33 but haven't resolved yet. Any insight as to how to fix this? Many thanks

@speedfreakhorror
Copy link

@speedfreakhorror Were you able to resolve this? I'm having the same issue.
In the field settings, I've asked it to return the term object instead of the term ID, but when I do so, this shortcode makes the content of the entire page disappear.
I also attempted to use get_sub_field_object on line 33 but haven't resolved yet. Any insight as to how to fix this? Many thanks

Yes I was able to solve it by using the plugin custom content shortcode from the WordPress plugin repo. It works perfectly with ACF.

@jnce84
Copy link

jnce84 commented Sep 26, 2019

Hello
I added the github function and tried to add my shorcode but "XXX does not have any rows". Any idea ?

[acf_repeater field="jour_x" sub_fields="photo_jour_x,description_jour_x"]
Photo: %photo_jour_x%
Description: %description_jour_x%
[/acf_repeater]

Thanks
Jonathan

@CodeCurosity
Copy link

When i include multiple fields in sub_fields attribute it seems to have wrong order, it shows first value of first field then first value of second field then second value of first field so here is what i did to keep things clean.

I have two fields in repeater field color & size and this is what i did to achieve what i need.

[acf_repeater field="color_and_sizes" sub_fields="size"]
%size%
[/acf_repeater]

then add the shortcode again for color

[acf_repeater field="color_and_sizes" sub_fields="color"]
%color%
[/acf_repeater]

@GreenLinkMedia
Copy link

GreenLinkMedia commented Dec 9, 2019

I'm having trouble pulling the link url in a subfield using this method. My first sub field is just text and my second sub field is a link. How can I edit your code to pull the correct link and wrap it in an href? Nevermind, I decided to redo the way the field was setup from the previous developer and made it a URL and not a file field. This works perfect, thank you!

@digitayfun
Copy link

This is great solution and working inside Elementor single template thanks very much.

@Kennyboy7
Copy link

To get this to work in elementor pro I needed to use the post id or it couldn't find any rows. It took a while to figure that one out.

@darcizzle2021
Copy link

darcizzle2021 commented Apr 4, 2021

Hello, I'm using this code and is working fine with almost all the fields, but i want to use a taxonomy field and i get only the id value in frontend. How I can modify this code so it shows the taxonomy value and not the id.

@websitecareio
Copy link

websitecareio commented Nov 8, 2021

Suggested change. This way someone could use it for arrays (life file uploads) .Example:

[acf_repeater field="downloads" sub_fields="fil.url"]
%fil.url%
[/acf_repeater]

and this way get the array values out.

Code:

// If this is an array we are searching values from. $pos = strpos(trim($sub), "."); if ($pos !== false) { $end = explode(".", $sub, 2); $subValue = get_sub_field(trim($end[0])); $_tmp = str_replace("%$sub%", $subValue[$end[1]], $_tmp); } else { $subValue = get_sub_field(trim($sub)); $_tmp = str_replace("%$sub%", $subValue, $_tmp); }

@think2308
Copy link

Thank you FranciscoG! Works perfect in elementor! So cool!

@landlogicit
Copy link

Good Job

@Thijmens
Copy link

Works also with php 8.0?

I have an error on php 8.0..
Backend fatal error: PHP Fatal error: Uncaught TypeError: str_replace(): Argument #2 ($replace) must be of type string when argument #1 ($search) is a string in...

@jessiemarpedrosa
Copy link

Thank you FranciscoG for this handy code. I'm using Kadence theme + Code Snippets.
Just a reminder though that, for multiple sub fields, you need to remove spaces for it to work.
Super amazing and thanks again!

@ppthemedr
Copy link

ppthemedr commented Sep 29, 2023

I have made some updates to add a line break after each row and/or to wrap the whole thing into a ul li / list structure. Especially handy if you need to put this shortcode in tinymce in wordpress which messes up your html structure.

function my_acf_repeater($atts, $content = '') {
  extract(shortcode_atts(array(
    "field" => null,
    "sub_fields" => null,
    "post_id" => null, // Use option for ACF options page
    "wrap_li" => false, // Option to wrap content in <li>
    "add_br" => false, // Option to add line breaks within <li> elements
  ), $atts));

  if (empty($field) || empty($sub_fields)) {
    return "";
  }

  $sub_fields = explode(",", $sub_fields);

  $repeater_items = array();

  if (have_rows($field, $post_id)) :
    while (have_rows($field, $post_id)) : the_row();

      $item_content = $content;
      foreach ($sub_fields as $sub) {
        $subValue = get_sub_field(trim($sub));
        $item_content = str_replace("%$sub%", $subValue, $item_content);
      }

      if ($add_br === "true") {
        $item_content .= "<br>";
      }

      $repeater_items[] = $item_content;

    endwhile;
  else :
    $repeater_items[] = "$field does not have any rows";
  endif;

  // Build the final HTML
  $final_content = ($wrap_li === "true") ? '<ul>' : '';

  foreach ($repeater_items as $item) {
    $final_content .= ($wrap_li === "true") ? "<li>$item</li>" : $item;
  }

  $final_content .= ($wrap_li === "true") ? '</ul>' : '';

  return $final_content;
}

add_shortcode("acf_repeater", "my_acf_repeater");

@code5rick
Copy link

Awesome work! Thanks for sharing with the community, @FranciscoG. Here's my fork: click here

  • Now, when an ACF is an array, instead of displaying 'Array', it will show the results.
  • Added an option to activate Var_dump for inspecting all the used variables and applying them to the array. This feature is specific for cases where you are using the "Taxonomy" field and want to link the post title to the taxonomy archive page.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment