HeadstartWP – Einen benutzerdefinierten Gutenberg-Block erstellen
Wie immer schwimmen wir gegen den Strom und beginnen mit der Dokumentation https://developer.wordpress.org/block-editor/. Man kann über WordPress sagen, was man will, aber die Dokumentation ist zweifellos gut gemacht und eine wahre Fundgrube an Informationen.
Nachdem wir uns die Dokumentation angesehen haben, können wir nun zu diesem Artikel übergehen. Wir werden uns ansehen, wie man Gutenberg-Blöcke innerhalb eines Themes erstellt, und wir werden einen Block erstellen, der in diesem Blog zur Präsentation von Highlights auf der Projektseite verwendet werden soll.
Wie in einem früheren Artikel erläutert, habe ich für meine WordPress-Installation ein Parent-Theme ausgewählt und mein eigenes Child-Theme erstellt. Lassen Sie uns kurz einen Schritt zurückgehen: Alle Tutorials, die ich bisher zum Erstellen von Gutenberg-Blöcken gesehen habe, begannen mit der Erstellung eines Plugins, aber in meinem Fall ziehe ich es vor, direkt in der Vorlage fortzufahren, da diese Blöcke nur in diesem speziellen Theme verwendet werden und sehr einfach sein werden.
Ich habe meine IDE geöffnet und über das Terminal @wordpress/create-block ( https://www.npmjs.com/package/@wordpress/create-block ) aus, um einen Startblock zu erstellen, den ich in den src/blocks/ Ordner meines Child-Themes verschoben habe.
Ich habe die automatisch generierte .php-Datei gelöscht und die Blockregistrierung in die functions.php des Themes verschoben, da ich für diese Blöcke keinen PHP-Code hinzufügen muss.
1
2
3
4
5
6
7
8
function prefix_blocks_init() {
$blocks = glob(__DIR__ . '/build/blocks/*');
foreach ( $blocks as $block ) {
register_block_type( $block );
}
}
add_action( 'init', 'prefix_blocks_init' );Mit dieser einfachen Funktion werde ich alle Blöcke registrieren, die ich im Ordner „blocks“ hinzufügen werde. Ich weise noch einmal darauf hin, dass ihr die einzelnen index.php-Dateien beibehalten könnt, falls PHP-Code für die Blöcke hinzugefügt werden muss.
Außerdem habe ich die Dateien „package.json“ und „package-lock.json“ aus dem jeweiligen Blockordner gelöscht, um Skripte und Abhängigkeiten in die „package.json“ der Vorlage zu verschieben. Da es zwei Skripte gibt, die auf den Befehl „build“ reagieren, habe ich den Skripten der Blöcke einen Suffix hinzugefügt und sie [Befehl]-blocks genannt.
Um zu überprüfen, ob alles korrekt ist, führen Sie einen einfachen npm run build-blocks aus – Sie werden sehen, dass der kompilierte Code im Ordner „build“ erscheint und Ihr Basisblock im Backend der Website verfügbar ist.
Passen wir den Standardblock
an Der Block, den Sie mit @wordpress/create-block
, ist sehr einfach, und wir müssen einige Felder hinzufügen: Ausrichtung, Titel, Medien, Beschreibung, CTA und Link. Fügen wir also diesen Codeausschnitt zu unserer block.json.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
"attributes": {
"alignment": {
"type": "string",
"default": "none"
},
"title": {
"type": "string",
"selector": "h2"
},
"mediaID": {
"type": "number"
},
"mediaURL": {
"type": "string"
},
"description": {
"type": "string",
"selector": ".description"
},
"ctaLabel": {
"type": "string",
"selector": ".button"
},
"sectionLink": {
"type": "object"
}
},Um die Eingabefelder in die Datei „edit.js“ einzufügen, empfehle ich, die aus der Block-Bibliothek (https://github.com/WordPress/gutenberg/tree/trunk/packages/block-library/src) von Gutenberg als Vorlage zu verwenden, da du sicher sein kannst, dass dort stets die aktuellste API verwendet wird. Gutenberg ist kein neues Projekt, wird aber bis heute ständig aktualisiert und erweitert, weshalb es immer wichtig ist, einen Blick auf die neuesten Funktionen zu werfen.
Wir fahren direkt damit fort, die benötigten Attribute hinzuzufügen, indem wir den Code in edit.js:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
/**
* Retrieves the translation of text.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-i18n/
*/
import { __ } from '@wordpress/i18n';
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { __experimentalLinkControl as LinkControl, AlignmentToolbar, BlockControls, MediaUpload, RichText, useBlockProps, } from '@wordpress/block-editor';
import { Button, ToolbarButton, Popover } from '@wordpress/components';
import { useRef, useState } from '@wordpress/element';
import { link } from '@wordpress/icons';
/**
* Lets webpack process CSS, SASS or SCSS files referenced in JavaScript files.
* Those files can contain any CSS code that gets applied to the editor.
*
* @see https://www.npmjs.com/package/@wordpress/scripts#using-css
*/
import './editor.scss';
/**
* The edit function describes the structure of your block in the context of the
* editor. This represents what the editor will render when the block is used.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#edit
*
* @return {WPElement} Element to render.
*/
export default function Edit({ attributes, setAttributes, isSelected }) {
const { alignment, title, mediaID, mediaURL, description, ctaLabel, sectionLink } = attributes;
const isURLSet = !! sectionLink;
const blockProps = useBlockProps();
const [ isEditingURL, setIsEditingURL ] = useState( false );
const [ popoverAnchor, setPopoverAnchor ] = useState( null );
const richTextRef = useRef();
const onChangeAlignment = ( newAlignment ) => {
setAttributes( {
alignment: newAlignment === undefined ? 'none' : newAlignment,
} );
};
const onChangeTitle = ( newTitle ) => {
setAttributes( { title: newTitle } );
};
const onSelectImage = ( newMedia ) => {
setAttributes( {
mediaURL: newMedia.url,
mediaID: newMedia.id,
} );
};
const onChangeDescription = ( value ) => {
setAttributes( { description: value } );
};
const onChangeCTALabel = ( newCtaLabel ) => {
setAttributes( { ctaLabel: newCtaLabel } );
};
function startEditing( event ) {
event.preventDefault();
setIsEditingURL( true );
}
const onChangeSectionLink = ( newSectionLink ) => {
setAttributes( { sectionLink: newSectionLink } );
};
console.log( 'sectionLink: ', sectionLink );
return (
<div { ...blockProps }>
{ attributes.title && ! isSelected ? (
<>
<p>{ __( 'Project alignment', 'headstartwp' ) + ': ' + alignment }</p>
<p>{ __( 'Project title', 'headstartwp' ) + ': ' + title }</p>
<p>{ __( 'Project mediaID', 'headstartwp' ) + ': ' + mediaID }</p>
<p>{ __( 'Project mediaURL', 'headstartwp' ) + ': ' + mediaURL }</p>
<p>{ __( 'Project description', 'headstartwp' ) + ': ' + description }</p>
<p>{ __( 'Project CTA label', 'headstartwp' ) + ': ' + ctaLabel }</p>
<p>{ __( 'Project section link', 'headstartwp' ) + ': ' + sectionLink?.url || '' }</p>
</>
) : (
<>
<BlockControls>
<AlignmentToolbar
value={ alignment }
onChange={ onChangeAlignment }
/>
<ToolbarButton
name="link"
icon={ link }
title={ __( 'Link' ) }
onClick={ startEditing }
/>
</BlockControls>
{ isSelected && ( isEditingURL || isURLSet ) && (
<Popover
placement="bottom"
onClose={ () => {
setIsEditingURL( false );
richTextRef.current?.focus();
} }
anchor={ popoverAnchor }
focusOnMount={ isEditingURL ? 'firstElement' : false }
__unstableSlotName={ '__unstable-block-tools-after' }
shift
>
<LinkControl
className="wp-block-navigation-link__inline-link-input"
value={ sectionLink }
onChange={ onChangeSectionLink }
onRemove={ () => {
unlink();
richTextRef.current?.focus();
} }
forceIsEditingLink={ isEditingURL }
/>
</Popover>
) }
<div className="title">
<h3>{ __( 'Title', 'headstartwp' ) }</h3>
<RichText
placeholder={ __( 'Project title', 'headstartwp' ) }
value={ title }
onChange={ onChangeTitle }
/>
</div>
<div className="image">
<h3>{ __( 'Image', 'headstartwp' ) }</h3>
<MediaUpload
onSelect={ onSelectImage }
allowedTypes="image"
value={ mediaID }
render={ ( { open } ) => (
<Button
className={
mediaID ? 'image-button' : 'button button-large'
}
onClick={ open }
>
{ ! mediaID ? (
__( 'Upload Image', 'headstartwp' )
) : (
<img
src={ mediaURL }
alt={ __(
'Upload Project Image',
'headstartwp'
) }
/>
) }
</Button>
) }
/>
</div>
<div className="description">
<h3>{ __( 'Description', 'headstartwp' ) }</h3>
<RichText
placeholder={ __( 'Project description', 'headstartwp' ) }
value={ description }
onChange={ onChangeDescription }
className="description"
/>
</div>
<div className="ctaLabel">
<h3>{ __( 'CTA label', 'headstartwp' ) }</h3>
<RichText
placeholder={ __( 'Project CTA label', 'headstartwp' ) }
value={ ctaLabel }
onChange={ onChangeCTALabel }
className="ctaLabel"
/>
</div>
</>
) }
</div>
);
}Die Datei `save.js` hingegen wird äußerst einfach sein:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* React hook that is used to mark the block wrapper element.
* It provides all the necessary props like the class name.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/packages/packages-block-editor/#useblockprops
*/
import { useBlockProps } from '@wordpress/block-editor';
/**
* The save function defines the way in which the different attributes should
* be combined into the final markup, which is then serialized by the block
* editor into `post_content`.
*
* @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-edit-save/#save
*
* @return {WPElement} Element to render.
*/
export default function save( { attributes } ) {
const blockProps = useBlockProps.save( { attributes: attributes });
return (
<div { ...blockProps }></div>
);
}Eines der schönsten Dinge an Gutenberg ist, dass die Blöcke ästhetisch so formatiert sind, wie wir sie in der Produktion haben möchten. Das wird im Moment noch nicht der Fall sein, aber sobald wir den Code für das Frontend geschrieben haben, werden wir ihn auch ins Backend übernehmen, um diesen Mangel auszugleichen. Öffnen wir gleich eine Seite, wählen wir unseren neuen Block aus und füllen wir alle Eingabefelder aus.
Nach dem Speichern sieht das Ergebnis so aus:
Wenn wir die Seite im Frontend betrachten, finden wir unseren Block mit allen Daten, die wir im Backend eingegeben haben, bereit zur Verwendung im `data-wp-block`:
Wenn Sie wissen möchten, wie es weitergeht, und die Arbeit abschließen möchten, lesen Sie diesen anderen Artikel https://blog.riccardodicurti.it/headstartwp-add-a-form-with-contact-form-7, in dem wir eine Komponente für HeadstartWP erstellen, oder warten Sie auf die Veröffentlichung von Teil zwei, in dem wir gemeinsam fortfahren werden.