¿Plantillas de Tipos de Entrada Personalizados desde la Carpeta del Plugin?
Me gustaría ofrecer mi tipo de entrada personalizado como un Plugin, para que la gente pueda usarlo sin tener que tocar la carpeta de su tema. Pero las plantillas de tipos de entrada personalizados -- como single-movies.php -- residen en la carpeta del tema. ¿Hay alguna manera de hacer que WordPress busque el archivo single-movies.php en la carpeta del plugin? ¿Enlazando una función en la Jerarquía de Filtros? ¿O usando get_template_directory(); ?

Puedes usar el hook de filtro single_template
.
/* Filtrar el single_template con nuestra función personalizada */
add_filter('single_template', 'my_custom_template');
function my_custom_template($single) {
global $post;
/* Verifica la plantilla single por tipo de post */
if ( $post->post_type == 'NOMBRE DEL TIPO DE POST' ) {
if ( file_exists( RUTA_DEL_PLUGIN . '/Archivo_Personalizado.php' ) ) {
return RUTA_DEL_PLUGIN . '/Archivo_Personalizado.php';
}
}
return $single;
}

Es una respuesta increíble. Por favor comparte dónde puedo obtener todos los hooks de plantilla disponibles como single_template.

@gowri El filtro es llamado por la función get_query_template()
. Es un hook variable, por lo que la primera parte {$type}_template
cambia dependiendo del parámetro que se pase a esa función. Mira wp-includes/template.php para algunos ejemplos comunes

Este tutorial cubre el hook single_template con una buena explicación. Una vez que entiendas los hooks, el comentario de @shea sugiere un enfoque más simple que la respuesta de @Bainternet, usando add_filter( 'single-movies_template', 'my_custom_template' );
como en el tutorial enlazado. (Esta pregunta está cerrada a nuevas respuestas, así que no puedo agregarla por sí sola.)

Podrías reemplazar PLUGIN_PATH
con plugin_dir_path( __FILE__ )
y luego eliminar la primera barra del nombre de tu archivo. La ruta completa se vería algo así: return plugin_dir_path( __FILE__ ) . 'Custom_File.php';

PLUGIN_PATH generó un error, aquí hay una publicación excelente que muestra cómo hacer esto y funcionó para mí inmediatamente: https://wpsites.net/free-tutorials/load-single-template-from-plugin-for-different-post-types/

Respuesta actualizada
Versión más limpia y corta.
function load_movie_template( $template ) {
global $post;
if ( 'movie' === $post->post_type && locate_template( array( 'single-movie.php' ) ) !== $template ) {
/*
* Esto es un post de tipo 'movie'
* Y no se encuentra una plantilla 'single movie' en
* los directorios del tema o tema hijo, así que cargarla
* desde el directorio de nuestro plugin.
*/
return plugin_dir_path( __FILE__ ) . 'single-movie.php';
}
return $template;
}
add_filter( 'single_template', 'load_movie_template' );
Respuesta anterior
Añadida una comprobación para una plantilla específica de tipo de post personalizado en la carpeta del tema a la respuesta de @Brainternet.
function load_cpt_template($template) {
global $post;
// ¿Es este un post de tipo "my-custom-post-type"?
if ($post->post_type == "my-custom-post-type"){
// Ruta de tu plugin
$plugin_path = plugin_dir_path( __FILE__ );
// Nombre de la plantilla single para el tipo de post personalizado
$template_name = 'single-my-custom-post-type.php';
// ¿Existe una plantilla single específica para mi tipo de post en la carpeta del tema? ¿O tampoco existe en mi plugin?
if($template === get_stylesheet_directory() . '/' . $template_name
|| !file_exists($plugin_path . $template_name)) {
// Entonces devuelve "single.php" o "single-my-custom-post-type.php" del directorio del tema.
return $template;
}
// Si no, devuelve la plantilla del tipo de post personalizado de mi plugin.
return $plugin_path . $template_name;
}
// Esto no es mi tipo de post personalizado, no hacer nada con $template
return $template;
}
add_filter('single_template', 'load_cpt_template');
Ahora puedes permitir que los usuarios del plugin copien la plantilla desde tu plugin a su tema para sobrescribirla.
Con este ejemplo, las plantillas deben estar en el directorio raíz tanto del plugin como del tema.

Usar locate_template
en lugar de get_stylesheet_directory
me parece la opción más limpia (encontrado aquí: http://code.tutsplus.com/tutorials/a-guide-to-wordpress-custom-post-types-creation-display-and-meta-boxes--wp-27645).

La respuesta actualizada no funcionó, la respuesta aceptada (o tu respuesta antigua) sí funciona.

Me gustaría señalar que cuando estás utilizando el método de filtro para esto, es extremadamente importante priorizar el filtro de la siguiente manera:
add_filter('single_template', 'my_custom_template', 99);
Si no haces esto, a veces WordPress intentará volver a verificar después de este filtro. Me estuve arrancando los pelos por esto durante como 2 horas.

En mis propios plugins suelo utilizar locate_template()
lo que permite anular la plantilla del plugin copiándola en el tema actual:
function templateInclude(string $template): string
{
if (is_single() && get_query_var('post_type') === 'custom_post_type') {
$templates = [
'single-custom_post.php',
'templates/single-custom_post.php'
];
$template = locate_template($templates);
if (!$template) {
$template = __DIR__ . '/templates/single-custom_post.php';
}
}
return $template;
}
add_filter('template_include', 'templateInclude');
Ahora el usuario puede anular la plantilla del plugin copiándola desde la carpeta del plugin templates/single-custom_post.php
y colocándola directamente en la raíz o dentro de una carpeta templates
en el tema activo.
Supongo que deberías poder usar el mismo enfoque cuando utilices el filtro single_template
también.

Hay una forma mucho mejor de hacerlo que estoy usando para mis plugins.
Como @campsjos menciona aquí, en lugar de verificar la existencia del archivo, puedes verificar
locate_template
que buscará en el archivo de plantilla anulado por el tema. Lo cual es bastante obvio.
function my_plugin_templates() {
if (is_singular('movie')) {
if (file_exists($this->template_dir . 'single-movie.php')) {
return $this->template_dir . 'single-movie.php';
}
}
}
Usa el filtro template_include
para cargar el código anterior.
add_filter('template_include' , 'my_plugin_templates');

gracias a esta página pude resolver la misma pregunta para mí.
Como referencia, esto es con lo que terminé:
function pluginName_myposttype_single_template($single_template) {
$myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';
return get_post_type() === 'myposttype' && file_exists($myposttype_template) ? $myposttype_template : $single_template;
}
add_filter('single_template', 'pluginName_myposttype_single_template');
el hook de filtro {$type}_template no funcionó para mí
function pluginName_myposttype_single_template($single_template) {
$myposttype_template = PLUGIN_DIR . 'templates/single-myposttype.php';
if ( file_exists($myposttype_template) ) {
$single_template = $myposttype_template;
}
return $single_template;
}
add_filter('single-myposttype_template', 'pluginName_myposttype_single_template');

Esto funcionó para mí, por favor pruébalo, gracias.
Las plantillas se cargan en el archivo cpt, que se encuentra en
custom_plugin -> app -> cpt -> cpt_article.php
La plantilla está ubicada en
custom_plugin -> app -> templates
add_filter( 'single_template', 'load_my_custom_template', 99, 1 );
function load_custom_templates($single_template) {
global $post;
if ($post->post_type == 'article' ) {
$single_template = trailingslashit( plugin_dir_path( __FILE__ ) .'app/templates' ).'single_article.php';
}
return $single_template;
}

La respuesta anterior es excelente, pero verificando la variable $single permite que la plantilla sobrescriba una plantilla si esta es proporcionada por el tema/child theme.
/* Filtra el single_template con nuestra función personalizada */
add_filter('single_template', 'your_cpt_custom_template');
function your_cpt_custom_template( $single ) {
global $wp_query, $post;
/* Verifica la plantilla individual por tipo de publicación */
if ( !$single && $post->post_type == 'cpt' ) {
if( file_exists( plugin_dir_path( __FILE__ ) . 'single-cpt.php' ) )
return plugin_dir_path( __FILE__ ) . 'single-cpt.php';
}
return $single;
}

Esto no verifica si single-cpt.php está presente en un child theme o en el tema principal. Solo verifica contra single.php que siempre estará presente en cualquier tema.
