이것은 @kaiser에 대한 대안입니다. 답변에 , 꽤 괜찮은 것을 발견했지만 (+1) 핵심 WP 함수와 함께 사용하려면 추가 작업이 필요하며 템플릿 계층 구조와 통합되어 있습니다.
내가 공유하려는 접근 방식은 템플릿의 렌더 데이터를 처리하는 단일 클래스 (내가 작업중 인 것에서 제거 된 버전)를 기반으로합니다.
그것은 (IMO) 흥미로운 기능을 가지고 있습니다 :
- 템플릿은 표준 워드 프레스 템플릿 파일 (single.php, page.php)이며 약간 더 강력합니다.
- 기존 템플릿 만 작동하므로 기존 테마의 템플릿을 손쉽게 통합 할 수 있습니다.
- @kaiser 접근 방식 과 달리
$this
키워드에서 키워드를 사용하여 변수에 액세스 하면 정의되지 않은 변수의 경우 프로덕션에서 통지를 피할 수 있습니다
Engine
클래스
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()
);
}
}
( 여기 에서 Gist로 사용 가능 )
사용하는 방법
필요한 것은 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}'
첫 번째는 모든 템플릿에 대해 실행되고, 두 번째는 템플릿에 따라 다르며 사실 동적 부분 {$type}
은 파일 확장자가없는 템플릿 파일의 기본 이름입니다.
예를 들어 필터 'gm_template_data_single'
를 사용하여 데이터를single.php
템플릿 .
이러한 후크에 연결된 콜백 은 배열을 반환해야합니다 . 여기서 키는 변수 이름입니다.
예를 들어 템플릿 데이터처럼 메타 데이터를 다음과 같이 전달할 수 있습니다.
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
true가 모두 같으면 클래스는 디버그 모드에서 작동합니다. 변수가 정의되어 있지 않으면 예외가 발생 함을 의미합니다.
클래스가 디버그 모드에 있지 않을 때 (아마도 프로덕션 환경에서) 정의되지 않은 변수에 액세스하면 빈 문자열이 출력됩니다.
데이터 모델
데이터를 정리하는 좋은 방법은 모델 클래스를 사용하는 것입니다.
그것들은 위에서 설명한 것과 동일한 필터를 사용하여 데이터를 반환하는 매우 간단한 클래스 일 수 있습니다. 따라야 할 특정 인터페이스가 없으며 선호도에 따라 구성 할 수 있습니다.
아래에는 예가 있지만 자신의 방식으로 자유롭게 할 수 있습니다.
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>
페이지의 섹션을 참조하십시오.
부분
워드 프레스는 같은 기능을 가지고 get_header()
또는 get_template_part()
그 메인 템플릿에 파셜을로드 할 수 있습니다.
이 기능은 다른 모든 WordPress 기능과 마찬가지로 Engine
클래스를 사용할 때 템플릿에서 사용할 수 있습니다 .
유일한 문제는 핵심 WordPress 기능을 사용하여로드 된 부분 내부에서을 사용하여 사용자 정의 템플릿 데이터를 얻는 고급 기능 을 사용할 수 없다는 것 $this
입니다.
이러한 이유로이 Engine
클래스에는 partial()
부분 (전체 하위 테마 호환 방식)을로드하고 사용자 정의 템플릿 데이터를 부분적으로 사용할 수 있는 메소드 가 있습니다.
사용법은 매우 간단합니다.
partials/content.php
theme (또는 child theme) 폴더 안에 파일이 있다고 가정하면 다음을 사용하여 포함시킬 수 있습니다.
<?php $this->partial('partials/content') ?>
그 부분 안에서는 모든 부모 테마 데이터에 액세스하는 것이 가능합니다.
WordPress 함수와 달리이 Engine::partial()
방법을 사용하면 특정 데이터를 부분적으로 전달할 수 있으며 단순히 데이터 배열을 두 번째 인수로 전달할 수 있습니다.
<?php $this->partial('partials/content', array('greeting' => 'Welcome!')) ?>
기본적으로 partials는 상위 테마에서 사용 가능한 데이터 및 전달 된 데이터 설명에 액세스 할 수 있습니다.
부분적으로 명시 적으로 전달 된 일부 변수의 상위 테마 변수 이름이 동일하면 명시 적으로 전달 된 변수가 우선합니다.
그러나 격리 된 모드 에서 부분을 포함 할 수도 있습니다 . 즉 부분이 상위 테마 데이터에 액세스 할 수 없습니다. 그렇게하려면 true
세 번째 인수로 전달하십시오 partial()
.
<?php $this->partial('partials/content', array('greeting' => 'Welcome!'), true) ?>
결론
꽤 단순하더라도 Engine
수업은 완벽하지만 확실히 향상 될 수 있습니다. 예를 들어 변수가 정의되어 있는지 여부를 확인할 수있는 방법이 없습니다.
WordPress 기능 및 템플릿 계층 구조와 100 % 호환되므로 기존 및 타사 코드와 문제없이 통합 할 수 있습니다.
그러나 부분적으로 만 테스트되었으므로 아직 발견하지 못한 문제가있을 수 있습니다.
"우리는 무엇을 얻었습니까?" 의 다섯 가지 포인트 에서 @kaiser의 대답 :
- 데이터 구조를 변경하지 않고 템플릿을 쉽게 교환
- 템포를 쉽게 읽을 수 있습니다
- 글로벌 범위를 피하십시오
- 단위 테스트 가능
- 다른 부품을 손상시키지 않고 모델 / 데이터 교환 가능
수업에도 유효합니다.