Black Friday 50% OFF! Coupon “BLACKFRIDAY50” Ends in:

0

Days

:

0

Hrs

:

0

Mins

:

0

Secs

Shop now!
WPLake > Learning Hub > ACF Repeater Field: Complete Guide with Code Snippets
  • Deutsch
  • Español
  • Français
  • Italiano

ACF Repeater Field: Complete Guide with Code Snippets

Explore ACF Repeater: a versatile field type for dynamic content, supporting nesting and multiple use cases. Learn to display items as sliders or grids.
hot air balloons are kinda like repeater fields

Key Points at a Glance

  1. ACF Repeater Field: The ACF Repeater is an advanced field type available in ACF Pro, allowing us to create repeatable sets of various field types.
  2. Use Cases: Common uses include creating dynamic sliders, team grids, related item lists, FAQs, event schedules, and portfolios. The Repeater field is versatile for managing complex data structures.
  3. Nested Repeaters: ACF Repeater supports unlimited nesting, allowing complex data structures with multiple layers of repeating fields.
  4. Misuse Warning: Using the Repeater field as a substitute for a Custom Post Type (CPT) is inefficient and not recommended for data that needs to be queried or used across multiple pages.
  5. Alternative Fields: For more flexible content structures, consider ACF’s Flexible Content field.
  6. Querying Data: To query Repeater field data, direct MySQL queries are required, as standard WP_Query does not support complex meta_key searches.

Table of Contents

The ACF Repeater is an advanced field type within the Advanced Custom Fields plugin, categorized under the Layout group. This field, available in the ACF Pro version, lets you define repeatable sets of various field types.

ACF Repeater field UI

ACF Repeater allows you to define a repeatable set of various field types.
ACF Repeater allows you to define a repeatable set of various field types.
acf repeater pagination
The Repeater field offers three layout options and pagination for results.
acf repeater layout settings
The three types of layout options for the ACF Repeater field. Fltr: Block Layout, Table Layout, and Row Layout.
repeater row layout
Close look at the row layout of the Repeater field.

ACF Repeater field-related addons

ACF addons can be an important part of the workflow, and there are several addons especially useful for the ACF Repeater field:

  • ACF to Custom Database Tables is an add-on for Advanced Custom Fields that saves your custom field data in a dedicated, structured database table, improving organization and performance.
  • ACF Table Field Plugin extends the functionality of Advanced Custom Fields by allowing easy-to-edit tables.
  • ACF Tooltip enhances the user experience by managing lengthy instruction texts in ACF fields. Instead of cluttering the edit screen, this plugin allows you to add tooltips to field labels, keeping the interface clean and space-efficient.
  • WPGraphQL for ACF allows you to expose ACF fields and field groups to GraphQL, enabling seamless querying of ACF data within your GraphQL queries.

Repeater fields in other meta-field plugins

When it comes to handling multiple fields, ACF takes a distinct approach. Many of its field types (such as File or Link) do not support multiple values. To manage multiple fields, you typically need to use the Repeater field to wrap these fields together.

Although some exceptions exist, like the Select field, most fields do not support multiple values without the Repeater.

Other meta plugins, such as Meta Box and Pods, provide a 'repeatable' setting for any field type. This allows you to create multiple rows for any field type without needing a separate Repeater field.

ACF’s approach with a dedicated Repeater field has its own drawbacks but also offers greater flexibility by letting you combine different field types within a single row. This can be especially useful for creating complex data structures.

While Pods doesn’t have a direct Repeater alternative, Meta Box offers the MB Group field. This feature lets you group different fields together and, along with the 'repeatable' setting, serves as a direct alternative to ACF’s Repeater. Read our comparison of the best meta field plugins to learn about the differences between vendors.

1. ACF Repeater field essentials

1.1) Field settings

General tab

  1. Subfields:
    This is where you define the fields that will be repeated within each row of the Repeater. You can add various types of fields (text, image, link, etc.) to create the structure and data you need for each repeated entry.
  2. Layout:
    This setting determines how the rows within the Repeater are displayed in the admin area. Options include:
    Table: Displays rows in a tabular format, which is useful for a spreadsheet-like overview.
    Block: Displays each row as a block, offering a more visually distinct view.
    Row: Displays rows in a linear format, focusing on a simple list.
  3. Pagination:
    This setting allows you to enable or disable pagination for the rows in the Repeater. Pagination helps manage large numbers of rows by splitting them across multiple pages, making the admin interface more navigable.

Validation tab

  1. Min Rows:
    Sets the minimum number of rows that must be present in the Repeater field. This ensures that at least a certain number of entries are always provided.
  2. Max Rows:
    Specifies the maximum number of rows allowed in the Repeater field. This restricts the number of entries that can be added, preventing the field from growing too large.

Presentation tab

  1. Collapsed Field:
    When enabled, editors can collapse a row, which hides all the fields except for the one specified here. This provides a cleaner preview interface, which is especially useful for setups with multiple fields.
  2. Button Label:
    Customizes the label of the button used to add new rows in the Repeater field. This label can be changed to something more descriptive or fitting for the content being repeated (e.g., "Add New Testimonial").

1.2) Storage format and supported field locations

For search-enabling purposes, the Repeater field in ACF saves each field value in a separate row within the database. For instance, if you have a Repeater field named datasheets with datasheet (text) and attachment (file) fields inside, and you have 2 rows, the database will store the following records:

datasheets_0_datasheet 
datasheets_0_attachment
datasheets_1_datasheet 
datasheets_1_attachment

As you see ACF follows the {repeater-name}_{row-index}_{field-name} format.

In the real database, it looks like this:

repeater in db
Repeater subfields in the WordPress post meta table.

Performance note: While the repeater storage format may look excessive, this approach allows you to search by repeater values later. The performance worries are fair if you're expecting to have dozens of records inside each repeater instance.
Currently (Aug 2024), ACF doesn't offer table storage, as MetaBox does, so if you're using an ACF repeater with dozens of records, be ready for potential performance issues.
P.S. This does not apply if you use the Repeater field inside ACF Blocks. In this case, all the data is stored within the block's single JSON settings file.

Supported field locations

You can use the ACF Repeater field across various locations, and it stores data consistently regardless of where it is applied:

  1. Post Objects (Post, Page, Media Attachment, CPT Item, WooCommerce Product):
    All content types, including posts, pages, media attachments, and custom post types, are stored in the wp_posts table. The Repeater field data is stored in the wp_postmeta table, associated with the relevant post or custom post type item.
  2. Options Page
    The Repeater field can be used on an ACF Options Page, storing its data in the wp_options table. This setup makes the Repeater data available as a global site-wide setting, useful for options like site-wide banners or settings.
  3. User Profiles:
    When the Repeater field is added to user profiles, its data is stored in the wp_usermeta table, linked to the corresponding user. This can be useful for user-specific data, such as additional user information or settings.
  4. Terms (e.g., Post Categories):
    The Repeater field can be attached to terms, such as post categories, tags, or custom taxonomies. In this case, the data is stored in the wp_termmeta table, connected to the specific term.
  5. ACF Gutenberg Block:
    The Repeater field can be included in custom ACF Gutenberg blocks. When used within an ACF Block, the Repeater data is stored within the post_content as part of the block's JSON data structure in the wp_posts table, making it a part of the block's content.

1.3) Alternative field types

If you need to combine different field types within a single row, the Repeater field isn't the only option available in ACF. The ACF Flexible Content field is another powerful choice, offering even greater flexibility.

Unlike the static rows defined in a Repeater field, the Flexible Content field allows you to create various 'layouts' that editors can dynamically choose from. This makes it an ideal solution for more complex and customizable content structures.

For handling images or attachments specifically, consider using the ACF Gallery field instead of the Repeater. The Gallery field is designed specifically for managing collections of images or attachments, providing a more tailored solution for such needs.

2. Use cases of the ACF Repeater field

The Repeater field is one of the cornerstone field types in ACF and can be utilized in countless ways. Here are some of the most popular real-life use cases:

  1. Items Slider (e.g., Testimonials):
    Use the Repeater field to build a dynamic slider for items like testimonials. With subfields for an image, name, and testimonial text, each entry becomes a slide.
  2. Teams Grid:
    Perfect for creating a team members section, the Repeater field allows you to add fields for each team member’s photo, name, job title, and bio, dynamically generating a grid layout that’s easy to update.
  3. Related Items:
    Use the Repeater field to list related items such as products, blog posts, or resources. Set up subfields like a Relationship or Post Object to link with other instances.
  4. FAQ Section:
    For creating a frequently asked questions (FAQ) section, the Repeater field is ideal. You can set up subfields for the question and answer.
  5. Event Schedules or Timelines:
    The Repeater field is great for creating event schedules or timelines. Add subfields for the event title, date, time, description, and location. This is particularly useful for conferences, webinars, or any event with multiple sessions or activities.
  6. Portfolio or Case Studies:
    When building a portfolio or case studies section, the Repeater field can help manage multiple entries. Add subfields for project name, description, date, images, and a link to the full case study. This approach makes it easy to showcase work dynamically.
  7. Service Lists:
    For websites that offer multiple services, use the Repeater field to create a dynamic list of services. Include subfields for the service name, description, icon or image, and pricing, allowing easy updates to service offerings.
  8. Product Features or Specifications:
    The Repeater field is excellent for displaying product features or specifications. Set up subfields for each feature, such as a title, icon, and description. This is useful for e-commerce sites where products have multiple attributes.

3. Inner Repeaters (nested, Repeater within a Repeater)

ACF Repeater supports an unlimited number of nested repeaters, allowing you to create a repeater within a repeater, and so on. This capability is particularly useful for complex data structures where you need multiple layers of repeating fields.

For instance, if you’re developing a custom ACF Gutenberg Block for managing awards, you might need not only a list of awards but also a nested repeater for managing multiple years of each award. This flexibility allows editors to handle intricate data setups efficiently.

Moreover, ACF Repeater does not impose restrictions on the types of fields you can nest within repeaters. You can include any field type, including Group and Gallery inside your repeater. It gives you the power to create sophisticated and dynamic content structures.

We'll show how to deal with the inner repeaters in the Code Snippets section.

4. Misuse of the ACF Repeater field

The Repeater field is a powerful tool, but it's crucial to understand its limitations and use it appropriately.

The most significant mistake you can make with the Repeater field is using it as a substitute for a Custom Post Type (CPT).

  • Good Repeater Usage:
    A single list of testimonials on a homepage or another specific page.
  • Bad Repeater Usage:
    A list of company employees used across several pages (e.g., "Our Editors," "Our Managers").

The key difference lies in how the data is used. The Repeater field is ideal for managing local, on-page data. However, if the data appears on multiple pages or needs to be queried (e.g., filtering employees by role), a CPT is the better choice.

As mentioned earlier, the Repeater field stores each row-field pair separately in the database, typically in the wp_postmeta table. If your code attempts to read all Repeater items and filter them by a specific field (like members with an editorial position) in PHP, this is an inefficient use case.

The correct approach would be to create a "Members" CPT with a role taxonomy and use a taxonomy query to filter members. In this scenario, each member's details can still be stored in ACF fields, but they are only queried when needed, optimizing performance and scalability.

Tip: If you're new to Custom Post Types and Taxonomies in WordPress, don't worry: ACF offers UI for CPT and Taxonomy management.

5. How to manage repeater rows in the UI

Managing repeater rows in the ACF (Advanced Custom Fields) user interface is straightforward but involves a few specific actions:

  1. Add a Row:
    To add a new row, click the "Add Row" button located below the repeater field table. This will create a new empty row at the bottom of the table.
  2. Remove a Row:
    Hover over the last column of the row you want to remove. A minus icon ("-") will appear. Click on this icon to delete the row.
  3. Clone a Row:
    Hover over the last column of the row you wish to clone, press and hold the Shift key, and click on the duplicate icon that appears. This will create an exact copy of the selected row.
  4. Reorder Rows:
    Hover over the first column of the row you want to move. When the cursor changes to a dragging icon (crosshair or hand), click and drag the row up or down to the desired position.
  5. Insert a Row Below a Specific Row:
    Hover over the last column of the row where you want to insert a new row below, and click the plus icon ("+") that appears. This will add a new row immediately below the selected one.

6. ACF Repeater field support in Themes and Builders

ACF is one of the most popular WordPress plugins, and it's supported by many page builders right out of the box. However, most of these integrations are basic, providing limited control over the layout.

To achieve universal compatibility with any theme and page builder while gaining advanced control over your layout, consider using the Advanced Views Framework or custom code snippets as discussed in the following chapter.

Here's a snapshot of the built-in features offered by some of the most popular WordPress themes and page builders for displaying ACF Repeater fields:

Theme/BuilderACF-related featureACF Repeater type support
Astra-no
AvadaDynamic Contentyes
BeaverACF Moduleyes
BricksDynamic datayes
DiviACF Moduleyes
ElementorDynamic Tagsno (not declared)
GeneratePress-no
Gutenberg-no
KadenceDynamic Contentyes
OceanWP-no
Visual ComposerDynamic Contentno (not declared)
WPBackery-no

While this list may seem brief, many themes come with their own page builders. Check your theme’s documentation for guidance on displaying ACF Repeater fields, or refer to the universal methods outlined below for a more flexible approach.

7. Code snippets for the ACF Repeater field

ACF functions and their responses are essentially wrappers around built-in WordPress features. This means that to load and display field values, you need to be familiar not only with ACF but also with core WordPress classes and functions. Additionally, writing markup from scratch and manually escaping data can be time-consuming.

To streamline development, you can use the Advanced Views Framework. This WordPress framework offers smart templates for the front end, simplifying post queries and template creation. It generates default markup and automatically loads the escaped data into the template, allowing you to focus on the layout itself.

Unlike drag-and-drop page builders, smart templates in Advanced Views are modular and based on a template engine (Twig or Blade), providing full control over the markup and helping you avoid the pitfalls of global CSS and JavaScript files. The framework natively supports all ACF field types, along with other data sources.

Note: AVF: Lite edition is free and supports all plain ACF field types, but Repeater is a multi-level field, supported only in the AVF: Pro edition. The good news that Pro contains a lot of useful features, including an option for custom Gutenberg blocks, which allows to turn any element into the Gutenberg block without any React coding.

Below are examples for both Advanced Views Pro and custom code:

7.1) Loading and displaying items

The simplest way to display items is to place them in a single row.

repeater datasheets styled output
The row of repeater items.

In this example, our repeater contains a Text field with the label name, and a File field, with the attachment name.

Using Advanced Views Framework

  1. Navigate to the Views section and create a new View.
  2. Select the Repeater field in the Fields tab. In the field settings, go to the Subfields tab, select the subfields you want to display (as shown on the AVF Repeater Docs page)
  3. Save the View; a template will be automatically generated. You can copy and modify this template as needed.
  4. To integrate it into your page, paste the generated shortcode or use the Custom Gutenberg block option.

The great news is that AVF automatically picks up the field data, including the return format, and loads it into the template, allowing you to focus on the layout itself.

For this example, we used the following template:

{% if repeater.value %}
    <div class="acf-view__repeater">

        {% for item in repeater.value %}
            <div class="acf-view__item">

                {% if item.label.value %}
                    <p class="acf-view__item-label">
                        {{ item.label.value }}
                    </p>
                {% endif %}

                {% if item.attachment.value %}
                    <a class="acf-view__item-attachment" target="{{ item.attachment.target }}"
                       href="{{ item.attachment.value }}" download='{{ item.attachment.title }}'>
                        {{ item.attachment.linkLabel|default(item.attachment.title) }}
                    </a>
                {% endif %}

            </div>
        {% endfor %}

    </div>
{% endif %}

And also a bit of CSS to get the desired look. You should it to the CSS code field of your View and the framework will automatically enqueue it on the target pages:

#view__repeater {
    display: flex;
    gap: 20px;
}

#this__item {
    display: flex;
    flex-direction: column;
    gap: 10px;
    border: 1px solid gray;
    border-radius: 10px;
}

Loading from different locations: To load a field from different locations (e.g., user profile), use the object-id shortcode argument.

Using custom code

To get the Repeater data, you need to use the ACF get_field() function. As the second argument, you need to specify the source to load the value from. Don't forget about security, and escape the output as shown below:

// Get the Repeater field data
$repeater_field = get_field('your_repeater_field_name'); // from the current post
$repeater_field = get_field('your_repeater_field_name', 10); // from a specific post by ID
$repeater_field = get_field('your_repeater_field_name', 'option'); // from the options page
$repeater_field = get_field('your_repeater_field_name', 'user_1'); // from the user by ID
$repeater_field = get_field('your_repeater_field_name', 'category_2'); // from the category term with ID 2
$repeater_field = get_field('your_repeater_field_name', 'genre_3'); // from the custom genre term with ID 3

// Check if the repeater field has data
if ( $repeater_field ) {
	// items wrapper
	echo '<div class="repeater">';

	// Loop through each row in the Repeater field
	foreach ( $repeater_field as $row ) {
		// Get sub-field values
		$label      = $row['label']; // Text sub-field
		$attachment = $row['attachment']; // File sub-field

		// Get attachment details (URL, title, etc.)
		$attachment_url   = isset( $attachment['url'] ) ? esc_url( $attachment['url'] ) : '';
		$attachment_title = isset( $attachment['title'] ) ? esc_attr( $attachment['title'] ) : '';

		// Output the label
		printf( '<div class="repeater__item"><p class="repeater__label">%s</p>', esc_html( $label ) );

		// Output the attachment link if available
		if ( $attachment_url ) {
			printf(
				'<a class="repeater__file" href="%s" download="">%s</a>',
				esc_url($attachment_url),
				esc_html($attachment_title)
			);
		}

		// Close the repeater item div
		echo '</div>';
	}

	// Close the items wrapper div
	echo '</div>';
}

Now we need to add some CSS to get the desired look. You should it to the style.css of your theme. However, by default, this code will be global and appear on all the site pages.

.repeater {
    display: flex;
    gap: 20px;
}

.repeater__item {
    display: flex;
    flex-direction: column;
    gap: 10px;
    border: 1px solid gray;
    border-radius: 10px;
}

7.2) Displaying items as a Grid

The CSS grid feature is the simplest way to display Repeater items as a grid.

Repeater items in a Grid
Repeater items in a Grid.

In the following example, we have the Title (Text field), Image (Image field), Price (Text field), and Year (Number field) subfields.

Using Advanced Views Framework

Create a View and select the Repeater field in the Fields tab. In the field settings, go to the Subfields tab, select the subfields you want to display (as shown on the AVF Repeater Docs page), and then click the Publish button. Your template will look like this:

{% if repeater.value %}
    <div class="acf-view__repeater">

        {% for item in repeater.value %}
            <div class="acf-view__item">

                {% if item.title.value %}
                    <h3 class="acf-view__item-title">
                        {{ item.title.value }}
                    </h3>
                {% endif %}

                {% if item.image.value %}
                    <img class="acf-view__item-image" src="{{ item.image.value }}" width="{{ item.image.width }}"
                         height="{{ item.image.height }}"
                         alt="{{ item.image.alt }}" decoding="{{ item.image.decoding }}"
                         loading="{{ item.image.loading }}"
                         srcset="{{ item.image.srcset }}" sizes="{{ item.image.sizes }}">
                {% endif %}

                {% if item.price.value %}
                    <p class="acf-view__item-price">
                        {{ item.price.value }}
                    </p>
                {% endif %}

                {% if item.year.value %}
                    <p class="acf-view__item-year">
                        {{ item.year.value }}
                    </p>
                {% endif %}

            </div>
        {% endfor %}

    </div>
{% endif %}

Now you can add the following CSS to the CSS code field of your View:

#view__repeater {
 display: grid;
 grid-template-columns: 1fr;
 gap: 20px;
}

@media screen and (min-width:992px) {
#view__repeater {
  grid-template-columns: repeat(2, 1fr);
 }
}

Using get_field() function

Add the following code to the target theme template:

// Get the Repeater field data
$repeater_field = get_field( 'your_repeater_field_name' );

// Check if the repeater field has data
if ( $repeater_field ) {
	// Items wrapper
	echo '<div class="repeater">';

	// Loop through each row in the Repeater field
	foreach ( $repeater_field as $row ) {
		// Get sub-field values
		$title = $row['title'] ?? ''; // Text sub-field
		$image = $row['image'] ?? ''; // Image sub-field
		$price = $row['price'] ?? ''; // Text sub-field
		$year  = $row['year'] ?? ''; // Number sub-field

		// Get image ID and details
		$image_id  = isset( $image['ID'] ) ? intval( $image['ID'] ) : 0;
		$image_alt = isset( $image['alt'] ) ? esc_attr( $image['alt'] ) : 'Image';

		// Output the item
		echo '<div class="repeater__item">';

		// Output the title
		if ( $title ) {
			printf( '<h3 class="repeater__title">%s</h3>', esc_html( $title ) );
		}

		// Output the image using wp_get_attachment_image()
		if ( $image_id ) {
			echo wp_get_attachment_image( $image_id, 'full', false, array( 'alt' => $image_alt ) );
		}

		// Output the price
		if ( $price ) {
			printf( '<p class="repeater__price">%s</p>', esc_html( $price ) );
		}

		// Output the year
		if ( $year ) {
			printf( '<p class="repeater__year">%s</p>', esc_html( $year ) );
		}

		// Close the item div
		echo '</div>';
	}

	// Close the items wrapper div
	echo '</div>';
}

And the following CSS to the style.css of your theme:

.repeater {
    display: grid;
    grid-template-columns: 1fr;
    gap: 20px;
}

@media screen and (min-width:992px) {
    .repeater {
        grid-template-columns: repeat(2, 1fr);
    }
}

7.3) Displaying items as a Slider

A slider is an excellent way to present repeater items dynamically. To create a slider, you'll need to choose and implement a JavaScript library. In this example, we’ll use Splide.

ACF Repeater items in a slider
ACF Repeater items in a slider.

In this case, we have the description (WYSIWYG field), name (Link field), and position (WYSIWYG field) subfields.

The simplest way to turn the repeater into the slider is to use Advanced Views, as the framework comes with pre-configured Slider, Masonry, and Image gallery libraries.

Using Advanced Views Framework

After adding the repeater field to the target View, change the 'Enable Slider' option to 'Splide v4' and press the Save button, as described on the AVF Repeater Docs page. The framework will automatically change the field markup to incorporate the necessary classes, and add the default JS instance:

var repeater = this.querySelector('.acf-view__repeater');
if (repeater_inner) {
	/* https://splidejs.com/guides/options/ */
	new Splide(repeater, {
		type: 'loop',
		perPage: 1,
		perMove: 1,
	}).mount();
}

Now you can customize the settings according to your needs, using any available Splide options.

Using custom theme code

In this case, you need to download the CSS and JS code of the Splide library to your theme. Then, print the gallery in the target template with the necessary splide classes:

// Get the Repeater field data
$repeater_field = get_field( 'your_repeater_field_name' );

// Check if the repeater field has data
if ( $repeater_field ) {
	// Wrapper for the Splide slider
	echo '<div class="splide">';

	// Items wrapper for Splide slider
	echo '<div class="splide__track">';
	echo '<ul class="splide__list">';

	// Loop through each row in the Repeater field
	foreach ( $repeater_field as $row ) {
		// Get sub-field values using null coalescing operator
		$description = $row['description'] ?? ''; // WYSIWYG sub-field
		$name        = $row['name'] ?? ''; // Link sub-field
		$position    = $row['position'] ?? ''; // WYSIWYG sub-field

		// Output the item
		echo '<li class="splide__slide">';

		// Output the description
		if ( $description ) {
			printf( '<div class="slider__description">%s</div>', wp_kses_post( $description ) );
		}

		// Output the name as a link
		if ( $name ) {
			printf( '<a class="slider__name" href="%s">%s</a>', esc_url( $name['url'] ), esc_html( $name['title'] ) );
		}

		// Output the position
		if ( $position ) {
			printf( '<div class="slider__position">%s</div>', wp_kses_post( $position ) );
		}

		// Close the slide item
		echo '</li>';
	}

	// Close the Splide list and track wrapper divs
	echo '</ul>';
	echo '</div>';

	// Close the general Splide wrapper div
	echo '</div>';
}

Then enqueue the library's CSS using the wp_enqueue_style function, and add the following JS to your theme's script.js:

import '/wp-content/themes/YOUR_THEME/assets/js/splide.js';

document.addEventListener('DOMContentLoaded', function () {
    var slider = document.body.querySelector('.splide');
    if (slider) {
        /* https://splidejs.com/guides/options/ */
        new Splide(slider, {
            type: 'loop',
            perPage: 1,
            perMove: 1,
        }).mount();
    }
});

Now you can customize the settings according to your needs, using any available Splide options.

7.4) Displaying nested repeater

A nested repeater refers to having a Repeater field within another Repeater field. To display nested repeaters, you'll need to first handle the outer repeater rows, and then process the nested repeater values using an additional loop.

The simplest way to manage nested repeaters is by using the Pro edition of the Advanced Views Framework. The framework streamlines the loading and processing of nested repeaters, allowing you to focus on designing the layout rather than dealing with complex data handling.

Using Advanced Views Framework

AVF supports nested repeaters with no restrictions on the depth of nesting. To display a nested repeater, follow the steps, mentioned in the AVF Nested Repeater guide:

  1. Create the Parent View:
    Go to the Views section and create a new 'Parent' View.
    Select the target repeater field in the Fields tab and save the View.
  2. Create the Child View:
    Create another View, this will be the 'Child' View.
    In the 'Parent Group' field of this View, choose the target repeater field that is nested within the Parent View and save the View.
  3. Configure the Parent View:
    Open the 'Parent' View.
    In the repeater field settings of the Parent View, select the 'Child' View you just created from the 'View' setting and save the Parent View.

That’s it! You can now use the 'Parent' View wherever needed, and it will display both the outer repeater fields and the nested inner repeater. Also, you can customize the template further and add CSS/JS as usual.

Using get_field() function

Let's modify the code from our Grid example, reviewed above, to turn the single year field into the year's repeater:

// Get the Repeater field data
$repeater_field = get_field( 'your_repeater_field_name' );

// Check if the repeater field has data
if ( $repeater_field ) {
	// Items wrapper
	echo '<div class="repeater">';

	// Loop through each row in the Repeater field
	foreach ( $repeater_field as $row ) {
		// Get sub-field values
		$title = $row['title'] ?? ''; // Text sub-field
		$image = $row['image'] ?? ''; // Image sub-field
		$price = $row['price'] ?? ''; // Text sub-field

		// Get nested repeater field data (if any)
		$nested_repeater = $row['nested_years_repeater'] ?? []; // Replace with your nested repeater field name

		// Get image ID and details
		$image_id  = $image['ID'] ?? 0;
		$image_alt = $image['alt'] ?? 'Image';

		// Output the item
		echo '<div class="repeater__item">';

		// Output the title
		if ( $title ) {
			printf( '<h3 class="repeater__title">%s</h3>', esc_html( $title ) );
		}

		// Output the image using wp_get_attachment_image()
		if ( $image_id ) {
			echo wp_get_attachment_image( $image_id, 'full', false, [ 'alt' => $image_alt ] );
		}

		// Output the price
		if ( $price ) {
			printf( '<p class="repeater__price">%s</p>', esc_html( $price ) );
		}

		// Output the nested repeater
		if ( $nested_repeater ) {
			echo '<div class="nested-repeater">';

			foreach ( $nested_repeater as $nested_row ) {
				$nested_year  = $nested_row['nested_year'] ?? ''; // Replace with your nested sub-field name

				// Output the nested repeater item
				echo '<div class="nested-repeater__item">';

				// Output the nested year
				if ( $nested_year ) {
					printf( '<p class="nested-repeater__year">%s</p>', esc_html( $nested_year ) );
				}

				// Close the nested item div
				echo '</div>';
			}


			// Close the nested repeater wrapper div
			echo '</div>';
		}

		// Close the item div
		echo '</div>';
	}

	// Close the items wrapper div
	echo '</div>';
}

7.5) Displaying a random repeater row

Since the Repeater field's response is an array, you can use built-in PHP functions to pick a random row.

Using Advanced Views Framework

Use the random function as shown on the AVF Repeater Docs page:

{% set randomItem = random(repeater.value) %}
{# todo work with the item as usually: randomItem.subfield.value #}

Using custom theme code

Here can use the array_rand function in PHP to pick a random row index. Once you've selected a random row, you can process and display it as usual. Here's an example to illustrate this:

// Get the Repeater field data
$repeater_field = get_field( 'your_repeater_field_name' );

// Check if the repeater field has data
if ( $repeater_field ) {
	// Pick a random row index
	$random_index = array_rand( $repeater_field );
	$random_row   = $repeater_field[ $random_index ];

	// Get sub-field values from the random row
	$description = $random_row['description'] ?? ''; // WYSIWYG sub-field
	$name        = $random_row['name'] ?? '';        // Link sub-field
	$position    = $random_row['position'] ?? '';    // WYSIWYG sub-field

	// todo create the target HTML
}

7.6) Custom rows sorting

If you have a Repeater field with subfields like "Title" and "Year" and you want to sort the rows by the "Year" field in ascending order, you can use PHP's sort functions. This allows you to sort the rows based on a specific subfield value.

Using Advanced Views Framework

Use the sort filter as shown on the AVF Repeater Docs page:

{% for item in repeater.value|sort((a, b) => a.year <=> b.year) %}
{# todo print item fields #}
{% endfor %}

Using custom theme code

Here we can use the PHP usort function:

// Get the Repeater field data
$repeater_field = get_field( 'your_repeater_field_name' );

// Check if the repeater field has data
if ( $repeater_field ) {
	// Sort the rows by the 'year' subfield in ascending order
	usort( $repeater_field, function ( $a, $b ) {
		$year_a = $a['year'] ?? 0; // Handle missing or null values by defaulting to 0
		$year_b = $b['year'] ?? 0; // Handle missing or null values by defaulting to 0

		return $year_a <=> $year_b; // Ascending order comparison
	} );
	// todo output the rows as usually
}

Tip: To change the sorting order to descending, you simply need to adjust the comparison logic within the usort function. For descending order, you can reverse the comparison by swapping the variables, so placing $year_b at the left side.

7.7) Updating the repeater field programmatically

To update the Repeater field programmatically, you can use the ACF update_field function. Since this field stores items in an array, the data you pass must be an array of sub-field values.

add_action('acf/init', function() {
    // Define the repeater data
    $repeater_data = array(
        array(
            'sub_field_1' => 'Value 1', // Replace with your actual sub-field key and value
            'sub_field_2' => 'Value 2', // Replace with your actual sub-field key and value
        ),
        array(
            'sub_field_1' => 'Value 3', // Replace with your actual sub-field key and value
            'sub_field_2' => 'Value 4', // Replace with your actual sub-field key and value
        ),
    );

    // Update the Repeater field
    update_field('my_repeater_field', $repeater_data, 1); // Replace 'my_repeater_field' with your Repeater field key, and 1 with the target post ID
});

If you need to update the Repeater field on a user or term object, you must add the appropriate prefix, just as shown in the "loading" field value section.

Note: You should call the update_field function inside the acf/init action, or in any hooks that happen later.

8. Querying by the ACF Repeater field

The way ACF Repeater stores data in the database - using individual rows for each field value - allows you to query repeater fields, but it requires manual handling.

To query by repeater fields, you'll need to work directly with MySQL queries because WP_Query and other WordPress query builders do not support querying meta fields using LIKE for meta_key comparison. This approach is necessary to query across all repeater rows.

Below we provide examples of how to master MySql queries depending on where the Repeater field values are stored. To better understand the used tables and columns, you can read the WordPress database description in the WP Docs.

8.1) By postmeta (Post, Page, Any CPT)

We execute the direct MySql query in WordPress we need to use the global wpdb class. Replace the repeater-name and field-name in the code with the name of your repeater field and target subfield.

global $wpdb;

// Prepare the query
$query = $wpdb->prepare(
	"SELECT post_id
    FROM $wpdb->postmeta
    WHERE meta_key LIKE 'repeater-name_%_field-name'
    AND meta_value = %s",
	'the very first item'
);

// Execute the query. The array will contain the post IDs of the posts where the key is found.
$results = $wpdb->get_col( $query );

8.2) By termmeta (Terms)

The same as by postmeta, but only using termmeta table name from the wpdb class:

global $wpdb;

// Prepare the query
$query = $wpdb->prepare(
	"SELECT term_id
    FROM $wpdb->termmeta
    WHERE meta_key LIKE 'repeater-name_%_field-name'
    AND meta_value = %s",
	'the very first item'
);

// Execute the query. The array will contain the term IDs of the terms where the key is found.
$results = $wpdb->get_col( $query );

8.3) By usermeta (user profile)

In this case using usermeta of the wpdb class:

global $wpdb;

// Prepare the query
$query = $wpdb->prepare(
	"SELECT user_id
    FROM $wpdb->usermeta
    WHERE meta_key LIKE 'repeater-name_%_field-name'
    AND meta_value = %s",
	'the very first item'
);

// Execute the query. The array will contain the user IDs of the users where the key is found.
$results = $wpdb->get_col( $query );

8.4) Inside ACF Blocks

ACF Blocks save their data as JSON in the post_content. This data cannot be queried directly. However, if you enable the "Save in Meta" feature for ACF Blocks, the field values are also saved in post meta, allowing you to query them similarly to other postmeta fields.

9. Related Repeater field filters and hooks

ACF offers a variety of filters and hooks that enable you to modify field data and behavior, extending WordPress's core hooks functionality. You can utilize the standard add_action and add_filter functions to attach custom code to these hooks.

Below are some of the most commonly used hooks along with the ACF Repeater field type:

9.1) acf/load_field

The acf/load_field filter allows you to modify the field settings before it is displayed on the editor's screen. This filter is particularly useful for dynamically adjusting the field's configuration, such as setting default values, changing labels, or customizing available options.

add_filter('acf/load_field/name=my_repeater_field', function (array $field): array {
    // Modify the field settings as needed
    $field['instructions'] = 'Please fill out all repeater fields.';

    return $field;
});

9.2) acf/render_field

The acf/render_field action allows you to add custom HTML before or after a field's input on the editor's screen in the WordPress admin. This can be particularly useful for adding custom-styled text, icons, styles, or additional interactive elements to enhance the field's functionality.

// Replace field key with yours
add_action('acf/render_field/key=field_123456789abc', function (array $field): void {
    // Your custom HTML
    echo '<div class="my-custom-class">Custom field-related element</div>';
});

Note: By default, the acf/render_field action is triggered after the field input has been printed. If you need to print your HTML before the input, you should set the priority number to 9 or lower in the third argument of the add_action WordPress function.

9.3) acf/validate_value

Use the acf/validate_value filter to validate the values entered into the field. You can ensure that the entered value meets specific criteria:

add_filter('acf/validate_value/name=my_repeater_field', function($valid, $value, array $field) {
    if (true !== $valid) {
        return $valid; // Skip validation if there is an existing error
    }

    // Custom validation: Ensure each repeater row has a non-empty value
    foreach ($value as $row) {
        if (empty($row['sub_field_1']) && empty($row['sub_field_2'])) {
            $valid = 'Please fill out at least one sub-field in the repeater row.';
            break;
        }
    }

    return $valid;
}, 10, 3);

9.4) acf/validate_save_post

The acf/validate_save_post action allows you to perform custom form validations before saving ACF fields. This is particularly useful when you need to validate one field's value based on another field's input or enforce specific rules across multiple fields.

add_action('acf/validate_save_post', function () {
    // Get the repeater field values from ACF fields
    $repeater_1 = $_POST['acf']['field_repeater_id_1'] ?? [];
    $repeater_2 = $_POST['acf']['field_repeater_id_2'] ?? [];

    if (empty($repeater_1) || empty($repeater_2)) {
        return;
    }

    // Check if the number of rows in both repeaters are the same
    if (count($repeater_1) !== count($repeater_2)) {
        // Add a validation error if the row counts do not match
        acf_add_validation_error('field_repeater_id_1', 'The number of rows must match.');
        acf_add_validation_error('field_repeater_id_2', 'The number of rows must match.');
    }
});

Tip: To find the field key, navigate to the ACF field group in the WordPress admin. Click on the Screen Options button at the top right corner of the page, then check the Field Keys option. Once enabled, the field keys will be displayed next to each field name in the group.

9.5) acf/save_post

The acf/save_post action is triggered when the current item (page/product/user) is saved. You can use it to perform any additional actions, e.g. updating related data.

add_action('acf/save_post', function ($post_id) {
    // Retrieve the repeater field value (replace with your actual repeater field key)
    $repeater = get_field('project_repeater', $post_id); // Field key for repeater

    if (!$repeater) {
        return;
    }

    // Process each row in the repeater field
    foreach ($repeater as $row) {
        // Get the related post ID from the relationship field
        $related_post_id = $row['sub_field_1']; // Replace with your actual sub-field key

        if (!$related_post_id) {
            continue;
        }

        // Fetch the current related items for the related post
        $related_items = get_field('related_item', $related_post_id);

        // If there are no related items, initialize as an array
        if (!$related_items) {
            $related_items = [];
        }

        // Add the current post ID to the related items array
        if (!in_array($post_id, $related_items, true)) {
            $related_items[] = $post_id;
        }

        // Update the related items field with the new array
        update_field('related_item', $related_items, $related_post_id);
    }
});

Stuck with development or facing an issue?

WPLake offers affordable on-demand website development and design.

No matter the size of your project - contact us now, and we'll get it done for you!

Get assistance now

FAQ mode

/

Learning mode

  1. Can I update a Repeater field programmatically?

    Yes, you can set up the Repeater field value programmatically using the ACF update_field function. Ensure the structure of the rows matches the response format of the get_field function.

Was this article helpful?

Totally useless

Slightly helpful

Very helpful

Course navigation: ACF Plugin

Content links (101)

About the Author

Baxter Jones

With over 15 years of experience in the web industry, I specialize in design, user experience, and web best practices. I have a keen eye for detail and thrive on following a structured process in my work. I’m passionate about WordPress, considering it the best innovation since sliced bread. When I’m not at my computer, you’ll find me enjoying time in the garden.

0 Comments

    Leave a comment

    Reply to 

    Please be considerate when leaving a comment.

    Not shown publicly


    Got it