Wenn du ein neues Kontrollelement zur Seitenleiste eines existierenden Blocks hinzufügen willst, gibt es dafür Filter. Oder wenn es dein eigener Block ist, kannst du dafür die InspectorControls verwenden. Aber wenn du globale Einstellungen hinzufügen willst, die eine Einstellung für den gesamten Beitrag festlegen, dann musst du das anders machen.

Da ich selbst keine vernünftig beschriebene und aktuelle Lösung in einem Blogbeitrag oder einer Dokumentation finden konnte, ist hier nun mein eigener.

Im Grunde braucht es das Registrieren eines Plugins und dann die Verwendung von PluginDocumentSettingPanel, um ein eigenes Panel zur Haupt-Seitenleiste unter den globalen Einstellungen hinzuzufügen. Zusätzlich, um den Wert bzw. die Werte des Panels zu speichern, müssen selbige als Beitrags-Metafeld in der Datenbank gespeichert werden. Mein Beispiel ist Teil eines Facebook-Plugins, das dich auswählen lässt, welche Conversion-Typen beim Besuch der Seite gefeuert werden. Außerdem ist das nur der React-Teil. Insbesondere beim Speichern der Metadaten muss darauf geachtet werden, dass das Metafeld korrekt registriert ist, damit es über die REST-API verfügbar ist.

Um das Plugin zu registrieren, verwenden wir registerPlugin aus @wordpress/plugins:

registerPlugin( 'my-facebook-conversions-api-meta-box', {
	icon: '',
	render: () => {
		return ( <PluginDocumentSettingPanel
			name="my-facebook-conversions-api-panel"
			title={ __( 'Facebook Conversions', 'my-facebook-conversions-api' ) }
			className="my-facebook-conversions-api-panel"
		>
			<div>My Panel Content</div>
		</PluginDocumentSettingPanel> );
	},
} );
Code-Sprache: JavaScript (javascript)

Dies fügt ein neues Panel mit einem div darin hinzu. Ich habe das icon angegeben, aber leer, da ansonsten ein Standard-Icon neben dem Panel-Titel angezeigt wird, das ich für deplatziert halte. Auch haben andere Standard-Panels kein solches Icon. Der name gibt eine eindeutige Identifizierung an und sollte daher einzigartig sein. Der title wird als Panel-Titel angezeigt und mit className können eigene Klassen zum Panel hinzugefügt werden.

In meinem Fall wollte ich das Panel nur für Seiten anzeigen, sodass ich hier noch eine Prüfung eingebaut habe:

import { useSelect } from '@wordpress/data';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';

registerPlugin( 'my-facebook-conversions-api-meta-box', {
	icon: '',
	render: () => {
		const postType = useSelect(
			( select ) => select( 'core/editor' ).getCurrentPostType(),
			[]
		);
		
		// ignore post types other than page
		if ( postType !== 'page' ) {
			return null;
		}
		
		return ( <PluginDocumentSettingPanel
			name="my-facebook-conversions-api-panel"
			title={ __( 'Facebook Conversions', 'my-facebook-conversions-api' ) }
			className="my-facebook-conversions-api-panel"
		>
			<div>My Panel Content</div>
		</PluginDocumentSettingPanel> );
	},
} );
Code-Sprache: JavaScript (javascript)

Der wichtigste Teil, die Anzeige des Panels, sollte nun erledigt sein. Aber wir müssen sicherstellen, dass die Daten korrekt gespeichert werden. In meinem Fall benutze ich eine Liste an Auswahlkästchen, wobei mehrere davon angeklickt sein können, ihre Daten aber gemeinsam in einem Beitrags-Metafeld gespeichert werden. Das sieht dann so aus:

import { CheckboxControl } from '@wordpress/components';
import { useEntityProp } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { __ } from '@wordpress/i18n';

const ConversionTypeControl = ( () => {
	const postType = useSelect(
		( select ) => select( 'core/editor' ).getCurrentPostType(),
		[]
	);
	const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
	const metaFieldValue = meta.my_facebook_conversions_api_conversion_type;
	const updateMetaValue = ( option, value ) => {
		// make sure the value gets updated correctly
		// @see https://stackoverflow.com/questions/56452438/update-a-specific-property-of-an-object-attribute-in-a-wordpress-gutenberg-block#comment99517264_56459084
		let newValue = JSON.parse( JSON.stringify( meta ) );
		
		if ( ! newValue.my_facebook_conversions_api_conversion_type ) {
			newValue = {
				my_facebook_conversions_api_conversion_type: [],
			};
		}
		
		if ( ! newValue.my_facebook_conversions_api_conversion_type.includes( option ) && value ) {
			newValue.my_facebook_conversions_api_conversion_type.push( option );
		}
		else if ( ! value ) {
			const index = newValue.my_facebook_conversions_api_conversion_type.indexOf( option );
			
			if ( index > -1 ) {
				newValue.my_facebook_conversions_api_conversion_type.splice( index, 1 );
			}
		}
		
		setMeta( { ...meta, ...newValue } );
	};
	
	const options = [
		{ label: __( 'Add Payment Info', 'my-facebook-conversions-api' ), value: 'AddPaymentInfo' },
		{ label: __( 'Add to Cart', 'my-facebook-conversions-api' ), value: 'AddToCart' },
		{ label: __( 'Add to Wishlist', 'my-facebook-conversions-api' ), value: 'AddToWishlist' },
		{ label: __( 'Complete Registration', 'my-facebook-conversions-api' ), value: 'CompleteRegistration' },
		{ label: __( 'Contact', 'my-facebook-conversions-api' ), value: 'Contact' },
		{ label: __( 'Customize Product', 'my-facebook-conversions-api' ), value: 'CustomizeProduct' },
		{ label: __( 'Donate', 'my-facebook-conversions-api' ), value: 'Donate' },
		{ label: __( 'Find Location', 'my-facebook-conversions-api' ), value: 'FindLocation' },
		{ label: __( 'Initiate Checkout', 'my-facebook-conversions-api' ), value: 'InitiateCheckout' },
		{ label: __( 'Lead', 'my-facebook-conversions-api' ), value: 'Lead' },
		{ label: __( 'Page View', 'my-facebook-conversions-api' ), value: 'PageView' },
		{ label: __( 'Schedule Appointment', 'my-facebook-conversions-api' ), value: 'Schedule' },
		{ label: __( 'Search', 'my-facebook-conversions-api' ), value: 'Search' },
		{ label: __( 'Submit Application', 'my-facebook-conversions-api' ), value: 'SubmitApplication' },
		{ label: __( 'View Content', 'my-facebook-conversions-api' ), value: 'ViewContent' },
	];
	
	return ( <div className="my-facebook-conversions-api__meta-box my-facebook-conversions-api__meta-box--conversion-type">
		<p>{ __( 'Conversion type:', 'my-facebook-conversions-api' ) }</p>
		{ Object.values( options ).map( ( option, index ) => {
			return ( <CheckboxControl
				key={ option + index }
				label={ option[ 'label' ] }	
				checked={ metaFieldValue?.includes( option['value'] ) }
				value={ option[ 'value' ] }
				onChange={ ( value ) => updateMetaValue( option[ 'value' ], value ) }
			/> )
		} ) }
	</div> );
} );
Code-Sprache: JavaScript (javascript)

Von oben nach unten: Um die Daten für den richtigen Inhaltstypen zu speichern, müssen wir diesen erst einmal abfragen (Zeile 7 – 10). Um ihn dann zu speichern, benutzen wir useEntityProp, das uns erlaubt, Metadaten schnell und einfach abzufragen oder abzuspeichern (Zeile 11). Ersteres machen wir auch in Zeile 12. Die Konstante updateMetaValue repräsentiert eine individuelle Funktion, die die Metadaten korrekt speichert, sodass mehrere Werte dort gleichzeitig gespeichert werden können (Hinweis: in PHP habe ich das Metafeld als Typ array registriert).

Die options in Zeile 38 – 54 werden in Zeile 58 – 66 durchiteriert und geben für jede Option ein entsprechendes Auswahlkästchen zurück.

Diese gesamte ConversionTypeControl wird dann in der Render-Funktion von registerPlugin in Zeile 90 verwendet. So sieht der Code am Ende vollständig aus:

import { CheckboxControl } from '@wordpress/components';
import { useEntityProp } from '@wordpress/core-data';
import { useSelect } from '@wordpress/data';
import { PluginDocumentSettingPanel } from '@wordpress/edit-post';
import { __ } from '@wordpress/i18n';
import { registerPlugin } from '@wordpress/plugins';

const ConversionTypeControl = ( () => {
	const postType = useSelect(
		( select ) => select( 'core/editor' ).getCurrentPostType(),
		[]
	);
	const [ meta, setMeta ] = useEntityProp( 'postType', postType, 'meta' );
	const metaFieldValue = meta.my_facebook_conversions_api_conversion_type;
	const updateMetaValue = ( option, value ) => {
		// make sure the value gets updated correctly
		// @see https://stackoverflow.com/questions/56452438/update-a-specific-property-of-an-object-attribute-in-a-wordpress-gutenberg-block#comment99517264_56459084
		let newValue = JSON.parse( JSON.stringify( meta ) );
		
		if ( ! newValue.my_facebook_conversions_api_conversion_type ) {
			newValue = {
				my_facebook_conversions_api_conversion_type: [],
			};
		}
		
		if ( ! newValue.my_facebook_conversions_api_conversion_type.includes( option ) && value ) {
			newValue.my_facebook_conversions_api_conversion_type.push( option );
		}
		else if ( ! value ) {
			const index = newValue.my_facebook_conversions_api_conversion_type.indexOf( option );
			
			if ( index > -1 ) {
				newValue.my_facebook_conversions_api_conversion_type.splice( index, 1 );
			}
		}
		
		setMeta( { ...meta, ...newValue } );
	};
	
	const options = [
		{ label: __( 'Add Payment Info', 'my-facebook-conversions-api' ), value: 'AddPaymentInfo' },
		{ label: __( 'Add to Cart', 'my-facebook-conversions-api' ), value: 'AddToCart' },
		{ label: __( 'Add to Wishlist', 'my-facebook-conversions-api' ), value: 'AddToWishlist' },
		{ label: __( 'Complete Registration', 'my-facebook-conversions-api' ), value: 'CompleteRegistration' },
		{ label: __( 'Contact', 'my-facebook-conversions-api' ), value: 'Contact' },
		{ label: __( 'Customize Product', 'my-facebook-conversions-api' ), value: 'CustomizeProduct' },
		{ label: __( 'Donate', 'my-facebook-conversions-api' ), value: 'Donate' },
		{ label: __( 'Find Location', 'my-facebook-conversions-api' ), value: 'FindLocation' },
		{ label: __( 'Initiate Checkout', 'my-facebook-conversions-api' ), value: 'InitiateCheckout' },
		{ label: __( 'Lead', 'my-facebook-conversions-api' ), value: 'Lead' },
		{ label: __( 'Page View', 'my-facebook-conversions-api' ), value: 'PageView' },
		{ label: __( 'Schedule Appointment', 'my-facebook-conversions-api' ), value: 'Schedule' },
		{ label: __( 'Search', 'my-facebook-conversions-api' ), value: 'Search' },
		{ label: __( 'Submit Application', 'my-facebook-conversions-api' ), value: 'SubmitApplication' },
		{ label: __( 'View Content', 'my-facebook-conversions-api' ), value: 'ViewContent' },
	];
	
	return ( <div className="my-facebook-conversions-api__meta-box my-facebook-conversions-api__meta-box--conversion-type">
		<p>{ __( 'Conversion type:', 'my-facebook-conversions-api' ) }</p>
		{ Object.values( options ).map( ( option, index ) => {
			return ( <CheckboxControl
				key={ option + index }
				label={ option[ 'label' ] }	
				checked={ metaFieldValue?.includes( option['value'] ) }
				value={ option[ 'value' ] }
				onChange={ ( value ) => updateMetaValue( option[ 'value' ], value ) }
			/> )
		} ) }
	</div> );
} );

registerPlugin( 'my-facebook-conversions-api-meta-box', {
	icon: '',
	render: () => {
		const postType = useSelect(
			( select ) => select( 'core/editor' ).getCurrentPostType(),
			[]
		);
		
		// ignore post types other than page
		if ( postType !== 'page' ) {
			return null;
		}
		
		return ( <PluginDocumentSettingPanel
			name="my-facebook-conversions-api-panel"
			title={ __( 'Facebook Conversions', 'my-facebook-conversions-api' ) }
			className="my-facebook-conversions-api-panel"
		>
			<ConversionTypeControl />
		</PluginDocumentSettingPanel> );
	},
} );
Code-Sprache: JavaScript (javascript)

Wenn man bereits individuelle Kontrollelemente zu Blöcken hinzugefügt oder selbst eigene Blöcke erstellt hat, ist das Hinzufügen eines Panels zu den globalen Dokument-Einstellungen kein großes Thema. Wenn du weißt, wie es geht. Ich musste eine Zeit lang suchen, um die korrekten Stellen zu finden, insbesondere was registerPlugin und PluginDocumentSettingPanel angeht. Also hilft das hier hoffentlich anderen, nicht so lang suchen zu müssen. 🙂

Schreibe einen Kommentar

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