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

私もこれを試しています。WordPressの投稿をDiscourseに埋め込めば、ユーザーを2つの異なるサイトではなくDiscourseに誘導できることに気づきました。

どなたかこれを実現する方法を見つけましたか?しばらくの間、これで苦労しています。

iframe を追加するためにこれのようなものを使用していますか?

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();

        // Return an iframe for this post type.
        return $output;
    }

    // Return the default output, or do something else with it here.
    return $output;
}
add_filter( 'discourse_publish_format_html', 'your_namespace_publish_format_html' );

ただし、投稿の高さを基準に height プロパティを設定したいと考えていますか?

もしそうなら、どの程度の正確さが必要ですか?投稿の文字数を数え、高さが設定されている画像やその他の要素の高さを追加し、さらに余裕を持たせるだけで十分かもしれません。その方法についていくつか提案があるかもしれません。

また、JavaScript を使用して、指定された幅でレンダリングされた投稿の正確な高さを取得することも可能です。

「いいね!」 1

discourse_publish_format_html フィルターに統合する段階にすら達していません。Discourse に手動で投稿を追加し、iframe 内のコンテンツの高さを読み取って iframe のサイズを変更する JavaScript を見つけようとしていました。

オンラインでその方法に関するチュートリアルをいくつか見ましたが、なぜか Discourse でその JavaScript を機能させることができませんでした。API の page changedecorateCookedElement を試しましたが、それでも機能させることができませんでした。

可能であれば、WordPress 以外のサイトから埋め込む場合でも iframe をフルハイトにリサイズできるように、Discourse 自体で実行したいと考えています。

興味深い問題ですね。Discourse の投稿で iframe 要素の height 属性を直接編集するとどうなるでしょうか? 編集後に投稿を表示したとき、新しい高さが使用されるでしょうか、それとも編集した高さが有効になるには Discourse の投稿を再ベイクする必要がありますか?

編集:これは十分に興味深いので、本日中にテストしてみます。

「いいね!」 1

height="400px" を iframe タグに追加すると、ページをリフレッシュした後にサイズが変更されます。height="100%" として追加しても、何も起こらないようです。

iframe に関する CSS プロパティを追加すると、少なくとも手動で入力したものに対しては、高さが適切に変更されるようです。

ああ、うまくいきました。問題は、iframeタグにカスタムクラスを使用していたことで、Discourseはそのようなタグをすべて削除してしまうのです。数日前の教訓を活かすべきでした(https://meta.discourse.org/t/formatting-posts-to-look-more-like-wordpress-blog/301133/6)。カスタムHTMLクラスがここで機能しないのはセキュリティ上の理由だと聞きましたが、なぜなのかよくわかりません:confused:

しかし、.topic-body iframeセレクターを使用してiframeの高さを調整するためのコードは次のとおりです(これが他の人にも機能するかどうかはわかりませんが、私には機能するようです)。

<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); // Adjust the delay as needed                  
      },
      { id: "component-id", onlyStream: true}
    );
</script>

編集:実際には、機能しません。iframeタグにheight="4000px"を追加したため、機能していたのだと思います。

「いいね!」 1

これは難しい問題です。Discourseの内部からiframeの内容にアクセスするのは簡単ではないと思います。iframeのソースとDiscourseサイトが同じドメインの異なるサブドメインにある場合は、機能させることができるかもしれません。

問題が正しく理解できている場合、iframeのソースとDiscourseで実行するスクリプトの両方で、document.domainをルートドメインに設定する必要があります。

iframeのソースが実際にルートドメインである場合は、スクリプトを次のように調整してみてください。

<script type="text/discourse-plugin" version="0.8.18">
   document.domain = "your_root_domain.com"; // あなたのドメインに編集してください
    api.decorateCookedElement(
      element => {

iframeのドメインもルートドメインのサブドメインである場合は、iframeでもdocument.domainをルートドメインに設定する必要があります。

iframe(または他のもの)をDiscourseでスタイリングするには、データ属性を持つdivでコンテンツをラップできます。

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

テーマCSS:

[data-full-height] > iframe {
      // オプションで外側のiframeをここにスタイル設定できます:高さ、幅など
     // 残念ながら、iframeのコンテナ要素には設定された高さがないため、height: 100% は機能しません。
}

document.domainアプローチが機能しない場合は、iframeの親ドキュメントとDiscourseの間で通信するためにwindow.postMessageを使用するなどの他のソリューションがあるかもしれません。

ソースサイトでiframeの高さを計算するという私の最初の考えは機能しないと思います。表示されるiframeの幅は、Discourseが表示されるデバイスによって異なります。

「いいね!」 1

うーん、私のフォーラムはルートドメインのサブドメインなので、提案されたとおりにルートドメインを追加したところ、次のエラーが発生しました。

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

今度は postMessage を試していますが、うまくいきません。Discourse の JavaScript がどのように機能するかをよりよく理解する必要があると思います。他のサイトと同じように機能すると仮定していましたが、そうではないのかもしれません。あるいは、特にクロスオリジン関連の JavaScript があまり得意ではないだけかもしれません(笑)。

ご確認いただきありがとうございます!

しばらくこのことを考えていました。以下は概念実証です(ただし、iframeのスクロールバーを削除する問題は解決していません)。

埋め込んでいる投稿にスクリプトタグを追加します。

<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' // 複数のiframeがある場合は、一意の識別子を使用してください
        }, '*'); // セキュリティのため、親ドメインを指定することを検討してください
    }

    // 初期高さを送信
    window.onload = sendHeight;

    // オプション:リサイズやその他のイベントで高さを更新
    window.onresize = sendHeight;
</script>

スクリプトでは識別子"zalgFrame"を使用しています。

Discourseテーマでは:

<script type="text/discourse-plugin" version="1.29.0">
let iframeHeight, iframeId;
window.addEventListener('message', (event) => {
  if (event.origin !== "http://wp-discourse.test") return; // 私のテストドメイン、あなたのドメインに更新するかコメントアウトしてください
  // `wp-discourse.test`から渡されたiframeの高さを取得し、そこで設定したiframeIDと一致するか確認します
  if (event.data.iframeHeight && event.data.iframeId === 'zalgFrame') {
      // iframeがあるDiscourseページをコンソールを開いて確認してください
      // ウィンドウをリサイズすると、親サイトから更新された高さが送信されているのが見えるはずです
      console.log("we got an event:" + event.data.iframeHeight);
      iframeHeight = event.data.iframeHeight;
      iframeId = event.data.iframeId;
  }
  }, false);
</script>

Discourseの投稿では:

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

したがって、レンダリングされたiframeの実際の高さを親ウィンドウから取得することは可能です。

イベントリスナーからのデータをapi.decorateCookedElementへの呼び出しにどのように取り込むのか分かりません。長いiframeから縦スクロールバーを削除するのに役立つかどうかも定かではありません。大きな高さ(1600px)をiframe要素にハードコーディングしようとしても、スクロールバーが表示されてしまいます。

編集:完全を期すために:

<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;
        // data-zalgFram divでラップされたiframeは1つだけという仮定に基づいています
        let iframe = e.querySelector("[data-zalgFrame] iframe");
        if (iframe) {
          iframe.style.height = `${iframeHeight}px`;
        }
        // iframeの実際のレンダリング高さを設定した後
        // イベントリスナーを削除します
        window.removeEventListener("message", handleMessage, false);
      }
    }
    window.addEventListener("message", handleMessage, false);
  },
  { id: "component-id", onlyStream: true }
);
</script>

高さが~1000pxを超える場合、Discourseによって追加されるスクロールバーを回避する方法はないようです。そのため、このアプローチは推奨しません。

OPへの回答は、ある程度可能ですが、おそらくあまり意味がないということだと思います。(window.postMessage()メソッドについて学んだことを除いては :slight_smile:

「いいね!」 2

ここでは、皆さんの大変な努力に感謝しており、それをそがすつもりはありません。しかし、このトピックの前提、つまり

について、正直に言って懐疑的です。

ジムさん、これについて(本気の)質問が2つあります。

  1. 通常のトピック埋め込み機能ではなく、ここでiframeを使用したい理由は何ですか?
  2. ユーザーにそこでコンテンツを消費してほしくない場合、なぜまだWordPressサイトを持っているのですか?
「いいね!」 1

元のトピックの著者に代わって話すことはできませんが、私の場合は次のように答えることができます。

WordPressに多くのプラグインをハッキングして、ポッドキャストプレーヤー(オーディオが再生されると単語がハイライトされ、その部分のオーディオにジャンプできるインタラクティブなトランスクリプト)、インタラクティブなチャプター/ショーノート、検索/ソート/フィルタリング可能なプレイリストを搭載できるようにしました。

そのため、iframeなしでここに埋め込むだけでは、私が組み込んだJavaScriptやすべてのスタイルにアクセスできなくなります。

ああ、そしてWordPressでそれらのものをハッキングする方が、Discourseよりもはるかに簡単です。ここではJavaScriptやプラグインの作成に本当に苦労しています。

ポッドエピソードをホストするには、いずれにしてもWordPressサイトが必要です。しかし、そこでコンテンツを消費してもらいたいかどうかは、よくわかりません。WordPressでコメントにDiscourseを使用するようになってから、インタラクティブ性が低下しました。以前はWordPressのコメントに投稿がありましたが、Discourseではドメインの境界を越える必要があり、別の場所でやり取りすることになります。DiscourseがWordPressフォーラムに埋め込み形式で簡単に投稿できるようにしてくれれば、おそらくそちらに集中するでしょう。

必要かどうかはわかりませんが、人々が集まる中心的な場所を1つ持ちたいという気持ちがあり、以前はWordPressに埋め込まれたDiscourseのコメント/投稿を考えていましたが、今はWordPressの投稿を埋め込んだDiscourseの方が簡単で、人々がお互いに交流するきっかけになる可能性が高いと考えています。

「いいね!」 2

すごいですね!

なぜですか?

わかります!それにもかかわらず、私の以前の質問(「なぜですか?」)への回答に応じて、それらをDiscourseの投稿に適切に埋め込むことは、動的なiframeよりも安定したアプローチになります。

インタラクティビティの低下についてお聞きして残念です。ここでのあなたの意味も理解しています。このテーマに関するSimonのより広範なトピックが思い浮かびます。

「いいね!」 1

できるかもしれない、という意味です。以前、ここでmediaelement.jsを使用するオーディオプレーヤーを実装しようとして苦労しました。プラグインAPIをあまり理解していないようです。長期的にはできるかもしれませんが、今はiframe埋め込みでかなりうまくいっているように見えます。主な課題は、iframeに埋め込まれたテキストの検索可能性ですが、そのテキストを投稿で公開し、非表示にするかアコーディオンの下に配置することを考えていました。そうすれば、検索にも表示されるはずです。

さらに、コンテンツが(あるいはどんな専門用語であれ lol)調理されるときに多くのHTMLクラスが削除されてしまうことが、実際にはより大きな問題だと思います。そのため、WordPressの投稿をここに公開して同様のCSSを使用しようとすると、多くの書き直しが必要になり、それがこのプラグインを書くきっかけとなりました。

「いいね!」 1

なるほど。少し考えてみます。Simonがすでに提案したこと以上の動的なiframeに関する重要な洞察はありませんが、あなたのケースは私に少し考えさせてくれます。

「いいね!」 1

このテーマについて、私が現在取り組んでいることを(Discourseをウェブサイトのコメントシステムとして利用しています)言及する価値があるかもしれません。現在は主にヘッドレスWordPressサイトに焦点を当てていますが、一般的なアプローチは、通常のWordPressサイトやWordPress以外のサイトにも役立つ可能性があります。

「いいね!」 2

どこで見たか覚えていませんが、調理済みコンテンツに、確か 1000px の最大高さが隠されているのではないでしょうか?

それがあなたの解決策を妨げているのかもしれません。

明日見てみます :folded_hands:t2:

「いいね!」 1

iframe要素にあります。

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

これは、data属性でiframeをターゲットにすることで、テーマで修正できます。

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

この変更は、より長いiframeを表示するために必要ですが、私が目にしていたスクロールバーはiframeソースページから来ていました。良い結果を得る唯一の方法は、ブログで投稿の埋め込みバージョンを作成することです。基本的に、投稿コンテンツ以外のすべてを削除し、スタイルを少し調整します。たとえば、WordPressのカスタム投稿タイプを使用します。

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;
        // 少し当てずっぽうですが、このケースでは `scrollHeight` が正しいターゲットだと思います
        const height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

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

    // 初期高さを送信
    window.onload = sendHeight;

    // オプション:リサイズなどのイベントで高さを更新
    window.onresize = sendHeight;
</script>
<?php
endwhile; endif;
?>

本番サイトでこれを機能させるには、少し調整が必要かもしれませんが、さらに調査する価値はあるようです。

OK、これで動作しました。JavaScriptのどこかにバグがあって、それが原因だったのだと思います。やったー、サイトに非常によく統合されているようです。@simonさん、本当にありがとうございます!

「いいね!」 1