Añadir página de plantilla personalizada programáticamente
Estoy intentando añadir una página de plantilla desde un plugin, y mi archivo de plantilla está en la carpeta del plugin. ¿Es esto posible? Aquí está mi código:
global $user_ID;
$new_post = array(
'post_title' => 'Test Template Page',
'post_content' => 'Some text',
'post_status' => 'publish',
'post_date' => date('Y-m-d H:i:s'),
'post_author' => $user_ID,
'post_type' => 'page',
'post_category' => array(0)
);
$post_id = wp_insert_post($new_post);
if (!$post_id) {
wp_die('Error creating template page');
} else {
update_post_meta($post_id, '_wp_page_template', 'tp-file.php');
}
tp-file.php es mi página de plantilla personalizada. Cuando coloco ese archivo en la carpeta my-theme, funciona bien, pero quiero hacer esto con el archivo desde la carpeta del plugin para no tener que obligar a los usuarios a copiar ese archivo desde la carpeta del plugin a la carpeta del tema. ¿Es esto posible? ¿Alguna idea?

El artículo enlazado va por buen camino, pero lo haré más simple para ti.. ;)
add_filter( 'page_template', 'catch_plugin_template' );
function catch_plugin_template( $template ) {
if( 'tp-file.php' == basename( $template ) )
$template = WP_PLUGIN_DIR . '/yourpluginname/tp-file.php';
return $template;
}
El filtro básicamente verifica si tu plantilla de página especial está configurada para la página actual, si es así, actualiza la ruta para apuntar a la plantilla de tu plugin.
Solo asegúrate de que la ruta sea correcta, de lo contrario verás errores de inclusión... :)
Seguimiento #1
Ok, el primer problema es que WordPress valida cualquier plantilla configurada como plantilla de página, es decir, verifica si el archivo está en la carpeta del tema y es un archivo de plantilla válido, si no, lo omite e incluye una plantilla más genérica, como page.php...
Sin embargo, esto no cambia el hecho de que el campo meta aún contiene el valor de tu plantilla personalizada, y también is_page_template( 'tp-file.php' )
devolverá correctamente true si se usa en lugar de mi declaración condicional anterior, por ejemplo..
// Filtro de plantilla de página
add_filter('page_template', 'catch_plugin_template');
// Callback del filtro de plantilla de página
function catch_plugin_template($template) {
// Si tp-file.php es la plantilla configurada
if( is_page_template('tp-file.php') )
// Actualizar ruta (debe ser una ruta, usa WP_PLUGIN_DIR y no WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Devolver
return $template;
}
NOTA: He cambiado el código para usar WP_PLUGIN_DIR
ya que la constante WP_PLUGIN_URL
no es adecuada para rutas... (los includes deben usar una ruta, no una URL).
Un problema, y esto realmente no es algo que puedas solucionar, es que al ver la página desde el área de administración, al editar la página, la plantilla no aparecerá como la plantilla activa, y guardar cambios podría, por supuesto, cambiar la plantilla activa. No hay mucho que podamos hacer allí, el menú desplegable de plantillas de página se genera a partir de una función que escanea los archivos del tema, no hay hooks disponibles que permitan extender la lista con plantillas de plugins.
Personalmente, lo que sugeriría, como solución alternativa, sería guardar un campo meta adicional con cada página creada usando tu plugin especial, luego agregar un hook a save_post
o wp_insert_post_data
y verificar si este campo meta existe, si existe, también verificar que la plantilla de página esté configurada como tp-file.php
, y si no, actualizarla a tp-file.php
. El campo meta adicional sería simplemente una bandera, por así decirlo, para indicar qué páginas necesitan tener adjunta la plantilla de tu plugin.
Aquí tienes tu plugin funcionando en su forma más básica (sí, lo probé)... :)
<?php
/*
Plugin Name: TP Test Plugin
Plugin URI:
Description: TP Test Plugin
Version: 1.0.0
Author:
Author URI:
*/
global $wp_version;
if( version_compare( $wp_version, "2.9", "<" ) )
exit( 'Este plugin requiere WordPress 2.9 o más reciente. <a href="http://codex.wordpress.org/Upgrading_WordPress">¡Por favor actualiza!</a>' );
// Agregar callback al menú de administración
add_action('admin_menu', 'create_tp_menu');
// Callback para agregar elementos al menú
function create_tp_menu() {
add_management_page('TP Test', 'TP Test', 'manage_options', 'tp-teste', 'wp_tp_test_fnc' );
}
function wp_tp_test_fnc() {
//include('tp-form-file.php');
if( !empty( $_POST['tp_name'] ) ) {
$tp_name = $_POST['tp_name'];
global $user_ID;
$new_post = array(
'post_title' => $tp_name,
'post_content' => 'Algún texto',
'post_status' => 'publish',
'post_date' => date('Y-m-d H:i:s'),
'post_author' => $user_ID,
'post_type' => 'page',
);
$post_id = wp_insert_post($new_post);
if( !$post_id )
wp_die('Error al crear la página de plantilla');
else
update_post_meta( $post_id, '_wp_page_template', 'tp-file.php' );
/*
$pt = get_page_templates();
$pt['TP file test'] = WP_PLUGIN_URL . '/tp-test/tp-file.php';
echo "<pre>";
print_r($pt);
echo "</pre>";
*/
}
?>
<fieldset style="margin: 50px 100px;background-color: #cccccc;padding: 30px;border: 1px solid #ccc">
<legend style="background-color: #ccccff;padding: 20px;font-weight: bold;font-size: 18px">Crear Página de Plantilla</legend>
<form name="frm_main" action="" method="POSt">
<input class="text" type="text" name="tp_name" size="50" />
<br />
<input class="button" type="submit" value="Crear Página de Plantilla" name="btn_submit" />
</form>
</fieldset>
<?php
}
// Filtro de plantilla de página
add_filter('page_template', 'catch_plugin_template');
// Callback del filtro de plantilla de página
function catch_plugin_template($template) {
// Si tp-file.php es la plantilla configurada
if( is_page_template('tp-file.php') )
// Actualizar ruta (debe ser una ruta, usa WP_PLUGIN_DIR y no WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Devolver
return $template;
}
Espero que eso ayude a aclarar las cosas.. :)

Gracias @t31os Lo intenté y no funcionó, luego encontré esto http://adambrown.info/p/wp_hooks/hook/page_template que está obsoleto, ¿alguna otra idea?

También probé algo como esto, pero no funcionó: $pt = get_page_templates(); $pt['TP testing'] = WP_PLUGIN_URL . '/tp-test/tp-file.php';

Funciona perfectamente para mí... necesitaré más detalles que simplemente "no funcionó"...

Parece que los archivos de plantilla no están habilitados en la subcarpeta, encontré eso en theme.php en la función get_page_templates, ¿alguna otra idea?

No es relevante, el código que proporcioné funcionará perfectamente siempre que la ruta esté configurada correctamente y la página solicitada tenga _wp_page_template
establecido en tp-file.php
... Acabo de volver a probarlo para estar seguro, y nuevamente confirmé que funciona (necesitaré ver más de tu código si quieres que te ayude a descubrir por qué no funciona en tu configuración).

Gracias por tu tiempo, mi código no cambió, lo único es que agregué tu código a mi archivo principal del plugin, échale un vistazo aquí: http://pastebin.com/sNR9s0sP

Ok, pero ¿qué sucede cuando cargas una página que tiene _wp_page_template
configurado como tp-file.php
? ¿Ves un error de inclusión, ves una página en blanco, ves algo más? Ayúdame a ayudarte... ;)

Veo "Algún texto" como si fuera una página normal, y si voy al backend veo que la plantilla de página está configurada como predeterminada, y no está en la lista mi archivo de plantilla

Me voy a la cama en unos minutos, pero aclararé el problema mañana para ti. Mientras el campo meta _wp_page_template
permanezca configurado correctamente debería funcionar, independientemente de que no se muestre en el lado del administrador (lo cual es de esperar - lo explicaré en la actualización de la respuesta mañana).

Oye, esto es extraño, el código no funciona cuando el formulario está en un archivo separado, pero si está junto, entonces sí funciona.

Intenta establecer una acción en tu formulario, por ejemplo: action="<?php admin_url( '/?page=tp-teste' ) ?>"
, para asegurarte de que se envía correctamente a la página de tu plugin.

El filtro page_template
está obsoleto ahora. (http://adambrown.info/p/wp_hooks/hook/page_template)
Intenta usar single_template
(o archive_template
para plantillas de archivo) en su lugar.
Basado en la respuesta de @t31os:
// Filtro de plantilla de página
add_filter('single_template', 'catch_plugin_template');
// Callback del filtro de plantilla de página
function catch_plugin_template($template) {
// Si tp-file.php es la plantilla establecida
if( is_page_template('tp-file.php') )
// Actualizar la ruta (debe ser una ruta, usa WP_PLUGIN_DIR y no WP_PLUGIN_URL)
$template = WP_PLUGIN_DIR . '/tp-test/tp-file.php';
// Devolver
return $template;
}

Si el filtro single_template
no funciona, puedes usar este filtro:
add_filter('template_include', 'catch_plugin_template');
Tomado de aquí: https://www.pradipdebnath.com/2019/08/17/how-to-add-page-template-from-plugin-in-wordpress/

No estoy seguro si está obsoleto, solo cambió desde la versión 4.7. https://developer.wordpress.org/reference/hooks/type_template/. El argumento está vacío si el/los temas no proporcionan la plantilla, no si la página la ha seleccionado (almacenada) en la base de datos desde el menú desplegable de selección.

Un problema, y esto realmente no es algo que puedas solucionar, es que cuando visualizas la página desde el área de administración, al editar la página, la plantilla no aparecerá listada como la plantilla activa, y guardar los cambios podría por supuesto cambiar la plantilla activa. No hay mucho que podamos hacer ahí, el desplegable de plantillas de página se genera a partir de una función que escanea los archivos del tema, no hay hooks disponibles que pueda ver que nos permitan extender la lista con plantillas de plugins.
En realidad encontré un hook en otro hilo que hace exactamente eso:
WordPress: ¿Se pueden crear plantillas de página programáticamente?
Pego el código aquí por conveniencia:
CONST CUSTOM_PAGE_TEMPLATES = array(
array('slug' => 'home', 'label' => 'Inicio'),
array('slug' => 'content-page', 'label' => 'Página de contenido'),
array('slug' => 'ordering', 'label' => 'Pedidos'),
array('slug' => 'reviews', 'label' => 'Reseñas')
);
/**
* Añade plantillas de página sin archivo al desplegable de plantillas
*/
add_filter('theme_page_templates', function($page_templates, $wp_theme, $post) {
foreach(CUSTOM_PAGE_TEMPLATES as $template) {
// Añade si no existe ya
if (!isset($page_templates[$template['slug']])) {
$page_templates[$template['slug']] = $template['label'];
}
}
return $page_templates;
}, PHP_INT_MAX, 3);
Espero que esto le ayude a alguien.
