นี่เป็นวิธีทางเลือกสำหรับคำตอบ@kaiserซึ่งฉันพบว่าค่อนข้างดี (+1 จากฉัน) แต่ต้องการงานเพิ่มเติมที่จะใช้กับฟังก์ชั่น core WP และเป็นแบบต่อเนื่องที่รวมเข้ากับลำดับชั้นของเทมเพลต
วิธีที่ฉันต้องการแบ่งปันนั้นขึ้นอยู่กับชั้นเรียนเดียว (เป็นเวอร์ชันที่แยกออกมาจากสิ่งที่ฉันกำลังทำอยู่) ที่ดูแลข้อมูลการแสดงผลสำหรับเทมเพลต
มันมีคุณสมบัติที่น่าสนใจ (IMO):
- แม่แบบเป็นไฟล์แม่แบบ WordPress มาตรฐาน (single.php, page.php) พวกเขาได้รับพลังงานมากขึ้นเล็กน้อย
- เทมเพลตที่มีอยู่ใช้งานได้ดังนั้นคุณสามารถรวมเทมเพลตจากธีมที่มีอยู่ได้โดยไม่ต้องใช้ความพยายาม
- ซึ่งแตกต่างจากวิธี@kaiserในแม่แบบที่คุณเข้าถึงตัวแปรโดยใช้
$this
คำสำคัญ: สิ่งนี้ทำให้คุณมีโอกาสที่จะหลีกเลี่ยงการแจ้งเตือนในการผลิตในกรณีที่มีตัวแปรที่ไม่ได้กำหนด
The Engine
Class
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()
);
}
}
(มีอยู่ในส่วนสำคัญที่นี่)
วิธีใช้
สิ่งเดียวที่จำเป็นคือการเรียกEngine::init()
วิธีการที่อาจเกี่ยวกับ'template_redirect'
ตะขอ ที่สามารถทำได้ในรูปแบบfunctions.php
หรือจากปลั๊กอิน
require_once '/path/to/the/file/Engine.php';
add_action('template_redirect', array('GM\Template\Engine', 'init'), 99);
นั่นคือทั้งหมดที่
แม่แบบที่มีอยู่ของคุณจะทำงานตามที่อธิบายไว้ แต่ตอนนี้คุณมีความเป็นไปได้ในการเข้าถึงข้อมูลแม่แบบที่กำหนดเอง
ข้อมูลเทมเพลตที่กำหนดเอง
ในการส่งผ่านข้อมูลที่กำหนดเองไปยังเทมเพลตมีสองตัวกรองดังนี้
'gm_template_data'
'gm_template_data_{$type}'
อันแรกนั้นใช้สำหรับเทมเพลตทั้งหมดส่วนที่สองคือเทมเพลตเฉพาะอันที่จริงแล้วส่วน dymamic {$type}
เป็นชื่อไฟล์พื้นฐานของไฟล์เทมเพลตที่ไม่มีนามสกุลไฟล์
เช่นตัวกรอง'gm_template_data_single'
สามารถใช้เพื่อส่งผ่านข้อมูลไปยังsingle.php
เทมเพลต
การเรียกกลับที่แนบมากับ hooks เหล่านี้จะต้องส่งคืนอาร์เรย์โดยที่คีย์คือชื่อตัวแปร
ตัวอย่างเช่นคุณสามารถส่งผ่านข้อมูลเมตาเป็นข้อมูลเทมเพลตที่ชอบ:
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;
};
จากนั้นภายในเทมเพลตคุณสามารถใช้:
<?= $this->extra_title ?>
โหมดแก้ไขข้อบกพร่อง
เมื่อทั้งค่าคงที่WP_DEBUG
และWP_DEBUG_DISPLAY
เป็นจริงคลาสจะทำงานในโหมดดีบัก หมายความว่าหากไม่ได้กำหนดตัวแปรข้อยกเว้นจะถูกส่งออกไป
เมื่อคลาสไม่ได้อยู่ในโหมดดีบัก (อาจเป็นในการผลิต) การเข้าถึงตัวแปรที่ไม่ได้กำหนดจะส่งออกสตริงว่างเปล่า
ตัวแบบข้อมูล
วิธีที่ดีและบำรุงรักษาในการจัดระเบียบข้อมูลของคุณคือการใช้คลาสโมเดล
พวกเขาสามารถเป็นคลาสที่ง่ายมากที่ส่งคืนข้อมูลโดยใช้ตัวกรองเดียวกันที่อธิบายไว้ข้างต้น ไม่มีอินเทอร์เฟซพิเศษให้ติดตามพวกเขาสามารถจัดระเบียบตามความต้องการของคุณ
ด้านล่างมีเพียงตัวอย่าง แต่คุณมีอิสระที่จะทำในแบบของคุณเอง
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);
__invoke()
วิธี (ที่วิ่งเมื่อชั้นถูกนำมาใช้เช่นการติดต่อกลับ) กลับสตริงที่จะใช้สำหรับ<title>
แท็กของแม่
ขอบคุณที่ข้อเท็จจริงที่ว่าอาร์กิวเมนต์ที่สองผ่านไป'gm_template_data'
เป็นชื่อแม่แบบวิธีการส่งกลับชื่อที่กำหนดเองสำหรับหน้าแรก
มีรหัสข้างต้นเป็นไปได้ที่จะใช้สิ่งที่ชอบ
<title><?= $this->seo_title ?></title>
ใน<head>
ส่วนของหน้า
partials
WordPress มีฟังก์ชั่นเช่นget_header()
หรือget_template_part()
ที่สามารถใช้ในการโหลดบางส่วนลงในเทมเพลตหลัก
ฟังก์ชั่นเหล่านี้เช่นเดียวกับฟังก์ชั่น WordPress อื่น ๆ สามารถใช้ในเทมเพลตเมื่อใช้Engine
คลาส
ปัญหาเดียวก็คือว่าภายใน partials โหลดโดยใช้ฟังก์ชั่นหลัก WordPress เป็นไปไม่ได้ที่จะใช้ขั้นสูง$this
คุณลักษณะของการรับข้อมูลโดยใช้แม่แบบกำหนดเอง
ด้วยเหตุผลนี้Engine
คลาสมีวิธีการpartial()
ที่อนุญาตให้โหลดบางส่วน (ในวิธีที่เข้ากันได้กับธีมลูกทั้งหมด) และยังสามารถใช้ในส่วนของเทมเพลตข้อมูลที่กำหนดเองได้
การใช้งานค่อนข้างง่าย
สมมติว่ามีไฟล์ชื่อpartials/content.php
ในโฟลเดอร์ theme (หรือธีมลูก) มันสามารถรวมโดยใช้:
<?php $this->partial('partials/content') ?>
ภายในบางส่วนนั้นจะสามารถเข้าถึงข้อมูลธีมหลักทั้งหมดได้ในลักษณะเดียวกัน
ซึ่งแตกต่างจากฟังก์ชั่น WordPress Engine::partial()
วิธีการอนุญาตให้ส่งผ่านข้อมูลที่เฉพาะเจาะจงไปยัง partials เพียงแค่ส่งอาร์เรย์ของข้อมูลเป็นอาร์กิวเมนต์ที่สอง
<?php $this->partial('partials/content', array('greeting' => 'Welcome!')) ?>
โดยค่าเริ่มต้น partials สามารถเข้าถึงข้อมูลที่มีอยู่ในชุดรูปแบบหลักและส่งผ่านข้อมูลอย่างชัดเจน
หากตัวแปรบางตัวที่ส่งผ่านไปยังบางส่วนมีชื่อเดียวกันของตัวแปรธีมหลักอย่างชัดเจนดังนั้นตัวแปรนั้นจะผ่านการชนะอย่างชัดเจน
อย่างไรก็ตามยังเป็นไปได้ที่จะรวมบางส่วนในโหมดแยกเช่นบางส่วนไม่มีการเข้าถึงข้อมูลชุดรูปแบบหลัก ในการทำเช่นนั้นให้ส่งtrue
อาร์กิวเมนต์ที่สามไปที่partial()
:
<?php $this->partial('partials/content', array('greeting' => 'Welcome!'), true) ?>
ข้อสรุป
แม้ว่าจะค่อนข้างเรียบง่าย แต่Engine
คลาสก็ค่อนข้างสมบูรณ์ แต่ก็สามารถปรับปรุงให้ดีขึ้นได้ เช่นไม่มีวิธีการตรวจสอบว่ามีการกำหนดตัวแปรหรือไม่
ด้วยความเข้ากันได้ 100% กับฟีเจอร์ WordPress และลำดับชั้นของเทมเพลตคุณสามารถรวมเข้ากับโค้ดที่มีอยู่และรหัสบุคคลที่สามได้โดยไม่มีปัญหา
อย่างไรก็ตามโปรดทราบว่ามีการทดสอบเพียงบางส่วนเท่านั้นดังนั้นจึงอาจมีปัญหาที่ฉันยังไม่ได้ค้นพบ
ห้าคะแนนภายใต้"เราได้อะไรมา?" ในคำตอบ@kaiser :
- แลกเปลี่ยนแม่แบบได้อย่างง่ายดายโดยไม่ต้องเปลี่ยนโครงสร้างข้อมูล
- อ่านเทมเพิลได้ง่าย
- หลีกเลี่ยงขอบเขตทั่วโลก
- สามารถทดสอบหน่วย
- สามารถแลกเปลี่ยนข้อมูลรุ่น / ข้อมูลโดยไม่ทำอันตรายส่วนประกอบอื่น ๆ
ถูกต้องสำหรับชั้นเรียนของฉันเช่นกัน