How to automatically adjust iframe height for embedded wordpress posts

I am currently working on a custom embed template for wordpress posts so I can embed them via wp discourse plugin in an iframe

Currently you can only add a fixed iframe height into the post. The post looks like this:

The HTML used:

<iframe src="https://wordpress-92041-921046.cloudwaysapps.com/growbox-dimensionieren/" width="1200" height="2000" "frameborder="0"></iframe>
  1. Is there any way to set up the iframe height in a variable manner to adjust to the embedded content size?
  2. Since it will be put into a wp discourse template (like @simon) did here , is there any way to set the iframe height in a dynamic way based on some parameters of the wp post? (character count or such?)
1 „Gefällt mir“

Ich versuche das auch, da ich festgestellt habe, dass ich, wenn ich meine WordPress-Beiträge in Discourse einbetten kann, meine Benutzer einfach zu Discourse und nicht zu zwei verschiedenen Websites leiten kann.

Hat jemand herausgefunden, wie das geht? Ich kämpfe schon seit einiger Zeit damit.

Verwenden Sie etwas wie dieses, um den iframe hinzuzufügen:

function your_namespace_publish_format_html( $output ) {
    global $post;

    if ( 'my_iframe_post_type' === $post->post_type) {
        ob_start();

        ?>
    <iframe width="690" height="600" src="<?php echo esc_url( the_permalink() ); ?>" frameborder="0"></iframe>
    <?php
        $output = ob_get_clean();

        // Geben Sie einen iframe für diesen Post-Typ zurück.
        return $output;
    }

    // Geben Sie die Standardausgabe zurück oder tun Sie hier etwas anderes damit.
    return $output;
}
add_filter( 'discourse_publish_format_html', 'your_namespace_publish_format_html' );

aber möchten Sie die height-Eigenschaft basierend auf der Höhe des Posts festlegen?

Wenn ja, wie genau muss sie sein? Ich frage mich, ob Sie einfach die Anzahl der Zeichen im Post zählen, dann die Höhe von Bildern oder anderen Elementen hinzufügen, die eine festgelegte Höhe haben, und dann noch etwas für gute Maße hinzufügen könnten. Ich habe vielleicht einige Vorschläge, wie das gemacht werden kann.

Es wäre auch möglich, Javascript zu verwenden, um die genaue Höhe des Posts zu ermitteln, wenn er mit einer bestimmten Breite gerendert wird.

1 „Gefällt mir“

Ah, ich bin noch nicht einmal so weit, es in den discourse_publish_format_html-Filter zu integrieren. Ich habe es gerade manuell in einen Beitrag in Discourse eingefügt und versucht, das JavaScript herauszufinden, um die Höhe des Inhalts innerhalb des iFrames zu lesen und dann die Größe des iFrames zu ändern.

Ich habe online schon einige Tutorials gesehen, wie man das macht, aber aus irgendeinem Grund bekomme ich dieses JS in Discourse nicht zum Laufen. Ich habe es mit der Seitenänderung und decorateCookedElement in der API versucht, aber es funktioniert immer noch nicht.

Wenn möglich, würde ich es lieber in Discourse selbst machen, damit ich auch iFrames von Nicht-WordPress-Seiten auf volle Höhe skalieren kann.

Das ist ein interessantes Problem. Was passiert, wenn Sie das height-Attribut eines iframe-Elements in einem Discourse-Beitrag manuell bearbeiten? Wird die neue Höhe verwendet, wenn Sie den Beitrag nach der Bearbeitung der Höhe anzeigen, oder müssen Sie den Discourse-Beitrag erneut backen, damit die bearbeitete Höhe wirksam wird?

Bearbeiten: Es ist interessant genug, dass ich das später heute testen werde.

1 „Gefällt mir“

Wenn ich es mit height="400px" zum iframe-Tag hinzufüge, wird es nach dem Neuladen der Seite in der Größe geändert. Wenn ich es als height="100%" hinzufüge, scheint es nichts zu bewirken.

Wenn ich CSS-Eigenschaften für den iframe hinzufüge, scheint dies ebenfalls die Höhe richtig zu ändern, zumindest auf das, was ich manuell eingebe.

Ugh, ich habe es zum Laufen gebracht. Das Problem war, dass ich eine benutzerdefinierte Klasse für das iframe-Tag verwendet habe und Discourse alle diese Tags entfernt. Ich hätte aus meinen Fehlern der letzten Tage lernen sollen (Formatting posts to look more like Wordpress blog - #6 by jimkleiber). Ich habe gelesen, dass es Sicherheitsgründe dafür gibt, warum benutzerdefinierte HTML-Klassen hier nicht funktionieren, aber ich bin mir nicht sicher, warum :confused:

Hier ist jedoch der Code zum Anpassen der Höhe eines iframes mit dem Selektor .topic-body iframe (ich bin mir nicht sicher, ob dieser Code für andere funktioniert, er scheint für mich zu funktionieren):

<script type="text/discourse-plugin" version="0.8.18">
    api.decorateCookedElement(
      element => {
        setTimeout(function() {
          let iframes = element.querySelectorAll('.topic-body iframe');
          if (iframes) {
            iframes.forEach(function(iframe) {
              iframe.onload = function() {
                let iframeDocument = this.contentDocument || this.contentWindow.document;
                let contentHeight = Math.max(
                  iframeDocument.body.scrollHeight,
                  iframeDocument.documentElement.scrollHeight
                ) + 'px';
                this.style.height = contentHeight;
              };
            });
          }
        }, 5000); // Passen Sie die Verzögerung nach Bedarf an
      },
      { id: "component-id", onlyStream: true}
    );
</script>

EDIT: Eigentlich funktioniert es nicht. Ich habe height="4000px" im iframe-Tag hinzugefügt, und deshalb hat es meiner Meinung nach funktioniert.

1 „Gefällt mir“

Das ist ein kniffliges Problem. Ich glaube nicht, dass es einfach ist, von innerhalb von Discourse auf den Inhalt des iframes zuzugreifen. Es könnte möglich sein, es zum Laufen zu bringen, wenn die Quelle des iframes und Ihre Discourse-Site auf verschiedenen Subdomains derselben Domain liegen.

Wenn ich das Problem richtig verstehe, müssten Sie document.domain sowohl auf der Subdomain, von der Sie den Inhalt abrufen, als auch im Skript, das Sie auf Discourse ausführen, auf die Root-Domain setzen.

Wenn die Quelle des iframes tatsächlich Ihre Root-Domain ist, versuchen Sie vielleicht, das Skript anzupassen:

<script type="text/discourse-plugin" version="0.8.18">
   document.domain = "your_root_domain.com"; // bearbeiten Sie dies zu Ihrer Domain
    api.decorateCookedElement(
      element => {

Wenn die Domain des iframes ebenfalls eine Subdomain Ihrer Root-Domain ist, müssten Sie document.domain auch auf die Root-Domain setzen.

Für das Styling von iframes (oder irgendetwas anderem) auf Discourse können Sie den Inhalt in einen div einpacken, der ein Datenattribut hat:

<div data-full-height>
<iframe src="http://wp-discourse.test/zalg_iframe/this-is-a-test-this-is-only-a-test/" height="600" width="690"></iframe>
</div>

Theme CSS:

[data-full-height] > iframe {
      // optional styling des äußeren iframes hier: Höhe, Breite usw.
     // leider funktioniert height: 100% nicht - das enthaltende Element des iframes hat keine festgelegte Höhe.
}

Wenn der Ansatz mit document.domain nicht funktioniert, gibt es möglicherweise andere Lösungen - die Verwendung von window.postMessage, um zwischen dem übergeordneten Dokument des iframes und Discourse zu kommunizieren.

Ich glaube nicht, dass meine ursprüngliche Idee, die Höhe des iframes auf seiner Quell-Site zu berechnen, funktionieren wird - die Breite des gerenderten iframes variiert je nach Gerät, auf dem Discourse angezeigt wird.

1 „Gefällt mir“

Hmm, mein Forum ist eine Subdomain meiner Root-Domain, also habe ich die Root-Domain wie vorgeschlagen hinzugefügt und diese Fehlermeldung erhalten:

Uncaught DOMException: Failed to read a named property 'document' from 'Window': Blocked a frame with origin 

Jetzt versuche ich, die postMessage-Sache zu machen, scheitere aber. Ich glaube, ich muss besser verstehen, wie Discourse-JavaScript funktioniert. Ich nehme an, es funktioniert wie bei anderen Websites, und vielleicht tut es das nicht, oder vielleicht bin ich es einfach, der JavaScript nicht so gut beherrscht, besonders bei Cross-Origin-Sachen, lol.

Vielen Dank, dass Sie sich das angesehen haben!

Ich habe mich schon eine Weile gefragt. Hier ist ein Proof of Concept (beachten Sie, dass er das Problem der Entfernung von Scrollbalken aus Iframes nicht löst).

Fügen Sie ein Skript-Tag zum Beitrag hinzu, den Sie einbetten:

<script>
    function sendHeight() {
        const body = document.body,
            html = document.documentElement;

        const height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

        window.parent.postMessage({
            'iframeHeight': height,
            'iframeId': 'zalgFrame' // Verwenden Sie eine eindeutige Kennung, wenn Sie mehrere Iframes haben
        }, '*'); // Erwägen Sie die Angabe der übergeordneten Domäne aus Sicherheitsgründen
    }

    // Senden Sie die anfängliche Höhe
    window.onload = sendHeight;

    // Optional: Höhe bei Größenänderung oder anderen Ereignissen aktualisieren
    window.onresize = sendHeight;
</script>

Ich verwende die Kennung "zalgFrame" im Skript.

In Ihrem Discourse-Theme:

<script type="text/discourse-plugin" version="1.29.0">
let iframeHeight, iframeId;
window.addEventListener('message', (event) => {
  if (event.origin !== "http://wp-discourse.test") return; // meine Testdomäne, ändern Sie sie zu Ihrer Domäne oder kommentieren Sie sie aus
  // erhält die Iframe-Höhe, die von `wp-discourse.test` übergeben wird, und bestätigt, dass die iframeId mit der dort gesetzten iframeID übereinstimmt
  if (event.data.iframeHeight && event.data.iframeId === 'zalgFrame') {
      // besuchen Sie die Discourse-Seite mit dem Iframe mit geöffneter Konsole
      // Sie sollten aktualisierte Höhen sehen, die von der übergeordneten Website gesendet werden, während Sie das Fenster vergrößern/verkleinern
      console.log("we got an event:" + event.data.iframeHeight);
      iframeHeight = event.data.iframeHeight;
      iframeId = event.data.iframeId;
  }
  }, false);
</script>

In einem Discourse-Beitrag:

<div data-iframe-test-one>
<iframe src="http://wp-discourse.test/zalg_iframe/this-is-a-test-this-is-only-a-test/" width="100%" height="1659"></iframe>
</div>

Es ist also möglich, die tatsächliche Höhe des gerenderten Iframes vom übergeordneten Fenster aus zu erhalten.

Ich weiß nicht, wie ich die Höhe aus den Daten des Event-Listeners in einen Aufruf von api.decorateCookedElement bekomme. Ich bin mir nicht sicher, ob das überhaupt funktionieren würde, um die vertikale Scrollleiste bei langen Iframes zu entfernen. Wenn ich versuche, eine große Höhe (1600px) fest in das iframe-Element zu kodieren, habe ich immer noch eine Scrollleiste.

Bearbeiten: Der Vollständigkeit halber:

<script type="text/discourse-plugin" version="1.29.0">
api.decorateCookedElement(
  (e) => {
    let iframeHeight, iframeId;

    function handleMessage(event) {
      if (event.origin !== "http://wp-discourse.test") return;
      if (event.data.iframeHeight && event.data.iframeId === "zalgFrame") {
        iframeHeight = event.data.iframeHeight;
        iframeId = event.data.iframeId;
        // basierend auf der Annahme, dass nur 1 Iframe im data-zalgFram Div verpackt ist
        let iframe = e.querySelector("[data-zalgFrame] iframe");
        if (iframe) {
          iframe.style.height = `${iframeHeight}px`;
        }
        // nach dem Setzen der tatsächlichen gerenderten Höhe des Iframes
        // entfernen Sie den Event-Listener
        window.removeEventListener("message", handleMessage, false);
      }
    }
    window.addEventListener("message", handleMessage, false);
  },
  { id: "component-id", onlyStream: true }
);
</script>

Für Höhen über ~1000px scheint es keine Möglichkeit zu geben, eine von Discourse hinzugefügte Scrollleiste zu vermeiden, daher empfehle ich den Ansatz nicht.

Ich denke, die Antwort auf die OP ist, dass es irgendwie möglich ist, aber wahrscheinlich nicht viel bewirkt. (Außer dass ich etwas über die Methode window.postMessage() gelernt habe :slight_smile:

2 „Gefällt mir“

Ich schätze die tapferen Bemühungen hier und möchte sie nicht schmälern, aber ich muss zugeben, dass ich ein wenig skeptisch bin, was die Prämisse dieses Themas angeht, d. h.

Ich habe zwei (echte) Fragen dazu, Jim:

  1. Was ist der Grund, warum Sie hier einen iframe anstelle der normalen Topic-Embed-Funktionalität wünschen?
  2. Ich bin neugierig, warum Sie überhaupt eine Wordpress-Seite haben, wenn Sie nicht möchten, dass Benutzer dort Inhalte konsumieren?
1 „Gefällt mir“

Ich kann nicht für den ursprünglichen Autor des Themas sprechen, aber ich kann in meinem Fall Antworten geben:

Ich habe eine ganze Reihe von Plugins für WordPress zusammengebastelt, die es mir ermöglichen, einen Podcast-Player mit interaktiven Transkripten (die Wörter werden hervorgehoben, während die Audiospur abgespielt wird, und man kann klicken, um zu diesem Teil des Audios zu springen), interaktiven Kapiteln/Show-Notizen und einer durchsuchbaren/sortierbaren/filterbaren Playlist zu haben.

Um sie hier ohne iFrame einzubetten, könnte ich also nicht auf den Javascript-Code und das gesamte Styling zugreifen, das ich hineingesteckt habe.

Oh, und ich finde es für mich viel einfacher, diese Dinge auf WordPress zusammenzubasteln als auf Discourse. Ich habe wirklich Schwierigkeiten, Javascript und Plugins hier zu verwenden.

Um die Podcast-Episoden zu hosten, werde ich die WordPress-Seite sowieso benötigen. Aber ob ich möchte, dass Benutzer dort Inhalte konsumieren, bin ich mir nicht sicher. Seit ich Discourse für Kommentare auf WordPress verwende, ist die Interaktivität zurückgegangen. Früher hatten die Leute Kommentare auf WordPress gepostet, aber Discourse verlangt von ihnen, eine Domain-Schwelle zu überschreiten, und dann interagieren sie an einem separaten Ort. Wenn Discourse es den Leuten erleichtern würde, auf eine eingebettete Weise in einem WordPress-Forum zu posten, würde ich mich wahrscheinlich darauf konzentrieren.

Ich bin mir nicht sicher, ob es nötig ist, aber ich habe das Gefühl, dass ich einen Hauptort haben möchte, an dem sich die Leute versammeln können, und früher dachte ich, es wäre WordPress mit eingebetteten Discourse-Kommentaren/Posts, aber jetzt denke ich, dass Discourse mit eingebetteten WordPress-Posts einfacher sein könnte und die Leute eher dazu anregen würde, miteinander zu interagieren.

2 „Gefällt mir“

Cool!

Warum nicht?

Ich verstehe! Nichtsdestotrotz wäre es, je nach Ihrer Antwort auf meine vorherige Frage („Warum nicht?“) eine stabilere Lösung, sie ordnungsgemäß in einen Discourse-Beitrag einzubetten, als ein dynamisches iFrame.

Es tut mir leid, von dem Rückgang zu hören, und ich verstehe auch, was Sie hier meinen. Simons umfassenderes Thema zu diesem Thema kommt mir in den Sinn

1 „Gefällt mir“

Ich meine, vielleicht könnte ich das? Ich hatte hier früher Schwierigkeiten, einen Audioplayer zu finden, der mediaelement.js verwendet. Ich glaube, ich verstehe die Plugin-API nicht sehr gut. Es scheint einfach eine Menge Arbeit zu sein, die ich vielleicht langfristig machen könnte, aber im Moment sieht es mit dem iFrame-Embed tatsächlich ziemlich gut aus. Die größte Herausforderung wäre die Durchsuchbarkeit des Textes, der in den iFrame eingebettet ist, aber ich dachte daran, diesen Text im Beitrag zu veröffentlichen und ihn zu verstecken oder unter ein Akkordeon zu stellen, damit er trotzdem in den Suchergebnissen erscheint.

Außerdem denke ich, dass das größere Problem eigentlich darin besteht, dass so viele der HTML-Klassen entfernt werden, wenn der Inhalt gekocht wird (oder wie auch immer die Terminologie lautet, lol), und so scheint es, dass das einfache Veröffentlichen des WordPress-Beitrags hier und die Verwendung eines ähnlichen CSS viel Umschreiben erfordert, was mich dazu inspiriert hat, dies zu schreiben:

1 „Gefällt mir“

Ich verstehe. Lassen Sie mich darüber nachdenken. Ich habe keine wesentlichen Erkenntnisse über dynamische iframes hinaus dessen, was Simon bereits vorgeschlagen hat, aber Ihr Fall bringt mich zum Nachdenken.

1 „Gefällt mir“

Es ist vielleicht erwähnenswert, dass ich aktiv daran arbeite (Discourse zur Steuerung des Kommentarsystems für Websites nutzend). Derzeit konzentriere ich mich hauptsächlich auf Headless-WordPress-Sites, aber der allgemeine Ansatz könnte für reguläre WordPress- und Nicht-WordPress-Sites hilfreich sein.

2 „Gefällt mir“

Ich kann mich nicht erinnern, wo ich es gesehen habe, aber es gibt eine versteckte maximale Höhe von, ich glaube, 1000px, vielleicht im gekochten Inhalt?

Das könnte also Ihre Lösung beeinträchtigen.

Ich schaue morgen nach :folded_hands:t2:

1 „Gefällt mir“

Das ist bei iframe-Elementen:

iframe {
  max-width: 100%;
  max-height: #{\"min(1000px, 200vh)\"};
}

Das kann in einem Theme behoben werden, indem iframes mit dem data-Attribut angesprochen werden:

[data-zalgFrame] > iframe {
    max-height: 100%;
    border: none;
}

Diese Änderung muss vorgenommen werden, um längere iframes anzuzeigen, aber die Scrollbalken, die ich gesehen habe, kamen von der iframe-Quellseite. Die einzige Möglichkeit, gute Ergebnisse zu erzielen, ist die Erstellung von Einbettungsversionen von Beiträgen auf meinem Blog – im Grunde alles außer dem Beitrag Inhalt entfernen und ein wenig mit den Stilen herumspielen. Zum Beispiel mit einem WordPress Custom Post Type:

single-zag_iframe.php
<?php
if ( have_posts() ) : while ( have_posts() ) : the_post();
?>
<style>
    body {
        overflow: hidden;
        height: 100%;
    }
    article.zalg-iframe {
        width: 100%;
        height: 100%;
        margin-left: auto;
        margin-right: auto;
        font-size: 1.25em;
        word-break: break-word;
    }
    article.zalg-iframe img {
        max-width: 100%;
        height: auto;
    }
</style>
<article class="zalg-iframe">
    <?php
    the_content();
    ?>
</article>
<script>
    function sendHeight() {
        const body = document.body,
            html = document.documentElement;
        // a bit of a crap shoot, I think `scrollHeight` is the correct target for this case
        const height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

        window.parent.postMessage({
            'iframeHeight': height,
            'iframeId': 'zalgFrame'
        }, '*');
    }

    // Send initial height
    window.onload = sendHeight;

    // Optional: Update height on resize or other events
    window.onresize = sendHeight;
</script>
<?php
endwhile; endif;
?>

Es könnte etwas Fummelei erfordern, um dies auf einer Produktionsseite zum Laufen zu bringen, aber es scheint sich näher anzusehen zu lohnen.

Ok, ich habe das zum Laufen gebracht, ich glaube, ich hatte irgendwo anders einen Fehler in JS, der das verhindert hat. Woohoo, es scheint sehr gut in meine Seite integriert zu sein. Vielen Dank, @simon!

1 „Gefällt mir“