Como corrigir o erro de loop em Repeater aninhado no ACF PRO
O que é loop em Repeater aninhado no ACF PRO?
O loop em Repeater aninhado no ACF PRO e o padrão de código usado para exibir um Repeater colocado dentro de outro Repeater, como uma lista de serviços onde cada serviço tem vários itens. Para isso o ACF usa o par have_rows e the_row: o have_rows abre o loop e devolve verdadeiro enquanto houver linhas, e o the_row avanca para a próxima linha e move o ponteiro interno do ACF para aquela linha. Dentro de cada linha do Repeater pai você abre um novo have_rows com o nome do Repeater filho e repete o ciclo.
O problema surge quando esse ciclo e quebrado no nível aninhado. Segundo a documentação oficial do ACF, usar have_rows sem chamar the_row cria um loop infinito que resulta em tela branca, e o escopo de um loop have_rows e limitado a linha atual, ou seja, get_sub_field e the_sub_field so enxergam os dados da iteracao corrente. Quando o the_row do filho e esquecido, o nome do sub Repeater esta errado ou o have_rows do pai e do filho se confundem, o resultado e loop infinito, linhas duplicadas ou um Repeater filho que nunca aparece.
Como identificar
- A página abre em branco (White Screen of Death) ou trava ao carregar um template que percorre um Repeater dentro de outro Repeater.
- O log de erros registra esgotamento de memória, com mensagem ‘Fatal error: Allowed memory size of X bytes exhausted’, causado pelo loop que nunca termina.
- O Repeater pai exibe as linhas, mas o Repeater filho aninhado não mostra nenhum item, mesmo havendo dados salvos no campo.
- Os itens do Repeater filho aparecem repetidos ou misturados entre as linhas do pai, em vez de respeitar cada linha.
- get_sub_field do campo aninhado retorna vazio ou nulo dentro do loop interno, apesar de o campo estar preenchido no editor.
Como prevenir
- Sempre escreva o the_row() na mesma linha do while( have_rows(…) ) para nunca esquecer e evitar o loop infinito que a doc do ACF descreve.
- Indente e comente cada nível do Repeater aninhado, deixando claro qual have_rows pertence ao pai e qual pertence ao filho, evitando trocar os nomes dos campos.
- Mantenha get_sub_field e the_sub_field sempre dentro do while do nível correspondente, respeitando o escopo limitado a linha atual.
- Teste o template com um post que tenha várias linhas no pai e no filho em staging antes de subir, para flagrar duplicacao ou linhas filhas ausentes.
Causa
- O while( have_rows('repeater_filho') ) do Repeater aninhado não chama the_row() dentro do laco; a documentação oficial do ACF afirma que usar have_rows sem the_row cria um loop infinito com tela branca.
- O have_rows do Repeater filho recebe o nome do Repeater pai (ou o nome do sub campo errado), entao o ACF reabre o loop do pai dentro do laco e o ponteiro nunca chega ao fim, repetindo as linhas indefinidamente.
- O get_sub_field do campo aninhado e chamado fora do while do Repeater filho, fora do escopo da linha atual, e por isso retorna vazio, já que o escopo do have_rows e limitado a linha corrente.
- O the_row() do loop pai foi esquecido antes de abrir o have_rows do filho, fazendo o ACF buscar o sub Repeater sem uma linha pai ativa e não encontrar as linhas filhas.
- Um have_rows aninhado e iniciado dentro do mesmo Repeater (mesmo nome em pai e filho por copia de código), criando recursao sobre o próprio campo e estourando a memória do PHP.
Como resolver
- Faça backup e abra o template em staging: Antes de mexer no código, copie o arquivo do tema que percorre os Repeaters (por exemplo single.php, page.php ou um template de bloco) e trabalhe em um ambiente de teste. Um loop infinito derruba a página inteira, entao reverter precisa ser simples.
Acesse o site por FTP ou pelo gerenciador de arquivos da hospedagem Abra o template do tema que renderiza o Repeater (ex.: wp-content/themes/seu-tema/single.php) - Garanta um the_row() em cada nível do loop: Confirme que tanto o while do Repeater pai quanto o while do Repeater filho chamam the_row() logo após o have_rows. A documentação do ACF e explicita: have_rows sem the_row gera loop infinito e tela branca. Cada nível aninhado precisa do seu próprio par have_rows e the_row.
while( have_rows('repeater_pai') ) : the_row(); while( have_rows('repeater_filho') ) : the_row(); - Use o nome do sub campo correto no loop filho: O have_rows interno deve receber o nome do Repeater filho exatamente como aparece no grupo de campos, e não o nome do pai. Nome errado faz o ACF reabrir o loop do pai e repetir as linhas. Confira o nome em ACF -> Grupos de Campos abrindo o sub campo do tipo Repeater.
Painel WP -> ACF -> Grupos de Campos -> abra o sub Repeater e copie o Nome do campo Use esse nome dentro do loop pai: while( have_rows('nome_do_sub_repeater') ) : the_row(); - Acesse os sub campos dentro do escopo da linha: Chame get_sub_field e the_sub_field somente dentro do while correspondente, pois o escopo do have_rows e limitado a linha atual. Acessar o sub campo do filho fora do laco interno retorna vazio. No nível do pai use get_sub_field do pai; no nível do filho use get_sub_field do filho.
Dentro do while do filho: $valor = get_sub_field('campo_do_filho'); Para imprimir direto: the_sub_field('campo_do_filho'); - Recarregue a página e confira o log de erros: Limpe qualquer cache de página, recarregue o template corrigido e verifique se as linhas filhas aparecem por linha do pai. Se ainda houver tela branca, abra o debug.log para confirmar que o esgotamento de memória do loop infinito desapareceu.
Defina WP_DEBUG e WP_DEBUG_LOG como true no wp-config.php para gravar o log Abra wp-content/debug.log e procure por 'Allowed memory size' após recarregar
<?php
// Loop correto de um Repeater dentro de outro Repeater no ACF PRO.
if ( have_rows( 'servicos' ) ) :
while ( have_rows( 'servicos' ) ) : the_row();
// Sub campo do nivel pai (escopo = linha atual do pai).
$titulo = get_sub_field( 'titulo' );
echo '<h3>' . esc_html( $titulo ) . '</h3>';
// Repeater filho: nome do sub campo + the_row() obrigatorio.
if ( have_rows( 'itens' ) ) :
echo '<ul>';
while ( have_rows( 'itens' ) ) : the_row();
// Sub campo do filho lido dentro do laco interno.
$item = get_sub_field( 'nome_item' );
echo '<li>' . esc_html( $item ) . '</li>';
endwhile;
echo '</ul>';
endif;
endwhile;
endif;














