{"id":179,"date":"2026-09-15T19:18:41","date_gmt":"2026-09-15T22:18:41","guid":{"rendered":"https:\/\/postping.com.br\/blog\/polylang-instagram-perfil-por-idioma\/"},"modified":"2026-09-15T19:18:41","modified_gmt":"2026-09-15T22:18:41","slug":"polylang-instagram-perfil-por-idioma","status":"publish","type":"post","link":"https:\/\/postping.com.br\/blog\/polylang-instagram-perfil-por-idioma\/","title":{"rendered":"Polylang e Instagram: um perfil para cada idioma do site"},"content":{"rendered":"<p>D\u00e1 para o artigo em portugu\u00eas sair no Instagram em portugu\u00eas e a vers\u00e3o em espanhol sair em outro perfil, sem duplicar nada e sem postar \u00e0 m\u00e3o? D\u00e1, e o <a href=\"https:\/\/wordpress.org\/plugins\/polylang\/\">Polylang<\/a> j\u00e1 entrega metade do caminho: para ele, a vers\u00e3o em espanhol nunca foi o mesmo artigo. A outra metade \u00e9 do lado da Meta, onde cada perfil tem autoriza\u00e7\u00e3o pr\u00f3pria, limite pr\u00f3prio e um rel\u00f3gio de validade pr\u00f3prio.<\/p>\n<p>As duas metades usam a palavra \u201cpost\u201d para coisas diferentes, e \u00e9 da\u00ed que vem quase todo erro de configura\u00e7\u00e3o. No WordPress com Polylang, tr\u00eas idiomas s\u00e3o tr\u00eas registros no banco. No Instagram, s\u00e3o tr\u00eas contas profissionais que n\u00e3o se conhecem. Quem trata o conjunto como \u201cum artigo com tr\u00eas legendas\u201d acaba com o texto em franc\u00eas no perfil brasileiro, ou com dois perfis em sil\u00eancio.<\/p>\n<h2>Tr\u00eas idiomas, tr\u00eas posts<\/h2>\n<p>O Polylang n\u00e3o guarda tradu\u00e7\u00f5es dentro do artigo original. Cada idioma \u00e9 um post separado, com ID pr\u00f3prio, permalink pr\u00f3prio, imagem destacada pr\u00f3pria e data de publica\u00e7\u00e3o pr\u00f3pria. A p\u00e1gina do plugin no diret\u00f3rio do WordPress descreve o alcance disso: ele traduz posts, p\u00e1ginas, m\u00eddia, categorias, tags, tipos de conte\u00fado personalizados, taxonomias e feeds RSS. S\u00e3o <strong>800 mil<\/strong> instala\u00e7\u00f5es ativas na vers\u00e3o 3.8.9, testada at\u00e9 o WordPress 7.1 e exigindo PHP 7.4 ou superior.<\/p>\n<p>O que liga os tr\u00eas registros \u00e9 uma tabela de tradu\u00e7\u00e3o, e a fun\u00e7\u00e3o que l\u00ea essa tabela \u00e9 <code>pll_get_post_translations( $post_id )<\/code>. Ela devolve um array associativo com o c\u00f3digo do idioma na chave e o ID do post traduzido no valor, incluindo o pr\u00f3prio post consultado. Um artigo em tr\u00eas idiomas totalmente traduzido devolve tr\u00eas entradas; um artigo pela metade devolve duas, e essa diferen\u00e7a \u00e9 o que voc\u00ea vai usar depois para saber se pode publicar.<\/p>\n<p>Para descobrir em que idioma est\u00e1 um post espec\u00edfico, a fun\u00e7\u00e3o \u00e9 <code>pll_get_post_language( $post_id, $field )<\/code>. O segundo par\u00e2metro aceita <code>name<\/code>, <code>locale<\/code> ou <code>slug<\/code>, e o padr\u00e3o \u00e9 <code>slug<\/code>, o c\u00f3digo de duas letras. \u00c9 esse valor que uma automa\u00e7\u00e3o usa como chave para decidir o destino: <code>pt<\/code> vai para um lugar, <code>es<\/code> vai para outro. H\u00e1 ainda <code>pll_get_post( $post_id, $slug )<\/code>, que devolve o ID da tradu\u00e7\u00e3o num idioma espec\u00edfico, e <code>pll_home_url( $slug )<\/code>, que devolve o endere\u00e7o da home naquele idioma.<\/p>\n<p>Publicar um artigo traduzido em tr\u00eas idiomas s\u00e3o tr\u00eas eventos, n\u00e3o um. Tr\u00eas transi\u00e7\u00f5es de rascunho para publicado, possivelmente em dias diferentes, se o tradutor entregar o espanhol na quinta e o ingl\u00eas na segunda seguinte. Cada uma delas dispara a sua pr\u00f3pria rotina, com o seu pr\u00f3prio permalink na legenda. Isso resolve sozinho um problema que atormenta quem tenta fazer o contr\u00e1rio: n\u00e3o existe momento em que o sistema precise escolher entre tr\u00eas textos, porque em cada disparo s\u00f3 existe um.<\/p>\n<h2>Tr\u00eas perfis, tr\u00eas autoriza\u00e7\u00f5es<\/h2>\n<p>Do lado do Instagram, a unidade n\u00e3o \u00e9 o site: \u00e9 a conta profissional. A publica\u00e7\u00e3o pela API oficial acontece em dois passos, e os dois carregam o identificador da conta. Primeiro um <code>POST<\/code> para <code>\/&lt;IG_ID&gt;\/media<\/code>, que cria um cont\u00eainer com a imagem e a legenda; depois um <code>POST<\/code> para <code>\/&lt;IG_ID&gt;\/media_publish<\/code>, que publica aquele cont\u00eainer. Se o cont\u00eainer n\u00e3o for publicado em 24 horas, ele expira e some.<\/p>\n<p>Com tr\u00eas idiomas em tr\u00eas perfis, o <code>IG_ID<\/code> muda em cada chamada, e o token que assina a chamada tamb\u00e9m. Cada conta precisou ser autorizada separadamente, com algu\u00e9m logado naquela conta clicando em permitir. N\u00e3o existe um consentimento que cubra as tr\u00eas de uma vez s\u00f3 porque pertencem \u00e0 mesma empresa.<\/p>\n<p>Cada uma dessas autoriza\u00e7\u00f5es produz um token de longa dura\u00e7\u00e3o v\u00e1lido por 60 dias. O endpoint <code>GET \/refresh_access_token<\/code>, com <code>grant_type<\/code> em <code>ig_refresh_token<\/code>, renova por mais 60 dias a partir da data da renova\u00e7\u00e3o, desde que o token tenha pelo menos 24 horas de vida e ainda n\u00e3o tenha expirado. A permiss\u00e3o exigida \u00e9 <code>instagram_business_basic<\/code>.<\/p>\n<p>Tr\u00eas contas significam tr\u00eas desses rel\u00f3gios correndo em paralelo, e eles n\u00e3o est\u00e3o sincronizados. O perfil que costuma quebrar \u00e9 o do idioma secund\u00e1rio, justamente o que publica menos: o site sai no ar em novembro, o ingl\u00eas recebe quatro artigos at\u00e9 o Natal, ningu\u00e9m mexe nele em janeiro e fevereiro, e em mar\u00e7o a renova\u00e7\u00e3o que dependia de o token estar vivo j\u00e1 n\u00e3o tem mais token vivo para renovar. O sintoma n\u00e3o aparece no idioma principal, que continua funcionando, e por isso demora a ser notado. Se o seu j\u00e1 apareceu, a leitura dos c\u00f3digos est\u00e1 em <a href=\"https:\/\/postping.com.br\/blog\/token-meta-expirado\/\">por que o token da Meta expira antes da hora<\/a>.<\/p>\n<p>Existe um n\u00famero que assusta menos do que parece. A Meta limita cada conta do Instagram a 100 publica\u00e7\u00f5es por API dentro de uma janela m\u00f3vel de 24 horas, e d\u00e1 o endpoint <code>GET \/&lt;IG_ID&gt;\/content_publishing_limit<\/code> para conferir o consumo. O limite \u00e9 por conta, n\u00e3o por aplicativo e n\u00e3o por site. Um blog que publica dois artigos por dia em tr\u00eas idiomas gasta duas publica\u00e7\u00f5es em cada um dos tr\u00eas perfis, e n\u00e3o seis em um s\u00f3. A conta muda quando os tr\u00eas idiomas v\u00e3o para o mesmo perfil ou quando uma ag\u00eancia concentra v\u00e1rios clientes na mesma conta, e a\u00ed os 100 passam a ser um teto real em vez de um n\u00famero distante.<\/p>\n<h2>Onde o idioma some<\/h2>\n<p>A documenta\u00e7\u00e3o do Polylang abre o cap\u00edtulo de fun\u00e7\u00f5es com um aviso: voc\u00ea precisa checar a exist\u00eancia da fun\u00e7\u00e3o antes de us\u00e1-la, \u201ccaso contr\u00e1rio seu site vai quebrar feio com um erro fatal na pr\u00f3xima atualiza\u00e7\u00e3o do Polylang\u201d. Na pr\u00e1tica, toda chamada fica dentro de um <code>function_exists( 'pll_get_post_language' )<\/code>, e o caminho sem Polylang precisa existir e funcionar. Um site que instala o plugin hoje e desinstala em seis meses n\u00e3o pode levar junto a publica\u00e7\u00e3o autom\u00e1tica.<\/p>\n<p>O segundo problema \u00e9 mais sutil e custa mais tempo: nem toda fun\u00e7\u00e3o do Polylang responde igual em todo contexto. Quando o WordPress atende uma requisi\u00e7\u00e3o REST, o objeto principal do plugin \u00e9 uma inst\u00e2ncia de <code>PLL_REST_Request<\/code>, e n\u00e3o de <code>PLL_Frontend<\/code>. Fun\u00e7\u00f5es que checam s\u00f3 pelo segundo caso devolvem vazio. Foi exatamente isso que o relato aberto em outubro de 2019 no reposit\u00f3rio do plugin descreveu para <code>pll_the_languages()<\/code>, que devolve string vazia dentro de uma requisi\u00e7\u00e3o REST; a mesma raiz voltou em setembro de 2020 em outro relato, com <code>pll_current_language<\/code> devolvendo <code>false<\/code> na API. Os dois est\u00e3o fechados, e o que sobra deles vale para qualquer integra\u00e7\u00e3o.<\/p>\n<p>O crit\u00e9rio \u00e9 escolher a fun\u00e7\u00e3o pela pergunta que ela responde. \u201cQual \u00e9 o idioma atual da requisi\u00e7\u00e3o\u201d \u00e9 uma pergunta de frontend e n\u00e3o tem resposta boa quando quem est\u00e1 publicando \u00e9 o editor de blocos falando com a REST, o WP-CRON ou o WP-CLI. \u201cQual \u00e9 o idioma deste post\u201d \u00e9 uma pergunta sobre um registro do banco, e <code>pll_get_post_language( $post_id )<\/code> responde igual em qualquer contexto. Automa\u00e7\u00e3o de publica\u00e7\u00e3o sempre tem o ID do post em m\u00e3os, ent\u00e3o sempre pode usar a segunda pergunta.<\/p>\n<p>O terceiro problema separa as edi\u00e7\u00f5es do plugin, e \u00e9 o que costuma derrubar quem monta a esteira num servi\u00e7o externo. Filtrar a REST por idioma com <code>GET \/wp\/v2\/posts?lang=fr<\/code>, e atribuir idioma e tradu\u00e7\u00f5es com <code>POST \/wp\/v2\/posts\/3376?lang=fr&amp;translations[en]=3374<\/code>, \u00e9 recurso do Polylang Pro. Os campos <code>lang<\/code> e <code>translations<\/code> nas respostas v\u00eam junto. Na vers\u00e3o gratuita eles n\u00e3o existem: uma ferramenta que leia <code>\/wp\/v2\/posts<\/code> de fora para decidir o destino recebe os tr\u00eas idiomas misturados, sem nenhum campo que diga qual \u00e9 qual.<\/p>\n<p>Nem tudo ficou atr\u00e1s da porta paga. O endpoint de idiomas <code>\/wp-json\/pll\/v1\/languages<\/code> passou a vir inclu\u00eddo no Polylang a partir da 3.7, e responde com <code>locale<\/code>, <code>slug<\/code>, <code>name<\/code>, <code>is_default<\/code>, <code>home_url<\/code>, <code>flag_url<\/code> e <code>fallbacks<\/code>, entre outras propriedades. Leitura \u00e9 aberta; criar, alterar e apagar idiomas exige um usu\u00e1rio com a capacidade <code>manage_options<\/code>. Serve para a ferramenta descobrir quais idiomas o site tem antes de pedir que algu\u00e9m preencha tr\u00eas configura\u00e7\u00f5es.<\/p>\n<p>Vale olhar com aten\u00e7\u00e3o para qual campo vira a chave do seu mapa, porque <code>slug<\/code> e <code>locale<\/code> n\u00e3o s\u00e3o intercambi\u00e1veis. O slug \u00e9 o c\u00f3digo de duas letras, e \u00e9 o que <code>pll_get_post_language<\/code> devolve quando voc\u00ea n\u00e3o pede nada. O locale \u00e9 o do WordPress, e \u00e9 ele que separa <code>pt_BR<\/code> de <code>pt_PT<\/code>. Um site com portugu\u00eas do Brasil e portugu\u00eas de Portugal nos mesmos dois perfis distintos n\u00e3o pode ser roteado por \u201cpt\u201d, porque os dois idiomas reduzem ao mesmo prefixo: a chave precisa ser o locale, pedido explicitamente no segundo par\u00e2metro. O endpoint de idiomas devolve os dois campos lado a lado, junto com um campo <code>facebook<\/code> por idioma, e ler essa resposta uma vez poupa a descoberta de que o mapa estava amb\u00edguo depois do terceiro post no perfil errado.<\/p>\n<p>O <a href=\"https:\/\/postping.com.br\/blog\/wordpress-instagram-facebook-automatico\/\">Post Ping resolve essa etapa dentro do WordPress<\/a>, e \u00e9 por isso que ela n\u00e3o esbarra na diferen\u00e7a entre as edi\u00e7\u00f5es: o idioma do artigo \u00e9 lido no pr\u00f3prio site, no momento da publica\u00e7\u00e3o, e o destino sai desse valor. Cada idioma aponta para o seu Instagram, a sua P\u00e1gina do Facebook, o seu canal do Discord e o seu bot do Telegram. A conex\u00e3o com a Meta continua sendo uma por conta, porque essa parte \u00e9 regra da Meta e nenhum plugin contorna: voc\u00ea vai autorizar tr\u00eas vezes, uma por perfil, pelo fluxo oficial.<\/p>\n<h2>Quando falta a tradu\u00e7\u00e3o<\/h2>\n<p>O desenho acima assume que todo artigo existe nos tr\u00eas idiomas, e quase nenhum blog multil\u00edngue funciona assim. O normal \u00e9 o idioma principal acumular v\u00e1rios artigos para cada texto que chega traduzido, porque tradu\u00e7\u00e3o custa dinheiro e nem todo texto merece. Isso cria tr\u00eas situa\u00e7\u00f5es que precisam de decis\u00e3o expl\u00edcita, e a pior escolha \u00e9 n\u00e3o decidir.<\/p>\n<p>A primeira \u00e9 o artigo sem tradu\u00e7\u00e3o. Se o texto existe s\u00f3 em portugu\u00eas, o perfil em espanhol n\u00e3o recebe nada naquele dia. Isso \u00e9 o correto, ainda que o gr\u00e1fico de frequ\u00eancia fique feio: mandar o texto em portugu\u00eas para um perfil onde todo mundo espera espanhol rende deixar de seguir, n\u00e3o alcance. <code>pll_get_post_translations<\/code> mostra o buraco antes de ele virar problema, porque devolve duas entradas onde deveria haver tr\u00eas.<\/p>\n<p>A segunda \u00e9 a tradu\u00e7\u00e3o que chega depois. O artigo em portugu\u00eas sai na segunda, o espanhol fica pronto na quinta. O perfil em espanhol recebe o post na quinta, com o permalink da vers\u00e3o em espanhol e a data da vers\u00e3o em espanhol. Quem olha o conjunto de fora v\u00ea dois perfis em ritmos diferentes, e isso \u00e9 o comportamento certo, n\u00e3o um defeito de sincronismo. For\u00e7ar os tr\u00eas a sa\u00edrem juntos significa segurar o portugu\u00eas por tr\u00eas dias esperando o tradutor.<\/p>\n<p>A terceira \u00e9 o idioma que n\u00e3o tem perfil. Muito site tem tr\u00eas idiomas e duas contas, porque abrir e alimentar um perfil no Instagram custa mais trabalho que traduzir uma p\u00e1gina. A\u00ed \u00e9 preciso dizer para onde vai o idioma \u00f3rf\u00e3o, e a resposta honesta costuma ser \u201cpara lugar nenhum\u201d. A propriedade <code>fallbacks<\/code> da API de idiomas do Polylang existe para o caso de voc\u00ea querer o contr\u00e1rio, apontando um idioma como reserva de outro. Use com cuidado: reserva silenciosa \u00e9 como o texto em franc\u00eas aparece no perfil brasileiro.<\/p>\n<p>E existe o caso em que nada disso vale. Se os tr\u00eas idiomas v\u00e3o para o mesmo perfil do Instagram, voc\u00ea n\u00e3o tem um problema de roteamento, tem um problema de legenda: escrever bil\u00edngue sem dobrar o tamanho do texto, decidir qual idioma abre a legenda, e conviver com a m\u00e9trica de um p\u00fablico que entende metade do que voc\u00ea posta. \u00c9 outro artigo, e a \u00fanica parte deste que continua valendo \u00e9 a dos 100 por janela de 24 horas, que agora conta os tr\u00eas idiomas no mesmo balde.<\/p>\n<h2>Como conferir que cada idioma chegou<\/h2>\n<p>Uma configura\u00e7\u00e3o de tr\u00eas idiomas parece certa muito antes de estar certa, ent\u00e3o force o teste em vez de esperar o primeiro artigo de verdade.<\/p>\n<p>Crie um rascunho curto no idioma principal e uma tradu\u00e7\u00e3o dele no segundo idioma, ligando as duas pela caixa de tradu\u00e7\u00f5es do Polylang. Antes de publicar, confirme na base que o v\u00ednculo existe: <code>pll_get_post_translations<\/code> aplicado ao ID do rascunho principal precisa devolver duas entradas, com os dois c\u00f3digos de idioma e os dois IDs. Se devolver uma s\u00f3, o v\u00ednculo n\u00e3o foi salvo e o resto do teste n\u00e3o significa nada.<\/p>\n<p>Antes de publicar qualquer coisa, leia <code>GET \/&lt;IG_ID&gt;\/content_publishing_limit<\/code> nas duas contas e anote os dois n\u00fameros. Publique s\u00f3 o artigo do idioma principal. Espere a rotina rodar e leia os dois n\u00fameros de novo.<\/p>\n<ul>\n<li>Subiu um, e foi o da conta do idioma principal. \u00c9 o \u00fanico resultado que significa roteamento correto.<\/li>\n<li>Subiram os dois, e a\u00ed a detec\u00e7\u00e3o de idioma devolveu vazio: sem idioma para filtrar, a rotina mandou para todos os destinos configurados.<\/li>\n<li>Subiu o da conta errada. O mapa entre c\u00f3digo de idioma e conta est\u00e1 trocado e vai errar em todo artigo, n\u00e3o s\u00f3 neste.<\/li>\n<li>N\u00e3o subiu nenhum, e o problema nem chegou a ser o idioma. Quem responde qual foi \u00e9 o c\u00f3digo de erro da chamada.<\/li>\n<\/ul>\n<p>Falta conferir o endere\u00e7o. Abra a publica\u00e7\u00e3o que saiu e compare o link da legenda com o que <code>pll_home_url<\/code> devolve para aquele c\u00f3digo de idioma: o permalink precisa estar sob o mesmo prefixo. Um post em espanhol com link para a vers\u00e3o em portugu\u00eas \u00e9 o erro mais silencioso dos quatro, porque a publica\u00e7\u00e3o aconteceu, o contador subiu e a \u00fanica v\u00edtima \u00e9 o leitor que chega numa p\u00e1gina que n\u00e3o sabe ler. Se aparecer c\u00f3digo de erro em qualquer etapa, <a href=\"https:\/\/postping.com.br\/blog\/erro-publicacao-instagram-subcodigo\/\">a leitura dele come\u00e7a pelo subc\u00f3digo<\/a>. Vencidas as quatro perguntas no idioma principal, repita o roteiro inteiro publicando a tradu\u00e7\u00e3o, e s\u00f3 apague os rascunhos e as publica\u00e7\u00f5es de teste depois que o segundo contador tiver subido sozinho.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Com Polylang, cada idioma do site pode publicar no seu pr\u00f3prio Instagram. O que a API exige por conta, onde o idioma some e o teste que confere o destino.<\/p>\n","protected":false},"author":1,"featured_media":178,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-179","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-publicacao-automatica"],"_links":{"self":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts\/179","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/comments?post=179"}],"version-history":[{"count":0,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/posts\/179\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/media\/178"}],"wp:attachment":[{"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/media?parent=179"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/categories?post=179"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/postping.com.br\/blog\/wp-json\/wp\/v2\/tags?post=179"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}