Closed sayontan closed 2 years ago
This is not a problem with Hierarchy.
Hierarchy default "loader" is FileRequireLoader
(https://github.com/Brain-WP/Hierarchy/blob/master/src/Loader/FileRequireLoader.php) which does a a simple require
of the template file, and so you can use $this
inside templates required like that.
If you want to use both Hierarchy's QueryTemplate
and a "renderer" object, you have to create your own loader, kile it is examplained at the end of the README, in the "QueryTemplate Usage Example: Loading and Rendering Mustache Templates" section.
Instead of using a mustache engine, you would use your custom engine.
Something like this:
<?php
namespace MyTheme;
class Template
{
private $context;
private $baseDir = '';
public function __construct(array $context = [])
{
$this->context = $context;
}
public function __get(string $name)
{
return $this->context[$name] ?? '';
}
public function render(string $template): string
{
$this->baseDir = trailingslashit(dirname($template));
ob_start();
require $template;
return ob_get_clean() ?: '';
}
public function partial(string $template, array $data = []): string
{
$newObj = new self(array_merge($this->context, $data));
if (!is_file($template) && is_file($this->baseDir . $template)) {
$template = $this->baseDir . $template;
}
return $newObj->render($template);
}
}
class MyLoader implements \Brain\Hierarchy\Loader\Loader
{
public function load(string $templatePath): string
{
global $wp_query, $wp;
$baseData = ['query' => $wp_query, 'wp' => $wp];
// You need a way to build data to pass to templates...
$data = (array)apply_filters('my_theme_template_data', $baseData, $templatePath, $wp_query, $wp);
return (new Template($data))->render($templatePath);
}
}
(Please note the code above uses Hierarchy version 3.0 released today. In version 2 the interface had a different name.)
At that point you could do:
add_action('template_redirect', function(): void
{
if (!\Brain\Hierarchy\QueryTemplate::mainQueryTemplateAllowed()) {
return;
}
global $wp_query;
$template = new \Brain\Hierarchy\QueryTemplate();
echo $template->loadTemplate($wp_query);
exit;
}, 99);
An then you can write templates using the standard WP hierarchy, but inside templates you can use $this->varName
to access variables passed in the main template "data", and you can use $this->partial('templateName')
to load partials using relative path to templates instead of full paths.
And inside partials you'll have access to both the "main" data, plus and data that you could pass explicitly via $this->partial()
method.
WP functions like get_header()
or get_footer()
will continue to work, but in the templates they'll load (header.php
/footer.php
) you'll not have access to the main data passed to your templates, nor you'll be able to use $this
inside header.php
and/or footer.php
.
However, nothing stops you to use $this->partial('header')
/ $this->partial('footer')
if you want to keep the same approach even in header/footer files, but then you'd probably want to trigger manually WP hooks. For example:
// this is index.php, for example
do_action('get_header', '', $this->context);
$this->partial('header');
/* ...rest of template here.. */
do_action('get_footer', '', $this->context);
$this->partial('footer');
To be honest this is probably more of a request for help rather than a bug report.
I reached this package from a StackOverflow thread (https://wordpress.stackexchange.com/questions/184235/best-way-of-passing-php-variable-between-partials). In there you have described a way to pass variables to templates without putting them in global scope. I was using that approach as the foundation for my theme, but I ran into issues when I tried combining it with a plugin that adds WooCommerce support to my theme (basically it was hell trying to get WooCommerce to read from a file in my plugin's folders). That brought me to the "Hierarchy" project that you have, since it helps define additional paths to traverse.
However, once I put in the code, I started running into a different issue. Let's say I have a file, index.php. This gets picked up by the approach you have in the ReadMe.
However, in index.php there if I have
$this->partial('header');
as per the SO post (header.php is a file in the theme), I get an error saying thatpartial
is not a method defined inFile_Require_Loader
(my files are renamed with underscores)If I switch out the call to
get_header()
instead, I get an error from header.php sayingUncaught Error: Using $this when not in object context
. That is becauseheader.php
also makes use of$this->partial()
.So, regardless of what I do, I cannot get past the first step. Obviously there is no method called
partial
in File_Require_Loader. But I am unable to figure out what the equivalent method is. I tried usingload
, but that tells me that there is no file calledheader
(since the code is doing arequire $templatePath
).It is likely that I am doing something incorrectly or that I am missing something, but I cannot figure out what.
This is my basic flow:
functions.php
has a call,add_action('after_setup_theme', 'my_theme_setup');
my_theme_setup
I have a call to the constructor of my core framework file.The constructor of my core framework file has this: