"Beitrag vollständig anzeigen"-Button funktioniert nicht bei Installationen in Unterordnern

Ich habe kürzlich unsere Discourse-Installation in einen Unterordner verschoben. Danach funktionierte die Schaltfläche „Vollständigen Beitrag anzeigen“ nicht mehr – man klickt, um den Inhalt zu erweitern, aber der vollständige Beitrag wird nicht geladen.

An meinen WP Discourse-Konfigurationen hat sich nichts geändert.

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

Wenn ich die Einbettungs-URL direkt im Browser aufrufe, wird ein 404-Fehler zurückgegeben:

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

1 „Gefällt mir“

Das ist nicht relevant, dieser Pfad antwortet nur mit einem application/json Content-Type. https://tecnoblog.net/comunidade/posts/483289/expand-embed.json gibt zurück

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

Das \u003cdiv\u003e\u003cdiv\u003e\u003c/div\u003e\u003c/div\u003e sollte der Inhalt sein.

Haben Sie zufällig auch die Blog-URL geändert?

Die Onebox-Anzeige kommt mir auch seltsam vor, ich würde erwarten, dass sie einen zwischengespeicherten gekürzten Inhalt anzeigt, daher gehe ich davon aus, dass body.present? in der obigen Bedingung falsch ist.

Können Sie sich in die Rails-Konsole einloggen und prüfen, ob TopicEmbed.where(topic_id: 157441).pick(:embed_url) Ihnen die korrekte Blog-Inhalts-URL anzeigt?

Können Sie irgendwelche damit zusammenhängenden Fehler unter https://tecnoblog.net/comunidade/logs finden?

2 „Gefällt mir“

Oh, okay!

Es gibt die Beitrags-URL zurück:

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”

Ich glaube nicht, dass es verwandte Fehler im Protokoll gibt.

Nein! Die Blog-URL ist schon immer tecnoblog.net gewesen

Es ist auch erwähnenswert, dass die IP des Servers in der CF-Firewall umgangen wird:

2 „Gefällt mir“

Ich musste dieses Problem schon ein paar Mal auf diese Weise debuggen, und es ist kompliziert, also haben Sie etwas Geduld mit mir.

Führen Sie das folgende Skript aus und teilen Sie die Ausgabe hier mit:

# Ersetzen Sie dies durch die Topic-ID oder URL, die Sie debuggen
topic_id = 386983

# 1. Prüfen, ob TopicEmbed existiert und seinen Inhalt
te = TopicEmbed.find_by(topic_id: topic_id)
puts "TopicEmbed existiert: #{te.present?}"
puts "Embed URL: #{te&.embed_url}"
puts "Inhalts-Cache vorhanden: #{te&.embed_content_cache.present?}"
puts "Länge des Inhalts-Cache: #{te&.embed_content_cache&.length || 0}"
puts "Content SHA1: #{te&.content_sha1}"

# 2. Den tatsächlichen gecachten Inhalt prüfen (erste 500 Zeichen)
puts "\n--- Vorschau des gecachten Inhalts ---"
puts te&.embed_content_cache&.truncate(500)

# 3. Versuchen, von der Remote-URL abzurufen
if te&.embed_url.present?
  puts "\n--- Versuch des Remote-Abrufs ---"
  begin
    response = TopicEmbed.find_remote(te.embed_url)
    puts "Remote-Abruf erfolgreich: #{response.present?}"
    puts "Remote-Body vorhanden: #{response&.body.present?}"
    puts "Länge des Remote-Body: #{response&.body&.length || 0}"
    puts "Remote-Titel: #{response&.title}"
    puts "Remote-Body: #{response&.body&.truncate(500)}"
  rescue => e
    puts "Remote-Abruf FEHLGESCHLAGEN: #{e.message}"
  end
end

# 4. Prüfen, was expanded_for zurückgeben würde
if te.present?
  puts "\n--- Test von expanded_for ---"
  post = Post.find(te.post_id)

  # Cache löschen, um einen neuen Abruf zu erzwingen
  Discourse.cache.delete("embed-topic:#{topic_id}")

  begin
    expanded = TopicEmbed.expanded_for(post)
    puts "Erweiterter Inhalt vorhanden: #{expanded.present?}"
    puts "Länge des erweiterten Inhalts: #{expanded&.length || 0}"
  rescue => e
    puts "expanded_for FEHLGESCHLAGEN: #{e.message}"
  end
end

# 5. Relevante Einstellungen prüfen
puts "\n--- Website-Einstellungen ---"
puts "embed_truncate: #{SiteSetting.embed_truncate}"
puts "allowed_embed_selectors: #{SiteSetting.allowed_embed_selectors}"
puts "blocked_embed_selectors: #{SiteSetting.blocked_embed_selectors}"

Dies wird zeigen, warum https://tecnoblog.net/comunidade/t/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/157462?u=falco fehlschlägt

4 „Gefällt mir“
discourse(prod)> # Ersetzen Sie dies durch die Topic-ID oder URL, die Sie debuggen
discourse(prod)> topic_id = 386983
discourse(prod)>
discourse(prod)> # 1. Prüfen, ob TopicEmbed existiert und seinen Inhalt
discourse(prod)> te = TopicEmbed.find_by(topic_id: topic_id)
discourse(prod)> puts "TopicEmbed exists: #{te.present?}"
discourse(prod)> puts "Embed URL: #{te&.embed_url}"
discourse(prod)> puts "Content cache present: #{te&.embed_content_cache.present?}"
discourse(prod)> puts "Content cache length: #{te&.embed_content_cache&.length || 0}"
discourse(prod)> puts "Content SHA1: #{te&.content_sha1}"
discourse(prod)>
discourse(prod)> # 2. Den tatsächlichen zwischengespeicherten Inhalt prüfen (erste 500 Zeichen)
discourse(prod)> puts "\n— Cached content preview —"
discourse(prod)> puts te&.embed_content_cache&.truncate(500)
discourse(prod)>
discourse(prod)> # 3. Versuch, von der Remote-URL abzurufen
discourse(prod)* if te&.embed_url.present?
discourse(prod)*   puts "\n— Attempting remote fetch —"
discourse(prod)*   begin
discourse(prod)*     response = TopicEmbed.find_remote(te.embed_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)}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "Remote fetch FAILED: #{e.message}"
discourse(prod)*   end
discourse(prod)* end
discourse(prod)>
discourse(prod)> # 4. Prüfen, was expanded_for zurückgeben würde
discourse(prod)* if te.present?
discourse(prod)*   puts "\n— Testing expanded_for —"
discourse(prod)*   post = Post.find(te.post_id)
discourse(prod)*
discourse(prod)*   # Cache löschen, um einen neuen Abruf zu erzwingen
discourse(prod)*   Discourse.cache.delete("embed-topic:#{topic_id}")
discourse(prod)*
discourse(prod)*   begin
discourse(prod)*     expanded = TopicEmbed.expanded_for(post)
discourse(prod)*     puts "Expanded content present: #{expanded.present?}"
discourse(prod)*     puts "Expanded content length: #{expanded&.length || 0}"
discourse(prod)*   rescue => e
discourse(prod)*     puts "expanded_for FAILED: #{e.message}"
discourse(prod)*   end
discourse(prod)* end
discourse(prod)>
discourse(prod)> # 5. Relevante Einstellungen prüfen
discourse(prod)> puts "\n— Site Settings —"
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 exists: false
Embed URL:
Content cache present: false
Content cache length: 0
Content SHA1:

— Cached content preview —

— Site Settings —
embed_truncate: true
allowed_embed_selectors:
blocked_embed_selectors:
=> nil
discourse(prod)>

:thinking:

1 „Gefällt mir“

Sind Sie sicher, dass dies die richtige Themenschaltfläche ist? https://tecnoblog.net/comunidade/t/-/386983 führt zu einer 404.

1 „Gefällt mir“

Ach, das ist es. Das Thema, auf das ich verlinkt habe, ist eigentlich die 157462.

Mein Fehler!

Hier sind die Ergebnisse für die korrekte Themen-ID

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

Hat dein Cloudflare-Bypass funktioniert? Es sieht so aus, als ob der Body für https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento nur 22 Zeichen lang ist, ohne einen Titel-Tag.

Ja! Alle Anfragen vom Discourse-Server werden umgangen:

Screenshot 2025-12-12 at 14.44.21

Was mir aufgefallen ist, ist, dass die Einbettungs-URL am Ende keinen abschließenden Schrägstrich hat. Alle URLs sollten den abschließenden Schrägstrich haben.

Screenshot 2025-12-12 at 14.45.51

Vielleicht folgt Discourse der Weiterleitung also nicht?

Aber warum speichert es die URL auch ohne den abschließenden Schrägstrich?

1 „Gefällt mir“

Das lässt sich leicht testen, versuchen Sie es mit

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

Ich denke, es funktioniert:

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/>Aulas práticas continuam obrigatórias, mas a carga horária mínima foi reduzida de ...
=> nil


Hier ohne den abschließenden Schrägstrich:

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

Derselbe Fehler tritt auch bei alten Beiträgen auf, bei denen sich der Beitrags-Slug geändert hat.

Zum Beispiel war die URL in diesem Beitrag:

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

Jetzt hat sie sich geändert zu:

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

1 „Gefällt mir“

Das ist das Hauptproblem, wie es scheint. Wenn Sie Discourse-Kommentare auf einer anderen Website per Javascript einbetten verwenden, steuern Sie dies über einen Parameter, es ist super einfach zu beheben.

Ich bin nicht damit vertraut, wie WP-Discourse dies bestimmt, es sollte den Post-Kanoniker verwenden, aber ich bin mir da nicht sicher. Irgendwelche Ideen, @angus?

Gibt es eine Möglichkeit, Discourse zu zwingen, alle Einbettungs-URLs aus einer Kategorie zu aktualisieren und der endgültigen Zielseite zu folgen?

Ich beabsichtige, auf die Einbettung von Discourse (die vollständige Einbettung, die Sie getestet haben) umzusteigen, wenn diese für die Produktion bereit ist. Aber wenn die Einbettungs-URLs nicht übereinstimmen, würde dies wahrscheinlich neue Themen für jeden Beitrag erstellen und die Kommentare verlieren…

1 „Gefällt mir“

Führen Sie aus

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

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

Es funktioniert!

Aber gibt es eine Lösung für Fälle wie diesen?

Gemini hat diesen Code vorgeschlagen:

# Konfiguration
CATEGORY_SLUG = 'tb' 
category = Category.find_by(slug: CATEGORY_SLUG)

unless category
  puts "FEHLER: Kategorie '#{CATEGORY_SLUG}' nicht gefunden."
  exit
end

puts "Starte vollständige URL-Überprüfung in der Kategorie '#{category.name}'..."
puts "Dies kann je nach Anzahl der Themen und der Antwort Ihres Servers dauern..."

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"]
  
  # Überspringen, wenn kein embed_url vorhanden ist
  next unless current_url.present?

  begin
    # Führt die GET-Anfrage durch und folgt Weiterleitungen
    response = Faraday.get(current_url)
    final_url = response.env.url.to_s

    # Wenn die Anfrage erfolgreich war (200 OK)
    if response.status == 200
      # Prüft, ob die endgültige URL von der in der Datenbank gespeicherten URL abweicht
      # Der Vergleich ignoriert hier subtile Unterschiede, aber wir vergleichen exakte Strings
      if final_url != current_url
        puts "\n[AKTUALISIEREN] Thema ##{topic.id}:"
        puts "   Von:   #{current_url}"
        puts "   Nach: #{final_url}"
        
        topic.custom_fields["embed_url"] = final_url
        topic.save_custom_fields(true)
        count_updated += 1
      else
        # print "." # Zum Anzeigen des visuellen Fortschritts (Punkte) auskommentieren
        count_ok += 1
      end
    else
      puts "\n[HTTP FEHLER #{response.status}] Thema ##{topic.id} - URL: #{current_url}"
      count_errors += 1
    end

  rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
    puts "\n[VERBINDUNGSFEHLER] Thema ##{topic.id} - URL: #{current_url} - #{e.message}"
    count_errors += 1
  rescue StandardError => e
    puts "\n[ALLGEMEINER FEHLER] Thema ##{topic.id} - #{e.message}"
    count_errors += 1
  end
  
  # Optional: Kleine Pause, um Ihren WordPress-Server nicht zu überlasten
  # sleep 0.1 
end

puts "\n\nZusammenfassung:"
puts "------------------------------------------------"
puts "Überprüfte Themen (OK): #{count_ok}"
puts "Aktualisierte Themen:      #{count_updated}"
puts "Gefundene Fehler:        #{count_errors}"
puts "------------------------------------------------"

Endlich Fortschritte :sweat_smile:

Ein solches Skript ist eine großartige Idee, aber erstellen Sie unbedingt ein Backup, bevor Sie es ausführen.

Selbst ein Backup nur dieser kleinen Tabelle wäre großartig.

1 „Gefällt mir“

Ok! Ich werde versuchen, es später auszuführen, wenn das Team seine Schicht beendet hat.

1 „Gefällt mir“

Hallo zusammen, ich sehe, der abschließende Schrägstrich hat wieder zugeschlagen :slight_smile:

[Abschließende Schrägstriche sind] das Hauptproblem, wie es scheint. Wenn Sie Discourse-Kommentare über Javascript auf einer anderen Website einbetten verwenden, steuern Sie dies über einen Parameter, es ist super einfach zu beheben.

Nur zur Info, alle Themen-Embeds in Discourse entfernen abschließende Schrägstriche aus der embed_url; siehe TopicEmbed.normalize_url. Als Ergebnis eines separaten Falls, der die Überschneidung von Javascript-Embeds und WP Discourse-Embeds betraf, haben wir diese Behandlung für beide Einbettungsmethoden standardisiert. Siehe Apply TopicEmbed url normalisation to embed urls inserted in the PostCreator by angusmcleod · Pull Request #30641 · discourse/discourse · GitHub

@Thiago_Mobilon Haben Sie im Zuge dieser Umstellung auch Ihr Discourse aktualisiert? Es könnte sein, dass wir hier die Anwendung der Standardisierung der embed_url-Normalisierung auf WP Discourse-Embeds sehen, was auf ein Update Ihres Discourse zurückzuführen ist, das gleichzeitig mit der Umstellung auf die Unterordner-Installation erfolgte. Welche Version von Discourse verwenden Sie aktuell? (und welche Version haben Sie vor der Umstellung verwendet, falls Sie das wissen?)

Nur eine Randnotiz: Wenn ich diese beiden Befehle lokal mit der neuesten Version von Discourse ausführe, erhalte ich das gleiche Ergebnis, nämlich den HTML-Body des Artikels

# mit abschließendem Schrägstrich
TopicEmbed.find_remote("https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento/")

# ohne abschließenden Schrägstrich
TopicEmbed.find_remote("https://tecnoblog.net/noticias/governo-renova-app-da-cnh-para-baratear-obtencao-do-documento")

# erzeugt das gleiche Ergebnis

Haben Sie vielleicht etwas auf der WordPress-Seite geändert?

2 „Gefällt mir“

Hallo Angus!

Nein, das sind unterschiedliche Probleme. Der abschließende Schrägstrich trat auf, als wir in den Unterordner gewechselt sind, aber es gibt auch alte URLs von vor Jahren, die jetzt einen anderen Slug haben.

Ich musste die Installation neu erstellen, also ja, ich denke, dass dieser neue Standard die Ursache sein könnte.

Mein Vorschlag zur Behebung dieses Problems: Könnte Discourse nicht mindestens ein oder zwei Weiterleitungen folgen, um die Daten abzurufen? Das würde das Problem mit dem abschließenden Schrägstrich beheben und die Website auch gegen mögliche zukünftige URL-Änderungen absichern.

Außerdem ist es sicherer, da es nicht notwendig wäre, Skripte zur Aktualisierung alter Themen auszuführen, was auch der Datenbank schaden könnte.