PageTree démo by

Développeurs

Hooks de blocs pour les plugins

Depuis la 2.6, un autre plugin peut étendre tous les blocs PageTree sans modifier PageTree : ajouter des champs aux formulaires de blocs, changer les variables du template, ajouter des attributs à la racine du bloc, filtrer son HTML et charger des fichiers dans l’aperçu et dans les éditeurs de blocs.

Principes

  • Les hooks sont facultatifs : sans écouteur, PageTree produit le même HTML et charge les mêmes fichiers qu’avant.
  • Un écouteur doit être idempotent. Un événement peut être déclenché plusieurs fois pour le même bloc dans une requête (l’éditeur reconstruit les formulaires de blocs, l’aperçu se recharge, une page a plusieurs blocs) : n’ajoutez pas deux fois le même champ et n’enregistrez pas deux fois le même gestionnaire.
  • Une exception dans un écouteur est journalisée et ne casse jamais la page (voir Quand un écouteur échoue).
ÉvénementMomentArguments
pagetree.block.config.fieldsDéfinition du formulaire d’un bloc[$block, &$fields]
pagetree.block.renderAvant le rendu Twig[$block, &$templateVars, &$attributes, $component]
pagetree.block.renderedAprès le HTML du bloc[&$html, $component]
pagetree.preview.assetsAperçu de l’éditeur et mode édition du site[$page, &$headAssets]
pagetree.editor.blockfieldsÉditeur de blocs et panneau de bloc du site[&$assets, $context]

Ajouter des champs aux formulaires de blocs

pagetree.block.config.fields est déclenché quand la définition du formulaire d’un bloc est construite, avant que PageTree ajoute son propre champ Affiché ?. $fields est le tableau d’un fichier config_fields.yaml, modifié par référence. Le champ peut utiliser n’importe quel type de champ de formulaire d’October.

Event::listen('pagetree.block.config.fields', function ($block, &$fields) {
    if (isset($fields['fields']['css_classes'])) {
        return; // Plusieurs blocs partagent le même formulaire
    }

    $fields['fields']['css_classes'] = [
        'label' => 'Classes CSS',
        'type' => 'text',
        'default' => 'my-default-class',
    ];
});

L’événement est déclenché dans le formulaire de l’éditeur, dans l’aperçu, dans le panneau d’édition du site et quand PageTree calcule les valeurs par défaut d’un bloc : un bloc enregistré sans le champ est rendu avec sa valeur par défaut, sur le site public aussi.

Changer les variables et les attributs de la racine

pagetree.block.render est déclenché avant le rendu du template Twig d’un bloc. $templateVars contient les variables du template, $attributes un tableau vide d’attributs pour la racine du bloc, et $component le descripteur du bloc (id, type, data complété par les valeurs par défaut du formulaire).

Event::listen('pagetree.block.render', function ($block, &$templateVars, &$attributes, $component) {
    $classes = trim((string) ($component->data['css_classes'] ?? ''));
    if ($classes !== '') {
        $attributes['class'] = $classes;
        $attributes['data-block-type'] = $component->type;
    }
});

PageTree applique les attributs au premier élément racine du bloc, en sautant les commentaires et les balises link, script, style et meta. Une class est fusionnée avec les classes existantes ; tout autre attribut remplace l’existant. Les valeurs sont échappées et les noms d’attributs vérifiés : on*, srcdoc et les noms invalides sont ignorés, de même qu’un attribut d’adresse (href, src, action, formaction…) qui contient une adresse javascript:, vbscript: ou data:.

La variable blockAttributes

Un template qui place lui-même les attributs, sur une enveloppe ou un élément intérieur, affiche la variable sûre blockAttributes. PageTree ne les ajoute alors pas une seconde fois au premier élément racine. Pas besoin de |raw, et la variable affiche une chaîne vide quand il n’y a aucun attribut.

<section{{ blockAttributes }}>
    ...
</section>

Filtrer le HTML du bloc

pagetree.block.rendered est déclenché une fois le HTML du bloc rendu et les attributs de sa racine appliqués, pour ce que des attributs ne savent pas exprimer (enveloppe, balisage schema.org, marqueurs de mesure d’audience…). Modifiez $html par référence au lieu de renvoyer une chaîne : tous les écouteurs sont exécutés, dans l’ordre d’enregistrement, et plusieurs plugins peuvent donc étendre le même bloc.

Event::listen('pagetree.block.rendered', function (&$html, $component) {
    $html .= '<!-- block ' . e($component->id) . ' -->';
});

Charger des fichiers dans l’aperçu et les éditeurs

pagetree.preview.assets ajoute des fichiers à l’aperçu de l’éditeur et à la page du site en mode édition, jamais au rendu public normal. pagetree.editor.blockfields ajoute des fichiers aux deux éditeurs de blocs (le formulaire de l’éditeur et le panneau de bloc du site), avec addCss() / addJs() d’October.

Event::listen('pagetree.preview.assets', function ($page, &$headAssets) {
    $headAssets['css'][] = '/plugins/acme/preview/preview.css';
    $headAssets['js'][] = ['url' => '/plugins/acme/preview/preview.js', 'defer' => true];
});

Event::listen('pagetree.editor.blockfields', function (&$assets, $context) {
    $assets['js'][] = '/plugins/acme/editor/editor.js';
});

Chaque entrée est une URL, ou un tableau avec une url et des attributs facultatifs (defer, async, type, media, crossorigin, integrity…). PageTree construit et échappe lui-même les balises. Les URL relatives, absolues et sans protocole sont acceptées ; les URL javascript:, vbscript: et data: sont ignorées.

Événements JavaScript

Quand un formulaire de bloc s’affiche, les deux éditeurs déclenchent pagetree:block-form-ready sur la fenêtre courante, une fois par formulaire. La racine du formulaire porte aussi data-block-id : un plugin n’a pas besoin d’un MutationObserver pour trouver le formulaire.

window.addEventListener('pagetree:block-form-ready', function (event) {
    const { element, blockId, blockType, window } = event.detail;
});

L’aperçu de l’éditeur déclenche toujours pagetree:preview-document avec { document, window } à chaque installation du document d’aperçu : utilisez-le pour un comportement qui doit s’exécuter dans le document d’aperçu.

Quand un écouteur échoue

  • pagetree.block.render : l’exception est journalisée comme avertissement et le bloc est rendu comme sans écouteur, sans attributs et avec les variables du template d’avant l’événement.
  • pagetree.block.rendered : PageTree journalise un avertissement (sans les données du bloc) et renvoie le HTML qu’il avait avant le filtre. Les écouteurs enregistrés après lui ne sont pas exécutés pour ce bloc, et les modifications de ceux d’avant sont abandonnées elles aussi.
  • pagetree:block-form-ready : le déclenchement est protégé par un try/catch, un écouteur défaillant ne casse donc jamais l’éditeur.