Dies ist ein alternativer Ansatz zu @kaiser answer, den ich als ziemlich gut befunden habe (+1 von mir), der jedoch zusätzliche Arbeit erfordert, um mit den WP-Kernfunktionen verwendet zu werden, und der per se in die Vorlagenhierarchie integriert ist.
Der Ansatz, den ich teilen möchte, basiert auf einer einzelnen Klasse (es ist eine abgespeckte Version von etwas, an dem ich arbeite), die sich um das Rendern von Daten für Vorlagen kümmert.
Es hat einige (IMO) interessante Funktionen:
- Vorlagen sind Standard-WordPress-Vorlagendateien (single.php, page.php), die etwas mehr Leistung bringen
- vorhandene Vorlagen funktionieren einfach, sodass Sie ohne Aufwand Vorlagen aus vorhandenen Themen integrieren können
- Im Gegensatz zum @ kaiser- Ansatz greifen Sie in Vorlagen mithilfe von
$this
Schlüsselwörtern auf Variablen zu. Dadurch haben Sie die Möglichkeit, bei nicht definierten Variablen Benachrichtigungen in der Produktion zu vermeiden
Die Engine
Klasse
namespace GM\Template;
class Engine
{
private $data;
private $template;
private $debug = false;
/**
* Bootstrap rendering process. Should be called on 'template_redirect'.
*/
public static function init()
{
add_filter('template_include', new static(), 99, 1);
}
/**
* Constructor. Sets debug properties.
*/
public function __construct()
{
$this->debug =
(! defined('WP_DEBUG') || WP_DEBUG)
&& (! defined('WP_DEBUG_DISPLAY') || WP_DEBUG_DISPLAY);
}
/**
* Render a template.
* Data is set via filters (for main template) or passed to method for partials.
* @param string $template template file path
* @param array $data template data
* @param bool $partial is the template a partial?
* @return mixed|void
*/
public function __invoke($template, array $data = array(), $partial = false)
{
if ($partial || $template) {
$this->data = $partial
? $data
: $this->provide(substr(basename($template), 0, -4));
require $template;
$partial or exit;
}
return $template;
}
/**
* Render a partial.
* Partial-specific data can be passed to method.
* @param string $template template file path
* @param array $data template data
* @param bool $isolated when true partial has no access on parent template context
*/
public function partial($partial, array $data = array(), $isolated = false)
{
do_action("get_template_part_{$partial}", $partial, null);
$file = locate_template("{$partial}.php");
if ($file) {
$class = __CLASS__;
$template = new $class();
$template_data = $isolated ? $data : array_merge($this->data, $data);
$template($file, $template_data, true);
} elseif ($this->debug) {
throw new \RuntimeException("{$partial} is not a valid partial.");
}
}
/**
* Used in templates to access data.
* @param string $name
* @return string
*/
public function __get($name)
{
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
if ($this->debug) {
throw new \RuntimeException("{$name} is undefined.");
}
return '';
}
/**
* Provide data to templates using two filters hooks:
* one generic and another query type specific.
* @param string $type Template file name (without extension, e.g. "single")
* @return array
*/
private function provide($type)
{
$generic = apply_filters('gm_template_data', array(), $type);
$specific = apply_filters("gm_template_data_{$type}", array());
return array_merge(
is_array($generic) ? $generic : array(),
is_array($specific) ? $specific : array()
);
}
}
(Hier als Gist erhältlich .)
Wie benutzt man
Sie müssen nur die Engine::init()
Methode aufrufen , wahrscheinlich 'template_redirect'
aufgelegt. Dies kann über ein Theme functions.php
oder über ein Plugin erfolgen.
require_once '/path/to/the/file/Engine.php';
add_action('template_redirect', array('GM\Template\Engine', 'init'), 99);
Das ist alles.
Ihre vorhandenen Vorlagen funktionieren wie erwartet. Jetzt haben Sie jedoch die Möglichkeit, auf benutzerdefinierte Vorlagendaten zuzugreifen.
Benutzerdefinierte Vorlagendaten
Um benutzerdefinierte Daten an Vorlagen zu übergeben, gibt es zwei Filter:
'gm_template_data'
'gm_template_data_{$type}'
Der erste wird für alle Vorlagen ausgelöst, der zweite ist vorlagenspezifisch. Der dynamische Teil {$type}
ist der Basisname der Vorlagendatei ohne Dateierweiterung.
Mit dem Filter 'gm_template_data_single'
können zB Daten an die single.php
Vorlage übergeben werden.
Die an diese Hooks angehängten Rückrufe müssen ein Array zurückgeben , wobei die Schlüssel die Variablennamen sind.
Beispielsweise können Sie Metadaten wie folgt als Vorlagendaten übergeben:
add_filter('gm_template_data', function($data) {
if (is_singular()) {
$id = get_queried_object_id();
$data['extra_title'] = get_post_meta($id, "_theme_extra_title", true);
}
return $data;
};
Und dann können Sie innerhalb der Vorlage einfach Folgendes verwenden:
<?= $this->extra_title ?>
Debug-Modus
Wenn sowohl die Konstanten WP_DEBUG
als WP_DEBUG_DISPLAY
auch wahr sind, arbeitet die Klasse im Debug-Modus. Dies bedeutet, dass eine Ausnahme ausgelöst wird, wenn keine Variable definiert ist.
Wenn sich die Klasse nicht im Debug-Modus befindet (wahrscheinlich in der Produktion), wird beim Zugriff auf eine undefinierte Variable eine leere Zeichenfolge ausgegeben.
Datenmodelle
Eine schöne und verwaltbare Möglichkeit, Ihre Daten zu organisieren, ist die Verwendung von Modellklassen.
Dies können sehr einfache Klassen sein, die Daten mit den oben beschriebenen Filtern zurückgeben. Es gibt keine bestimmte Benutzeroberfläche, sie kann nach Ihren Wünschen organisiert werden.
Unten sehen Sie nur ein Beispiel, aber Sie können es auf Ihre eigene Weise tun.
class SeoModel
{
public function __invoke(array $data, $type = '')
{
switch ($type) {
case 'front-page':
case 'home':
$data['seo_title'] = 'Welcome to my site';
break;
default:
$data['seo_title'] = wp_title(' - ', false, 'right');
break;
}
return $data;
}
}
add_filter('gm_template_data', new SeoModel(), 10, 2);
Die __invoke()
Methode (die ausgeführt wird, wenn eine Klasse wie ein Rückruf verwendet wird) gibt eine Zeichenfolge zurück, die für das <title>
Tag der Vorlage verwendet werden soll.
Dank der Tatsache, dass das zweite übergebene Argument 'gm_template_data'
der Vorlagenname ist, gibt die Methode einen benutzerdefinierten Titel für die Homepage zurück.
Mit dem obigen Code ist es dann möglich, so etwas zu verwenden
<title><?= $this->seo_title ?></title>
im <head>
Abschnitt der Seite.
Teilstücke
WordPress verfügt über Funktionen wie get_header()
oder get_template_part()
die zum Laden von Partials in die Hauptvorlage verwendet werden können.
Diese Funktionen können, genau wie alle anderen WordPress-Funktionen, in Vorlagen verwendet werden, wenn die Engine
Klasse verwendet wird.
Das einzige Problem ist, dass in den mit den WordPress-Kernfunktionen geladenen Partials die erweiterte Funktion zum Abrufen benutzerdefinierter Vorlagendaten nicht verwendet werden kann $this
.
Aus diesem Grund verfügt die Engine
Klasse über eine Methode partial()
, mit der ein Teil geladen werden kann (vollständig untergeordnetes Thema) und die benutzerdefinierten Vorlagendaten weiterhin in Teilbereichen verwendet werden können.
Die Verwendung ist ziemlich einfach.
Angenommen, es gibt eine Datei mit dem Namen partials/content.php
im Ordner theme (oder child theme), kann sie mit folgendem Befehl eingefügt werden:
<?php $this->partial('partials/content') ?>
Innerhalb dieses Teils ist der Zugriff auf alle übergeordneten Themendaten auf dieselbe Weise möglich.
Im Gegensatz zu WordPress-Funktionen können mit dieser Engine::partial()
Methode bestimmte Daten an Partials übergeben werden, indem einfach ein Array von Daten als zweites Argument übergeben wird.
<?php $this->partial('partials/content', array('greeting' => 'Welcome!')) ?>
Standardmäßig haben Partials Zugriff auf Daten, die im übergeordneten Design verfügbar sind, und auf Daten, die explizit übergeben wurden.
Wenn eine explizit an partial übergebene Variable denselben Namen wie eine übergeordnete Designvariable hat, gewinnt die explizit übergebene Variable.
Es ist jedoch auch möglich, einen Teil im isolierten Modus einzuschließen, dh der Teil hat keinen Zugriff auf übergeordnete Themendaten. Übergeben Sie dazu einfach true
das dritte Argument an partial()
:
<?php $this->partial('partials/content', array('greeting' => 'Welcome!'), true) ?>
Fazit
Auch wenn es ziemlich einfach ist, ist der Engine
Unterricht ziemlich vollständig, kann aber sicherlich weiter verbessert werden. ZB gibt es keine Möglichkeit zu überprüfen, ob eine Variable definiert ist oder nicht.
Dank seiner 100% igen Kompatibilität mit WordPress-Funktionen und Vorlagenhierarchie können Sie es problemlos in vorhandenen Code und Code von Drittanbietern integrieren.
Beachten Sie jedoch, dass dies nur teilweise getestet wurde. Möglicherweise gibt es Probleme, die ich noch nicht entdeckt habe.
Die fünf Punkte unter "Was haben wir gewonnen?" in @kaiser Antwort :
- Tauschen Sie Vorlagen einfach aus, ohne die Datenstruktur zu ändern
- Habe leicht zu lesende Tempaltes
- Vermeiden Sie globalen Geltungsbereich
- Kann Unit-Test
- Kann das Modell / die Daten austauschen, ohne andere Komponenten zu beschädigen
sind auch für meine Klasse gültig.