Pasar una variable a get_template_part
El WP Codex dice que hay que hacer esto:
// Deseas hacer que $my_var esté disponible en la plantilla en `content-part.php`
set_query_var( 'my_var', $my_var );
get_template_part( 'content', 'part' );
Pero ¿cómo hago echo $my_var
dentro de la parte de la plantilla? get_query_var($my_var)
no me funciona.
He visto muchas recomendaciones para usar locate_template
en su lugar. ¿Es esa la mejor manera de hacerlo?

Como las entradas obtienen sus datos configurados a través de the_post()
(respectivamente mediante setup_postdata()
) y por lo tanto son accesibles a través de la API (get_the_ID()
por ejemplo), asumamos que estamos iterando a través de un conjunto de usuarios (ya que setup_userdata()
llena las variables globales del usuario actualmente conectado y no es útil para esta tarea) e intentemos mostrar metadatos por usuario:
<?php
get_header();
// etc.
// En el archivo de plantilla principal
$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' );
}
Luego, en nuestro archivo wpse-theme/template-parts/user-contact_methods.php
, necesitamos acceder al ID del usuario:
<?php
/** @var int $user_id */
$some_meta = get_the_author_meta( 'some_meta', $user_id );
var_dump( $some_meta );
Eso es todo.
Actualización (WP >= v5.5)
Como se menciona en los comentarios, las versiones actuales de WP ofrecen un tercer parámetro para get_template_part()
: array $args
. Así que desde esta versión, no necesitas usar set_query_var( 'foo', 'bar' )
nunca más. Ejemplo:
<?php
get_header();
// etc.
// En el archivo de plantilla principal
$users = new \WP_User_Query( [ ... ] );
foreach ( $users as $user )
{
$args = (array) $user;
get_template_part( 'template-parts/user', 'contact_methods', $args );
}
Luego, en nuestro archivo wpse-theme/template-parts/user-contact_methods.php
, necesitamos acceder al ID del usuario:
<?php
/** @var array $args */
$some_meta = get_the_author_meta( 'some_meta', $args['ID'] );
var_dump( $some_meta );
La explicación está realmente justo arriba de la parte que citaste en tu pregunta:
Sin embargo,
load_template()
, que es llamado indirectamente porget_template_part()
, extrae todas las variables de consulta deWP_Query
dentro del alcance de la plantilla cargada.
La función nativa de PHP extract()
"extrae" las variables (la propiedad global $wp_query->query_vars
) y coloca cada parte en su propia variable que tiene exactamente el mismo nombre que la clave. En otras palabras:
set_query_var( 'foo', 'bar' );
$GLOBALS['wp_query'] (objeto)
-> query_vars (array)
foo => bar (string 3)
extract( $wp_query->query_vars );
var_dump( $foo );
// Resultado:
(string 3) 'bar'

La función hm_get_template_part
de humanmade es extremadamente buena para esto y la uso todo el tiempo.
La llamas así:
hm_get_template_part( 'ruta_del_template', [ 'opcion' => 'valor' ] );
y luego dentro de tu plantilla, usas
$template_args['opcion'];
para obtener el valor. Maneja caché y todo, aunque puedes quitarlo si lo prefieres.
Incluso puedes devolver la plantilla renderizada como una cadena pasando 'return' => true
en el array de pares clave/valor.
/**
* Similar a get_template_part() pero permite pasar argumentos al archivo de plantilla
* Los argumentos están disponibles en la plantilla como el array $template_args
* @param string filepart
* @param mixed wp_args lista de argumentos al estilo de WordPress
*/
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;
}

Estuve investigando y encontré una variedad de respuestas. Parece que, de forma nativa, WordPress no permite acceder a variables en partes de plantillas (Template parts). Sin embargo, descubrí que usando include
junto con locate_template
sí permite que el alcance de las variables sea accesible en el archivo.
include(locate_template('nombre-de-tu-plantilla.php'));

Usar include
no pasará themecheck.

// puedes usar cualquier valor incluyendo objetos.
set_query_var( 'var_name_to_be_used_later', 'Valor a recuperar después' );
//Básicamente set_query_var usa la función extract() de PHP para hacer la magia.
luego más adelante en la plantilla.
var_dump($var_name_to_be_used_later);
//mostrará "Valor a recuperar después"
Recomiendo leer sobre la función PHP Extract().

Actualización
Como selrond respondió correctamente, a partir de WordPress 5.5 get_template_part() (ver changelog) ahora acepta un tercer parámetro array $args = array()
, que estará disponible en tu archivo de plantilla como $args
.
Mira este ejemplo:
$bar = 'bar';
// obtener helper-my-template.php
get_template_part(
'template-parts/helper',
'my-template',
array(
'foo' => $bar, // pasar este array es posible desde WP 5.5
)
);
En tu archivo de plantilla
ej. helper-my-template.php ahora puedes acceder a tu variable así:
<?php
/**
* @var array $args
*/
$foo = $args['foo'];
?>
<h1><?php echo $foo; ?></h1>
<?php // imprimirá 'bar' ?>

A partir de la versión 5.5, será posible pasar datos a las plantillas a través de las diversas funciones principales de carga de plantillas.
Todas las funciones de WordPress para cargar plantillas admitirán un parámetro adicional llamado $args
, que permite a los autores de temas pasar un array asociativo de datos a la plantilla cargada. Las funciones que admiten este nuevo parámetro son:
get_header()
get_footer()
get_sidebar()
get_template_part()
locate_template()
load_template()
Cualquier hook asociado con estas funciones también pasará los datos.
Para más información: https://make.wordpress.org/core/2020/07/17/passing-arguments-to-template-files-in-wordpress-5-5/

Me encontré con este mismo problema en un proyecto en el que estoy trabajando actualmente. Decidí crear mi propio pequeño plugin que permite pasar variables de manera más explícita a get_template_part usando una nueva función.
Por si te resulta útil, aquí está la página del proyecto en GitHub: https://github.com/JolekPress/Get-Template-Part-With-Variables
Y aquí un ejemplo de cómo funcionaría:
$variables = [
'name' => 'John',
'class' => 'featuredAuthor',
];
jpr_get_template_part_with_vars('author', 'info', $variables);
// En author-info.php:
echo "
<div class='$class'>
<span>$name</span>
</div>
";
// Mostraría:
<div class='featuredAuthor'>
<span>John</span>
</div>

El parámetro $args
para las funciones de carga de plantillas acaba de llegar en WordPress 5.5 "Eckstine":
Pasar datos a archivos de plantilla
Las funciones de carga de plantillas (get_header(), get_template_part(), etc.) tienen un nuevo argumento $args. Así que ahora puedes pasar toda una matriz de datos a esas plantillas.

Me gusta el plugin Pods y su función pods_view. Funciona de manera similar a la función hm_get_template_part
mencionada en la respuesta de djb. Yo uso una función adicional (findTemplate
en el código a continuación) para buscar primero un archivo de plantilla en el tema actual, y si no se encuentra, devuelve la plantilla con el mismo nombre en la carpeta /templates
de mi plugin. Esta es una idea aproximada de cómo uso pods_view
en mi plugin:
/**
* Función auxiliar para encontrar una plantilla
*/
function findTemplate($filename) {
// Buscar primero en la carpeta del tema
$template = locate_template($filename);
if (!$template) {
// De lo contrario, usar el archivo en la carpeta /templates de nuestro plugin
$template = dirname(__FILE__) . '/templates/' . $filename;
}
return $template;
}
// Mostrar la plantilla 'template-name.php' desde la carpeta del tema
// *o* desde la carpeta '/template' de nuestro plugin, pasando dos variables
// locales para que estén disponibles en el archivo de plantilla
pods_view(
findTemplate('template-name.php'),
array(
'passed_variable' => $variable_to_pass,
'another_variable' => $another_variable,
)
);
pods_view
también soporta caché, pero no lo necesité para mis propósitos. Puedes encontrar más información sobre los argumentos de la función en las páginas de documentación de Pods. Consulta las páginas de pods_view y Almacenamiento en caché parcial de páginas y partes de plantillas inteligentes con Pods.

Basado en la respuesta de @djb utilizando código de humanmade.
Esta es una versión ligera de get_template_part que puede aceptar argumentos. De esta manera, las variables tienen alcance local dentro de esa plantilla. No es necesario usar global
, get_query_var
, set_query_var
.
/**
* Similar a get_template_part() pero permite pasar argumentos al archivo de plantilla
* Los argumentos están disponibles en la plantilla como el array $args.
* Los argumentos pueden pasarse como parámetros URL, ej: 'key1=value1&key2=value2'.
* Los argumentos pueden pasarse como un array, ej: ['key1' => 'value1', 'key2' => 'value2']
* La ruta del archivo está disponible en la plantilla como el string $file.
* @param string $slug El nombre slug para la plantilla genérica.
* @param string|null $name El nombre de la plantilla especializada.
* @param array $args Los argumentos pasados a la plantilla
*/
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();
}
Por ejemplo en cart.php
:
<? php _get_template_part( 'components/items/apple', null, ['color' => 'red']); ?>
En apple.php
:
<p>El color de la manzana es: <?php echo $args['color']; ?></p>

¿Qué tal esto?
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();
}
}
Al usar ${$key}
puedes agregar las variables al ámbito actual de la función.
Funciona para mí, rápido y fácil, y no se filtra ni se almacena en el ámbito global.

Para aquellos que buscan una forma muy sencilla de pasar variables, puedes cambiar la función para incluir:
include( locate_template( 'TuPlantilla.php', false, false ) );
Y así podrás usar todas las variables que están definidas antes de incluir la plantilla, sin necesidad de PASAR adicionalmente cada una a la plantilla.
Créditos para: https://mekshq.com/passing-variables-via-get_template_part-wordpress/

Esta es la solución exacta y funcionó correctamente. https://developer.wordpress.org/reference/functions/set_query_var/
