Incluir archivo PHP en el contenido usando [shortcode]
Esto es lo que tengo
No estoy teniendo suerte encontrando cómo incluir simplemente un archivo en el editor de contenido usando un shortcode.
Por ejemplo, si quisiera incluir form.php dentro de mi Página de Contacto, ¿cómo podría hacer que esto suceda usando un shortcode?
A continuación está lo que intenté hacer sin éxito.
¡Cualquier ayuda sería apreciada!
// Implementación del Shortcode
function magic_stuff($atts) {
// activar el buffer de salida para capturar la salida del script
ob_start();
// incluir archivo (el contenido se guardará en el buffer de salida)
include(TEMPLATEPATH.'/wp-content/themes/grainandmortar/inc_static/test.php');
// guardar y devolver el contenido que ha sido generado
$content = ob_get_clean();
return $content;
}
//registrar el manejador del Shortcode
add_shortcode('magic', 'magic_stuff');
Aquí hay otra forma de hacerlo, utilizando get_template_part
de WordPress
function include_file($atts) {
$a = shortcode_atts( array(
'slug' => 'NULL',
), $atts );
if($a['slug'] != 'NULL'){
ob_start();
get_template_part($a['slug']);
return ob_get_clean();
}
}
add_shortcode('include', 'include_file');
ejemplos:
[include slug="form"]
[include slug="sub-folder/filename_without_extension"]

Modifiqué un código de una antigua publicación de blog para lograr esto y permitir que se incluyan cadenas de consulta (query strings) en el archivo también.
El crédito original va para amberpanther.com, y resulta que también crearon un plugin con esto.
//crear el shortcode [include] que acepta una ruta de archivo y cadena de consulta
//esta función fue modificada de un post en www.amberpanther.com que puedes encontrar en el enlace abajo:
//http://www.amberpanther.com/knowledge-base/using-the-wordpress-shortcode-api-to-include-an-external-file-in-the-post-content/
//INICIO código de amberpanther.com
function include_file($atts) {
//si se especificó la ruta del archivo
extract(
shortcode_atts(
array(
'filepath' => 'NULL'
), $atts
)
);
//INICIO porción de código modificada para aceptar cadenas de consulta
//verificar si hay cadena de consulta de variables después de la ruta del archivo
if(strpos($filepath,"?")) {
$query_string_pos = strpos($filepath,"?");
//crear variable global para la cadena de consulta para poder accederla en los archivos incluidos si es necesario
//también separarla de la ruta limpia del archivo que almacenaremos en una nueva variable para inclusión
global $query_string;
$query_string = substr($filepath,$query_string_pos + 1);
$clean_file_path = substr($filepath,0,$query_string_pos);
//si no hay cadena de consulta
} else {
$clean_file_path = $filepath;
}
//FIN porción de código modificada
//verificar si se especificó la ruta y si el archivo existe
if ($filepath != 'NULL' && file_exists(get_stylesheet_directory_uri() . "/" . $clean_file_path)){
//activar el buffer de salida para capturar la salida del script
ob_start();
//incluir el archivo especificado
include(TEMPLATEPATH.$clean_file_path);
//asignar la salida del archivo a la variable $content y limpiar el buffer
$content = ob_get_clean();
//retornar el $content
//el retorno es importante para que la salida aparezca en la posición correcta
//en el contenido
return $content;
}
}
//registrar el manejador del Shortcode
add_shortcode('include', 'include_file');
//FIN código de amberpanther.com
//shortcode con cadena de consulta de ejemplo:
//[include filepath="/get-posts.php?format=grid&taxonomy=testing&term=stuff&posttype=work"]
Configuré el mío para obtener desde el URI de la hoja de estilos (para que funcione con temas hijos y similares), pero podrías ajustar ese código fácilmente para obtener desde cualquier lugar (incluyendo directorios de plugins), o eliminarlo por completo y simplemente usar la ruta completa al incluir el archivo. Incluso podrías añadir un condicional con un carácter disparador al inicio que le indique usar una ruta específica basada en el primer carácter del nombre del archivo, como usar "#" para el directorio de plantillas, etc.
Yo lo uso para incluir un archivo llamado get-posts.php que está en mi directorio de plantillas y formatea la salida de varios posts basado en una serie de parámetros proporcionados en la cadena de consulta. Me evita necesitar plantillas especiales porque puedo incluir el archivo, enviarle un formato y este mostrará los posts con el marcado que he especificado en el archivo get-posts.php.
También permite a los clientes incluir tipos de posts personalizados en entradas de blog reales en formatos específicos y es bastante útil.
Déjame saber si necesitas alguna aclaración sobre algo.

No deberías usar TEMPLATEPATH
o STYLESHEETPATH
. En su lugar, usa get_template/stylesheet_dir()
o el equivalente *_url()
para rutas/URIs

ericissocial ¡Muchas gracias! Voy a implementarlo todo y probarlo, te aviso cómo me va.

No hay problema, deberías seguir la recomendación de kaiser y usar la funcionalidad GET_template en lugar del TEMPLATEPATH que tenía en el código. Kaiser, gracias por el aviso, editaré el código en mi respuesta cuando no lo esté viendo desde mi teléfono.

Hay un error en la solución proporcionada por @adedoy, ya que $slug nunca está definido. Esto funcionó para mí:
function include_file($atts) {
$atts = shortcode_atts(
array(
'path' => 'NULL',
), $atts, 'include' );
ob_start();
get_template_part($atts['path']);
return ob_get_clean();
}
add_shortcode('include', 'include_file');
Uso: [include path="ruta/desde/la/raiz"]

Ok, primero eliminaría el buffer de salida.
Segundo cambio:
include(TEMPLATEPATH.'/wp-content/themes/grainandmortar/inc_static/test.php');
Por:
include( get_stylesheet_directory() . '/inc_static/test.php');
Finalmente,
Leyendo la documentación aquí: https://codex.wordpress.org/Shortcode_API
Necesitas retornar algo, si tu test.php no produce una salida en un formato que se pueda retornar, vas a tener problemas.
Así que asegúrate de que test.php haga algo como:
$output = "CONTENIDO"; // una variable que puedas retornar después del include.
// o
function test() {
// hacer algo
return $contenido; // una función que retorna un valor que puedes llamar después del include.
}
Luego de incluir tu archivo test.php -- simplemente retornas $output
o haces algo como return test();
.

Solo por curiosidad sobre tu razonamiento - ¿por qué no usar el almacenamiento en búfer de salida para los shortcodes?

Hola @mattLummus -- al final del día es cuestión de perspectiva. Creo que no lo NECESITAS para lograr el objetivo y no ganas mucho haciéndolo -- además, haré eco de lo dicho aquí: https://stackoverflow.com/questions/5454345/output-buffer-vulnerabilities-php -- "El almacenamiento en búfer de salida se considera feo si se usa para evitar la advertencia de No se pueden enviar encabezados, la salida ya comenzó en... El almacenamiento en búfer de salida se usa entonces para compensar un diseño deficiente..."

Sí, parece una solución un poco improvisada en ese caso particular. Generalmente cuando usamos buffers de salida no es para solucionar otro problema, sino simplemente porque estamos en un caso donde escribimos más marcado que PHP y preferimos la sintaxis de OB (poder salir de PHP y escribir HTML plano en lugar de un montón de declaraciones echo y HTML escrito en cadenas).
¡Gracias por la respuesta en cualquier caso!

Descubrí que el código de inclusión originalmente escrito por los chicos de AmberPanther no funcionaba tan bien para mí, así que encontré otro plugin de WordPress que hace prácticamente lo mismo. Se llama Include Me, creado por Stefano Lissa. El uso es bastante simple: escribes la ruta al archivo, empezando desde el directorio raíz de tu sitio.
Por ejemplo, dentro de tu página de WordPress escribirías:
[includeme file="wp-content/themes/tu-tema/code/ejemplo-codigo.php"]
y dentro de tu archivo functions.php incluirías:
<?php
if (is_admin()) {
include dirname(__FILE__) . '/admin.php';
} else {
function includeme_call($attrs, $content = null) {
if (isset($attrs['file'])) {
$file = strip_tags($attrs['file']);
if ($file[0] != '/')
$file = ABSPATH . $file;
ob_start();
include($file);
$buffer = ob_get_clean();
$options = get_option('includeme', array());
if (isset($options['shortcode'])) {
$buffer = do_shortcode($buffer);
}
} else {
$tmp = '';
foreach ($attrs as $key => $value) {
if ($key == 'src') {
$value = strip_tags($value);
}
$value = str_replace('&', '&', $value);
if ($key == 'src') {
$value = strip_tags($value);
}
$tmp .= ' ' . $key . '="' . $value . '"';
}
$buffer = '<iframe' . $tmp . '></iframe>';
}
return $buffer;
}
// Aquí porque la función DEBE definirse antes del "add_shortcode" ya que
// "add_shortcode" verifica el nombre de la función con "is_callable".
add_shortcode('includeme', 'includeme_call');
}
Por supuesto, también recomendaría simplemente instalar el plugin para que puedas aprovechar las actualizaciones. https://wordpress.org/plugins/include-me/
