Como corrigir o loop infinito no Repeater Field do ACF PRO
O que é o ACF Repeater loop infinito?
O loop infinito no Repeater Field do ACF PRO é quando um template percorre as linhas do campo Repeater com have_rows sem avançar o ponteiro interno de linha, e o laço nunca termina. A função have_rows apenas verifica se há linhas e devolve verdadeiro ou falso. Quem move o ponteiro para a próxima linha é a função the_row, chamada dentro do while. Sem the_row, a condição continua verdadeira para sempre e o PHP reexecuta a mesma linha até o servidor cortar a requisição por tempo de execução ou por memória.
Como identificar
- A página com o Repeater fica carregando e nunca termina, e depois cai com Maximum execution time of 30 seconds exceeded.
- O log de erros do PHP registra Allowed memory size of X bytes exhausted na linha do template que tem o while have_rows.
- O mesmo conteúdo de uma única linha do Repeater aparece repetido centenas de vezes antes de a página travar.
- Em Repeater aninhado, o laço interno reusa o nome do campo do laço externo e o segundo nível nunca avança.
Como prevenir
- Copie sempre o padrão have_rows, while, the_row, get_sub_field da documentação do ACF em vez de escrever o laço de memória.
- Em Repeater aninhado, nomeie os sub campos de forma distinta do campo pai para nunca confundir os ponteiros.
- Quando o Repeater roda em listagens, feche cada iteração com reset_rows e teste a página com muitos itens em staging antes de publicar.
Causa
- O while have_rows não chama the_row no corpo do laço, então o ponteiro interno de linha nunca avança e a condição fica sempre verdadeira.
- Em Repeater aninhado, o laço interno usa o mesmo nome de campo do laço externo em vez do nome do sub campo, e os dois ponteiros se misturam.
- O código avalia have_rows com um nome de campo que não existe no post atual, e um have_rows mal posicionado fora do escopo da linha mantém o laço aberto.
- Uma chamada a get_field do mesmo Repeater dentro do while reabre o array e reposiciona o estado do laço, impedindo o ponteiro de chegar ao fim.
- O Repeater roda em uma página de listagem em loop de posts sem reset_rows entre os posts, e o estado de linha de um post vaza para o seguinte.
Como resolver
- Confirme que the_row está dentro do while: abra o template e garanta que cada laço de Repeater chama a função que avança o ponteiro como primeira instrução dentro do while. É a ausência dela que cria o laço sem fim.
- Use o padrão canônico de loop do ACF: estruture o laço com a verificação, o while que avança a linha e a leitura do sub campo, exatamente como a documentação do ACF orienta.
if ( have_rows('itens') ) { while ( have_rows('itens') ) { the_row(); $título = get_sub_field('título'); } } - Separe os ponteiros no Repeater aninhado: no laço interno, percorra o sub campo Repeater pelo nome dele, nunca pelo nome do campo do laço externo. Cada have_rows mantém o próprio ponteiro quando o nome está correto.
while ( have_rows('itens') ) { the_row(); while ( have_rows('sub_itens') ) { the_row(); } } - Não reabra o campo dentro do laço: remova qualquer chamada a get_field do mesmo Repeater de dentro do while, porque ela reposiciona o estado do laço e impede o ponteiro de chegar ao fim. Leia os valores apenas com get_sub_field.
- Resete o estado entre posts: quando o Repeater roda dentro de um loop de posts, chame a função de reset do ACF ao fim de cada iteração para o estado de linha de um post não vazar para o próximo.
reset_rows(); - Ative o log e isole a linha: ligue o log de erros do PHP e abra o registro: a mensagem de tempo de execução ou de memória aponta a linha exata do while have_rows que ficou aberta, o que confirma a causa antes de publicar a correção.
define( 'WP_DEBUG', true ); define( 'WP_DEBUG_LOG', true );
<?php
// Repeater com filho aninhado, ponteiros separados e reset por post.
if ( have_rows( 'itens' ) ) {
while ( have_rows( 'itens' ) ) {
the_row(); // avanca o ponteiro do laco externo
$titulo = get_sub_field( 'titulo' );
echo esc_html( $titulo );
if ( have_rows( 'sub_itens' ) ) {
while ( have_rows( 'sub_itens' ) ) {
the_row(); // ponteiro proprio do laco interno
echo esc_html( get_sub_field( 'rotulo' ) );
}
}
}
}
reset_rows(); // limpa o estado quando o Repeater roda dentro de um loop de posts














