Average of Sub-Field Values in an ACF Repeater Field

Quick Summary

  • Loop through the repeater with have_rows() and the_row(), add each test_score sub-field to a total, and divide by the number of rows from count( get_field() ).
  • get_field() returns the repeater as an array of rows, so array_column(), array_filter() with is_numeric and array_sum() give the same average and also keep decimals and skip empty scores.
  • Check that the repeater has rows first: on PHP 8, count() and array_column() throw a fatal TypeError on the false that get_field() returns for an empty repeater.

To get the average of a number stored in an ACF repeater, such as the mean of all test scores entered as rows, add up the sub-field in every row and divide the total by the number of rows. This snippet does it with a have_rows() loop. It needs Advanced Custom Fields PRO for the Repeater field and goes in the template that displays the post the repeater belongs to, for example single.php.

PHP
<?php

if ( have_rows('ss_results') ) :

$count = count(get_field('ss_results'));
$totaltaskpercentage = 0;

while ( have_rows('ss_results') ) : the_row();
$totaltaskpercentage += intval( get_sub_field('test_score'));
endwhile;

$final_result = $totaltaskpercentage / $count;
echo round($final_result, 2);

endif;

 ?>

How it works

  • if ( have_rows( 'ss_results' ) ) runs the code only when the repeater has rows, so it never divides by zero.
  • get_field( 'ss_results' ) returns the repeater as an array of rows, so count() gives the number of rows.
  • The have_rows() and the_row() loop goes through each row and adds its test_score sub-field to $totaltaskpercentage. intval() turns each score into a whole number, so decimals are dropped.
  • The total divided by the number of rows gives the average in $final_result. The echo prints it rounded to two decimal places; change the 2 for more or fewer.
  • Replace ss_results and test_score with your own field names: the Field Name of the repeater and of the sub-field, not their labels.
  • If the template can load while ACF is inactive, check that ACF is active before calling its functions.

A shorter version with array functions

get_field() returns the whole repeater as an array. Each row is an array keyed by sub-field name, so three rows of scores come back as [ [ 'test_score' => '80' ], [ 'test_score' => '92.5' ], [ 'test_score' => '71' ] ]. PHP’s array functions can calculate the average from that without a loop:

PHP
<?php
$rows = get_field( 'ss_results' );

if ( $rows ) {
    $scores = array_filter( array_column( $rows, 'test_score' ), 'is_numeric' );

    if ( $scores ) {
        echo round( array_sum( $scores ) / count( $scores ), 2 );
    }
}
?>
  • get_field() returns false when the repeater has no rows, so if ( $rows ) stops there.
  • array_column() takes the test_score value from every row.
  • array_filter() with is_numeric drops rows whose score is empty, so they don’t count towards the average.
  • array_sum() adds the remaining scores, decimals included, and count() gives how many there are.

Which version should you use?

The two versions only differ when a score has decimals or a row has no score. With the three rows above, 80, 92.5 and 71, the loop prints 81 because intval() turns 92.5 into 92, and the array version prints 81.17. With 80, an empty score and 71, the loop counts the empty row as 0 and prints 50.33; the array version skips it and prints 75.5.

  • Keep the loop when scores are whole numbers and an empty row should count as zero.
  • Use the array version when scores can have decimals or some rows may be left empty.
  • To keep decimals in the loop, change intval() to floatval(). Empty rows still count as zero.

Common problems

  • Fatal error: count(): Argument #1 ($value) must be of type Countable|array. Since PHP 8.0, count() throws a TypeError when it gets something other than an array, and array_column() does the same. get_field() returns false for a repeater without rows, so always check for rows before counting, as both versions do.
  • Warning: array_sum(): Addition is not supported on type string. Since PHP 8.3, array_sum() warns when it meets a value it can’t add, such as an empty score. The is_numeric filter keeps those values out.
  • The repeater belongs to another post or an options page. Pass its ID as the second argument: have_rows( 'ss_results', $post_id ) and get_field( 'ss_results', $post_id ), or 'option' instead of the ID for an ACF options page. The same pattern is used to read the first row of another post’s repeater.
Share on X (opens in a new tab) Share on LinkedIn (opens in a new tab) Share on Facebook (opens in a new tab)

ChatGPT (opens in a new tab) Claude (opens in a new tab) Gemini (opens in a new tab) Perplexity (opens in a new tab) Grok (opens in a new tab)

More Insights

See More