Đây là một cách tiếp cận khác với câu trả lời @kaiser , tôi thấy khá ổn (+1 từ tôi) nhưng yêu cầu công việc bổ sung phải được sử dụng với các chức năng WP cốt lõi và nó được tích hợp thấp với hệ thống phân cấp mẫu.
Cách tiếp cận tôi muốn chia sẻ dựa trên một lớp duy nhất (đó là phiên bản rút gọn từ thứ tôi đang làm) chăm sóc dữ liệu kết xuất cho các mẫu.
Nó có một số tính năng thú vị (IMO):
- các mẫu là các tệp mẫu WordPress tiêu chuẩn (single.php, page.php), chúng có thêm một chút sức mạnh
- các mẫu hiện có chỉ hoạt động, vì vậy bạn có thể tích hợp mẫu từ các chủ đề hiện có mà không cần nỗ lực
- Không giống như cách tiếp cận @kaiser , trong các mẫu bạn truy cập các biến bằng
$this
từ khóa: điều này mang đến cho bạn khả năng tránh các thông báo trong sản xuất trong trường hợp các biến không xác định
các Engine
Lớp
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()
);
}
}
(Có sẵn như là Gist ở đây.)
Cách sử dụng
Điều duy nhất cần thiết là gọi Engine::init()
phương thức, có thể là trên 'template_redirect'
hook. Điều đó có thể được thực hiện trong chủ đề functions.php
hoặc từ một plugin.
require_once '/path/to/the/file/Engine.php';
add_action('template_redirect', array('GM\Template\Engine', 'init'), 99);
Đó là tất cả.
Các mẫu hiện có của bạn sẽ hoạt động như expcted. Nhưng bây giờ bạn có khả năng truy cập dữ liệu mẫu tùy chỉnh.
Dữ liệu mẫu tùy chỉnh
Để truyền dữ liệu tùy chỉnh cho các mẫu, có hai bộ lọc:
'gm_template_data'
'gm_template_data_{$type}'
Phần đầu tiên được kích hoạt cho tất cả các mẫu, phần thứ hai là mẫu cụ thể, trên thực tế, phần dymamic {$type}
là tên cơ sở của tệp mẫu không có phần mở rộng tệp.
Ví dụ: bộ lọc 'gm_template_data_single'
có thể được sử dụng để truyền dữ liệu đến single.php
mẫu.
Các cuộc gọi lại được gắn vào các hook này phải trả về một mảng , trong đó các khóa là tên biến.
Ví dụ: bạn có thể truyền dữ liệu meta dưới dạng lượt thích dữ liệu mẫu:
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;
};
Và sau đó, bên trong mẫu bạn chỉ có thể sử dụng:
<?= $this->extra_title ?>
Chế độ kiểm tra sửa lỗi
Khi cả hai hằng WP_DEBUG
và WP_DEBUG_DISPLAY
đều đúng, lớp hoạt động ở chế độ gỡ lỗi. Nó có nghĩa là nếu một biến không được xác định, một ngoại lệ được đưa ra.
Khi lớp không ở chế độ gỡ lỗi (có thể trong sản xuất) truy cập vào một biến không xác định sẽ tạo ra một chuỗi rỗng.
Mô hình dữ liệu
Một cách hay và dễ bảo trì để sắp xếp dữ liệu của bạn là sử dụng các lớp mô hình.
Chúng có thể là các lớp rất đơn giản, trả về dữ liệu bằng các bộ lọc được mô tả ở trên. Không có giao diện cụ thể để theo dõi, họ có thể được tổ chức accordi theo sở thích của bạn.
Dưới đây, chỉ có một ví dụ, nhưng bạn có thể tự do làm theo cách của riêng bạn.
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);
Các __invoke()
phương pháp (mà chạy khi một lớp được sử dụng như một callback) trả về một chuỗi được sử dụng cho các <title>
thẻ của mẫu.
Nhờ thực tế là đối số thứ hai được truyền qua 'gm_template_data'
là tên mẫu, phương thức trả về một tiêu đề tùy chỉnh cho trang chủ.
Có mã ở trên, sau đó có thể sử dụng một cái gì đó như
<title><?= $this->seo_title ?></title>
trong <head>
phần của trang.
Hạt
WordPress có các chức năng như get_header()
hoặc get_template_part()
có thể được sử dụng để tải các phần vào mẫu chính.
Các hàm này, giống như tất cả các hàm WordPress khác, có thể được sử dụng trong các mẫu khi sử dụng Engine
lớp.
Vấn đề duy nhất là bên trong các phần được tải bằng các chức năng cốt lõi của WordPress không thể sử dụng tính năng nâng cao để nhận dữ liệu mẫu tùy chỉnh bằng cách sử dụng $this
.
Vì lý do này, Engine
lớp có một phương thức partial()
cho phép tải một phần (theo cách tương thích hoàn toàn với chủ đề con) và vẫn có thể sử dụng trong các phần dữ liệu mẫu tùy chỉnh.
Cách sử dụng khá đơn giản.
Giả sử có một tệp có tên partials/content.php
trong thư mục theme (hoặc theme theme), nó có thể được bao gồm bằng cách sử dụng:
<?php $this->partial('partials/content') ?>
Bên trong một phần đó sẽ có thể truy cập tất cả dữ liệu chủ đề gốc là cùng một cách.
Không giống như các chức năng của WordPress, Engine::partial()
phương thức cho phép truyền dữ liệu cụ thể cho các phần, chỉ cần truyền một mảng dữ liệu làm đối số thứ hai.
<?php $this->partial('partials/content', array('greeting' => 'Welcome!')) ?>
Theo mặc định, các phần có quyền truy cập vào dữ liệu có sẵn trong chủ đề gốc và dữ liệu được thông qua.
Nếu một số biến được truyền rõ ràng cho một phần có cùng tên của biến chủ đề gốc, thì biến đó được truyền rõ ràng sẽ thắng.
Tuy nhiên, cũng có thể bao gồm một phần trong chế độ cách ly , tức là một phần không có quyền truy cập vào dữ liệu chủ đề gốc. Để làm điều đó, chỉ cần chuyển true
làm đối số thứ ba cho partial()
:
<?php $this->partial('partials/content', array('greeting' => 'Welcome!'), true) ?>
Phần kết luận
Ngay cả khi khá đơn giản, Engine
lớp học khá hoàn chỉnh, nhưng chắc chắn có thể được cải thiện hơn nữa. Ví dụ, không có cách nào để kiểm tra xem một biến có được xác định hay không.
Nhờ khả năng tương thích 100% với các tính năng WordPress và phân cấp mẫu, bạn có thể tích hợp nó với mã bên thứ ba và bên thứ ba mà không gặp vấn đề gì.
Tuy nhiên, lưu ý rằng chỉ được thử nghiệm một phần, vì vậy có thể có những vấn đề tôi chưa phát hiện ra.
Năm điểm dưới "Chúng ta đã đạt được gì?" trong câu trả lời @kaiser :
- Dễ dàng trao đổi mẫu mà không thay đổi cấu trúc dữ liệu
- Dễ đọc tempaltes
- Tránh phạm vi toàn cầu
- Có thể kiểm tra đơn vị
- Có thể trao đổi Mô hình / dữ liệu mà không làm hại các thành phần khác
tất cả đều hợp lệ cho lớp học của tôi là tốt.