Botão "Mostrar Post Completo" não funciona em instalações de subpasta

Recentemente, movi nossa instalação do Discourse para uma subpasta. Depois de fazer isso, o botão “Mostrar postagem completa” parou de funcionar – você clica para expandir o conteúdo, mas ele não carrega a postagem completa.

Nada mudou nas minhas configurações do WP Discourse.

https://tecnoblog.net/comunidade/t/paramount-oferece-us-108-bilhoes-em-dinheiro-para-tomar-warner-da-netflix/157441

Ao acessar a URL do embed diretamente no navegador, ele retorna um erro 404:

https://tecnoblog.net/comunidade/posts/483289/expand-embed

1 curtida

Isso não tem relação, essa rota só responde com um content-type de application/json. O link https://tecnoblog.net/comunidade/posts/483289/expand-embed.json está retornando

"\"\u003cdiv\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e\\n\u003chr\u003e\\n\u003csmall\u003eEste é um tópico de discussão auxiliar para a entrada original em \u003ca href='https://tecnoblog.net/noticias/paramount-oferece-us-108-bilhoes-em-dinheiro-para-tomar-warner-da-netflix'\u003ehttps://tecnoblog.net/noticias/paramount-oferece-us-108-bilhoes-em-dinheiro-para-tomar-warner-da-netflix\u003c/a\u003e\u003c/small\u003e\\n\""

O \u003cdiv\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e deveria ser o conteúdo.

Você também alterou a URL do blog por acaso?

A exibição do onebox também me parece estranha, eu esperaria que tivesse um conteúdo truncado em cache em vez disso, então estou assumindo que body.present? é falso na condicional acima.

Você pode entrar no console do Rails e verificar se TopicEmbed.where(topic_id: 157441).pick(:embed_url) mostra a URL correta do conteúdo do blog?

Você consegue identificar algum erro relacionado em https://tecnoblog.net/comunidade/logs?

2 curtidas

Ah, ok!

Retorna a url do post:

discourse(prod)=> TopicEmbed.where(topic_id: 157441).pick(:embed_url)
=> “``https://tecnoblog.net/noticias/paramount-oferece-us-108-bilhoes-em-dinheiro-para-tomar-warner-da-netflix”

Não creio que haja nenhum erro relacionado no log.

Nop! A URL do blog sempre foi a tecnoblog.net

Vale mencionar também que o IP do servidor está com o bypass no Firewall do CF:

2 curtidas

Tive que depurar esses problemas assim algumas vezes e é complicado, então tenha paciência comigo.

Execute o seguinte script e compartilhe a saída aqui

# Substitua pelo ID do tópico ou URL que você está depurando
topic_id = 386983

# 1. Verifica se TopicEmbed existe e seu conteúdo
te = TopicEmbed.find_by(topic_id: topic_id)
puts "TopicEmbed existe: #{te.present?}"
puts "URL do Embed: #{te&.embed_url}"
puts "Cache de conteúdo presente: #{te&.embed_content_cache.present?}"
puts "Comprimento do cache de conteúdo: #{te&.embed_content_cache&.length || 0}"
puts "SHA1 do Conteúdo: #{te&.content_sha1}"

# 2. Verifica o conteúdo em cache real (primeiros 500 caracteres)
puts "\n--- Prévia do conteúdo em cache ---"
puts te&.embed_content_cache&.truncate(500)

# 3. Tenta buscar da URL remota
if te&.embed_url.present?
  puts "\n--- Tentando busca remota ---"
  begin
    response = TopicEmbed.find_remote(te.embed_url)
    puts "Busca remota sucesso: #{response.present?}"
    puts "Corpo remoto presente: #{response&.body.present?}"
    puts "Comprimento do corpo remoto: #{response&.body&.length || 0}"
    puts "Título remoto: #{response&.title}"
    puts "Corpo remoto: #{response&.body&.truncate(500)}"
  rescue => e
    puts "Busca remota FALHOU: #{e.message}"
  end
end

# 4. Verifica o que expanded_for retornaria
if te.present?
  puts "\n--- Testando expanded_for ---"
  post = Post.find(te.post_id)

  # Limpa o cache para forçar uma nova busca
  Discourse.cache.delete("embed-topic:#{topic_id}")

  begin
    expanded = TopicEmbed.expanded_for(post)
    puts "Conteúdo expandido presente: #{expanded.present?}"
    puts "Comprimento do conteúdo expandido: #{expanded&.length || 0}"
  rescue => e
    puts "expanded_for FALHOU: #{e.message}"
  end
end

# 5. Verifica as configurações relevantes do site
puts "\n--- Configurações do Site ---"
puts "embed_truncate: #{SiteSetting.embed_truncate}"
puts "allowed_embed_selectors: #{SiteSetting.allowed_embed_selectors}"
puts "blocked_embed_selectors: #{SiteSetting.blocked_embed_selectors}"

Isso mostrará por que https://tecnoblog.net/comunidade/t/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/157462?u=falco está falhando

4 curtidas
discourse(prod)> # Substitua pelo ID ou URL do tópico que você está depurando
discourse(prod)> topic_id = 386983
discourse(prod)>
discourse(prod)> # 1. Verificar se TopicEmbed existe e seu conteúdo
discourse(prod)> te = TopicEmbed.find_by(topic_id: topic_id)
discourse(prod)> puts "TopicEmbed existe: #{te.present?}"
discourse(prod)> puts "URL do Embed: #{te&.embed_url}"
discourse(prod)> puts "Cache de conteúdo presente: #{te&.embed_content_cache.present?}"
discourse(prod)> puts "Tamanho do cache de conteúdo: #{te&.embed_content_cache&.length || 0}"
discourse(prod)> puts "SHA1 do Conteúdo: #{te&.content_sha1}"
discourse(prod)>
discourse(prod)> # 2. Verificar o conteúdo em cache real (primeiros 500 caracteres)
discourse(prod)> puts "\n— Prévia do conteúdo em cache —"
discourse(prod)> puts te&.embed_content_cache&.truncate(500)
discourse(prod)>
discourse(prod)> # 3. Tentar buscar do URL remoto
discourse(prod)* if te&.embed_url.present?
discourse(prod)*   puts "\n— Tentando busca remota —"
discourse(prod)*   begin
discourse(prod)*     response = TopicEmbed.find_remote(te.embed_url)
discourse(prod)*     puts "Busca remota bem-sucedida: #{response.present?}"
discourse(prod)*     puts "Corpo remoto presente: #{response&.body.present?}"
discourse(prod)*     puts "Tamanho do corpo remoto: #{response&.body&.length || 0}"
discourse(prod)*     puts "Título remoto: #{response&.title}"
discourse(prod)*     puts "Corpo remoto: #{response&.body&.truncate(500)}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "Busca remota FALHOU: #{e.message}"
discourse(prod)*   end
discourse(prod)> end
discourse(prod)>
discourse(prod)> # 4. Verificar o que expanded_for retornaria
discourse(prod)* if te.present?
discourse(prod)*   puts "\n— Testando expanded_for —"
discourse(prod)*   post = Post.find(te.post_id)
discourse(prod)*
discourse(prod)*   # Limpar cache para forçar nova busca
discourse(prod)*   Discourse.cache.delete("embed-topic:#{topic_id}")
discourse(prod)*
discourse(prod)*   begin
discourse(prod)*     expanded = TopicEmbed.expanded_for(post)
discourse(prod)*     puts "Conteúdo expandido presente: #{expanded.present?}"
discourse(prod)*     puts "Tamanho do conteúdo expandido: #{expanded&.length || 0}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "expanded_for FALHOU: #{e.message}"
discourse(prod)*   end
discourse(prod)> end
discourse(prod)>
discourse(prod)> # 5. Verificar configurações relevantes
discourse(prod)> puts "\n— Configurações do Site —"
discourse(prod)> puts "embed_truncate: #{SiteSetting.embed_truncate}"
discourse(prod)> puts "allowed_embed_selectors: #{SiteSetting.allowed_embed_selectors}"
discourse(prod)> puts "blocked_embed_selectors: #{SiteSetting.blocked_embed_selectors}"
TopicEmbed existe: false
URL do Embed:
Cache de conteúdo presente: false
Tamanho do cache de conteúdo: 0
SHA1 do Conteúdo:

— Prévia do conteúdo em cache —

— Configurações do Site —
embed_truncate: true
allowed_embed_selectors:
blocked_embed_selectors:
=> nil
discourse(prod)>

:thinking:

1 curtida

Você tem certeza de que este é o ID de tópico correto? https://tecnoblog.net/comunidade/t/-/386983 leva a um 404.

1 curtida

Ah, é isso. O tópico que eu linkei é, na verdade, o 157462.

Minhas desculpas!

Aqui estão os resultados para o ID de tópico correto

TopicEmbed exists: true
Embed URL: https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento
Content cache present: true
Content cache length: 22
Content SHA1:

— Cached content preview —

<div><div></div></div>

— Attempting remote fetch —
Remote fetch success: true
Remote body present: true
Remote body length: 22
Remote title:
Remote body: 

— Testing expanded_for —
Expanded content present: true
Expanded content length: 309

— Site Settings —
embed_truncate: true
allowed_embed_selectors:
blocked_embed_selectors:
=> nil

Sua solução de contorno (bypass) do Cloudflare funcionou? Parece que o corpo para https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento tem apenas 22 caracteres, sem nenhuma tag de título.

Sim! Todas as requisições do servidor discourse estão sendo ignoradas:

Screenshot 2025-12-12 at 14.44.21

O que eu notei é que a URL do embed não tem uma barra final. Todos os URLs deveriam ter a barra final.

Screenshot 2025-12-12 at 14.45.51

Então, talvez o discourse não esteja seguindo o redirecionamento?

Mas também, por que ele está salvando o URL sem a barra final?

1 curtida

Isso é fácil de testar, tente

url = "https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/"
response = TopicEmbed.find_remote(url)
puts "Busca remota sucesso: #{response.present?}"
puts "Corpo remoto presente: #{response&.body.present?}"
puts "Tamanho do corpo remoto: #{response&.body&.length || 0}"
puts "Título remoto: #{response&.title}"
puts "Corpo remoto: #{response&.body&.truncate(500)}"

Acho que funciona:

discourse(prod)> url = “https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/”
discourse(prod)> response = TopicEmbed.find_remote(url)
discourse(prod)> puts “Remote fetch success: #{response.present?}”
discourse(prod)> puts “Remote body present: #{response&.body.present?}”
discourse(prod)> puts “Remote body length: #{response&.body&.length || 0}”
discourse(prod)> puts “Remote title: #{response&.title}”
discourse(prod)> puts “Remote body: #{response&.body&.truncate(500)}”
Remote fetch success: true
Remote body present: true
Remote body length: 3776
Remote title: Governo renova app da CNH para baratear obtenção do documento • Tecnoblog
Remote body: 

<figure><img src="https://files.tecnoblog.net/wp-content/uploads/2025/12/cnh-brasil-app-1060x596.jpg">

	<figcaption>Aplicativo CNH do Brasil (imagem: Emerson Alecrim/Tecnoblog)</figcaption></figure>

</div>

<details>
    Resumo
    <div><ul>
<li>App CNH do Brasil substitui CDT e passa a oferecer recursos para obtenção da CNH, em especial, aulas teóricas gratuitas;</li>
<li>Aulas práticas continuam obrigatórias, mas a carga horária mínima foi reduzida de ...
=> nil


Aqui sem a barra final:

discourse(prod)> url = “https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento”
discourse(prod)> response = TopicEmbed.find_remote(url)
discourse(prod)> puts “Remote fetch success: #{response.present?}”
discourse(prod)> puts “Remote body present: #{response&.body.present?}”
discourse(prod)> puts “Remote body length: #{response&.body&.length || 0}”
discourse(prod)> puts “Remote title: #{response&.title}”
discourse(prod)> puts “Remote body: #{response&.body&.truncate(500)}”
Remote fetch success: true
Remote body present: true
Remote body length: 22
Remote title:
Remote body: 
=> nil

O mesmo erro acontece em posts antigos, onde o slug do post mudou.

Por exemplo, neste post, a url costumava ser:

https://tecnoblog.net/486925/o-que-e-pirataria-digital/

Agora, mudou para:

https://tecnoblog.net/responde/o-que-e-pirataria-digital/

1 curtida

Esse é o principal problema, aparentemente. Ao usar Embed Discourse comments on another website via Javascript você controla isso através de um parâmetro, é super fácil de corrigir.

Não estou familiarizado com como o WP-Discourse determina isso, ele deveria estar usando o canônico da postagem, mas não tenho certeza sobre isso. Alguma ideia @angus?

Existe uma maneira de forçar o discourse a atualizar todos os URLs incorporados de uma categoria, seguindo-os até o destino final?

Pretendo migrar para o embed do discourse (aquele embed completo que você tem testado) quando estiver pronto para produção. Mas se os URLs incorporados não corresponderem, então provavelmente criará novos tópicos para cada postagem e perderá os comentários…

1 curtida

Execute

te = TopicEmbed.find_by(topic_id: 157462)
te.embed_url = te.embed_url + "/"
te.save

Isso corrige https://tecnoblog.net/comunidade/t/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/157462 ?

Funcionou!

Mas existe uma correção para casos como este?

O Gemini sugeriu este código:

# Configuração
CATEGORY_SLUG = 'tb' 
category = Category.find_by(slug: CATEGORY_SLUG)

unless category
  puts "ERRO: Categoria '#{CATEGORY_SLUG}' não encontrada."
  exit
end

puts "Iniciando varredura completa de URLs na categoria '#{category.name}'..."
puts "Isso pode demorar dependendo da quantidade de tópicos e da resposta do seu site..."

count_updated = 0
count_errors = 0
count_ok = 0

Topic.where(category_id: category.id).find_each do |topic|
  current_url = topic.custom_fields["embed_url"]
  
  # Pula se não tiver embed_url
  next unless current_url.present?

  begin
    # Faz a requisição GET seguindo redirects
    response = Faraday.get(current_url)
    final_url = response.env.url.to_s

    # Se a requisição foi bem sucedida (200 OK)
    if response.status == 200
      # Verifica se a URL final é diferente da URL salva no banco
      # A comparação ignora diferenças sutis se necessário, mas aqui comparamos string exata
      if final_url != current_url
        puts "\n[ATUALIZAR] Tópico ##{topic.id}:"
        puts "   De:   #{current_url}"
        puts "   Para: #{final_url}"
        
        topic.custom_fields["embed_url"] = final_url
        topic.save_custom_fields(true)
        count_updated += 1
      else
        # print "." # Descomente para ver progresso visual (pontinhos)
        count_ok += 1
      end
    else
      puts "\n[ERRO HTTP #{response.status}] Tópico ##{topic.id} - URL: #{current_url}"
      count_errors += 1
    end

  rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
    puts "\n[FALHA DE CONEXÃO] Tópico ##{topic.id} - URL: #{current_url} - #{e.message}"
    count_errors += 1
  rescue StandardError => e
    puts "\n[ERRO GERAL] Tópico ##{topic.id} - #{e.message}"
    count_errors += 1
  end
  
  # Opcional: Pausa pequena para não sobrecarregar seu servidor WordPress
  # sleep 0.1 
end

puts "\n\nResumo Final:"
puts "------------------------------------------------"
puts "Tópicos Verificados (OK): #{count_ok}"
puts "Tópicos Atualizados:      #{count_updated}"
puts "Erros Encontrados:        #{count_errors}"
puts "------------------------------------------------"

Finalmente algum progresso :sweat_smile:

Um script como esse é uma ótima ideia, apenas faça um backup antes de executá-lo.

Mesmo um backup de apenas esta pequena tabela seria ótimo.

1 curtida

Ok! Vou tentar executá-lo mais tarde, quando a equipe terminar o turno.

1 curtida

Olá pessoal, vejo que a barra final atacou novamente :slight_smile:

[barras finais são] o principal problema, aparentemente. Ao usar Incorporar comentários do Discourse em outro site via Javascript você controla isso por meio de um parâmetro, é super fácil de corrigir.

Apenas para constar que todos os embeds de tópicos no Discourse removem barras finais do embed_url; veja TopicEmbed.normalize_url. Como resultado de um caso separado envolvendo a intersecção de embeds de javascript e embeds do WP Discourse, padronizamos esse tratamento em ambos os métodos de embeds. Veja Apply TopicEmbed url normalisation to embed urls inserted in the PostCreator by angusmcleod · Pull Request #30641 · discourse/discourse · GitHub

@Thiago_Mobilon No curso dessa mudança você também atualizou seu Discourse? É possível que estejamos vendo a aplicação da padronização da normalização do embed_url nos embeds do WP Discourse sendo aplicada aqui como resultado de uma atualização do seu Discourse, que ocorreu ao mesmo tempo da mudança para a instalação em subpasta. Qual versão do Discourse você está executando atualmente? (e qual versão estava executando antes da mudança, se você souber?)

Apenas uma nota lateral de que quando executo estes dois comandos localmente na versão mais recente do Discourse, estou obtendo o mesmo resultado, ou seja, o corpo HTML do artigo

# com barra final
TopicEmbed.find_remote("https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/")

# sem barra final
TopicEmbed.find_remote("https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento")

# produz o mesmo resultado

Você talvez tenha feito alguma alteração no lado do Wordpress?

2 curtidas

Olá Angus!

Não, estes são problemas diferentes. A barra final começou quando mudamos para a subpasta, mas também há URLs antigas de anos atrás que têm um slug diferente agora.

Eu tive que reconstruir a instalação, então sim, acho que este novo padrão pode ser a causa.

Minha sugestão para corrigir este problema: o Discourse não pode seguir pelo menos um ou dois redirecionamentos para recuperar os dados? Isso resolveria o problema da barra final e também protegeria o site em caso de possíveis mudanças de URL no futuro.

Além disso, é mais seguro, pois não haveria necessidade de executar scripts para atualizar tópicos antigos, o que também poderia causar algum dano no banco de dados.