Передача переменной в get_template_part
Документация WordPress говорит делать это так:
// Вы хотите сделать $my_var доступной для части шаблона в `content-part.php`
set_query_var( 'my_var', $my_var );
get_template_part( 'content', 'part' );
Но как мне выполнить echo $my_var
внутри части шаблона? get_query_var($my_var)
не работает у меня.
Я видел множество рекомендаций использовать вместо этого locate_template
. Это лучший способ?

Посты получают свои данные через the_post()
(соответственно через setup_postdata()
) и поэтому доступны через API (например, get_the_ID()
). Давайте предположим, что мы перебираем набор пользователей (поскольку setup_userdata()
заполняет глобальные переменные текущего авторизованного пользователя и не подходит для этой задачи) и попытаемся отобразить метаданные для каждого пользователя:
<?php
get_header();
// и т.д.
// В основном файле шаблона
$users = new \WP_User_Query( [ ... ] );
foreach ( $users as $user )
{
set_query_var( 'user_id', absint( $user->ID ) );
get_template_part( 'template-parts/user', 'contact_methods' );
}
Затем в нашем файле wpse-theme/template-parts/user-contact_methods.php
нам нужно получить доступ к ID пользователя:
<?php
/** @var int $user_id */
$some_meta = get_the_author_meta( 'some_meta', $user_id );
var_dump( $some_meta );
Вот и всё.
Обновление (WP >= v5.5)
Как отмечено в комментариях, текущие версии WordPress предлагают третий параметр для get_template_part()
: array $args
. Начиная с этой версии, вам больше не нужно использовать set_query_var( 'foo', 'bar' )
. Пример:
<?php
get_header();
// и т.д.
// В основном файле шаблона
$users = new \WP_User_Query( [ ... ] );
foreach ( $users as $user )
{
$args = (array) $user;
get_template_part( 'template-parts/user', 'contact_methods', $args );
}
Затем в нашем файле wpse-theme/template-parts/user-contact_methods.php
нам нужно получить доступ к ID пользователя:
<?php
/** @var array $args */
$some_meta = get_the_author_meta( 'some_meta', $args['ID'] );
var_dump( $some_meta );
Объяснение фактически приведено выше той части, которую вы процитировали в своём вопросе:
Однако
load_template()
, который вызывается косвенно черезget_template_part()
, извлекает все переменные запросаWP_Query
в область видимости загружаемого шаблона.
Нативная PHP-функция extract()
"извлекает" переменные (свойство global $wp_query->query_vars
) и помещает каждую часть в свою собственную переменную, имя которой точно соответствует ключу. Другими словами:
set_query_var( 'foo', 'bar' );
$GLOBALS['wp_query'] (object)
-> query_vars (array)
foo => bar (string 3)
extract( $wp_query->query_vars );
var_dump( $foo );
// Результат:
(string 3) 'bar'

Функция hm_get_template_part
от humanmade отлично справляется с этой задачей, и я использую её постоянно.
Вызываете так:
hm_get_template_part( 'template_path', [ 'option' => 'value' ] );
А затем внутри шаблона используете:
$template_args['option'];
для получения значения. Она также поддерживает кеширование, хотя его можно отключить, если нужно.
Можно даже получить отрендеренный шаблон в виде строки, передав 'return' => true
в массиве ключ/значение.
/**
* Аналог get_template_part(), но с возможностью передачи аргументов в файл шаблона
* Аргументы доступны в шаблоне как массив $template_args
* @param string filepart
* @param mixed wp_args стиль списка аргументов
*/
function hm_get_template_part( $file, $template_args = array(), $cache_args = array() ) {
$template_args = wp_parse_args( $template_args );
$cache_args = wp_parse_args( $cache_args );
if ( $cache_args ) {
foreach ( $template_args as $key => $value ) {
if ( is_scalar( $value ) || is_array( $value ) ) {
$cache_args[$key] = $value;
} else if ( is_object( $value ) && method_exists( $value, 'get_id' ) ) {
$cache_args[$key] = call_user_method( 'get_id', $value );
}
}
if ( ( $cache = wp_cache_get( $file, serialize( $cache_args ) ) !== false ) {
if ( ! empty( $template_args['return'] ) )
return $cache;
echo $cache;
return;
}
}
$file_handle = $file;
do_action( 'start_operation', 'hm_template_part::' . $file_handle );
if ( file_exists( get_stylesheet_directory() . '/' . $file . '.php' ) )
$file = get_stylesheet_directory() . '/' . $file . '.php';
elseif ( file_exists( get_template_directory() . '/' . $file . '.php' ) )
$file = get_template_directory() . '/' . $file . '.php';
ob_start();
$return = require( $file );
$data = ob_get_clean();
do_action( 'end_operation', 'hm_template_part::' . $file_handle );
if ( $cache_args ) {
wp_cache_set( $file, $data, serialize( $cache_args ), 3600 );
}
if ( ! empty( $template_args['return'] ) )
if ( $return === false )
return false;
else
return $data;
echo $data;
}

Я изучил вопрос и нашел различные ответы. Похоже, что на нативном уровне WordPress действительно позволяет получать доступ к переменным в частях шаблонов. Я обнаружил, что использование include в сочетании с locate_template позволяет сделать область видимости переменных доступной в файле.
include(locate_template('your-template-name.php'));

Использование include
не пройдет проверку themecheck.

// можно использовать любые значения, включая объекты
set_query_var( 'var_name_to_be_used_later', 'Значение, которое будет получено позже' );
// По сути, set_query_var использует функцию PHP extract() для выполнения "магии".
затем позже в шаблоне:
var_dump($var_name_to_be_used_later);
// выведет "Значение, которое будет получено позже"
Рекомендую почитать про функцию PHP Extract().

Обновление
Как правильно ответил selrond, начиная с WordPress 5.5 функция get_template_part() (см. список изменений) теперь принимает третий параметр array $args = array()
, который будет доступен в вашем файле шаблона как $args
.
Пример использования:
$bar = 'bar';
// загружаем helper-my-template.php
get_template_part(
'template-parts/helper',
'my-template',
array(
'foo' => $bar, // передача массива возможна начиная с WP 5.5
)
);
В вашем файле шаблона
Например, в helper-my-template.php теперь можно получить доступ к переменной следующим образом:
<?php
/**
* @var array $args
*/
$foo = $args['foo'];
?>
<h1><?php echo $foo; ?></h1>
<?php // выведет 'bar' ?>

Начиная с версии 5.5, появилась возможность передавать данные в шаблоны через различные основные функции загрузки шаблонов.
Все функции WordPress для загрузки шаблонов теперь поддерживают дополнительный параметр $args
, который позволяет авторам тем передавать ассоциативный массив данных в загружаемый шаблон. Функции, которые поддерживают этот новый параметр:
get_header()
get_footer()
get_sidebar()
get_template_part()
locate_template()
load_template()
Любые хуки, связанные с этими функциями, также передают данные.
Подробнее: https://make.wordpress.org/core/2020/07/17/passing-arguments-to-template-files-in-wordpress-5-5/

Я столкнулся с такой же проблемой в текущем проекте и решил создать небольшой плагин, который позволяет более явно передавать переменные в get_template_part с помощью новой функции.
Если вам это может быть полезно, вот страница плагина на GitHub: https://github.com/JolekPress/Get-Template-Part-With-Variables
Вот пример того, как это работает:
$variables = [
'name' => 'John',
'class' => 'featuredAuthor',
];
jpr_get_template_part_with_vars('author', 'info', $variables);
// В файле author-info.php:
echo "
<div class='$class'>
<span>$name</span>
</div>
";
// Результат:
<div class='featuredAuthor'>
<span>John</span>
</div>

Параметр $args
для функций загрузки шаблонов только что появился в WordPress 5.5 "Eckstine":
Передача данных в файлы шаблонов
Функции загрузки шаблонов (get_header(), get_template_part() и др.) получили новый аргумент $args. Теперь вы можете передавать целый массив данных в эти шаблоны.

Мне нравится плагин Pods и его функция pods_view. Она работает аналогично функции hm_get_template_part
, упомянутой в ответе djb. Я использую дополнительную функцию (findTemplate
в коде ниже) для поиска файла шаблона сначала в текущей теме, и если он не найден, возвращается шаблон с тем же именем из папки /templates
моего плагина. Вот пример того, как я использую pods_view
в своем плагине:
/**
* Вспомогательная функция для поиска шаблона
*/
function findTemplate($filename) {
// Сначала ищем в папке темы
$template = locate_template($filename);
if (!$template) {
// Если не найдено, используем файл из папки /templates плагина
$template = dirname(__FILE__) . '/templates/' . $filename;
}
return $template;
}
// Выводим шаблон 'template-name.php' из папки темы
// *или* из папки '/template' плагина, передавая две локальные
// переменные для использования в файле шаблона
pods_view(
findTemplate('template-name.php'),
array(
'passed_variable' => $variable_to_pass,
'another_variable' => $another_variable,
)
);
pods_view
также поддерживает кэширование, но мне это не понадобилось. Подробнее о параметрах функции можно узнать в документации Pods. Смотрите страницы pods_view и Частичное кэширование страниц и умные части шаблонов с Pods.

На основе ответа от @djb с использованием кода от humanmade.
Это облегчённая версия get_template_part, которая может принимать аргументы. Таким образом, переменные ограничены областью видимости этого шаблона. Нет необходимости использовать global
, get_query_var
, set_query_var
.
/**
* Аналог get_template_part(), но позволяет передавать аргументы в файл шаблона
* Аргументы доступны в шаблоне как массив $args.
* Аргументы могут передаваться как параметры URL, например 'key1=value1&key2=value2'.
* Аргументы могут передаваться как массив, например ['key1' => 'value1', 'key2' => 'value2']
* Путь к файлу доступен в шаблоне как строка $file.
* @param string $slug Имя слага для общего шаблона.
* @param string|null $name Имя специализированного шаблона.
* @param array $args Аргументы, передаваемые в шаблон
*/
function _get_template_part( $slug, $name = null, $args = array() ) {
if ( isset( $name ) && $name !== 'none' ) $slug = "{$slug}-{$name}.php";
else $slug = "{$slug}.php";
$dir = get_template_directory();
$file = "{$dir}/{$slug}";
ob_start();
$args = wp_parse_args( $args );
$slug = $dir = $name = null;
require( $file );
echo ob_get_clean();
}
Например, в cart.php
:
<? php _get_template_part( 'components/items/apple', null, ['color' => 'red']); ?>
В apple.php
:
<p>Цвет яблока: <?php echo $args['color']; ?></p>

Как насчёт этого?
render( 'template-parts/header/header', 'desktop',
array( 'user_id' => 555, 'struct' => array( 'test' => array( 1,2 ) ) )
);
function render ( $slug, $name, $arguments ) {
if ( $arguments ) {
foreach ( $arguments as $key => $value ) {
${$key} = $value;
}
}
$name = (string) $name;
if ( '' !== $name ) {
$templates = "{$slug}-{$name}.php";
} else {
$templates = "{$slug}.php";
}
$path = get_template_directory() . '/' . $templates;
if ( file_exists( $path ) ) {
ob_start();
require( $path);
ob_get_clean();
}
}
Используя ${$key}
вы можете добавлять переменные в текущую область видимости функции.
Работает у меня, быстро и просто, при этом переменные не попадают в глобальную область видимости.

Для тех, кто ищет очень простой способ передачи переменных, можно изменить функцию на include:
include( locate_template( 'YourTemplate.php', false, false ) );
После этого вы сможете использовать все переменные, которые были определены до включения шаблона, без необходимости дополнительно передавать каждую переменную в шаблон.
Автор метода: https://mekshq.com/passing-variables-via-get_template_part-wordpress/

Это точное решение, и оно отлично сработало. https://developer.wordpress.org/reference/functions/set_query_var/
