Neugierig auf den Titel und möchtest einfach etwas Code sehen? Überspringen.
Dieses Tutorial wurde für Vue 2 geschrieben und verwendet „Inline-Vorlagen“. Vue 3 hat diese Funktion zwar als veraltet markiert, aber es gibt Alternativen (wie das Platzieren von Vorlagen in Skript-Tags), mit denen Sie die Idee übertragen können.
Vor ein paar Monaten habe ich eine WordPress-Website erstellt, die ein Formular mit vielen schicken bedingten Feldern erforderte. Unterschiedliche Optionen und Informationen waren für unterschiedliche Auswahlen erforderlich, die Sie im Formular treffen konnten, und unser Kunde benötigte die vollständige Kontrolle über alle Felder 1. Zusätzlich musste das Formular an mehreren Stellen auf jeder Seite erscheinen, mit leicht unterschiedlichen Konfigurationen.
Und die Header-Instanz des Formulars musste wechselseitig exklusiv mit dem Hamburger-Menü sein, sodass das Öffnen des einen das andere schloss.
Und das Formular hatte Textinhalte, die für SEO relevant waren.
Und wir wollten, dass die Serverantwort einige nette animierte Rückmeldungen liefert.
(Puh.)
Das Ganze fühlte sich komplex genug an, dass ich nicht wollte, dass ich den gesamten Zustand manuell verwalte. Ich erinnerte mich, Sarah Drasners Artikel „Replacing jQuery With Vue.js: No Build Step Necessary“ gelesen zu haben, der zeigt, wie man klassische jQuery-Muster durch einfache Vue-Mikro-Apps ersetzt. Das schien ein guter Ausgangspunkt zu sein, aber ich stellte schnell fest, dass die Dinge auf der PHP-Seite von WordPress unübersichtlich werden würden.
Was ich wirklich brauchte, waren wiederverwendbare Komponenten.
PHP → JavaScript
Ich liebe den statischen Ansatz von Jamstack-Tools, wie Nuxt, und wollte hier etwas Ähnliches tun – den gesamten Inhalt vom Server senden und auf der Client-Seite progressiv verbessern.
Aber PHP hat keine eingebaute Möglichkeit, mit Komponenten zu arbeiten. Es unterstützt jedoch das require-en von Dateien in anderen Dateien 2. WordPress hat eine Abstraktion von require namens get_template_part, die relativ zum Theme-Ordner ausgeführt wird und einfacher zu handhaben ist. Das Aufteilen von Code in Vorlagenteile ist das nächstliegende, was WordPress an Komponenten bietet 3.
Vue hingegen ist voller Komponenten – aber es kann seine Sache erst tun, wenn die Seite geladen wurde und JavaScript läuft.
Das Geheimnis dieser Verbindung der Paradigmen ist die weniger bekannte Vue-Direktive inline-template. Ihre großartigen und wunderbaren Kräfte erlauben es uns, eine Vue-Komponente anhand des Markups zu definieren, das wir bereits haben. Es ist der perfekte Mittelweg zwischen dem Erhalt statischer HTML-Daten vom Server und dem Einbinden dynamischer DOM-Elemente auf dem Client.
Zuerst erhält der Browser das HTML, dann bringt Vue es dazu, Dinge zu tun. Da das Markup von WordPress und nicht von Vue im Browser erstellt wird, können Komponenten problemlos alle Informationen verwenden, die Website-Administratoren bearbeiten können. Und im Gegensatz zu .vue-Dateien (die sich großartig zum Erstellen von App-ähnlicheren Dingen eignen), können wir die gleiche Trennung der Belange beibehalten, die wir für die gesamte Website verwenden – Struktur und Inhalt in PHP, Stil in CSS und Funktionalität in JavaScript.
Um zu zeigen, wie all das zusammenpasst, werden wir ein paar Funktionen für einen Rezeptblog erstellen. Zuerst fügen wir eine Möglichkeit hinzu, wie Benutzer Rezepte bewerten können. Dann erstellen wir ein Feedback-Formular, das auf dieser Bewertung basiert. Schließlich ermöglichen wir Benutzern, Rezepte nach Tags und Bewertung zu filtern.
Wir werden ein paar Komponenten erstellen, die sich den Zustand teilen und auf derselben Seite leben. Damit sie gut miteinander harmonieren – und um es einfach zu machen, zusätzliche Komponenten in Zukunft hinzuzufügen – machen wir die gesamte Seite zu unserer Vue-App und registrieren Komponenten darin.
Jede Komponente wird in ihrer eigenen PHP-Datei leben und mit get_template_part in das Theme eingebunden.
Grundlagen schaffen
Es gibt ein paar besondere Überlegungen, die man berücksichtigen muss, wenn man Vue auf bestehende Seiten anwendet. Erstens will Vue nicht, dass man Skripte darin lädt – es gibt bedrohliche Fehler in der Konsole aus, wenn man es tut. Der einfachste Weg, dies zu vermeiden, ist, ein Wrapper-Element um den Inhalt jeder Seite zu legen und dann Skripte außerhalb davon zu laden (was aus allen möglichen Gründen bereits ein gängiges Muster ist). Etwas wie das
<?php /* header.php */ ?>
<body <?php body_class(); ?>>
<div id="site-wrapper">
<?php /* footer.php */ ?>
</div> <!-- #site-wrapper -->
<?php wp_footer(); ?>
Die zweite Überlegung ist, dass Vue am Ende des body-Elements aufgerufen werden muss, damit es geladen wird, *nachdem* der Rest des DOMs zum Parsen verfügbar ist. Wir übergeben true als fünftes Argument (in_footer) für die wp_enqueue_script Funktion. Außerdem, um sicherzustellen, dass Vue zuerst geladen wird, registrieren wir es als Abhängigkeit des Hauptskripts.
<?php // functions.php
add_action( 'wp_enqueue_scripts', function() {
wp_enqueue_script('vue', get_template_directory_uri() . '/assets/js/lib/vue.js', null, null, true); // change to vue.min.js for production
wp_enqueue_script('main', get_template_directory_uri() . '/assets/js/main.js', 'vue', null, true);
Schließlich initialisieren wir in der Hauptskriptdatei Vue auf dem site-wrapper Element.
// main.js
new Vue({
el: document.getElementById('site-wrapper')
})
Die Sterne-Bewertungskomponente
Unsere einzelne Beitragsvorlage sieht derzeit so aus
<?php /* single-post.php */ ?>
<article class="recipe">
<?php /* ... post content */ ?>
<!-- star rating component goes here -->
</article>
Wir registrieren die Sterne-Bewertungskomponente und fügen einige Logiken hinzu, um sie zu verwalten.
// main.js
Vue.component('star-rating', {
data () {
return {
rating: 0
}
},
methods: {
rate (i) { this.rating = i }
},
watch: {
rating (val) {
// prevent rating from going out of bounds by checking it to on every change
if (val < 0)
this.rating = 0
else if (val > 5)
this.rating = 5
// ... some logic to save to localStorage or somewhere else
}
}
})
// make sure to initialize Vue after registering all components
new Vue({
el: document.getElementById('site-wrapper')
})
Wir werden die Komponentenvorlage in einer separaten PHP-Datei schreiben. Die Komponente besteht aus sechs Schaltflächen (einer für "nicht bewertet", 5 mit Sternen). Jede Schaltfläche enthält eine SVG mit entweder schwarzer oder transparenter Füllung.
<?php /* components/star-rating.php */ ?>
<star-rating inline-template>
<div class="star-rating">
<p>Rate recipe:</p>
<button @click="rate(0)">
<svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
</button>
<button v-for="(i in 5)" @click="rate(i)">
<svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
</button>
</div>
</star-rating>
Als Faustregel gebe ich dem obersten Element einer Komponente gerne einen Klassennamen, der identisch mit dem der Komponente selbst ist. Das macht es einfach, zwischen Markup und CSS zu argumentieren (z.B. kann <star-rating> als .star-rating betrachtet werden).
Und jetzt binden wir sie in unsere Seiten-Vorlage ein.
<?php /* single-post.php */ ?>
<article class="recipe">
<?php /* post content */ ?>
<?php get_template_part('components/star-rating'); ?>
</article>
Der gesamte HTML-Code innerhalb der Vorlage ist gültig und wird vom Browser verstanden, mit Ausnahme von <star-rating>. Wir können noch einen Schritt weiter gehen, um dies zu beheben, indem wir die Vue-Direktive is verwenden.
<div is="star-rating" inline-template>...</div>
Nehmen wir nun an, dass die maximale Bewertung nicht unbedingt 5 ist, sondern vom Website-Editor mit Advanced Custom Fields, einem beliebten WordPress-Plugin, das benutzerdefinierte Felder für Seiten, Beiträge und andere WordPress-Inhalte hinzufügt, gesteuert werden kann. Alles, was wir tun müssen, ist, diesen Wert als Prop der Komponente zu übergeben, die wir maxRating nennen werden.
<?php // components/star-rating.php
// max_rating is the name of the ACF field
$max_rating = get_field('max_rating');
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>">
<div class="star-rating">
<p>Rate recipe:</p>
<button @click="rate(0)">
<svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
</button>
<button v-for="(i in maxRating) @click="rate(i)">
<svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
</button>
</div>
</div>
Und in unserem Skript registrieren wir die Prop und ersetzen die magische Zahl 5.
// main.js
Vue.component('star-rating', {
props: {
maxRating: {
type: Number,
default: 5 // highlight
}
},
data () {
return {
rating: 0
}
},
methods: {
rate (i) { this.rating = i }
},
watch: {
rating (val) {
// prevent rating from going out of bounds by checking it to on every change
if (val < 0)
this.rating = 0
else if (val > maxRating)
this.rating = maxRating
// ... some logic to save to localStorage or somewhere else
}
}
})
Um die Bewertung des spezifischen Rezepts zu speichern, müssen wir die ID des Beitrags übergeben. Wieder die gleiche Idee.
<?php // components/star-rating.php
$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>">
<div class="star-rating">
<p>Rate recipe:</p>
<button @click="rate(0)">
<svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
</button>
<button v-for="(i in maxRating) @click="rate(i)">
<svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
</button>
</div>
</div>
// main.js
Vue.component('star-rating', {
props: {
maxRating: {
// Same as before
},
recipeId: {
type: String,
required: true
}
},
// ...
watch: {
rating (val) {
// Same as before
// on every change, save to some storage
// e.g. localStorage or posting to a WP comments endpoint
someKindOfStorageDefinedElsewhere.save(this.recipeId, this.rating)
}
},
mounted () {
this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId)
}
})
Jetzt können wir die gleiche Komponentendatei in der Archivseite (einer Schleife von Beiträgen) einbinden, ohne zusätzliche Einrichtung.
<?php // archive.php
if (have_posts()): while ( have_posts()): the_post(); ?>
<article class="recipe">
<?php // Excerpt, featured image, etc. then:
get_template_part('components/star-rating'); ?>
</article>
<?php endwhile; endif; ?>
Das Feedback-Formular
Der Moment, in dem ein Benutzer ein Rezept bewertet, ist eine großartige Gelegenheit, um weiteres Feedback zu erbitten. Fügen wir also ein kleines Formular hinzu, das direkt nach dem Setzen der Bewertung erscheint.
// main.js
Vue.component('feedback-form', {
props: {
recipeId: {
type: String,
required: true
},
show: { type: Boolean, default: false }
},
data () {
return {
name: '',
subject: ''
// ... other form fields
}
}
})
<?php // components/feedback-form.php
$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>" v-if="showForm(recipe-id)">
<form class="recipe-feedback-form" id="feedback-form-<?= $recipe_id ?>">
<input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
<label for="first-name-<?= $recipe_id ?>">Your name</label>
<?php /* ... */ ?>
</form>
</div>
Beachten Sie, dass wir jedem Formularelement eine eindeutige Zeichenfolge (in diesem Fall recipe-id) zum ID hinzufügen. Dies soll sicherstellen, dass sie alle eindeutige IDs haben, selbst wenn mehrere Kopien des Formulars auf der Seite vorhanden sind.
Wo soll dieses Formular also seinen Platz finden? Es muss die Bewertung des Rezepts kennen, damit es weiß, dass es geöffnet werden muss. Wir bauen nur gute alte Komponenten, also nutzen wir Komposition, um das Formular in die <star-rating> einzubetten.
<?php // components/star-rating.php
$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating" inline-template :max-rating="<?= $max_rating ?>" recipe-id="<?= $recipe_id ?>">
<div class="star-rating">
<p>Rate recipe:</p>
<button @click="rate(0)">
<svg><path d="..." :fill="rating === 0 ? 'black' : 'transparent'"></svg>
</button>
<button v-for="(i in maxRating) @click="rate(i)">
<svg><path d="..." :fill="rating >= i ? 'black' : 'transparent'"></svg>
</button>
<?php get_template_part('components/feedback-form'); ?>
</div>
</div>
Wenn Sie an dieser Stelle denken: „Wir sollten wirklich beide Komponenten zu einer einzigen Elternkomponente zusammenfassen, die den Bewertungszustand verwaltet“, dann geben Sie sich selbst 10 Punkte und warten Sie geduldig.
Eine kleine progressive Verbesserung, die wir hinzufügen können, um das Formular ohne JavaScript nutzbar zu machen, ist, ihm die traditionelle PHP-Aktion zu geben und diese dann in Vue zu überschreiben. Wir verwenden @submit.prevent, um die ursprüngliche Aktion zu verhindern, und führen dann eine submit Methode aus, um die Formulardaten in JavaScript zu senden.
<?php // components/feedback-form.php
$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>">
<form action="path/to/feedback-form-handler.php"
@submit.prevent="submit"
class="recipe-feedback-form"
id="feedback-form-<?= $recipe_id ?>">
<input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
<label for="first-name-<?= $recipe_id ?>">Your name</label>
<!-- ... -->
</form>
</div>
Dann, vorausgesetzt, wir wollen fetch verwenden, kann unsere submit Methode etwa so aussehen:
// main.js
Vue.component('feedback-form', {
// Same as before
methods: {
submit () {
const form = this.$el.querySelector('form')
const URL = form.action
const formData = new FormData(form)
fetch(URL, {method: 'POST', body: formData})
.then(result => { ... })
.catch(error => { ... })
}
}
})
Okay, was wollen wir in .then und .catch tun? Fügen wir eine Komponente hinzu, die Echtzeit-Feedback für den Status der Formularübermittlung anzeigt. Zuerst fügen wir den Zustand hinzu, um das Senden, Erfolg und Misserfolg zu verfolgen, sowie eine berechnete Eigenschaft, die uns mitteilt, ob wir auf Ergebnisse warten.
// main.js
Vue.component('feedback-form', {
// Same as before
data () {
return {
name: '',
subject: ''
// ... other form fields
sent: false,
success: false,
error: null
}
},
methods: {
submit () {
const form = this.$el.querySelector('form')
const URL = form.action
const formData = new FormData(form)
fetch(URL, {method: 'POST', body: formData})
.then(result => {
this.success = true
})
.catch(error => {
this.error = error
})
this.sent = true
}
}
})
Um das Markup für jeden Nachrichtentyp (Erfolg, Misserfolg, ausstehend) hinzuzufügen, könnten wir eine weitere Komponente wie die anderen erstellen, die wir bisher gebaut haben. Da diese Nachrichten jedoch bedeutungslos sind, wenn der Server die Seite rendert, ist es besser, sie nur bei Bedarf zu rendern. Dazu platzieren wir unser Markup in einem nativen HTML <template>-Tag, das im Browser nichts rendert. Dann verweisen wir per id darauf als Vorlage unserer Komponente.
<?php /* components/form-status.php */ ?>
<template id="form-status-component" v-if="false">
<div class="form-message-wrapper">
<div class="pending-message" v-if="pending">
<img src="<?= get_template_directory_uri() ?>/spinner.gif">
<p>Patience, young one.</p>
</div>
<div class="success-message" v-else-if="success">
<img src="<?= get_template_directory_uri() ?>/beer.gif">
<p>Huzzah!</p>
</div>
<div class="success-message" v-else-if="error">
<img src="<?= get_template_directory_uri() ?>/broken.gif">
<p>Ooh, boy. It would appear that: {{ error.text }}</p>
</div>
</div
</template>
Warum fragen Sie, v-if="false" oben hinzufügen? Das ist eine kleine, knifflige Sache. Sobald Vue das HTML <template> erfasst, wird es sofort denken, dass es sich um eine Vue <template> handelt und diese rendern. Es sei denn, Sie haben es erraten, wir sagen Vue, es soll es *nicht* rendern. Ein bisschen ein Hack, aber da haben Sie es.
Da wir dieses Markup nur einmal auf der Seite benötigen, binden wir die PHP-Komponente im Footer ein.
<?php /* footer.php */ ?>
</div> <!-- #site-wrapper -->
<?php get_template_part('components/form-status'); ?>
<?php wp_footer(); ?>
Jetzt registrieren wir die Komponente bei Vue…
// main.js
Vue.component('form-status', {
template: '#form-status-component'
props: {
pending: { type: Boolean, required: true },
success: { type: Boolean, required: true },
error: { type: [Object, null], required: true },
}
})
…und rufen sie innerhalb unserer Formular-Komponente auf.
<?php // components/feedback-form.php
$recipe_id = get_the_ID();
?>
<div is="feedback-form" inline-template recipe-id="<?= $recipe_id ?>">
<form action="path/to/feedback-form-handler.php"
@submit.prevent="submit"
class="recipe-feedback-form"
id="feedback-form-<?= $recipe_id ?>">
<input type="text" :id="first-name-<?= $recipe_id ?>" v-model="name">
<label for="first-name-<?= $recipe_id ?>">Your name</label>
<?php // ... ?>
</form>
<form-status v-if="sent" :pending="pending" :success="success" :error="error" />
</div>
Da wir <form-status> mit Vue.component registriert haben, ist sie global verfügbar, ohne sie speziell in den components: { } des Parents aufzunehmen.
Rezepte filtern
Nachdem Benutzer nun einige Teile ihres Erlebnisses auf unserem Blog personalisieren können, können wir alle möglichen nützlichen Funktionen hinzufügen. Insbesondere wollen wir es den Benutzern ermöglichen, eine minimale Bewertung festzulegen, die sie sehen möchten, und zwar über ein Eingabefeld oben auf der Seite.
Das Erste, was wir brauchen, ist ein globaler Zustand, um die vom Benutzer festgelegte Mindestbewertung zu verfolgen. Da wir am Anfang eine Vue-App auf der gesamten Seite initialisiert haben, sind globale Zustände einfach Daten auf der Vue-Instanz.
// main.js
// Same as before
new Vue({
el: document.getElementById('site-wrapper'),
data: {
minimumRating: 0
}
})
Und wo können wir die Steuerelemente zur Änderung unterbringen? Da die gesamte Seite die App ist, lautet die Antwort fast überall. Zum Beispiel am Anfang der Archivseite.
<?php /* archive.php */ ?>
<label for="minimum-rating-input">Only show me recipes I've rated at or above:</label>
<input type="number" id="minimum-rating-input" v-model="minimumRating">
<?php if (have_posts()): while ( have_posts()): the_post(); ?>
<article class="recipe">
<?php /* Post excerpt, featured image, etc. */ ?>
<?php get_template_part('components/star-rating'); ?>
</article>
<?php endwhile; endif; ?>
Solange es sich innerhalb unseres site-wrapper befindet und nicht innerhalb einer anderen Komponente, wird es einfach funktionieren. Wenn wir wollen, könnten wir auch eine Filterkomponente erstellen, die den globalen Zustand ändert. Und wenn wir ganz schick werden wollen, könnten wir sogar Vuex hinzufügen (da Vuex den Zustand standardmäßig nicht über Seiten hinweg speichern kann, könnten wir etwas wie vuex-persist hinzufügen, um localStorage zu verwenden).
Also, jetzt müssen wir ein Rezept basierend auf dem Filter ausblenden oder anzeigen. Dazu müssen wir den Rezeptinhalt in eine eigene Komponente packen, mit einer v-show-Direktive. Es ist wahrscheinlich am besten, die gleiche Komponente sowohl für die einzelne Seite als auch für die Archivseite zu verwenden. Leider können weder require noch get_template_part Parameter in die aufgerufene Datei übergeben – aber wir können global-Variablen verwenden.
<?php /* archive.php */ ?>
<label for="minimum-rating-input">Only show me recipes I've rated at or above:</label>
<input type="number" id="minimum-rating-input" v-model="minimumRating">
<?php
$is_archive_item = true;
if (have_posts()): while ( have_posts()): the_post();
get_template_part('components/recipe-content');
endwhile; endif; ?>
Wir können dann $is_archive_item als global-Variable innerhalb der PHP-Komponentendatei verwenden, um zu prüfen, ob sie gesetzt und true ist. Da wir den Inhalt auf der einzelnen Beitragsseite nicht ausblenden müssen, fügen wir die v-show-Direktive bedingt hinzu.
<?php // components/recipe-content.php
global $is_archive_item; ?>
<div is="recipe-content">
<article class="recipe"
<?php if ($is_archive_item): ?>
v-show="show"
<?php endif; ?>
>
<?php
if ($is_archive_item):
the_excerpt();
else
the_content();
endif;
get_template_part('components/star-rating');
?>
</article>
</div>
In diesem speziellen Beispiel hätten wir auch mit is_archive() innerhalb der Komponente testen können, aber in den meisten Fällen müssen wir explizite Props setzen.
Wir müssen den rating-Zustand und die Logik in die <recipe-content>-Komponente verschieben, damit diese weiß, ob sie sich selbst ausblenden muss. Innerhalb von <star-rating> erstellen wir ein benutzerdefiniertes v-model, indem wir rating durch value ersetzen und this.rating = i durch $emit('input', i) ersetzen. Unsere Komponentenregistrierung wird also jetzt so aussehen:
// main.js
Vue.component('recipe-content', {
data () {
rating: 0
},
watch: {
rating (val) {
// ...
}
},
mounted () {
this.rating = someKindOfStorageDefinedElsewhere.load(this.recipeId)
}
})
Vue.component('star-rating', {
props: {
maxRating: { /* ... */ },
recipeId: { /* ... */ },
value: { type: Number, required: true }
},
methods: {
rate (i) { this.$emit('input', i) }
},
})
Wir fügen v-model in star-rating.php ein und ändern rating zu value. Außerdem können wir nun das <feedback-form> in <recipe-content> verschieben.
<?php // components/star-rating.php
$max_rating = get_field('max_rating');
$recipe_id = get_the_ID();
?>
<div is="star-rating"
inline-template
:max-rating="<?= $ max_rating ?>"
recipe-id="<?= $recipe_id ?>"
v-model="value"
>
<div class="star-rating">
<p>Rate recipe:</p>
<button @click="rate(0)">
<svg><path d="..." :fill="value === 0 ? 'black' : 'transparent'"></svg>
</button>
<button v-for="(i in maxRating) @click="rate(i)">
<svg><path d="..." :fill="value >= i ? 'black' : 'transparent'"></svg>
</button>
</div>
</div>
<?php // components/recipe-content.php
global $is_archive_item; ?>
<div is="recipe-content">
<article class="recipe"
<?php if ($is_archive_item): ?>
v-show="show"
<?php endif; ?>
>
<?php
if ($is_archive_item):
the_excerpt();
else
the_content();
endif;
get_template_part('components/star-rating');
get_template_part('components/feedback-form');
?>
</article>
</div>
Nun ist alles so eingerichtet, dass die initiale Anzeige alle Rezepte zeigt und der Benutzer sie dann nach ihrer Bewertung filtern kann. Zukünftig könnten wir alle möglichen Parameter hinzufügen, um Inhalte zu filtern. Und das muss nicht auf Benutzereingaben basieren – wir können das Filtern basierend auf dem Inhalt selbst zulassen (z.B. Anzahl der Zutaten oder Kochzeit), indem wir die Daten von PHP an Vue übergeben.
Fazit
Nun, das war ein langer Ritt, aber sehen Sie, was wir gebaut haben: unabhängige, komponierbare, wartbare, interaktive, progressiv verbesserte Komponenten in unserem WordPress-Theme. Wir haben das Beste aus allen Welten vereint!
Ich benutze diesen Ansatz seit einiger Zeit in der Produktion und liebe die Art und Weise, wie er es mir ermöglicht, über die verschiedenen Teile meiner Themes nachzudenken. Ich hoffe, ich habe Sie inspiriert, es auch auszuprobieren.
- Natürlich, zwei Tage vor dem Launch, beschloss die Rechtsabteilung des Kunden, dass sie all diese Informationen nicht sammeln wollten. Derzeit ist das Live-Formular nur ein Schatten seiner selbst während der Entwicklung.
- Fun Fact: Rasmus Lerdorf sagte, dass seine ursprüngliche Absicht war, dass PHP nur zur Vorlagenerstellung dient und die gesamte Geschäftslogik in C behandelt wird. Lassen Sie das einen Moment auf sich wirken. Dann räumen Sie eine Stunde in Ihrem Zeitplan frei und sehen Sie sich den gesamten Vortrag an.
- Es gibt Drittanbieter-WordPress-Templating-Engines, die zu optimiertem PHP kompiliert werden können. Twig fällt mir zum Beispiel ein. Wir versuchen, den umgekehrten Weg zu gehen und Vanilla-PHP zum Verarbeiten durch JavaScript zu senden.
Schön!
Wäre es „einfacher“ gewesen, das als Gutenberg-Block zu implementieren!
Hallo Sameer, das ist eine tolle Frage.
Ich denke, die Anwendungsfälle sind im Wesentlichen unterschiedlich. Gutenberg ist letztendlich ein Werkzeug für Autoren – es ermöglicht Entwicklern, wiederverwendbare Inhaltsblöcke zu erstellen, die als Teil eines Beitrags oder einer Seite enthalten werden können. Dinge wie ein YouTube-Embed, Codeblöcke mit Syntax-Hervorhebung, Spaltensätze usw. sind gute Kandidaten – einige Beiträge werden fünf Codeblöcke haben und einige gar keine. Daher hat ein Großteil der Arbeit bei der Erstellung von Inhaltsblöcken mit der Benutzeroberfläche zu tun, die die Autoren verwenden werden (ist Editor Experience ein Schlagwort?).
Elemente, die Teil des Themes selbst und nicht des Inhalts sind, sind eine ganz andere Geschichte. Gutenberg-Blöcke können zum Beispiel nicht im Footer der Website verwendet werden (es ist technisch möglich, dies zu umgehen, aber es ist nicht schön). Außerdem können Gutenberg-Blöcke nicht ineinander verschachtelt werden und nicht miteinander kommunizieren (auch theoretisch hackbar, aber nicht ratsam).
Unterschiedliche Probleme, unterschiedliche Lösungen.
Dieser Artikel kam für mich genau zur richtigen Zeit. Danke.
Als WordPress-Entwickler, der sich in letzter Zeit sehr für Vue interessiert hat, bestätige ich, dass dies ein ziemlich großartiger Artikel ist! Danke.
Das ist großartig! Ich hatte einen Entwickler beauftragt, an einem Vue-Projekt zu arbeiten, und die Art und Weise, wie Sie Inline-Templates beschreiben, war sehr hilfreich. Danke für die Komponenten-Vorlagenbeispiele!
Wenn es in WordPress eine Möglichkeit gäbe, Komponenten zu handhaben. Ich würde mich nicht darum kümmern, wie sie sie nennen, Blöcke oder was auch immer.
Ich habe vor zwei Jahren mit Vue und WordPress gearbeitet und der beste Ansatz, den ich gefunden habe, ist die Verwendung von Template-Tags und die Registrierung von Komponenten. Alle Argumente der Komponente übergebe ich als Props. Aber ich rendere alle Template-Tags außerhalb der App-DIVs.
Das einzige Problem, das ich nicht gelöst habe, ist der erste Render. Bis Vue geladen ist, werden keine der Komponenten gerendert, und dieser Ansatz scheint es zu lösen.
Ich habe Ihr Tutorial befolgt, aber die Vue-Instanz löscht alles andere auf dem Beitrag, wenn ich sie auf site-wrapper initialisiere... Ich bin mir nicht sicher, ob ich etwas falsch mache...
Gibt es eine Möglichkeit, eine Single-File-Komponente (.vue) von Grund auf in WordPress zu verwenden? Ich möchte meine eigene Webpack-Konfiguration einrichten, aber ich kann keine Tutorials oder Blogs dazu finden.