Le WordPress d'aujourd'hui, décodé pour les développeurs

Blocs Gutenberg

Pourquoi cibler document casse un bloc dans l’éditeur iframé

Depuis que l'éditeur de blocs s'exécute dans un iframe, cibler l'objet document global dans le code d'un bloc ne pointe plus vers le contenu réellement affiché à l'écran.

Par WordPress Développement • 30 avril 2023 • 4 min de lecture • Aucun commentaire
Pourquoi cibler document casse un bloc dans l'éditeur iframé

document.querySelector('.wp-block-monsite-compteur') — cette ligne fonctionnait très bien il y a quelques versions, et elle a cessé de trouver quoi que ce soit du jour où l’éditeur de blocs a commencé à afficher le contenu dans un iframe dédié plutôt que directement dans la page d’administration.

Ce que change l’éditeur iframé

Avant cette évolution, l’éditeur affichait le contenu des blocs directement dans le document de la page d’administration WordPress. Un bloc pouvait donc interroger document sans distinction particulière : il n’existait qu’un seul document, celui de la fenêtre du navigateur dans son ensemble.

Depuis le passage à un rendu iframé du contenu de l’éditeur, deux documents distincts coexistent dans le même onglet : le document de la page d’administration, qui contient la barre d’outils, le panneau latéral et les menus, et le document interne à l’iframe, qui contient uniquement le contenu éditable des blocs. Un appel à document.querySelector exécuté depuis un script global cherche dans le premier document, jamais dans le second.

Fonctionnement interne

Le rendu du contenu dans un cadre isolé sert plusieurs objectifs : il permet d’appliquer des styles spécifiques au contenu (via theme.json et les styles de l’éditeur) sans qu’ils ne fuient vers l’interface d’administration, et il isole le contexte JavaScript du contenu de celui de l’interface globale, ce qui limite les interférences entre scripts de blocs différents.

// Ne fonctionne plus de façon fiable pour cibler le contenu du bloc :
const element = document.querySelector('.wp-block-monsite-compteur');

// Fonctionne, car il utilise la référence DOM fournie par React :
function Edit() {
  const blockProps = useBlockProps();
  return <div { ...blockProps }>Compteur : 0</div>;
}
L'essentiel à retenir : L'éditeur charge le contenu du bloc dans un document distinct de la fenêtre principale ; document.querySelector cherche dans le mauvais document depuis cette évolution ; Les hooks fournis par le bloc-editor donnent accès au bon contexte

Cas d’usage : accéder au bon document depuis le code du bloc

Quand un bloc a réellement besoin d’accéder au document dans lequel il est rendu (pour mesurer une dimension, attacher un écouteur d’événement natif, ou interroger un élément voisin), la bonne pratique consiste à remonter au document depuis une référence React plutôt que de cibler l’objet global :

import { useRef, useEffect } from '@wordpress/element';
import { useBlockProps } from '@wordpress/block-editor';

function Edit() {
  const reference = useRef();
  const blockProps = useBlockProps( { ref: reference } );

  useEffect( () => {
    if ( ! reference.current ) {
      return;
    }
    const documentDuBloc = reference.current.ownerDocument;
    const fenetreDuBloc = documentDuBloc.defaultView;
    // documentDuBloc et fenetreDuBloc pointent vers le bon contexte,
    // que le bloc soit rendu dans l'iframe ou non.
  }, [] );

  return <div { ...blockProps }>Contenu du bloc</div>;
}

La propriété ownerDocument d’un nœud DOM renvoie toujours le document qui le contient réellement, indépendamment de l’endroit d’où le script est exécuté, ce qui rend le bloc compatible aussi bien avec l’éditeur iframé qu’avec un rendu direct.

Pièges fréquents rencontrés sur ce sujet

  • Un écouteur d’événement posé sur window dans l’éditeur ne capte pas les événements survenant à l’intérieur de l’iframe, sauf à cibler explicitement reference.current.ownerDocument.defaultView ;
  • Une bibliothèque tierce qui manipule directement le DOM via document.getElementById peut nécessiter une adaptation pour fonctionner correctement dans l’éditeur, même si elle fonctionne sans problème côté front public ;
  • Un test manuel effectué uniquement sur le rendu front du site peut masquer ce problème, qui n’apparaît que dans l’expérience d’édition elle-même.

Une distinction à garder en tête au-delà de ce cas précis

Cette question du bon document à cibler dépasse le seul sujet de l’iframe : elle rappelle plus généralement qu’un bloc bien construit s’appuie sur les références fournies par React et par les hooks du block-editor, plutôt que sur des accès globaux qui supposent implicitement un contexte d’exécution particulier.

Un bloc qui cible document directement fait un pari implicite sur son environnement d’exécution ; ce pari a cessé d’être valable pour l’éditeur le jour où celui-ci a changé de structure interne.

En résumé

Cibler document globalement dans le code d’un bloc suppose qu’il n’existe qu’un seul document dans la page, une hypothèse devenue fausse depuis que l’éditeur affiche son contenu dans un iframe séparé. Passer par ownerDocument et par les références DOM fournies par React reste la façon la plus robuste d’écrire un bloc qui fonctionne correctement, que l’on soit dans l’éditeur ou sur le rendu public du site.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Partager :

À propos de l'auteur

WordPress Développement

Développeur WordPress, passionné par Elementor, le FSE et l’automatisation par IA.

Voir tous ses articles

Dans la même veine

À lire aussi