Core-Blocks erweitern

Einem Core-Block eine zusätzliche Option mitzugeben kann manchmal ganz praktisch sein. Mit einem selbstgeschriebenen Plugin ist dies gar nicht so eine Sache. Voraussetzung dafür ist, das Docker installiert ist, wie wir das beispielsweise hier beschrieben haben.

Wir wollten dem Core-Block Überschrift eine Option mitgeben, um diese bei Bedarf zu animieren. Die Option sollte in der Admin-Sidebar wählbar sein, verschiedene Einstellungen ermöglichen und im Frontend dem Element die entsprechenden CSS-Klassen hinzufügen.

Agentur für Webdesign, WordPress, WooCommerce, Online Shops und SEO | Digitalagentur & Webagentur Schwyz | Hier entsteht Ihre Webseite mit ♥ | Schwyz | Zug | Luzern | Altdorf | ulrich.digital
Die Option Animation V1 mit drei Einstellungen

Um den eigentlichen Block zu erstellen, haben wir das Tool Create-Guten-Block von Ahmad Awais benutzt, es kann hier heruntergeladen werden. Wie dieses Tool eingesetzt wird, kann auf Github direkt, oder in unserer Beschreibung hier nachgelesen werden.

Zuerst werden die Komponenten definiert, welche die Option enthalten soll.

import classnames from 'classnames';

const { __ } = wp.i18n;
const { addFilter } = wp.hooks;
const { Fragment } = wp.element;
const { InspectorAdvancedControls } = wp.blockEditor;
const { createHigherOrderComponent } = wp.compose;
const { ToggleControl } = wp.components;
const { RadioControl } = wp.components;
const { useState } = wp.element;

Dann haben definiert, bei welchen Blöcken unsere Option vorhanden sein soll:

const allowedBlocks = [ 'core/paragraph', 'core/heading' ];

Die Funktion addAttributes wird zwei Attribute festlegen. Wir prüfen sicherheitshalber die Abwärtskompatibilität mit älteren Gutenberg-Versionen und ob es sich um die vorhin festgelegten Block-Types handelt.

Wenn dem so ist, werden die beiden Attribute isAnimated und radioAnimation definiert. isAnimated wird dann für den Toggle-Button gebraucht ist ist vom Typ Boolean, radioAnimation wird einen String als Wert besitzen können.

function addAttributes( settings ) {
	if( typeof settings.attributes !== 'undefined' && allowedBlocks.includes( settings.name ) ){
		settings.attributes = Object.assign( settings.attributes, {
			isAnimated:{ 
				type: 'boolean',
				default: false,
			},
			radioAnimation:{
				type: 'string',
				default: 'once',
			}
		});
	}
	return settings;
}

Nun werden die Kontroll-Buttons im Advanced Block Panel angehängt. Die eigentliche Ausgabe in der Sidebar wird im <Fragment>-Tag definiert und sollte mehr oder weniger selbsterklärend sein.

const withAdvancedControls = createHigherOrderComponent( ( BlockEdit ) => {
	return ( props ) => {

		const {
			name,
			attributes,
			setAttributes,
			isSelected,
		} = props;

		const {
			isAnimated,
			radioAnimation,
		} = attributes;
			
		return (
			<Fragment>
				<BlockEdit {...props} />
				{ isSelected && allowedBlocks.includes( name ) &&
					<InspectorAdvancedControls>
						<ToggleControl
							label={ __( 'Animation V1' ) }
							checked={ !! isAnimated }
							onChange={ () => setAttributes( {  isAnimated: ! isAnimated } ) }
							help={ !! isAnimated ? __( 'Ist animiert.' ) : __( 'Ist nicht animiert.' ) }
						/>
                        
                        { isAnimated && (
                            <RadioControl
                                label="Verhalten"
                                selected={ radioAnimation }
                                options={ [
                                    { label: 'Nur einmal', value: 'once' },
                                    { label: 'Bei jedem Scroll-In', value: 'scroll_in_out' },
                                    { label: 'Loop', value: 'loop' },
                                ] }
                                onChange={ ( option ) => { setAttributes( { radioAnimation: option } ) } }
                                help="Wann soll der Text animiert werden?"
                            />
                        )}
                        
					</InspectorAdvancedControls>
				}
			</Fragment>
		);
	};
}, 'withAdvancedControls');

Die Funktion applyExtraClass hängt – je nach gewählter Option – dem Block die entsprechenden CSS-Klassen an.

function applyExtraClass( extraProps, blockType, attributes ) {

	const { isAnimated } = attributes;
 	const { radioAnimation } = attributes;

	if ( typeof isAnimated !== 'undefined' && isAnimated && allowedBlocks.includes( blockType.name ) ) {
		extraProps.className = classnames( extraProps.className, 'animation_v1' );
        
        if ( typeof radioAnimation !== 'undefined' && radioAnimation && allowedBlocks.includes( blockType.name ) ) {
            extraProps.className = classnames( extraProps.className, radioAnimation );
	       }
    }    

	return extraProps;
}

Nun werden drei Filter angehängt. Bei der Block-Registration werden unsere Attribute hinzugefügt, über den Aufruf unserer Funktion addAttributes. Beim Block editieren werden unsere Kontroll-Buttons aufgerufen, und schliesslich beim Speichern unsere Funktion applyExtraClass, welche die entsprechenden Klassen dem Block anhängt.

addFilter(
	'blocks.registerBlockType',
	'block-custom-block-ulrich-digital/custom-attributes',
	addAttributes
);

addFilter(
	'editor.BlockEdit',
	'block-custom-block-ulrich-digital/custom-advanced-control',
	withAdvancedControls
);

addFilter(
	'blocks.getSaveContent.extraProps',
	'block-custom-block-ulrich-digital/applyExtraClass',
	applyExtraClass
);

Hier der gesamte Code zusammengefasst und auskommentiert:

/**
 * External Dependencies
 */
import classnames from 'classnames';

/**
 * WordPress Dependencies
 */
const { __ } = wp.i18n;
const { addFilter } = wp.hooks;
const { Fragment }	= wp.element;
const { InspectorAdvancedControls } = wp.blockEditor;
const { createHigherOrderComponent } = wp.compose;
const { ToggleControl } = wp.components;
const { RadioControl } = wp.components;
const { useState } = wp.element;

//restrict to specific block names
const allowedBlocks = [ 'core/paragraph', 'core/heading' ];


/**
 * Add custom attributes
 * @param {Object} settings Settings for the block.
 * @return {Object} settings Modified settings.
 */
 
function addAttributes( settings ) {
	
	//check if object exists for old Gutenberg version compatibility
	//add allowedBlocks restriction
	if( typeof settings.attributes !== 'undefined' && allowedBlocks.includes( settings.name ) ){
	
		settings.attributes = Object.assign( settings.attributes, {
			isAnimated:{ 
				type: 'boolean',
				default: false,
			},
            radioAnimation:{
                type: 'string',
                default: 'once',
            }
		});
	}
	return settings;
}



/**
 * Add animation controls on Advanced Block Panel.
 *
 * @param {function} BlockEdit Block edit component.
 *
 * @return {function} BlockEdit Modified block edit component.
 */
const withAdvancedControls = createHigherOrderComponent( ( BlockEdit ) => {
	return ( props ) => {

		const {
			name,
			attributes,
			setAttributes,
			isSelected,
		} = props;

		const {
			isAnimated,
            radioAnimation,
		} = attributes;
		
		
		return (
			<Fragment>
				<BlockEdit {...props} />
				{ isSelected && allowedBlocks.includes( name ) &&
					<InspectorAdvancedControls>
						<ToggleControl
							label={ __( 'Animation V1' ) }
							checked={ !! isAnimated }
							onChange={ () => setAttributes( {  isAnimated: ! isAnimated } ) }
							help={ !! isAnimated ? __( 'Ist animiert.' ) : __( 'Ist nicht animiert.' ) }
						/>
                        
                        { isAnimated && (
                            <RadioControl
                                label="Verhalten"
                                selected={ radioAnimation }
                                options={ [
                                    { label: 'Nur einmal', value: 'once' },
                                    { label: 'Bei jedem Scroll-In', value: 'scroll_in_out' },
                                    { label: 'Loop', value: 'loop' },
                                ] }
                                onChange={ ( option ) => { setAttributes( { radioAnimation: option } ) } }
                                help="Wann soll der Text animiert werden?"
                            />
                        )}
                        
					</InspectorAdvancedControls>
				}
			</Fragment>
		);
	};
}, 'withAdvancedControls');

/**
 * Add custom element class in save element.
 *
 * @param {Object} extraProps     Block element.
 * @param {Object} blockType      Blocks object.
 * @param {Object} attributes     Blocks attributes.
 *
 * @return {Object} extraProps Modified block element.
 */
function applyExtraClass( extraProps, blockType, attributes ) {

	const { isAnimated } = attributes;
    const { radioAnimation } = attributes;

	if ( typeof isAnimated !== 'undefined' && isAnimated && allowedBlocks.includes( blockType.name ) ) {
        // add Class animation_v1, if selected
		extraProps.className = classnames( extraProps.className, 'animation_v1' );
        
        // add String, if isAnimated is true
        if ( typeof radioAnimation !== 'undefined' && radioAnimation && allowedBlocks.includes( blockType.name ) ) {
            extraProps.className = classnames( extraProps.className, radioAnimation );
	       }
    }    

	return extraProps;
}

//add filters

addFilter(
	'blocks.registerBlockType',
	'block-custom-block-ulrich-digital/custom-attributes',
	addAttributes
);

addFilter(
	'editor.BlockEdit',
	'block-custom-block-ulrich-digital/custom-advanced-control',
	withAdvancedControls
);

addFilter(
	'blocks.getSaveContent.extraProps',
	'block-custom-block-ulrich-digital/applyExtraClass',
	applyExtraClass
);
1 Star2 Stars3 Stars4 Stars5 Stars (0)

Schreibe einen Kommentar

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