Block-Attribute abhängig von der Block-Position setzen

In einem kürzlich abgeschlossenen Projekt wollte ich für die Bilder in einem Slider-Block das sizes-Attribut nutzen. Da der Slider aber nicht immer in derselben Situation angezeigt wird, also beispielsweise über die volle Breite des Viewports (ein sinnvoller Wert für sizes wäre hier 100vw), sondern auch in normaler Content-Breite oder innerhalb von Spalten-Blöcken, musste der Wert für ein optimales Ergebnis abhängig von der Position des Slider-Blocks sein.

Vor der unten stehende Lösung habe ich versucht, die dynamische Anpassung eines Attributwerts innerhalb der edit- oder save-Funktion auszuführen. Da hatte ich aber Probleme, wie Fehler bei der Blockvalidierung, weil direkt beim Laden im Editor irgendwelche Informationen noch nicht vorhanden waren.

Daher bin ich an der subscribe-Funktion hängen geblieben. Bei einer Änderung des Editor-Status wird die Liste der Blöcke überprüft und für die Slide-Blöcke eines Slider-Blocks das maxWidth-Attribut gesetzt – abhängig von der Position des Sliders in der Liste der Blöcke.

Hier der komplette Code (oder als Gist):

const { select, } = wp.data; wp.domReady( () => { /** * Get the slider blocks. * * @param {object} block * @param {array} sliderBlocks */ const getSliderBlocks = ( block, sliderBlocks ) => { if ( block.innerBlocks.length === 0 ) { return; } // Check if it is a slider block. If so, push innerBlocks to the sliderBlocks array. if ( block.name === 'slug/slider' ) { sliderBlocks.push( block ); return; } block.innerBlocks.map( innerBlock => getSliderBlocks( innerBlock, sliderBlocks ) ); }; const getBlockList = () => select( 'core/editor' ).getBlocks(); wp.data.subscribe( () => { let blockList = getBlockList(); if ( blockList ) { // Get slider blocks. let sliderBlocks = []; blockList.map( block => getSliderBlocks( block, sliderBlocks ) ); sliderBlocks.map( sliderBlock => { // Set maxWidth depending on position and settings of block. const blockParents = select( 'core/block-editor' ).getBlockParents( sliderBlock.clientId ); let maxWidth; // Check if the slider block has no parents. if ( blockParents.length === 0 ) { const align = sliderBlock.attributes.align; // Set maxWidth to 100vw if full align. if ( align !== undefined && align === 'full' ) { maxWidth = '100vw'; } // Set maxWidth to 1170 if no align. if ( align === undefined || align !== 'full' ) { maxWidth = '1170'; } } else { // Get column parents. const columnParents = select( 'core/block-editor' ).getBlockParentsByBlockName( sliderBlock.clientId, 'core/column' ); if ( columnParents.length > 0 ) { const columnParent = select( 'core/block-editor' ).getBlock( columnParents[0] ); let columnWidth = columnParent.attributes !== undefined && columnParent.attributes.width !== undefined && columnParent.attributes.width !== '' ? columnParent.attributes.width : 50; maxWidth = 1170 / 100 * columnWidth; } else { maxWidth = '1170'; } } // Set the attributes for the slide blocks. sliderBlock.innerBlocks.map( slideBlock => { slideBlock.attributes.maxWidth = maxWidth; } ); } ); } } ); } );

Nachdem das DOM bereit ist, definieren wir ab Zeile 12 zunächst eine Funktion getSliderBlocks(), an die ein Block sowie ein Array übergeben wird. Der Slider-Block funktioniert mit der InnerBlocks-Komponente, da die einzelnen Slides wiederum Blöcke sind, das heißt wenn block.innerBlocks.length keine Einträge hat, kann es kein Slider-Block sein und wir beenden den Funktionsdurchlauf.

Wenn es sich bei dem Block um einen Slider-Block handelt, fügen wir ihn dem übergebenen Array hinzu und beenden wieder den Durchlauf der Funktion.

Wenn es kein Slider-Block ist, der Block aber innerBlocks hat, führen wir die Funktion noch mal für die innerBlocks aus, um Slider-Blöcke aus Gruppe-, Spalten- und ähnlichen Blöcken zu erhalten.

In Zeile 26 erstellen wir die Funktion getBlockList(), um eine Liste der Blöcke aus der aktuellen Editor-Instanz zu ermitteln.

Danach hängen wir uns mit wp.data.subscribe() an Editor-Änderungen und holen uns zunächst die aktuelle Block-Liste. Wenn wir Blöcke haben, definieren wir ein Array sliderBlocks und durchlaufen in Zeile 32 für die Blöcke der obersten Ebene aus blockList die getSliderBlocks()-Funktion. Und wie bereits beschrieben, kümmern wir uns innerhalb dieser Funktion auch um verschachtelte Blöcke, wenn Zeile 32 also abgearbeitet ist, haben wir in sliderBlocks alle verwendeten Slider-Blöcke.

Jetzt müssen wir die Slider-Blöcke durchlaufen und prüfen, wo sie momentan eingefügt sind. In Zeile 36 holen wir deshalb die übergeordneten Blöcke zu dem aktuellen Slider-Block – dafür übergeben wir die clientId des Blocks an wp.data.select( 'core/block-editor' ).getBlockParents().

Falls wir hier ein leeres Ergebnis zurückbekommen, befindet sich der Slider auf der obersten Ebene. Jetzt müssen wir noch prüfen, ob für den Block die Einstellung »volle Breite« gesetzt wurde – diese Einstellung wird in dem align-Attribut gespeichert. Wir ermitteln also in Zeile 42 den aktuellen align-Wert und prüfen, ob er full entspricht.

Ist das der Fall, setzen wir maxWidth auf 100vw. Wenn keine besondere Ausrichtung gewählt oder sie zumindest etwas anderes als full ist, setzen wir maxWidth auf 1170, das entspricht der normalen Content-Breite der Projekt-Website in Pixeln.

Wenn wir übergeordnete Blöcke haben, holen wir uns in Zeile 54 eventuelle Spalte-Blöcke, die dem Slider-Block übergeordnet sind. Falls es welche gibt, also columnParents.length größer als 0 ist, sichern wir den ersten Spalte-Block in columnParent und in columnWidth die Breite der Spalte in Prozent, die im width-Attribut gespeichert ist. In Zeile 59 setzen wir maxWidth dann auf den der Spaltenbreite im Verhältnis zu unserer Gesamtbreite entsprechenden Wert.

Wenn der Slider nicht innerhalb einer Spalte liegt, setzen wir maxWidth in Zeile 61 auf 1170.

Um die jetzt ermittelte Breite für die Bilder nutzen zu können, durchlaufen wir abschließend in Zeile 66 bis 68 die Slide-Blöcke des Sliders und setzen das maxWidth-Attribut. Und damit sollten die Slides in ihrem maxWidth-Attribut immer die richtige Breite stehen haben, abhängig von der Position ihres Sliders. Dieser Wert kann jetzt für das sizes-Attribut des img-Elements genutzt werden.

Optimal wäre, wenn wir diese ganze Aktion nicht bei jeder Änderung des Editor-Status ausführen würden, sondern nur, wenn sich etwas an einem Slider-Block ändert. Falls jemand einen Weg kennt, das so umzusetzen, gerne Hinweis an mich 🙂

Das könnte auch interessant sein

2 Kommentare zu »Block-Attribute abhängig von der Block-Position setzen«

  1. Johannes

    Wirklich schade, dass solche Filter/Hooks bisher in Gutenberg "vergessen" worden sind. Ich finde, das macht WordPress zu einem Großteil auf und ist deswegen so beliebt bei Entwicklern.

    Siehst du Performanceprobleme durch die Nutzung der Subscribe-Funktion? Ich renne da immer sehr schnell in Probleme. lodash.debounce kann da zumindest ein bisschen helfen. Meine Erfahrung mit subscribe() habe ich übrigens hier aufgeschrieben: https://go-around.de/blog/wordpress-block-editor-subscribe/

    1. Florian Brinkmann

      Bisher habe ich noch keine Probleme festgestellt, aber wenn es viele Blöcke sind und/oder viel an die subscribe()-Funktion gehängt wird, müsste es ja eigentlich irgendwann zu merken sein.

      Danke für den Link. Ich hatte auch überlegt ob man sich die Blockliste nicht jedes mal holen muss, aber leider ist eine aktuelle Liste in meinem Fall ja recht wichtig … Mit debounce zu arbeiten ist aber eine gute Idee, werde ich mir mal näher anschauen.

Schreib einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.