# Como corrigir o erro de loop em Repeater aninhado no ACF PRO

O erro de loop em Repeater aninhado no ACF PRO acontece quando um have_rows de um Repeater filho e percorrido sem chamar the_row, ou quando o nome do sub campo não casa, gerando loop infinito com tela branca ou nenhuma linha exibida.

## 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.

**Antes de começar:** Antes de editar arquivos de template do tema ou ativar o WP_DEBUG em producao, faça backup completo do site (arquivos e banco) ou teste em staging. Um loop infinito de have_rows derruba a página inteira, entao garanta um caminho de reversao rápido.

## 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.

Erros relacionados

- [Como corrigir o Repeater Field que não salva dados no ACF PRO](https://full.services/wp-fixer/corrigir-repeater-nao-salva-acf-pro/)
- [Como corrigir Custom Fields que não aparecem no frontend no ACF PRO](https://full.services/wp-fixer/corrigir-custom-fields-frontend-acf-pro/)
- [Como corrigir o Relationship Field no ACF PRO](https://full.services/wp-fixer/corrigir-relationship-field-acf-pro/)

## 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

1. 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)
```

2. 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();
```

3. 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();
```

4. 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');
```

5. 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
```


## Código

```php
<?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;
```

## Perguntas frequentes

### Por que meu Repeater dentro de Repeater no ACF da tela branca

Quase sempre porque o while do Repeater filho chama have_rows sem o the_row. A documentação oficial do ACF afirma que usar have_rows sem the_row cria um loop infinito que resulta em tela branca. Adicione the_row logo após o have_rows em cada nível do loop.

### Como percorrer um Repeater aninhado no ACF PRO corretamente

Abra o while( have_rows('repeater_pai') ) : the_row(); e, dentro dele, abra outro while( have_rows('repeater_filho') ) : the_row();. Cada nível precisa do seu próprio par have_rows e the_row, e os sub campos são lidos com get_sub_field dentro do laco correspondente.

### Por que o Repeater filho não mostra nenhum item

Em geral o nome passado ao have_rows interno esta errado ou o get_sub_field foi chamado fora do while do filho. Como o escopo do have_rows e limitado a linha atual, acessar o sub campo fora do laco retorna vazio. Confirme o nome do sub Repeater em ACF -> Grupos de Campos.

### Posso usar o mesmo nome de campo no Repeater pai e no filho

Não e recomendado. Se o have_rows do filho receber o mesmo nome do pai, o ACF reabre o loop do pai dentro do laco e gera recursao, repetindo linhas ou estourando a memória. Use nomes distintos para o Repeater pai e o sub Repeater.

### Qual a diferenca entre get_sub_field e the_sub_field no loop aninhado

get_sub_field retorna o valor do sub campo da linha atual para você manipular em PHP, enquanto the_sub_field imprime o valor direto na tela. Ambos so funcionam dentro do while do nível correspondente, pois o escopo do have_rows e a linha corrente.

### Preciso usar get_row_layout em Repeater aninhado

Não para Repeater simples. get_row_layout serve para campos Flexible Content, onde cada linha tem um layout diferente. Para um Repeater dentro de outro Repeater, basta o ciclo have_rows, the_row e get_sub_field em cada nível.

### O que fazer se o log mostra esgotamento de memória nesse loop

O esgotamento de memória e sintoma do loop infinito. Verifique se todo while have_rows tem the_row e se os nomes de campo do pai e do filho estão corretos. Corrigido o ciclo, o loop termina e o erro de memória desaparece, sem precisar aumentar o limite de PHP.

**Fonte:** [Advanced Custom Fields — have_rows()](https://www.advancedcustomfields.com/resources/have_rows/)
