# Como corrigir o Relationship Field no ACF PRO

O Relationship field do ACF PRO que não funciona acontece quando get_field() devolve um array inesperado, o loop com setup_postdata mostra o post errado por falta de wp_reset_postdata, ou a meta_query usa igualdade em vez de LIKE no valor serializado.

## O que é Relationship Field do ACF PRO que não funciona?

O Relationship field do ACF PRO é o campo de seleção dupla que liga um post a outros posts, páginas ou custom post types. Quando ele não funciona, o sintoma cai em três famílias: a seleção não salva no editor, o template imprime branco ou erro em vez dos posts ligados, ou uma busca por quem aponta para um post não retorna resultado. O ponto que confunde é que o valor é guardado serializado na wp_postmeta, no formato a:2:{i:0;s:2:"35";i:1;s:2:"33";}, e o que o get_field() devolve depende do Return Format do campo (objeto WP_Post ou ID inteiro). Misturar esses dois mundos, ou esquecer de restaurar o post global depois do loop, é o que quebra o campo na prática, sem gerar erro fatal.

## Como identificar

- No template, o bloco que deveria listar os posts ligados renderiza em branco, mesmo com itens selecionados no editor.
- var_dump( get_field('posts_relacionados') ) imprime bool(false) ou array vazio em vez dos posts esperados.
- Depois do laço do relationship, o resto da página mostra o título e o link de um dos posts relacionados no lugar do post principal.
- Aviso Trying to get property ID of non-object ou Object of class WP_Post could not be converted no log, ao acessar o item do array.
- Uma WP_Query que busca quem referencia um post pelo relationship retorna zero posts, mesmo havendo ligações salvas.
- Ao tentar salvar, o ACF exibe a validação de mínimo ou máximo de posts e a seleção é descartada.

## Como prevenir

- Defina o Return Format do relationship logo na criação do campo e escreva o loop do template no mesmo formato, evitando o descompasso objeto contra ID.
- Encerre todo loop que usa setup_postdata com wp_reset_postdata, padronizando isso em todos os templates que listam posts relacionados.
- Ao consultar o relationship por código, use sempre compare LIKE com o ID entre aspas e nunca igualdade exata, porque o valor vive serializado.
- Versione a pasta acf-json no tema para os field groups viajarem com o código e o field name sempre resolver em cada ambiente.

Erros relacionados

- [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 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 exibem no frontend no ACF PRO](https://full.services/wp-fixer/corrigir-custom-fields-nao-exibem-acf-pro/)

## Causa

- O Return Format do campo está como Post Object e o template trata cada item como ID (ex.: passa o item direto para get_permalink esperando um número), ou o inverso: está como Post ID e o código acessa item->ID como se fosse objeto.
- O loop usa setup_postdata para imprimir cada relacionado mas não chama wp_reset_postdata ao final, então o post global fica apontando para o último relacionado e o restante da página sai trocado.
- A consulta que procura quais posts apontam para um alvo usa compare igual a igualdade exata no valor, mas o relationship é gravado serializado, então só compare LIKE com o ID entre aspas casa dentro do array serializado.
- O filtro Filter by Post Type, Filter by Post Status ou Filter by Taxonomy do campo está restringindo a coluna de escolha, então os posts que você espera ligar nem aparecem para seleção.
- A chamada usa o field key no formato field_5f3a1b2c em vez do field name do campo, e o grupo não está sincronizado, então o ACF não resolve o nome e devolve vazio.
- A regra de Minimum Posts ou Maximum Posts na aba de validação está sendo violada (zero selecionado num campo obrigatório, ou mais itens que o teto), e o ACF bloqueia o save da seleção.

## Como resolver

1. Veja o que o campo realmente devolve: No template, imprima o valor cru do campo no contexto onde ele falha. Isso revela se o retorno é uma lista de objetos WP_Post, uma lista de IDs, false ou vazio, e direciona toda a correção seguinte.

```
var_dump( get_field('posts_relacionados') );
```

2. Alinhe o Return Format com o código do template: Decida um formato e siga ele. No painel do ACF abra o campo e ajuste o Return Format, depois escreva o loop correspondente. Caminho no menu: Custom Fields -> Field Groups -> seu grupo -> o campo -> Return Format.

```
Custom Fields -> Field Groups -> [grupo] -> [campo] -> Return Format
$posts = get_field('posts_relacionados'); // Return Format = Post Object
foreach ( $posts as $post ) { setup_postdata( $post ); the_title(); }
```

3. Restaure o post global ao fim do loop: Sempre que usar setup_postdata para imprimir os relacionados, feche o laço restaurando o post principal. Sem isso o resto da página herda o último relacionado.

```
wp_reset_postdata();
```

4. Consulte o relationship com LIKE no valor serializado: Para buscar quais posts apontam para um alvo, não use igualdade exata: o valor é serializado. Use compare LIKE com o ID entre aspas, que casa o item dentro do array e evita falso positivo com IDs que são substring.

```
'meta_query' => array( array( 'key' => 'posts_relacionados', 'value' => '"' . $post_id . '"', 'compare' => 'LIKE' ) )
```

5. Revise os filtros da coluna de escolha: Se os posts que você quer ligar nem aparecem para selecionar, são os filtros do campo restringindo a lista. Confira Filter by Post Type, Filter by Post Status e Filter by Taxonomy e deixe-os cobrindo o que precisa aparecer. Caminho no menu: Custom Fields -> Field Groups -> o campo -> Filters.

```
Custom Fields -> Field Groups -> [campo] -> Filter by Post Type / Post Status / Taxonomy
```

6. Cheque a validação de mínimo e máximo: Se a seleção some ao salvar, é a regra de quantidade barrando. Ajuste Minimum Posts e Maximum Posts na configuração do campo para a faixa real de uso. Caminho no menu: Custom Fields -> Field Groups -> o campo -> Validation.

```
Custom Fields -> Field Groups -> [campo] -> Minimum Posts / Maximum Posts
```


## Código

```php
<?php
// Relationship com Return Format = Post Object: lista e restaura o post global.
$relacionados = get_field( 'posts_relacionados' );

if ( $relacionados ) {
    echo '<ul>';
    foreach ( $relacionados as $post ) {
        setup_postdata( $post ); // habilita the_title()/the_permalink()
        printf(
            '<li><a href="%s">%s</a></li>',
            esc_url( get_permalink() ),
            esc_html( get_the_title() )
        );
    }
    wp_reset_postdata(); // OBRIGATORIO: devolve o post principal
    echo '</ul>';
}

// Busca reversa: quem aponta para $alvo_id (valor serializado -> compare LIKE).
$apontam = get_posts( array(
    'post_type'  => 'any',
    'meta_query' => array( array(
        'key'     => 'posts_relacionados',
        'value'   => '"' . $alvo_id . '"',
        'compare' => 'LIKE',
    ) ),
) );
```

## Perguntas frequentes

### Por que o Relationship field do ACF retorna vazio no template?

Quase sempre é contexto ou nome de campo. Confirme que a chamada roda no post dono do valor, use o field name e não o field key, e imprima get_field() com var_dump para ver se o retorno é a lista esperada ou false.

### Qual a diferença entre Post Object e Post ID no Return Format?

Post Object devolve objetos WP_Post prontos para setup_postdata, e Post ID devolve só números inteiros, que você precisa passar para get_the_title($id) e get_permalink($id). O template tem de seguir o formato escolhido, senão dá erro de objeto ou de tipo.

### Por que minha página mostra o post errado depois do loop de relacionados?

O loop usou setup_postdata e não restaurou o post global. Chame wp_reset_postdata() ao fim do laço para que o restante do template volte a usar o post principal em vez do último relacionado.

### Como buscar quais posts apontam para um post pelo relationship?

Use uma meta_query com a chave do campo, value igual ao ID entre aspas e compare LIKE. O relationship é gravado serializado na wp_postmeta, então igualdade exata falha e só o LIKE com aspas casa o ID dentro do array.

### Os posts que quero ligar não aparecem na lista de seleção, por quê?

São os filtros do campo. Reveja Filter by Post Type, Filter by Post Status e Filter by Taxonomy na configuração do relationship, porque eles restringem a coluna de escolha e podem esconder o post type ou o status que você precisa.

### A seleção do relationship some ao salvar o post, o que é?

É a validação de quantidade. Verifique Minimum Posts e Maximum Posts na aba de validação do campo: campo obrigatório sem item, ou seleção acima do teto, faz o ACF descartar o save. Ajuste a faixa para o uso real.

### Preciso usar field name ou field key na chamada do relationship?

Use o field name (ex.: posts_relacionados) no template. O field key no formato field_xxxxxxxx só resolve com o grupo registrado e serve para registro via PHP, não para leitura no tema, e usá-lo por engano devolve vazio.

### Posso filtrar os posts retornados pelo relationship além do que o campo guarda?

Pode. Pegue os IDs ou objetos com get_field() e monte uma WP_Query com post__in para reordenar, paginar ou aplicar status, em vez de imprimir a lista crua. Assim você controla a saída sem alterar o que o editor selecionou.

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