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، فيمكنني فقط توجيه المستخدمين إلى 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 بناءً على ارتفاع المنشور؟

إذا كان الأمر كذلك، فما مدى الدقة التي تحتاجها؟ أتساءل عما إذا كان يمكنك فقط حساب عدد الأحرف في المنشور، ثم إضافة ارتفاع أي صور أو عناصر أخرى لها ارتفاع محدد، ثم إضافة المزيد للاحتياط. قد يكون لدي بعض الاقتراحات حول كيفية القيام بذلك.

قد يكون من الممكن أيضًا استخدام جافا سكريبت للحصول على الارتفاع الدقيق للمنشور عند عرضه بعرض معين.

إعجاب واحد (1)

آه، لم أصل حتى إلى هذه النقطة فيما يتعلق بدمجها في فلتر discourse_publish_format_html. كنت أقوم فقط بإضافتها يدويًا إلى منشور في Discourse وأحاول معرفة كيفية عمل JavaScript لقراءة ارتفاع المحتوى داخل الإطار المضمن (iframe) ثم تغيير حجم الإطار المضمن.

لقد رأيت عددًا كبيرًا من الدروس التعليمية حول كيفية القيام بذلك عبر الإنترنت، ولكن لسبب ما لم أتمكن من جعل هذا الـ JavaScript يعمل على Discourse. جربت مع تغيير الصفحة و decorateCookedElement في واجهة برمجة التطبيقات (API)، ومع ذلك لم أتمكن من جعله يعمل.

إذا كان ذلك ممكنًا، أفضل القيام بذلك في Discourse نفسه، حتى أتمكن من تغيير حجم الإطارات المضمنة إلى الارتفاع الكامل إذا قمت بتضمين محتوى من موقع غير WordPress أيضًا.

إنها مشكلة مثيرة للاهتمام. ماذا يحدث إذا قمت بتحرير السمة height لعنصر iframe يدويًا في منشور Discourse؟ عند عرض المنشور بعد تحرير الارتفاع، هل يتم استخدام الارتفاع الجديد، أم يتعين عليك إعادة خبز منشور Discourse ليصبح الارتفاع المعدل ساري المفعول؟

تعديل: إنها مثيرة للاهتمام بما يكفي لدرجة أنني سأختبر هذا لاحقًا اليوم.

إعجاب واحد (1)

إذا أضفته إلى علامة iframe باستخدام height="400px"، فسيتم تغيير حجمه بعد تحديث الصفحة. إذا أضفته كـ height="100%"، فلا يبدو أنه يفعل شيئًا.

إذا أضفت خصائص CSS الخاصة بعنصر iframe، فيبدو أنها تغير الارتفاع بشكل صحيح أيضًا، على الأقل إلى ما أدخله يدويًا.

أوه، لقد تمكنت من جعله يعمل. كانت المشكلة أنني كنت أستخدم فئة مخصصة على علامة iframe وتقوم Discourse بإزالة جميع هذه العلامات. كان يجب أن أتعلم درسي منذ بضعة أيام (Formatting posts to look more like Wordpress blog - #6 by jimkleiber). قرأت أن هذا لسبب أمني لعدم عمل فئات HTML المخصصة هنا ولكنني لست متأكدًا من السبب :confused:

ومع ذلك، إليك الكود لضبط ارتفاع iframe باستخدام المحدد .topic-body 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); // اضبط التأخير حسب الحاجة                  
      },
      { id: "component-id", onlyStream: true}
    );
</script>

تعديل: في الواقع، لم يعمل. لقد أضفت height="4000px" في علامة iframe وهذا هو السبب في أنه كان يعمل، أعتقد.

إعجاب واحد (1)

إنها مشكلة صعبة. لا أعتقد أنه من السهل الوصول إلى محتوى الإطار المضمن (iframe) من داخل Discourse. قد يكون من الممكن جعله يعمل إذا كان مصدر الإطار المضمن وموقع Discourse الخاص بك موجودين على نطاقات فرعية مختلفة لنفس النطاق.

إذا كنت أفهم المشكلة بشكل صحيح، فستحتاج إلى تعيين document.domain على كل من النطاق الفرعي الذي تسحب منه المحتوى، وفي البرنامج النصي الذي تقوم بتشغيله على Discourse إلى النطاق الجذر.

إذا كان مصدر الإطار المضمن هو في الواقع نطاقك الجذر، فربما حاول تعديل البرنامج النصي إلى:

   document.domain = "your_root_domain.com"; // edit that to your domain
    api.decorateCookedElement(
      element => {

إذا كان نطاق الإطار المضمن هو أيضًا نطاق فرعي لنطاقك الجذر، فستحتاج إلى تعيين document.domain إلى النطاق الجذر عليه أيضًا.

لتنسيق الإطارات المضمنة (أو أي شيء) على 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>

تنسيق المظهر (Theme CSS):

[data-full-height] > iframe {
      // optionally style outer iframe here: height, width, etc
     // unfortunately height: 100% won't work - the iframe's containing element doesn't have a set height.
}

إذا لم ينجح نهج document.domain، فقد تكون هناك حلول أخرى - استخدام window.postMessage للتواصل بين المستند الأصلي للإطار المضمن و Discourse.

لا أعتقد أن فكرتي الأولية لحساب ارتفاع الإطار المضمن على موقعه المصدر ستنجح - سيتغير عرض الإطار المضمن المعروض اعتمادًا على الجهاز الذي يتم عرض Discourse عليه.

إعجاب واحد (1)

حسنًا، المنتدى الخاص بي هو نطاق فرعي لنطاقي الرئيسي، لذا أضفت النطاق الرئيسي كما اقترحت وحصلت على هذا الخطأ:

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

الآن أحاول القيام بشيء postMessage ولكني أفشل. أعتقد أنني بحاجة إلى فهم أفضل لكيفية عمل جافاسكريبت Discourse، أعتقد أنني أفترض أنه يعمل مثل المواقع الأخرى وربما لا يعمل، أو ربما أنا فقط لا أعرف كيفية القيام بجافاسكريبت بشكل جيد، خاصة بالنسبة للأشياء عبر النطاقات lol.

شكرًا لك على إلقاء نظرة على هذا!

لقد كنت أتساءل عن هذا لفترة. إليك إثبات مفهوم (لاحظ أنه لا يحل مشكلة إزالة أشرطة التمرير من iframes).

أضف علامة نص برمجي إلى المنشور الذي تقوم بتضمينه:

<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' // استخدم معرفًا فريدًا إذا كان لديك iframes متعددة
        }, '*'); // ضع في اعتبارك تحديد النطاق الأصلي للأمان
    }

    // إرسال الارتفاع الأولي
    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; // نطاق الاختبار الخاص بي، قم بتحديثه إلى نطاقك أو قم بالتعليق عليه
  // يحصل على ارتفاع iframe الذي يتم تمريره من `wp-discourse.test` ويؤكد أن iframeId يطابق iframeID الذي قمت بتعيينه هناك
  if (event.data.iframeHeight && event.data.iframeId === 'zalgFrame') {
      // قم بزيارة صفحة Discourse مع iframe مع فتح وحدة التحكم الخاصة بك
      // يجب أن ترى ارتفاعات محدثة يتم إرسالها من الموقع الأصلي أثناء تغيير حجم النافذة
      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 على أي حال. لست متأكدًا من أن ذلك سيعمل على إزالة شريط التمرير العمودي من iframes الطويلة. إذا حاولت ترميز ارتفاع كبير (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;
        // بناءً على افتراض أنه سيكون هناك iframe واحد فقط مغلف في div data-zalgFram
        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)

أنا أقدر الجهود الشجاعة هنا ولا أريد أن أثبط عزيمتها، ومع ذلك يجب أن أعترف بأنني أشعر ببعض الشكوك حول فرضية هذا الموضوع، أي:

لدي سؤالان (حقيقيان) حول هذا يا جيم:

  1. ما هو السبب الذي يجعلك تريد إطارًا مضمنًا هنا بدلاً من وظيفة التضمين العادية للموضوع؟
  2. أنا فضولي لماذا لا يزال لديك موقع ووردبريس على الإطلاق إذا كنت لا تريد للمستخدمين استهلاك المحتوى هناك؟
إعجاب واحد (1)

لا يمكنني التحدث نيابة عن مؤلف الموضوع الأصلي، ولكن يمكنني تقديم إجابات في حالتي:

لقد قمت بتجميع عدد من الإضافات على ووردبريس تسمح لي بتشغيل مشغل بودكاست مع نصوص تفاعلية (تُبرز الكلمات أثناء تشغيل الصوت ويمكن النقر عليها للانتقال إلى هذا الجزء من الصوت)، وفصول تفاعلية/ملاحظات العرض، وقائمة تشغيل قابلة للبحث/الفرز/التصفية.

لذلك، لتضمينها هنا فقط بدون iframe، لن أتمكن من الوصول إلى جافاسكريبت وكل التصميم الذي وضعته فيه.

أوه، وأجد أنه من الأسهل بالنسبة لي تجميع هذه الأشياء على ووردبريس بدلاً من ديسكورس، أنا حقًا أعاني من القيام بجافاسكريبت والإضافات هنا.

لاستضافة حلقات البودكاست، سأحتاج إلى موقع ووردبريس بغض النظر. ولكن فيما يتعلق بما إذا كنت أريد من المستخدمين استهلاك المحتوى هناك، لست متأكدًا. بما أنني كنت أستخدم ديسكورس للتعليقات على ووردبريس، فقد انخفض التفاعل. اعتدت أن يكون لدي أشخاص ينشرون في تعليقات ووردبريس، ولكن ديسكورس يتطلب منهم عبور عتبة نطاق، وبعد ذلك يتفاعلون في مكان منفصل. إذا جعل ديسكورس الأمر أسهل للأشخاص للنشر بطريقة مضمنة في منتدى ووردبريس، فربما أركز على ذلك.

لست متأكدًا مما إذا كان ذلك ضروريًا، لدي فقط شعور بأنني أريد أن يكون هناك مكان رئيسي واحد ليتجمع فيه الناس، وقبل ذلك اعتقدت أنه سيكون ووردبريس مع تعليقات/نشر ديسكورس مضمنة ولكن الآن أفكر أن ديسكورس مع منشورات ووردبريس مضمنة قد يكون أسهل ومن المرجح أن يلهم الناس للتفاعل مع بعضهم البعض.

إعجابَين (2)

رائع!

لماذا لا؟

أتفهم! ومع ذلك، اعتمادًا على إجابتك على سؤالي السابق (“لماذا لا؟”)، سيكون تضمينها بشكل صحيح في منشور ديسكورس نهجًا أكثر استقرارًا من إطار تضمين ديناميكي.

يؤسفني سماع هذا الانخفاض، وأنا أفهم أيضًا ما تقصده هنا. الموضوع الأوسع لسيمون حول هذا الموضوع يتبادر إلى الذهن

إعجاب واحد (1)

أعني، ربما أستطيع؟ لقد واجهت صعوبة في استخدام مشغل صوتي يستخدم mediaelement.js هنا من قبل، أعتقد أنني لا أفهم واجهة برمجة تطبيقات المكونات الإضافية جيدًا. يبدو الأمر وكأنه الكثير من العمل الذي ربما أستطيع القيام به على المدى الطويل، ولكن في الوقت الحالي، يبدو الأمر جيدًا جدًا مع تضمين iframe. سيكون التحدي الرئيسي هو قابلية البحث عن النص المضمن في iframe، لكنني كنت أفكر في نشر هذا النص في المنشور وإخفائه أو وضعه تحت أكورديون، بحيث يظهر في عمليات البحث.

بالإضافة إلى ذلك، أعتقد أن المشكلة الأكبر هي في الواقع أن العديد من فئات HTML يتم تجريدها عند طهي المحتوى (أو أيًا كان المصطلح المستخدم lol)، وبالتالي فإن مجرد محاولة نشر منشور WordPress هنا واستخدام CSS مماثل يتطلب الكثير من إعادة الكتابة، مما ألهمي لكتابة هذا:

إعجاب واحد (1)

حسناً. دعني أفكر في هذا قليلاً. ليس لدي أي رؤى مهمة حول الإطارات المتداخلة الديناميكية بخلاف ما اقترحه سيمون بالفعل، ومع ذلك فإن حالتك تجعلني أفكر قليلاً.

إعجاب واحد (1)

ربما يجدر الإشارة إلى أنني أعمل بنشاط على هذا (باستخدام Discourse لتشغيل نظام التعليقات للمواقع). أركز بشكل أساسي على مواقع WordPress بدون رأس في الوقت الحالي، ولكن النهج العام قد يكون مفيدًا لمواقع WordPress العادية وغير مواقع WordPress.

إعجابَين (2)

لا أتذكر أين رأيت ذلك، ولكن هناك حد أقصى مخفي للارتفاع أعتقد أنه 1000 بكسل، ربما على المحتوى المطبوخ؟

لذا ربما هذا يعبث بحلك.

سألقي نظرة غدًا :folded_hands:t2:

إعجاب واحد (1)

إنه موجود في عناصر iframe:

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

يمكن إصلاح ذلك في سمة عن طريق استهداف عناصر iframe باستخدام السمة data:

[data-zalgFrame] \u003e 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;
        // 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;
?>

قد يستغرق الأمر بعض التعديلات للحصول على هذا ليعمل على موقع إنتاجي، ولكنه يبدو يستحق المزيد من البحث.

حسناً، لقد نجحت في تشغيل هذا. أعتقد أنني كنت أواجه خطأ في مكان آخر في جافاسكريبت كان يمنع ذلك. رائع! يبدو أنه مدمج بشكل جيد جداً في موقعي. شكراً جزيلاً لك يا @simon!

إعجاب واحد (1)