Ini adalah pendekatan alternatif untuk @kaiser jawaban , yang saya temukan cukup baik (+1 dari saya) tetapi membutuhkan pekerjaan tambahan untuk digunakan dengan fungsi-fungsi WP inti dan itu per-se terintegrasi rendah dengan hierarki templat.
Pendekatan yang ingin saya bagikan didasarkan pada satu kelas (ini adalah versi singkat dari sesuatu yang saya kerjakan) yang menangani render data untuk templat.
Ini memiliki beberapa (IMO) fitur menarik:
- templat adalah file templat WordPress standar (single.php, page.php) mereka mendapatkan sedikit lebih banyak kekuatan
- template yang ada hanya berfungsi, jadi Anda dapat mengintegrasikan template dari tema yang ada tanpa usaha
- tidak seperti pendekatan @iser , dalam templat Anda mengakses variabel menggunakan
$this
kata kunci: ini memberi Anda kemungkinan untuk menghindari pemberitahuan dalam produksi jika ada variabel yang tidak ditentukan
The Engine
Kelas
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()
);
}
}
(Tersedia sebagai Intisari di sini.)
Cara Penggunaan
Satu-satunya hal yang diperlukan adalah memanggil Engine::init()
metode, mungkin dengan cara apa pun 'template_redirect'
. Itu bisa dilakukan dalam tema functions.php
atau dari sebuah plugin.
require_once '/path/to/the/file/Engine.php';
add_action('template_redirect', array('GM\Template\Engine', 'init'), 99);
Itu saja.
Template Anda yang ada akan berfungsi seperti yang diharapkan. Tetapi sekarang Anda memiliki kemungkinan untuk mengakses data templat khusus.
Data Template Kustom
Untuk meneruskan data khusus ke template ada dua filter:
'gm_template_data'
'gm_template_data_{$type}'
Yang pertama dipecat untuk semua templat, yang kedua adalah templat khusus, pada kenyataannya, bagian dymamic {$type}
adalah nama dasar dari file templat tanpa ekstensi file.
Misalnya filter 'gm_template_data_single'
dapat digunakan untuk meneruskan data kesingle.php
templat.
Callback terlampir pada kait ini ini harus mengembalikan array , di mana kunci adalah nama variabel.
Misalnya, Anda dapat meneruskan data meta sebagai data templat suka seperti itu:
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;
};
Dan kemudian, di dalam templat Anda cukup menggunakan:
<?= $this->extra_title ?>
Mode Debug
Ketika kedua konstanta WP_DEBUG
danWP_DEBUG_DISPLAY
itu benar, kelas bekerja dalam mode debug. Ini berarti bahwa jika suatu variabel tidak didefinisikan pengecualian dilemparkan.
Ketika kelas tidak dalam mode debug (mungkin dalam produksi) mengakses variabel yang tidak terdefinisi akan menghasilkan string kosong.
Model Data
Cara yang bagus dan dapat dikelola untuk mengatur data Anda adalah dengan menggunakan kelas model.
Mereka bisa menjadi kelas yang sangat sederhana, yang mengembalikan data menggunakan filter yang sama yang dijelaskan di atas. Tidak ada antarmuka khusus untuk diikuti, mereka dapat diatur sesuai keinginan Anda.
Di bawah ini, hanya ada sebuah contoh, tetapi Anda bebas melakukannya dengan cara Anda sendiri.
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);
The __invoke()
metode (yang berjalan ketika kelas digunakan seperti callback) mengembalikan string yang akan digunakan untuk <title>
tag template.
Berkat fakta bahwa argumen kedua yang dilewati 'gm_template_data'
adalah nama templat, metode ini mengembalikan judul khusus untuk beranda.
Memiliki kode di atas, maka dimungkinkan untuk menggunakan sesuatu seperti
<title><?= $this->seo_title ?></title>
di <head>
bagian halaman.
Sebagian
WordPress memiliki fungsi seperti get_header()
atau get_template_part()
yang dapat digunakan untuk memuat sebagian ke templat utama.
Fungsi-fungsi ini, seperti semua fungsi WordPress lainnya, dapat digunakan dalam template ketika menggunakan Engine
kelas.
Satu-satunya masalah adalah bahwa di dalam parsial dimuat menggunakan fungsi inti WordPress tidak mungkin untuk menggunakan fitur canggih untuk mendapatkan data templat kustom menggunakan $this
.
Untuk alasan ini, Engine
kelas memiliki metode partial()
yang memungkinkan untuk memuat sebagian (dengan cara yang sepenuhnya kompatibel dengan tema anak) dan masih dapat digunakan secara parsial data templat kustom.
Penggunaannya cukup sederhana.
Dengan asumsi ada file bernama folder partials/content.php
theme (atau child theme), itu dapat dimasukkan menggunakan:
<?php $this->partial('partials/content') ?>
Di dalam parsial itu akan mungkin untuk mengakses semua data tema induk dengan cara yang sama.
Tidak seperti fungsi WordPress, Engine::partial()
metode memungkinkan untuk mengirimkan data tertentu ke parsial, hanya meneruskan array data sebagai argumen kedua.
<?php $this->partial('partials/content', array('greeting' => 'Welcome!')) ?>
Secara default, sebagian memiliki akses ke data yang tersedia dalam tema induk dan ke data yang dilewatkan secara eksplisit.
Jika beberapa variabel yang secara eksplisit diteruskan ke parsial memiliki nama yang sama dengan variabel tema induk, maka variabel yang diteruskan secara eksplisit menang.
Namun, juga dimungkinkan untuk memasukkan parsial dalam mode terisolasi , yaitu parsial tidak memiliki akses ke data tema induk. Untuk melakukan itu, sampaikan true
argumen ketiga ke partial()
:
<?php $this->partial('partials/content', array('greeting' => 'Welcome!'), true) ?>
Kesimpulan
Sekalipun cukup sederhana, Engine
kelasnya cukup lengkap, tetapi tentunya bisa lebih ditingkatkan. Misalnya tidak ada cara untuk memeriksa apakah suatu variabel didefinisikan atau tidak.
Berkat kompatibilitasnya 100% dengan fitur WordPress dan hierarki templat Anda dapat mengintegrasikannya dengan kode pihak ketiga yang ada dan tidak ada masalah.
Namun, perhatikan bahwa hanya sebagian yang diuji, jadi ada kemungkinan ada masalah yang belum saya temukan.
Lima poin di bawah "Apa yang kita dapatkan?" dalam jawaban @iser :
- Tukar templat dengan mudah tanpa mengubah struktur data
- Memiliki tempalt mudah dibaca
- Hindari ruang lingkup global
- Dapat Unit-Test
- Dapat bertukar Model / data tanpa merusak komponen lain
semua berlaku untuk kelas saya juga.