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;
} );
} );
}
} );
} );
Code-Sprache: JavaScript (javascript)
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 🙂
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/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.