`discourse_permalink` vazio causa falhas silenciosas de sincronização de comentários

Ambiente

  • Versão do WP-Discourse: 2.5.7

  • Versão do Discourse: 3.5.0.beta5-dev

  • Versão do WordPress: 6.9

  • Hospedagem: WP Engine (WordPress multisite)

  • Instância do Discourse: Auto-hospedada / Hospedagem do Discourse (forum.avweb.com)

Resumo

Publicações publicadas a partir do WordPress criam tópicos no Discourse com sucesso, mas discourse_permalink é armazenado como uma string vazia no meta da publicação. Isso faz com que todas as sincronizações de comentários subsequentes falhem silenciosamente, pois sync_comments() em discourse-comment.php é interrompido antecipadamente quando o permalink está vazio. O ID do tópico do Discourse e a flag de sincronização do webhook são gravados corretamente — apenas o permalink está faltando.

Identificamos 174 publicações afetadas em um único site em nossa rede multisite. O problema parece ter começado por volta de meados de dezembro de 2025.

Passos para Reproduzir

  1. Publique uma postagem do WordPress configurada para criar um tópico no Discourse

  2. O tópico é criado com sucesso no Discourse

  3. discourse_topic_id é salvo no meta da publicação ✓

  4. wpdc_sync_post_comments é definido como 1 (o webhook dispara corretamente) ✓

  5. discourse_permalink é salvo como uma string vazia ✗

  6. discourse_comments_raw nunca é gravado (a sincronização nunca é concluída)

Comportamento Esperado

discourse_permalink deve conter o URL completo do tópico do Discourse (ex: The China Chickens Come Home - AVweb - News Discussion - AVweb.com Discussion) após a criação bem-sucedida do tópico.

Comportamento Atual

discourse_permalink existe como uma chave meta, mas seu valor está vazio. Cada chamada subsequente para sync_comments() atinge esta verificação na linha 209 de lib/discourse-comment.php e retorna antecipadamente:

if ( ! $discourse_permalink ) {
    return 0;
}

Como a sincronização nunca é concluída, discourse_last_sync nunca é gravado, então o plugin tenta novamente a cada carregamento de página — e falha todas as vezes.

Diagnóstico

Rastreamos o problema através do seguinte caminho de código:

  1. DiscourseCommentFormatter::format() chama do_action('wpdc_sync_discourse_comments') que aciona DiscourseComment::sync_comments()

  2. sync_comments() verifica discourse_permalink — encontra-o vazio, retorna 0

  3. format() então verifica discourse_comments_raw no custom da publicação — encontra-o ausente, retorna bad_response_html()

  4. Comentários nunca são exibidos para a publicação afetada

O fluxo de criação de tópico está gravando discourse_topic_id, mas falhando em persistir o permalink. Conseguimos reconstruir os permalinks corretos consultando a API do Discourse em /t/{topic_id}.json e gravando-os de volta no meta da publicação, o que resolveu a sincronização para todas as 174 publicações.

Solução Alternativa (Workaround)

Escrevemos um script de reparo WP-CLI que:

  1. Encontra publicações onde wpdc_sync_post_comments = 1, mas discourse_comments_raw está ausente

  2. Busca o slug do tópico em /t/{topic_id}.json

  3. Reconstrói e salva o permalink

  4. Busca e salva comentários de /t/{slug}/{topic_id}/wordpress.json

Estamos executando isso em um cron agendado como uma medida paliativa.


Problemas Adicionais Encontrados Durante a Investigação

1. Bloqueio Global do MySQL Causa Falhas Silenciosas de Sincronização

Arquivo: lib/discourse-comment.php, linha 176

$got_lock = $wpdb->get_row( "SELECT GET_LOCK( 'discourse_lock', 0 ) got_it" );

sync_comments() usa um único bloqueio MySQL global (discourse_lock) compartilhado entre todas as publicações em toda a instalação. O tempo limite é 0 (não bloqueante), então se alguma publicação estiver sincronizando no momento, todas as outras publicações silenciosamente ignoram sua sincronização — sem registro, sem nova tentativa.

Em um site de alto volume que publica várias postagens por dia, isso cria uma condição de corrida onde as publicações consistentemente perdem o bloqueio e nunca sincronizam. Combinado com o período de sincronização de 10 minutos, uma publicação pode ficar permanentemente presa se perder o bloqueio em suas primeiras tentativas e, em seguida, o problema do permalink vazio impedir sincronizações futuras.

Correção sugerida: Usar um bloqueio por publicação:

$got_lock = $wpdb->get_row( "SELECT GET_LOCK( 'discourse_lock_{$post_id}', 0 ) got_it" );

Com o correspondente liberação:

$wpdb->get_results( "SELECT RELEASE_LOCK( 'discourse_lock_{$post_id}' )" );

2. Dupla Codificação de discourse_comments_raw

Arquivo: lib/discourse-comment.php, linha 222

update_post_meta( $post_id, 'discourse_comments_raw', esc_sql( $raw_body ) );

update_post_meta() usa $wpdb->prepare() internamente, então envolver o valor em esc_sql() causa dupla codificação. Ao longo de vários ciclos de sincronização, as aspas no corpo JSON se acumulam em caracteres de escape (\\\"\\\\\\\"\\\\\\\\\\\\\\\") até que o JSON se torne impossível de analisar.

Correção sugerida:

update_post_meta( $post_id, 'discourse_comments_raw', $raw_body );

Impacto

Esses problemas se acumulam: o permalink vazio impede a sincronização inicial, o bloqueio global impede a recuperação e a dupla codificação pode corromper dados para publicações que conseguem sincronizar. Em nossa instalação, 174 publicações (aproximadamente 2 meses de conteúdo) foram afetadas antes de identificarmos a causa raiz.

Olá, obrigado pelo seu relatório detalhado.

Como o plugin WP Discourse não alterou nenhuma implementação em torno do recurso com o qual você está tendo problemas, vamos pensar no que mais pode ter mudado naquela época. Você por acaso atualizou outro plugin naquele momento?

Um problema inicial que você pode resolver aqui é atualizar para a versão mais recente do plugin WP Discourse, a 2.6.1.

Obrigado. Trabalharemos para atualizar o plugin. Para constar, estamos usando-o em muitos dos nossos sites e eles costumam ter muitos posts e receber muito tráfego.

Entendido.

Isso é provavelmente fundamental. O que aconteceu em meados de dezembro de 2025?

Lembre-se de que o Wordpress é inerentemente um sistema composto/multipartidário. É relativamente fácil para uma parte do seu sistema afetar outra parte. Não estou dizendo que o plugin WP Discourse possa não ter um problema, mas, tudo o mais constante, precisamos entender o que mudou e como essa mudança produziu seu problema antes que possamos pensar em soluções.

Eu atualizei o plugin. Vamos ver se as coisas se estabilizam. Criamos um comando WP CLI personalizado para limpar o banco de dados, se você quiser dar uma olhada, enviei um convite. Obrigado.