Nachdem wir gesehen haben, dass sowohl Web Components als auch interaktive Web Components einfacher sind als gedacht, schauen wir uns nun an, wie man sie in ein Content-Management-System, namentlich WordPress, integriert.
Es gibt drei Hauptmöglichkeiten, sie hinzuzufügen. Erstens durch manuelle Eingabe auf der Website – sie direkt in Widgets oder Textblöcke einfügen, im Grunde überall dort, wo wir anderen HTML-Code platzieren können. Zweitens können wir sie als Ausgabe eines Themes in einer Theme-Datei hinzufügen. Und schließlich können wir sie als Ausgabe eines benutzerdefinierten Blocks hinzufügen.
Artikelreihe
- Web Components sind einfacher als man denkt
- Interaktive Web Components sind einfacher als man denkt
- Web Components in WordPress verwenden ist einfacher als Sie denken (Sie sind hier)
- Standard-Elemente mit Web Components aufpeppen „ist“ einfacher als man denkt
- Kontextsensitive Web Components sind einfacher als man denkt
- Web Component Pseudo-Klassen und Pseudo-Elemente sind einfacher als man denkt
Laden der Web-Component-Dateien
Unabhängig davon, wie wir Web Components letztendlich hinzufügen, müssen wir sicherstellen, dass
- die Vorlage unseres benutzerdefinierten Elements verfügbar ist, wenn wir sie benötigen,
- jeglicher benötigte JavaScript ordnungsgemäß eingebunden ist, und
- jeglicher nicht verkapselte Stil ordnungsgemäß eingebunden ist.
Wir werden die Web Component <zombie-profile> aus meinem vorherigen Artikel über interaktive Web Components hinzufügen. Schauen Sie sich den Code bei CodePen an.
Kommen wir zum ersten Punkt. Sobald wir die Vorlage haben, ist es einfach genug, sie in die Datei footer.php des WordPress-Themes einzufügen. Aber anstatt sie direkt ins Theme einzufügen, wäre es besser, sich in wp_footer einzuhaken, damit die Komponente unabhängig von der footer.php-Datei und unabhängig vom gesamten Theme geladen wird – vorausgesetzt, das Theme verwendet wp_footer, was die meisten tun. Wenn die Vorlage in Ihrem Theme nicht erscheint, wenn Sie es versuchen, überprüfen Sie doppelt, ob wp_footer in der footer.php-Datei Ihres Themes aufgerufen wird.
<?php function diy_ezwebcomp_footer() { ?>
<!-- print/echo Zombie profile template code. -->
<!-- It's available at https://codepen.io/undeadinstitute/pen/KKNLGRg -->
<?php }
add_action( 'wp_footer', 'diy_ezwebcomp_footer');
Als Nächstes binden wir das JavaScript unserer Komponente ein. Wir können das JavaScript auch über wp_footer hinzufügen, aber das Einbinden (Enqueueing) ist der empfohlene Weg, JavaScript mit WordPress zu verknüpfen. Legen wir also unser JavaScript in eine Datei namens ezwebcomp.js (dieser Name ist völlig beliebig), legen Sie diese Datei in das JavaScript-Verzeichnis des Themes (falls vorhanden) und binden Sie sie ein (in der Datei functions.php).
wp_enqueue_script( 'ezwebcomp_js', get_template_directory_uri() . '/js/ezwebcomp.js', '', '1.0', true );
Wir möchten sicherstellen, dass der letzte Parameter auf true gesetzt ist, d. h. dass das JavaScript vor dem schließenden Body-Tag geladen wird. Wenn wir es stattdessen im Head laden, findet es unsere HTML-Vorlage nicht und wird super mürrisch (wirft viele Fehler).
Wenn Sie Ihre Web Component vollständig verkapseln können, können Sie diesen nächsten Schritt überspringen. Aber wenn Sie (wie ich) dazu nicht in der Lage sind, müssen Sie diese nicht verkapselten Stile einbinden, damit sie dort verfügbar sind, wo die Web Component verwendet wird. (Ähnlich wie bei JavaScript könnten wir dies direkt zum Footer hinzufügen, aber das Einbinden der Stile ist der empfohlene Weg.) Also binden wir unsere CSS-Datei ein.
wp_enqueue_style( 'ezwebcomp_style', get_template_directory_uri() . '/ezwebcomp.css', '', '1.0', 'screen' );
Das war nicht *zu* schwer, oder? Und wenn Sie keine anderen Benutzer als Administratoren damit haben wollen, sind Sie bereit, diese überall dort hinzuzufügen, wo Sie sie haben möchten. Aber das ist nicht immer der Fall, also machen wir weiter!
Filtern Sie Ihre Web Component nicht heraus
WordPress bietet verschiedene Möglichkeiten, um Benutzern zu helfen, gültiges HTML zu erstellen, und um zu verhindern, dass Ihr Onkel Eddie das "urkomische" Bild, das er von Shady Al bekommen hat, direkt in den Editor einfügt (komplett mit Skripten, um jeden Ihrer Besucher zu überrumpeln).
Wenn wir also Web Components direkt in Blöcke oder Widgets einfügen, müssen wir vorsichtig sein mit den integrierten Code-Filtern von WordPress. Wenn wir sie ganz deaktivieren, würden wir Onkel Eddie (und damit Shady Al) freien Lauf lassen, aber wir können sie modifizieren, um unsere fantastische Web Component durch das Tor zu lassen, das Onkel Eddie (zum Glück) draußen hält.
Zuerst können wir den Filter wp_kses_allowed verwenden, um unsere Web Component zur Liste der Elemente hinzuzufügen, die *nicht* herausgefiltert werden sollen. Es ist so, als würden wir die Komponente auf eine Whitelist setzen, und das tun wir, indem wir sie dem Array der erlaubten Tags hinzufügen, das an die Filterfunktion übergeben wird.
function add_diy_ezwebcomp_to_kses_allowed( $the_allowed_tags ) {
$the_allowed_tags['zombie-profile'] = array();
}
add_filter( 'wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');
Wir fügen dem <zombie-profile>-Element ein leeres Array hinzu, da WordPress neben Elementen auch Attribute herausfiltert – und das bringt uns zu einem weiteren Problem: das Attribut slot ist standardmäßig nicht erlaubt. Daher müssen wir es explizit für jedes Element zulassen, bei dem Sie es voraussichtlich verwenden werden, und damit auch für jedes Element, zu dem Ihr Benutzer es möglicherweise hinzufügen möchte. (Warte, diese Elementlisten sind *nicht* dieselben, obwohl Sie sie sechsmal mit jedem Benutzer durchgesprochen haben ... wer hätte das gedacht?) Daher habe ich unten slot auf true für <span>, <img> und <ul> gesetzt, die drei Elemente, die ich in den <zombie-profile>-Komponente einfüge.
function add_diy_ezwebcomp_to_kses_allowed( $the_allowed_tags ) {
$the_allowed_tags['zombie-profile'] = array();
$the_allowed_tags['span']['slot'] = true;
$the_allowed_tags['ul']['slot'] = true;
$the_allowed_tags['img']['slot'] = true;
return $the_allowed_tags;
}
add_filter( 'wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');
Wir könnten das slot-Attribut auch für alle erlaubten Elemente aktivieren, indem wir Folgendes verwenden:
function add_diy_ezwebcomp_to_kses_allowed($the_allowed_tags) {
$the_allowed_tags['zombie-profile'] = array();
foreach ($the_allowed_tags as &$tag) {
$tag['slot'] = true;
}
return $the_allowed_tags;
}
add_filter('wp_kses_allowed_html', 'add_diy_ezwebcomp_to_kses_allowed');
Leider gibt es hier noch ein weiteres mögliches Problem. Möglicherweise stoßen Sie nicht darauf, wenn alle Elemente, die Sie in Ihre Slots einfügen, Inline-/Phrasenelemente sind, aber wenn Sie ein Block-Level-Element in Ihre Web Component einfügen, werden Sie wahrscheinlich einen Faustkampf mit dem Block-Parser im Code-Editor führen. Möglicherweise sind Sie ein besserer Faustkämpfer als ich, aber ich habe immer verloren.

Aus Gründen, die ich nicht vollständig erklären kann, geht der Client-seitige Parser davon aus, dass die Web Component nur Inline-Elemente enthalten soll. Wenn Sie dort ein <ul> oder <div>, <h1> oder ein anderes Block-Level-Element einfügen, wird das schließende Web-Component-Tag nach dem letzten Inline-/Phrasenelement verschoben. Schlimmer noch, laut einer Notiz im WordPress Developer Handbook ist es derzeit "nicht möglich, den Client-seitigen Parser zu ersetzen".
Das ist zwar frustrierend und etwas, worauf Sie Ihre Web-Redakteure schulen müssen, aber es gibt eine Lösung. Wenn wir die Web Component in einem benutzerdefinierten HTML-Block direkt im Block-Editor platzieren, lässt uns der Client-seitige Parser nicht weinend am Straßenrand zurück, schaukelnd und unsere Programmierfähigkeiten in Frage stellend ... Nicht, dass das jemals jemandem passiert wäre ... insbesondere nicht Leuten, die Artikel schreiben ...

Komponente im Theme
Das Ausgeben unserer schicken Web Component in unserer Theme-Datei ist unkompliziert, solange sie nicht außerhalb des HTML-Blocks aktualisiert wird. Wir fügen sie so hinzu, wie wir sie in jedem anderen Kontext hinzufügen würden, und wenn wir die Vorlage, Skripte und Stile bereit haben, werden die Dinge einfach funktionieren.
Aber nehmen wir an, wir möchten den Inhalt eines WordPress-Posts oder eines benutzerdefinierten Post-Typs in einer Web Component ausgeben. Sie wissen schon, einen Beitrag schreiben und dieser Beitrag ist der Inhalt für die Komponente. Das ermöglicht uns, den WordPress-Editor zu verwenden, um ein Archiv von <zombie-profile>-Elementen zu erstellen. Das ist großartig, weil der WordPress-Editor bereits die meisten Benutzeroberflächen hat, die wir benötigen, um den Inhalt für eine der <zombie-profile>-Komponenten einzugeben.
- Der Post-Titel kann der Name des Zombies sein.
- Ein normaler Absatzblock im Post-Inhalt kann für die Aussage des Zombies verwendet werden.
- Das Beitragsbild kann für das Profilbild des Zombies verwendet werden.
Das ist fast alles! Aber wir brauchen immer noch Felder für das Alter des Zombies, das Infektionsdatum und die Interessen. Wir erstellen diese mit der integrierten Funktion Benutzerdefinierte Felder von WordPress.

Wir verwenden den Vorlagenteil, der für die Ausgabe jedes Posts zuständig ist, z. B. content.php, um die Web Component auszugeben. Zuerst geben wir das öffnende <zombie-profile>-Tag aus, gefolgt von der Beitragsminiatur (falls vorhanden).
<zombie-profile>
<?php
// If the post featured image exists...
if (has_post_thumbnail()) {
$src = wp_get_attachment_image_url(get_post_thumbnail_id()); ?>
<img src="<?php echo $src; ?>" slot="profile-image">
<?php
}
?>
Als Nächstes geben wir den Titel für den Namen aus.
<?php
// If the post title field exits...
if (get_the_title()) { ?>
<span slot="zombie-name"><?php echo get_the_title(); ?></span>
<?php
}
?>
In meinem Code habe ich getestet, ob diese Felder vorhanden sind, bevor ich sie ausgebe, aus zwei Gründen:
- Es ist in den meisten Fällen einfach gute Programmierpraxis, die Labels und Elemente um leere Felder herum zu verstecken.
- Wenn wir am Ende einen leeren
<span>für den Namen ausgeben (z. B.<span slot="zombie-name"></span>), dann wird das Feld im endgültigen Profil als leer angezeigt, anstatt den integrierten Standardtext, das Bild usw. unserer Web Component zu verwenden (wenn Sie z. B. möchten, dass Textfelder leer sind, wenn sie keinen Inhalt haben, können Sie entweder ein Leerzeichen in das benutzerdefinierte Feld einfügen oder dieif-Anweisung im Code überspringen).
Als Nächstes holen wir uns die benutzerdefinierten Felder und platzieren sie in den Slots, zu denen sie gehören. Auch das gehört in die Theme-Vorlage, die den Post-Inhalt ausgibt.
<?php
// Zombie age
$temp = get_post_meta(the_ID(), 'Age', true);
if ($temp) { ?>
<span slot="z-age"><?php echo $temp; ?></span>
<?php
}
// Zombie infection date
$temp = get_post_meta(the_ID(), 'Infection Date', true);
if ($temp) { ?>
<span slot="idate"><?php echo $temp; ?></span>
<?php
}
// Zombie interests
$temp = get_post_meta(the_ID(), 'Interests', true);
if ($temp) { ?>
<ul slot="z-interests"><?php echo $temp; ?></ul>
<?php
}
?>
Einer der Nachteile der Verwendung von WordPress-Benutzerdefinierten Feldern ist, dass Sie keine spezielle Formatierung vornehmen können. Ein nicht-technischer Web-Redakteur, der dies ausfüllt, müsste HTML für die Listenelemente (<li>) für jedes einzelne Interesse in der Liste schreiben. (Sie können diese Schnittstellenbeschränkung wahrscheinlich umgehen, indem Sie ein robusteres benutzerdefinierte Feld-Plugin verwenden, wie z. B. Advanced Custom Fields, Pods oder ähnliches.)
Zuletzt fügen wir die Aussage des Zombies und das schließende <zombie-profile>-Tag hinzu.
<?php
$temp = get_the_content();
if ($temp) { ?>
<span slot="statement"><?php echo $temp; ?></span>
<?php
}
?>
</zombie-profile>
Da wir den Body des Posts für unsere Aussage verwenden, erhalten wir im Paket noch etwas zusätzlichen Code, wie z. B. Absatz-Tags um den Inhalt herum. Das Platzieren der Profilaussage in einem benutzerdefinierten Feld wird dies mildern, aber je nach Ihren Zwecken kann dies auch beabsichtigtes/gewünschtes Verhalten sein.
Sie können dann so viele Posts/Zombie-Profile hinzufügen, wie Sie benötigen, indem Sie sie einfach als Post veröffentlichen!
Block Party: Web Components in einem benutzerdefinierten Block
Das Erstellen eines benutzerdefinierten Blocks ist eine großartige Möglichkeit, eine Web Component hinzuzufügen. Ihre Benutzer können die erforderlichen Felder ausfüllen und die Web-Component-Magie nutzen, ohne Code oder technisches Wissen zu benötigen. Außerdem sind Blöcke vollständig unabhängig von Themes, sodass wir diesen Block wirklich auf einer Website verwenden und dann auf anderen WordPress-Websites installieren könnten – ähnlich wie wir erwarten, dass eine Web Component funktioniert!
Es gibt zwei Hauptteile eines benutzerdefinierten Blocks: PHP und JavaScript. Wir fügen auch ein wenig CSS hinzu, um die Bearbeitungserfahrung zu verbessern.
Zuerst das PHP.
function ez_webcomp_register_block() {
// Enqueues the JavaScript needed to build the custom block
wp_register_script(
'ez-webcomp',
plugins_url('block.js', __FILE__),
array('wp-blocks', 'wp-element', 'wp-editor'),
filemtime(plugin_dir_path(__FILE__) . 'block.js')
);
// Enqueues the component's CSS file
wp_register_style(
'ez-webcomp',
plugins_url('ezwebcomp-style.css', __FILE__),
array(),
filemtime(plugin_dir_path(__FILE__) . 'ezwebcomp-style.css')
);
// Registers the custom block within the ez-webcomp namespace
register_block_type('ez-webcomp/zombie-profile', array(
// We already have the external styles; these are only for when we are in the WordPress editor
'editor_style' => 'ez-webcomp',
'editor_script' => 'ez-webcomp',
));
}
add_action('init', 'ez_webcomp_register_block');
Das CSS ist nicht notwendig, es hilft jedoch, zu verhindern, dass das Profilbild des Zombies den Inhalt im WordPress-Editor überlappt.
/* Sets the width and height of the image.
* Your mileage will likely vary, so adjust as needed.
* "pic" is a class we'll add to the editor in block.js
*/
#editor .pic img {
width: 300px;
height: 300px;
}
/* This CSS ensures that the correct space is allocated for the image,
* while also preventing the button from resizing before an image is selected.
*/
#editor .pic button.components-button {
overflow: visible;
height: auto;
}
Das benötigte JavaScript ist etwas aufwendiger. Ich habe mich bemüht, es so weit wie möglich zu vereinfachen und es für alle so zugänglich wie möglich zu machen, daher habe ich es in ES5 geschrieben, um die Notwendigkeit der Kompilierung zu eliminieren.
Code anzeigen
(function (blocks, editor, element, components) {
// The function that creates elements
var el = element.createElement;
// Handles text input for block fields
var RichText = editor.RichText;
// Handles uploading images/media
var MediaUpload = editor.MediaUpload;
// Harkens back to register_block_type in the PHP
blocks.registerBlockType('ez-webcomp/zombie-profile', {
title: 'Zombie Profile', //User friendly name shown in the block selector
icon: 'id-alt', //the icon to usein the block selector
category: 'layout',
// The attributes are all the different fields we'll use.
// We're defining what they are and how the block editor grabs data from them.
attributes: {
name: {
// The content type
type: 'string',
// Where the info is available to grab
source: 'text',
// Selectors are how the block editor selects and grabs the content.
// These should be unique within an instance of a block.
// If you only have one img or one <ul> etc, you can use element selectors.
selector: '.zname',
},
mediaID: {
type: 'number',
},
mediaURL: {
type: 'string',
source: 'attribute',
selector: 'img',
attribute: 'src',
},
age: {
type: 'string',
source: 'text',
selector: '.age',
},
infectdate: {
type: 'date',
source: 'text',
selector: '.infection-date'
},
interests: {
type: 'array',
source: 'children',
selector: 'ul',
},
statement: {
type: 'array',
source: 'children',
selector: '.statement',
},
},
// The edit function handles how things are displayed in the block editor.
edit: function (props) {
var attributes = props.attributes;
var onSelectImage = function (media) {
return props.setAttributes({
mediaURL: media.url,
mediaID: media.id,
});
};
// The return statement is what will be shown in the editor.
// el() creates an element and sets the different attributes of it.
return el(
// Using a div here instead of the zombie-profile web component for simplicity.
'div', {
className: props.className
},
// The zombie's name
el(RichText, {
tagName: 'h2',
inline: true,
className: 'zname',
placeholder: 'Zombie Name…',
value: attributes.name,
onChange: function (value) {
props.setAttributes({
name: value
});
},
}),
el(
// Zombie profile picture
'div', {
className: 'pic'
},
el(MediaUpload, {
onSelect: onSelectImage,
allowedTypes: 'image',
value: attributes.mediaID,
render: function (obj) {
return el(
components.Button, {
className: attributes.mediaID ?
'image-button' : 'button button-large',
onClick: obj.open,
},
!attributes.mediaID ?
'Upload Image' :
el('img', {
src: attributes.mediaURL
})
);
},
})
),
// We'll include a heading for the zombie's age in the block editor
el('h3', {}, 'Age'),
// The age field
el(RichText, {
tagName: 'div',
className: 'age',
placeholder: 'Zombie\'s Age…',
value: attributes.age,
onChange: function (value) {
props.setAttributes({
age: value
});
},
}),
// Infection date heading
el('h3', {}, 'Infection Date'),
// Infection date field
el(RichText, {
tagName: 'div',
className: 'infection-date',
placeholder: 'Zombie\'s Infection Date…',
value: attributes.infectdate,
onChange: function (value) {
props.setAttributes({
infectdate: value
});
},
}),
// Interests heading
el('h3', {}, 'Interests'),
// Interests field
el(RichText, {
tagName: 'ul',
// Creates a new <li> every time `Enter` is pressed
multiline: 'li',
placeholder: 'Write a list of interests…',
value: attributes.interests,
onChange: function (value) {
props.setAttributes({
interests: value
});
},
className: 'interests',
}),
// Zombie statement heading
el('h3', {}, 'Statement'),
// Zombie statement field
el(RichText, {
tagName: 'div',
className: "statement",
placeholder: 'Write statement…',
value: attributes.statement,
onChange: function (value) {
props.setAttributes({
statement: value
});
},
})
);
},
// Stores content in the database and what is shown on the front end.
// This is where we have to make sure the web component is used.
save: function (props) {
var attributes = props.attributes;
return el(
// The <zombie-profile web component
'zombie-profile',
// This is empty because the web component does not need any HTML attributes
{},
// Ensure a URL exists before it prints
attributes.mediaURL &&
// Print the image
el('img', {
src: attributes.mediaURL,
slot: 'profile-image'
}),
attributes.name &&
// Print the name
el(RichText.Content, {
tagName: 'span',
slot: 'zombie-name',
className: 'zname',
value: attributes.name,
}),
attributes.age &&
// Print the zombie's age
el(RichText.Content, {
tagName: 'span',
slot: 'z-age',
className: 'age',
value: attributes.age,
}),
attributes.infectdate &&
// Print the infection date
el(RichText.Content, {
tagName: 'span',
slot: 'idate',
className: 'infection-date',
value: attributes.infectdate,
}),
// Need to verify something is in the first element since the interests's type is array
attributes.interests[0] &&
// Pint the interests
el(RichText.Content, {
tagName: 'ul',
slot: 'z-interests',
value: attributes.interests,
}),
attributes.statement[0] &&
// Print the statement
el(RichText.Content, {
tagName: 'span',
slot: 'statement',
className: 'statement',
value: attributes.statement,
})
);
},
});
})(
//import the dependencies
window.wp.blocks,
window.wp.blockEditor,
window.wp.element,
window.wp.components
);
Anschluss an Web Components
Nun, wäre es nicht großartig, wenn eine wohlmeinende, Artikel schreibende und absolut großartige Person eine Vorlage erstellen würde, in die Sie einfach Ihre Web Component einfügen und auf Ihrer Website verwenden könnten? Nun, dieser Kerl war nicht verfügbar (er half der Wohltätigkeit oder so etwas), also habe ich es getan. Es ist auf Github.
Do It Yourself – Einfache Web Components für WordPress
Das Plugin ist eine Code-Vorlage, die Ihre benutzerdefinierte Web Component registriert, die von der Komponente benötigten Skripte und Stile einbindet, Beispiele für die benutzerdefinierten Blockfelder liefert, die Sie möglicherweise benötigen, und sogar dafür sorgt, dass die Dinge im Editor gut gestylt sind. Stecken Sie dies in einen neuen Ordner in /wp-content/plugins, wie Sie es bei jeder anderen WordPress-Plugin manuell installieren würden, aktualisieren Sie es mit Ihrer spezifischen Web Component und aktivieren Sie es dann in WordPress auf dem Bildschirm "Installierte Plugins".
Nicht so schlimm, oder?
Auch wenn es wie viel Code aussieht, machen wir wirklich ein paar ziemlich Standard-WordPress-Dinge, um eine benutzerdefinierte Web Component zu registrieren und zu rendern. Und da wir es als Plugin verpackt haben, können wir dies in jede WordPress-Website einfügen und nach Herzenslust Zombie-Profile veröffentlichen.
Ich würde sagen, die Gratwanderung besteht darin, die Komponente im WordPress-Blockeditor genauso gut funktionieren zu lassen wie auf der Frontend. Ohne diese Überlegung hätten wir das mit viel weniger Code erledigt.
Dennoch haben wir es geschafft, dieselbe Komponente wie in meinen früheren Artikeln in ein CMS zu integrieren, was uns erlaubt, beliebig viele Zombie-Profile auf der Website zu platzieren. Wir haben unser Wissen über Web Components mit WordPress-Blöcken kombiniert, um einen wiederverwendbaren Block für unsere wiederverwendbare Web Component zu entwickeln.
Welche Art von Komponenten werden Sie für Ihre WordPress-Website erstellen? Ich stelle mir vor, dass es hier viele Möglichkeiten gibt und ich bin daran interessiert zu sehen, was Sie letztendlich erstellen.
Hallo, ich habe nach einer solchen Lösung gesucht, wie Sie sie hier zur Verfügung gestellt haben. Danke dafür. Ich
habe die Anweisungen im Github Readme durchgelesen und es ist alles ziemlich einfach. Ich möchte nur sicher sein, dass ich mit der Leistung dieses Plugins tatsächlich Materialinhalte von hier "https://m2.material.io/components/tabs/web#design-amp-api-documentation" verwenden kann? Ich freue mich auf eine Antwort. Vielen Dank.
Ich habe es nicht ausprobiert, aber ich sehe keinen Grund, warum es nicht gut funktionieren sollte. Lassen Sie mich wissen, wie es läuft.