El botón "Show Full Post" no funciona en instalaciones de subcarpetas

Recientemente moví nuestra instalación de Discourse a una subcarpeta. Después de hacer eso, el botón “Mostrar publicación completa” dejó de funcionar: haces clic para expandir el contenido, pero no carga la publicación completa.

Nada cambió en mi configuración de WP Discourse.

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

Al acceder a la URL de inserción directamente en el navegador, devuelve un error 404:

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

1 me gusta

Esto no está relacionado, esa ruta solo responde con un tipo de contenido application/json. https://tecnoblog.net/comunidade/posts/483289/expand-embed.json está devolviendo

"\"\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\""

El \u003cdiv\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e debería ser el contenido.

¿También cambiaste la URL del blog por casualidad?

La visualización de onebox también me parece extraña, esperaría que tuviera un contenido truncado en caché en su lugar, así que supongo que body.present? es falso en la condición anterior.

¿Puedes entrar a la consola de Rails y verificar si TopicEmbed.where(topic_id: 157441).pick(:embed_url) te muestra la URL de contenido del blog correcta?

¿Puedes detectar algún error relacionado en https://tecnoblog.net/comunidade/logs?

2 Me gusta

¡Ah, vale!

Devuelve la URL de la publicación:

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”

No creo que haya ningún error relacionado en el registro.

¡Nop! La URL del blog siempre ha sido tecnoblog.net

También vale la pena mencionar que la IP del servidor se omite en el Firewall de CF:

2 Me gusta

He tenido que depurar estos problemas de esta manera un par de veces y es complicado, así que ten paciencia.

Ejecuta el siguiente script y comparte la salida aquí

# Reemplaza con el ID o URL del tema que estás depurando
topic_id = 386983

# 1. Comprueba si TopicEmbed existe y su contenido
te = TopicEmbed.find_by(topic_id: topic_id)
puts "TopicEmbed existe: #{te.present?}"
puts "URL del Embed: #{te&.embed_url}"
puts "Caché de contenido presente: #{te&.embed_content_cache.present?}"
puts "Longitud de la caché de contenido: #{te&.embed_content_cache&.length || 0}"
puts "SHA1 del contenido: #{te&.content_sha1}"

# 2. Comprueba el contenido en caché real (primeros 500 caracteres)
puts "\n--- Vista previa del contenido en caché ---"
puts te&.embed_content_cache&.truncate(500)

# 3. Intenta obtener desde la URL remota
if te&.embed_url.present?
  puts "\n--- Intentando obtener de forma remota ---"
  begin
    response = TopicEmbed.find_remote(te.embed_url)
    puts "Obtención remota exitosa: #{response.present?}"
    puts "Cuerpo remoto presente: #{response&.body.present?}"
    puts "Longitud del cuerpo remoto: #{response&.body&.length || 0}"
    puts "Título remoto: #{response&.title}"
    puts "Cuerpo remoto: #{response&.body&.truncate(500)}"
  rescue => e
    puts "Obtención remota FALLIDA: #{e.message}"
  end
end

# 4. Comprueba lo que devolvería expanded_for
if te.present?
  puts "\n--- Probando expanded_for ---"
  post = Post.find(te.post_id)

  # Limpia la caché para forzar una nueva obtención
  Discourse.cache.delete("embed-topic:#{topic_id}")

  begin
    expanded = TopicEmbed.expanded_for(post)
    puts "Contenido expandido presente: #{expanded.present?}"
    puts "Longitud del contenido expandido: #{expanded&.length || 0}"
  rescue => e
    puts "expanded_for FALLIDO: #{e.message}"
  end
end

# 5. Comprueba la configuración del sitio
puts "\n--- Configuración del sitio ---"
puts "embed_truncate: #{SiteSetting.embed_truncate}"
puts "allowed_embed_selectors: #{SiteSetting.allowed_embed_selectors}"
puts "blocked_embed_selectors: #{SiteSetting.blocked_embed_selectors}"

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

4 Me gusta
discourse(prod)> # Reemplazar con el ID o URL del tema que se está depurando
discourse(prod)> topic_id = 386983
discourse(prod)>
discourse(prod)> # 1. Comprobar si existe TopicEmbed y su contenido
discourse(prod)> te = TopicEmbed.find_by(topic_id: topic_id)
discourse(prod)> puts "TopicEmbed existe: #{te.present?}"
discourse(prod)> puts "URL del Embed: #{te&.embed_url}"
discourse(prod)> puts "Caché de contenido presente: #{te&.embed_content_cache.present?}"
discourse(prod)> puts "Longitud de la caché de contenido: #{te&.embed_content_cache&.length || 0}"
discourse(prod)> puts "SHA1 del contenido: #{te&.content_sha1}"
discourse(prod)>
discourse(prod)> # 2. Comprobar el contenido real en caché (primeros 500 caracteres)
discourse(prod)> puts "\n— Vista previa del contenido en caché —"
discourse(prod)> puts te&.embed_content_cache&.truncate(500)
discourse(prod)>
discourse(prod)> # 3. Intentar obtener de la URL remota
discourse(prod)* if te&.embed_url.present?
discourse(prod)*   puts "\n— Intentando obtener de forma remota —"
discourse(prod)*   begin
discourse(prod)*     response = TopicEmbed.find_remote(te.embed_url)
discourse(prod)*     puts "Obtención remota exitosa: #{response.present?}"
discourse(prod)*     puts "Cuerpo remoto presente: #{response&.body.present?}"
discourse(prod)*     puts "Longitud del cuerpo remoto: #{response&.body&.length || 0}"
discourse(prod)*     puts "Título remoto: #{response&.title}"
discourse(prod)*     puts "Cuerpo remoto: #{response&.body&.truncate(500)}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "Obtención remota FALLIDA: #{e.message}"
discourse(prod)*   end
discourse(prod)* end
discourse(prod)>
discourse(prod)> # 4. Comprobar lo que devolvería expanded_for
discourse(prod)* if te.present?
discourse(prod)*   puts "\n— Probando expanded_for —"
discourse(prod)*   post = Post.find(te.post_id)
discourse(prod)*
discourse(prod)*   # Limpiar caché para forzar una nueva obtención
discourse(prod)*   Discourse.cache.delete("embed-topic:#{topic_id}")
discourse(prod)*
discourse(prod)*   begin
discourse(prod)*     expanded = TopicEmbed.expanded_for(post)
discourse(prod)*     puts "Contenido expandido presente: #{expanded.present?}"
discourse(prod)*     puts "Longitud del contenido expandido: #{expanded&.length || 0}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "expanded_for FALLIDO: #{e.message}"
discourse(prod)*   end
discourse(prod)* end
discourse(prod)>
discourse(prod)> # 5. Comprobar la configuración relevante
discourse(prod)> puts "\n— Configuración del sitio —"
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 del Embed:
Caché de contenido presente: false
Longitud de la caché de contenido: 0
SHA1 del contenido:

— Vista previa del contenido en caché —

— Configuración del sitio —
embed_truncate: true
allowed_embed_selectors:
blocked_embed_selectors:
=> nil
discourse(prod)>

:thinking:

1 me gusta

¿Estás seguro de que este es el ID de tema correcto? https://tecnoblog.net/comunidade/t/-/386983 lleva a un 404.

1 me gusta

Ah, ya veo. El tema al que enlacé es en realidad el 157462.

¡Mis disculpas!

Aquí están los resultados para el ID de tema correcto

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

¿Funcionó tu bypass de Cloudflare? Parece que el cuerpo para https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento es de solo 22 caracteres, sin etiqueta de título.

¡Sí! Todas las solicitudes del servidor de discourse se omiten:

Screenshot 2025-12-12 at 14.44.21

Lo que noté es que la URL incrustada no tiene una barra inclinada al final. Todas las URL deberían tener la barra inclinada.

Screenshot 2025-12-12 at 14.45.51

¿Así que tal vez discourse no está siguiendo la redirección?

Pero también, ¿por qué está guardando la URL sin la barra inclinada al final?

1 me gusta

Eso es fácil de probar, intenta

url = "https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/"
response = TopicEmbed.find_remote(url)
puts "Recuperación remota exitosa: #{response.present?}"
puts "Cuerpo remoto presente: #{response&.body.present?}"
puts "Longitud del cuerpo remoto: #{response&.body&.length || 0}"
puts "Título remoto: #{response&.title}"
puts "Cuerpo remoto: #{response&.body&.truncate(500)}"

Creo 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


Aquí sin la 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

El mismo error ocurre en publicaciones antiguas, donde el slug de la publicación ha cambiado.

Por ejemplo, en esta publicación, la URL solía ser:

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

Ahora, ha cambiado a:

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

1 me gusta

Ese es el principal problema al parecer. Cuando se usa Incrustar comentarios de Discourse en otro sitio web a través de Javascript se controla eso a través de un parámetro, es súper fácil de arreglar.

No estoy familiarizado con cómo WP-Discourse determina esto, debería estar usando la canónica de la publicación, pero no estoy seguro de eso. ¿Alguna idea @angus?

¿Hay alguna manera de forzar a Discourse a actualizar todas las URL incrustadas de una categoría, siguiéndolas hasta el destino final?

Tengo la intención de migrar al incrustado de Discourse (ese incrustado completo que has estado probando) cuando esté listo para producción. Pero si las URL incrustadas no coinciden, entonces probablemente crearía nuevos temas para cada publicación y perdería los comentarios…

1 me gusta

Ejecuta

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

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

Funciona!

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 algo de progreso :sweat_smile:

Un script como ese es una gran idea, solo haz una copia de seguridad antes de ejecutarlo.

Incluso una copia de seguridad de solo esta pequeña tabla sería genial.

1 me gusta

¡De acuerdo! Intentaré ejecutarlo más tarde, cuando el equipo termine su turno.

1 me gusta

Hola chicos, veo que la barra inclinada final ha vuelto a aparecer :slight_smile:

[las barras inclinadas finales son] el problema principal al parecer. Al usar Incrustar comentarios de Discourse en otro sitio web a través de Javascript lo controlas a través de un parámetro, es súper fácil de arreglar.

Solo como nota, todos los embeds de temas en Discourse eliminan las barras inclinadas finales de la embed_url; consulta TopicEmbed.normalize_url. Como resultado de un caso separado que involucra la intersección de embeds de javascript y embeds de WP Discourse, estandarizamos este manejo en ambos métodos de embeds. Consulta Apply TopicEmbed url normalisation to embed urls inserted in the PostCreator by angusmcleod · Pull Request #30641 · discourse/discourse · GitHub

@Thiago_Mobilon En el curso de este cambio, ¿también actualizaste tu Discourse? Es posible que estemos viendo la aplicación de la estandarización de la normalización de embed_url a los embeds de WP Discourse como resultado de una actualización de tu Discourse, que ocurrió al mismo tiempo que la migración a la instalación en subcarpeta. ¿Qué versión de Discourse estás ejecutando actualmente? (¿y qué versión estabas ejecutando antes de la migración, si lo sabes?)

Solo como nota al margen, cuando ejecuto estos dos comandos localmente en la última versión de Discourse, obtengo el mismo resultado, a saber, el cuerpo HTML del artículo

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

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

# produce el mismo resultado

¿Quizás hiciste algún cambio en el lado de Wordpress?

2 Me gusta

¡Hola Angus!

No, son problemas diferentes. La barra final comenzó cuando nos mudamos a la subcarpeta, pero también hay URLs antiguas de hace años que ahora tienen un slug diferente.

Tuve que reconstruir la instalación, así que sí, creo que este nuevo estándar podría ser la causa.

Mi sugerencia para solucionar este problema: ¿no podría Discourse seguir al menos una o dos redirecciones para recuperar los datos? Eso solucionaría el problema de la barra final y también haría que el sitio web sea más robusto en caso de posibles cambios de URL en el futuro.

Además, es más seguro, ya que no habría necesidad de ejecutar scripts para actualizar temas antiguos, lo que también podría causar algún daño en la base de datos.