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

Ci sto provando anche io, dato che ho capito che se incorporo i miei post di WordPress su Discourse, allora posso semplicemente indirizzare i miei utenti a Discourse e non a due siti diversi.

Qualcuno ha capito come fare? Ci sto lottando da un po’.

Stai usando qualcosa di simile per aggiungere l’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();

        // Restituisce un iframe per questo tipo di post.
        return $output;
    }

    // Restituisce l'output predefinito, o fai qualcos'altro qui.
    return $output;
}
add_filter( 'discourse_publish_format_html', 'your_namespace_publish_format_html' );

ma volendo impostare la proprietà height in base all’altezza del post?

Se sì, quanto esattamente deve essere? Mi chiedo se potresti semplicemente contare il numero di caratteri nel post, quindi aggiungere l’altezza di eventuali immagini o altri elementi che hanno un’altezza impostata, quindi aggiungere un po’ di più per sicurezza. Potrei avere alcuni suggerimenti su come farlo.

Potrebbe anche essere possibile utilizzare Javascript per ottenere l’altezza esatta del post quando viene renderizzato a una data larghezza.

1 Mi Piace

Ah, non sono ancora arrivato a quel punto nell’integrazione nel filtro discourse_publish_format_html. Stavo solo aggiungendolo manualmente a un post in Discourse e cercando di capire il javascript per leggere l’altezza del contenuto all’interno dell’iframe e poi ridimensionare l’iframe.

Ho visto parecchi tutorial su come farlo online ma per qualche motivo non riesco a far funzionare quel js su Discourse. Ho provato con il cambio di pagina e decorateCookedElement nell’API, eppure ancora non riesco a farlo funzionare.

Se possibile, preferirei farlo in Discourse stesso, in modo da poter ridimensionare gli iframe all’altezza intera anche se incorporo da un sito non WordPress.

È un problema interessante. Cosa succede se modifichi manualmente l’attributo height di un elemento iframe in un post di Discourse? Quando visualizzi il post dopo aver modificato l’altezza, viene utilizzata la nuova altezza o devi rielaborare il post di Discourse affinché l’altezza modificata abbia effetto?

Modifica: è abbastanza interessante che lo testerò più tardi oggi.

1 Mi Piace

Se lo aggiungo al tag iframe con height="400px" si ridimensionerà dopo l’aggiornamento della pagina. Se lo aggiungo come height="100%" non sembra fare nulla.

Se aggiungo proprietà CSS all’iframe, sembra che cambi l’altezza correttamente, almeno per quanto inserisco manualmente.

Ugh, ci sono riuscito. Il problema era che stavo usando una classe personalizzata sul tag iframe e Discourse rimuove tutti quei tag. Avrei dovuto imparare la lezione qualche giorno fa (Formatting posts to look more like Wordpress blog - #6 by jimkleiber). Ho letto che è per motivi di sicurezza il motivo per cui le classi HTML personalizzate non funzionano qui, ma non sono sicuro del perché :confused:

Tuttavia, ecco il codice per regolare l’altezza di un iframe con il selettore .topic-body iframe (non sono sicuro che questo codice funzioni per altri, sembra funzionare per me):

<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); // Regola il ritardo secondo necessità                  
      },
      { id: "component-id", onlyStream: true}
    );
</script>

EDIT: in realtà, non funziona. Ho aggiunto height="4000px" nel tag iframe ed è per questo che funzionava, credo.

1 Mi Piace

È un problema complicato. Non credo sia facile accedere al contenuto dell’iframe dall’interno di Discourse. Potrebbe essere possibile farlo funzionare se la sorgente dell’iframe e il tuo sito Discourse si trovano su sottodomini diversi dello stesso dominio.

Se ho capito bene il problema, dovresti impostare document.domain sia sul sottodominio da cui stai recuperando il contenuto, sia nello script che stai eseguendo su Discourse, al dominio principale.

Se la sorgente dell’iframe è effettivamente il tuo dominio principale, prova ad aggiustare lo script in questo modo:

<script type="text/discourse-plugin" version="0.8.18">
   document.domain = "your_root_domain.com"; // modificalo con il tuo dominio
    api.decorateCookedElement(
      element => {

Se anche il dominio dell’iframe è un sottodominio del tuo dominio principale, dovrai impostare document.domain al dominio principale anche su di esso.

Per lo styling degli iframe (o di qualsiasi altra cosa) su Discourse, puoi racchiudere il contenuto in un div con un attributo data:

<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 del tema:

[data-full-height] > iframe {
      // opzionalmente, applica lo stile all'iframe esterno qui: altezza, larghezza, ecc.
     // sfortunatamente height: 100% non funzionerà - l'elemento contenitore dell'iframe non ha un'altezza impostata.
}

Se l’approccio document.domain non funziona, potrebbero esserci altre soluzioni: usare window.postMessage per comunicare tra il documento padre dell’iframe e Discourse.

Non credo che la mia idea iniziale di calcolare l’altezza dell’iframe sul suo sito sorgente funzionerà: la larghezza dell’iframe renderizzato varierà a seconda del dispositivo su cui viene visualizzato Discourse.

1 Mi Piace

Hmm, il mio forum è un sottodominio del mio dominio principale, quindi ho aggiunto il dominio principale come suggerito e ho ricevuto questo errore:

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

Ora sto cercando di fare la cosa del postMessage ma sto fallendo. Penso di aver bisogno di capire meglio come funziona il javascript di Discourse, penso di presumere che funzioni come altri siti e forse non è così, o forse sono solo io che non conosco bene il javascript, specialmente per le cose cross-origin lol.

Grazie per aver dato un’occhiata a questo!

Mi stavo chiedendo questo da un po’. Ecco una prova di concetto (nota che non risolve il problema della rimozione delle barre di scorrimento dagli iframe).

Aggiungi un tag script al post che stai incorporando:

<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' // Usa un identificatore univoco se hai più iframe
        }, '*'); // Considera la specifica del dominio padre per la sicurezza
    }

    // Invia l'altezza iniziale
    window.onload = sendHeight;

    // Opzionale: aggiorna l'altezza al ridimensionamento o ad altri eventi
    window.onresize = sendHeight;
</script>

Sto usando l’identificatore "zalgFrame" nello script.

Nel tuo tema 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; // il mio dominio di test, aggiornalo al tuo dominio o commentalo
  // ottiene l'altezza dell'iframe passata da `wp-discourse.test` e conferma che iframeId corrisponde all'iframeID che ho impostato lì
  if (event.data.iframeHeight && event.data.iframeId === 'zalgFrame') {
      // visita la pagina Discourse con l'iframe con la console aperta
      // dovresti vedere le altezze aggiornate inviate dal sito padre mentre ridimensioni la finestra
      console.log("abbiamo ricevuto un evento:" + event.data.iframeHeight);
      iframeHeight = event.data.iframeHeight;
      iframeId = event.data.iframeId;
  }
  }, false);
</script>

In un post di 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>

Quindi è possibile ottenere l’altezza effettiva dell’iframe renderizzato dalla finestra padre.

Non so come ottenere l’altezza dai dati dal listener di eventi in una chiamata a api.decorateCookedElement. Non sono sicuro che funzionerebbe per rimuovere la barra di scorrimento verticale dagli iframe lunghi. Se provo a codificare un’altezza elevata (1600px) nell’elemento iframe, finisco ancora con una barra di scorrimento.

Modifica: per completezza:

<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;
        // basato sull'assunzione che ci sarà solo 1 iframe racchiuso nel div data-zalgFram
        let iframe = e.querySelector("[data-zalgFrame] iframe");
        if (iframe) {
          iframe.style.height = `${iframeHeight}px`;
        }
        // dopo aver impostato l'altezza effettiva renderizzata dell'iframe
        // rimuovi il listener di eventi
        window.removeEventListener("message", handleMessage, false);
      }
    }
    window.addEventListener("message", handleMessage, false);
  },
  { id: "component-id", onlyStream: true }
);
</script>

Per qualsiasi altezza superiore a ~1000px, non sembra esserci alcun modo per evitare che Discourse aggiunga una barra di scorrimento, quindi non consiglio questo approccio.

Penso che la risposta all’OP sia che è in qualche modo possibile, ma probabilmente non porta molto lontano. (Tranne che ho imparato il metodo window.postMessage() :slight_smile:

2 Mi Piace

Apprezzo gli sforzi valorosi qui e non voglio smorzarli, tuttavia devo ammettere che sono un po’ scettico sulla premessa di questo argomento, cioè:

Ho due (genuine) domande su questo Jim:

  1. Qual è il motivo per cui vuoi un iframe qui invece della normale funzionalità di incorporamento dell’argomento?
  2. Sono curioso di sapere perché avresti ancora un sito WordPress se non vuoi che gli utenti consumino contenuti lì?
1 Mi Piace

Non posso parlare per l’autore originale dell’argomento, ma posso rispondere nel mio caso:

Ho assemblato parecchi plugin su WordPress che mi permettono di avere un lettore podcast con trascrizioni interattive (le parole si evidenziano mentre l’audio viene riprodotto e si può fare clic per saltare a quella parte dell’audio), capitoli/note dello show interattivi e una playlist ricercabile/ordinabile/filtrabile.

Quindi, per incorporarli qui senza un iframe, non sarei in grado di accedere al javascript e a tutto lo stile che ho inserito.

Oh, e trovo molto più facile per me assemblare quelle cose su WordPress che su Discourse, fatico davvero a fare javascript e plugin qui.

Per ospitare gli episodi del podcast, avrò comunque bisogno del sito WordPress. Ma se voglio che gli utenti consumino contenuti lì, non sono sicuro. Da quando uso Discourse per i commenti su WordPress, l’interattività è diminuita. Una volta avevo persone che postavano nei commenti di WordPress, ma Discourse richiede loro di superare una soglia di dominio e poi interagiscono in un posto separato. Se Discourse rendesse più facile per le persone postare in modo incorporato su un forum WordPress, probabilmente mi concentrerei su quello.

Non sono sicuro se sia necessario, ho solo la sensazione di voler avere un posto principale dove le persone possano riunirsi, e prima pensavo che sarebbe stato WordPress con commenti/post di Discourse incorporati, ma ora sto pensando che Discourse con post di WordPress incorporati potrebbe essere più facile e più probabile che ispiri le persone a interagire tra loro.

2 Mi Piace

Fantastico!

Perché no?

Capisco! Tuttavia, a seconda della tua risposta alla mia precedente domanda (“Perché no?”), incorporarli correttamente in un post di Discourse sarebbe un approccio più stabile rispetto a un iframe dinamico.

Mi dispiace sentire del calo, e capisco anche cosa intendi qui. Mi viene in mente l’argomento più ampio di Simon su questo tema

1 Mi Piace

Voglio dire, forse potrei? Ho faticato a far funzionare un lettore audio con mediaelement.js qui prima, penso di non capire molto bene l’API dei plugin. Sembra solo un sacco di lavoro che forse potrei fare a lungo termine, ma al momento, sembra piuttosto buono con l’embed iframe. La sfida principale sarebbe la ricercabilità del testo incorporato nell’iframe, ma stavo pensando di pubblicare quel testo nel post e nasconderlo o metterlo sotto un fisarmonica, in modo che appaia comunque nelle ricerche.

Inoltre, penso che il problema più grande sia in realtà che così tante classi HTML vengono rimosse quando il contenuto viene “cotto” (o qualunque sia il termine lol), e quindi semplicemente provare a pubblicare il post di WordPress qui e usare un CSS simile sembra richiedere molte riscritture, il che mi ha ispirato a scrivere questo:

1 Mi Piace

Capisco. Ci penso un po’. Non ho particolari intuizioni sui frame iframe dinamici oltre a quanto già suggerito da Simon, tuttavia il tuo caso mi sta facendo riflettere un po’.

1 Mi Piace

Forse vale la pena notare che ci sto lavorando attivamente (utilizzando Discourse per alimentare il sistema di commenti per i siti web). Al momento mi sto concentrando principalmente sui siti WordPress headless, ma l’approccio generale potrebbe essere utile per siti WordPress normali e non WordPress.

2 Mi Piace

Non ricordo dove l’ho visto, ma c’è un’altezza massima nascosta di credo 1000px, forse sul contenuto cotto?

Quindi forse questo sta interferendo con la tua soluzione.

Darò un’occhiata domani :folded_hands:t2:

1 Mi Piace

È sugli elementi iframe:

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

Che può essere corretta in un tema prendendo di mira gli iframe con l’attributo data:

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

Questa modifica deve essere apportata per visualizzare iframe più lunghi, ma le barre di scorrimento che stavo vedendo provenivano dalla pagina sorgente dell’iframe. L’unico modo in cui ottengo buoni risultati è creare versioni incorporate dei post sul mio blog, essenzialmente rimuovendo tutto tranne il contenuto del post e armeggiando un po’ con gli stili. Ad esempio, con un tipo di post personalizzato di 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;
        // un po' un tiro alla cieca, penso che `scrollHeight` sia il target corretto per questo caso
        const height = Math.max(body.scrollHeight, body.offsetHeight,
            html.clientHeight, html.scrollHeight, html.offsetHeight);

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

    // Invia l'altezza iniziale
    window.onload = sendHeight;

    // Opzionale: aggiorna l'altezza al ridimensionamento o ad altri eventi
    window.onresize = sendHeight;
</script>
<?php
endwhile; endif;
?>

Potrebbe richiedere un po’ di lavoro per farlo funzionare su un sito di produzione, ma sembra valere la pena approfondire ulteriormente.

Ok, sono riuscito a farlo funzionare, penso di aver avuto un bug da qualche altra parte in js che lo impediva. Evvai, sembra molto ben integrato nel mio sito. Grazie mille @simon!

1 Mi Piace