Cómo añadir hojas de estilo solo a páginas con shortcodes específicos
Estoy ejecutando una función en páginas donde se usa el shortcode [make-me-a-map]
. Este añade JavaScript a la página y crea un mapa. Eso funciona bien (¡bien!), pero estoy teniendo problemas para añadir las hojas de estilo solo a esas páginas de manera similar.
functions.php (Actual)
add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");
function create_new_map () {
global $new_map_called_for;
$map_called_for = true;
wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
wp_enqueue_script('make-a-new-map');
}
function style_my_new_map() {
global $new_map_called_for;
if ($new_map_called_for == true) {
$tDir = get_template_directory_uri();
// Echo de hojas de estilo porque wp_register_style & wp_enqueue_style no funcionan actualmente
// Y add_action('wp_enqueue_script', 'style_my_new_maps') con esas funciones añadiría estilos a todas las páginas
// No solo a las que tienen el shortcode [make-me-a-map]
echo "<link rel='stylesheet' href='", $tDir, "/css/new-map.css' />", PHP_EOL;
// Echo de JavaScript directamente a la página (no se pudo hacer con wp_enqueue_script) para que el código JS conozca el directorio de la plantilla
echo '<script type="text/javascript">var templateDir = "', get_template_directory_uri(), '";</script>', PHP_EOL;
$map_called_for = false;
}
}
Esto no parece estar funcionando, desafortunadamente. Los estilos se están añadiendo a todas las páginas.
No usé wp_register_style & wp_enqueue_style porque este error sigue añadiendo etiquetas <Link />
al pie de página con esas funciones.
Podría haber usado add_action("wp_enqueue_scripts", "style_my_new_map")
en lugar de add_action('wp-head', "style_my_new_map")
pero hasta donde puedo ver y he comprobado, ¿no hay diferencia? Aún así añade las hojas de estilo a todas las páginas.
Así que mi pregunta es en realidad en dos partes: :)
- ¿Por qué el functions.php actual no funciona y añade estilos a todas las páginas? No estoy seguro si es por la llamada
global
o por la declaraciónif
... - ¿Cuál es la mejor manera de añadir las hojas de estilo al encabezado solo de las páginas donde se usa el shortcode mencionado, asumiendo que no conoceré los IDs de las páginas, etc.?
¡Gracias de antemano! P

Cargar Scripts y Estilos Dinámicamente Usando Shortcodes
Ventajas
- No busca en todas las publicaciones cada vez que se llama al shortcode.
- Capaz de añadir estilos y scripts dinámicamente solo cuando el shortcode está en la página.
- No usa expresiones regulares ya que tienden a ser más lentas que
strstr()
ostrpos()
. Podrías cambiarlas por regex si necesitas aceptar argumentos. - Reduce las llamadas a archivos
Explicación del Código
Encuentra los shortcodes en la página usando el hook
save_post
solo cuando la publicación no es una revisión y coincide con elpost_type
especificado.Guarda los IDs de las publicaciones encontradas como un array usando
add_option()
con autoload configurado como 'yes' a menos que la entrada ya exista. En ese caso usaráupdate_option()
.Usa el hook
wp_enqueue_scripts
para llamar a nuestra funciónadd_scripts_and_styles()
.Esa función entonces llama a
get_option()
para recuperar nuestro array de IDs de página. Si el$page_id
actual está en el$option_id_array
, añade los scripts y estilos.
Nota importante: Convertí el código de clases OOP con Namespaces, así que puede que haya omitido algo. Avísame en los comentarios si es así.
Ejemplo de Código: Encontrar Ocurrencias de Shortcodes
function find_shortcode_occurences($shortcode, $post_type = 'page')
{
$found_ids = array();
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => -1,
);
$query_result = new \WP_Query($args);
foreach ($query_result->posts as $post) {
if (false !== strpos($post->post_content, $shortcode)) {
$found_ids[] = $post->ID;
}
}
return $found_ids;
}
function save_option_shortcode_post_id_array( $post_id ) {
if ( wp_is_post_revision( $post_id ) OR 'page' != get_post_type( $post_id )) {
return;
}
$option_name = 'yourprefix-yourshortcode';
$id_array = find_shortcode_occurences($option_name);
$autoload = 'yes';
if (false == add_option($option_name, $id_array, '', 'yes')) update_option($option_name, $id_array);
}
add_action('save_post', 'save_option_shortcode_id_array' );
Ejemplo de Código: Shortcode para Incluir Scripts y Estilos Dinámicamente
function yourshortcode_add_scripts_and_styles() {
$page_id = get_the_ID();
$option_id_array = get_option('yourprefix-yourshortcode');
if (in_array($page_id, $option_id_array)) {
wp_enqueue_script( $handle, $src, $deps, $ver, $footer = true );
wp_enqueue_style( $handle, $src , $deps);
}
}
add_action('wp_enqueue_scripts', 'yourshortcode_add_scripts_and_styles');

Aún no lo he probado, pero esta es la respuesta que estaba buscando. Parece tener un inconveniente mínimo.

@JacobRaccuia Probé esto hace un tiempo y funcionó. No sé cómo funciona con versiones más nuevas de WP, pero dudo que haya cambiado mucho dada la naturaleza de la plataforma.

Esto funciona para mí:
function register_my_css () {
wp_register_style('my-style', plugins_url('styles.css', __FILE__));
}
function register_my_scripts () {
wp_register_script('my-script', plugins_url('scripts.js', __FILE__));
}
// solo encola los scripts/estilos cuando se llama al shortcode
function do_my_shortcode () {
wp_enqueue_style('my-style');
wp_enqueue_script('my-script');
// hacer cosas del shortcode...
}
// registrar css
add_action('wp_enqueue_scripts', 'register_my_css');
// registrar javascript
add_action('wp_enqueue_scripts', 'register_my_scripts');
// registrar shortcode
add_shortcode('my-shortcode', 'do_my_shortcode');
Más información aquí: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/

No, eso mostrará el shortcode encima del contenido.

2 preguntas así que 2 respuestas :)
¿Por qué el functions.php actual no funciona y agrega estilos a todas las páginas? No estoy seguro si es la llamada global o la sentencia if...
No funciona debido al orden en que se llaman estas funciones. Tu callback del shortcode se ejecuta durante el renderizado del contenido del post (muy probablemente durante la llamada a the_content
).
Tanto wp_enqueue_scripts
como wp_head
se llaman mucho antes: wp_head
en algún lugar de tu archivo header.php
del tema y wp_enqueue_scripts
durante la llamada a wp_head
.
¿Cuál es la mejor manera de agregar las hojas de estilo solo al encabezado de las páginas donde se usa el shortcode anterior, asumiendo que no conoceré los IDs de página, etc.?
No creo que exista una forma "mejor". No es una buena idea en absoluto. Los navegadores almacenan en caché los archivos CSS. Así que si tienes el mismo CSS en todas las páginas, el navegador solo lo cargará una vez. Si hay muchos archivos CSS para diferentes páginas, el navegador tendrá que cargarlos todos. Por eso no lo haría en absoluto, e incluiría estos estilos CSS en el archivo CSS global.
Aunque si tienes que incluirlo solo en las páginas que usan este shortcode, entonces (2 soluciones, la elección de cuál es mejor es tuya; creo que la 2ª es más elegante)...
- Puedes agregar estos estilos como estilos en línea. Solo ten cuidado de no incluirlos muchas veces. Así que imprímelos con tu shortcode y asegúrate de que solo se muestren una vez.
- Como los posts ya están seleccionados cuando se llama a
wp_head
/wp_enqueue_scripts
, puedes agregar alguna función a este hook, recorrer los posts seleccionados, verificar si contienen tu shortcode y encolar tu CSS si es necesario. (Por supuesto, no será muy eficiente).

Puedes engancharte a una acción después de que la consulta principal se haya ejecutado y determinar si necesitas cargar tus estilos y scripts.
add_action('template_include', 'custom_template_include');
function custom_template_include($template) {
if (is_single() || is_page()) {
global $post;
if (has_shortcode($post->post_content, 'your_short_code')) {
add_action('wp_enqueue_scripts', 'custom_enqueue_scripts');
}
}
return $template;
}
function custom_enqueue_scripts() {
// Encuela tus scripts y estilos aquí.
}

add_action( 'wp_enqueue_scripts', 'enqueue_shortcode_styles', 1 );
function enqueue_shortcode_styles() {
global $post;
if ( isset($post->post_content) && is_singular(array( 'post','page' ) ) && ! has_shortcode( $post->post_content, '$tag' ) ) {
wp_enqueue_style( 'shortcode-styles', get_stylesheet_directory_uri() . '/style.css' );
}
}
Yo usaría has_shortcode
para verificar el contenido de $post y cargar los scripts usando wp_enqueue_scripts, pero depende de dónde estén incrustados tus shortcodes.
Reemplaza $tag con tu etiqueta de shortcode en el código anterior.
Añade esto al archivo functions.php de tu tema hijo y cambia los condicionales si es necesario.

Una solución mucho más simple que funcionó para mí fue registrar el script fuera de la función del shortcode y luego encolar el script dentro de la función. De esta manera, solo se carga el script en las páginas que utilizan tu shortcode.
wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
wp_register_style('make-a-new-map-style', get_template_directory_uri() . '/css/new-map.css');
add_shortcode("make-me-a-map", "create_new_map");
add_action("wp_head", "style_my_new_map");
function create_new_map () {
wp_enqueue_script('make-a-new-map');
wp_enqueue_style('make-a-new-map-style');
global $new_map_called_for;
$map_called_for = true;
}
Puedes encontrar una descripción de este método aquí: http://mikejolley.com/2013/12/sensible-script-enqueuing-shortcodes/
Ten en cuenta que esto carga el CSS en el pie de página, lo cual puede no ser deseable o válido según W3C. En mi caso, eso no fue un problema.

Puedes hacerlo simplemente así:
// hook del shortcode
add_shortcode("make-me-a-map", "create_new_map");
// callback del shortcode
function style_my_new_map() {
global $new_map_called_for;
if ($new_map_called_for == true) {
wp_register_script('make-a-new-map', get_template_directory_uri() . '/js/new-map.js', array('jquery'), '0.1', true);
wp_enqueue_script('make-a-new-map');
// el resto de tus códigos
}
}
También funciona para hojas de estilo. Para cargar tu hoja de estilos al final, añade números a tu hook de shortcode, así:
add_shortcode("make-me-a-map", "create_new_map", 9999);
Lo he probado y funciona.

Cargando Scripts y Estilos Dinámicamente Usando Shortcode
Este es un código extendido para la solución proporcionada por Commandz anteriormente.
He encontrado que su método es el mejor y más factible ya que la opción de base de datos está disponible en casi todos los hooks.
Se ha modificado para encontrar las ocurrencias de shortcodes solo en el contenido del post actual, en lugar de revisar todos los posts - lo cual puede ser más lento cuando el número de posts es grande.
Se ha cambiado aquí en dos líneas después de pasar otra variable $post_id desde la acción save_post a la función find_shortcode_occurences()
if( !empty($post_id) ) {
$args['posts__in'] = $post_id;
}
Código modificado para ambas funciones
function find_shortcode_occurences($shortcode, $post_id='', $post_type = 'page') {
$found_ids = array();
$args = array(
'post_type' => $post_type,
'post_status' => 'publish',
'posts_per_page' => -1,
);
if( !empty($post_id) ) {
$args['posts__in'] = $post_id;
}
$query_result = new WP_Query($args);
foreach ($query_result->posts as $post) {
if (false !== strpos($post->post_content, $shortcode)) {
$found_ids[] = $post->ID;
}
}
return $found_ids;
}
add_action('save_post', 'save_option_for_sppro_pages' );
function save_option_for_sppro_pages( $post_id ) {
if ( wp_is_post_revision( $post_id ) {
return;
}
$option_name = 'database-option';
$shortcode = 'shortcode-name';
$id_array = find_shortcode_occurences($shortcode, $post_id);
$autoload = 'yes';
if (false == add_option($option_name, $id_array, '', 'yes')) {
$current_value = get_option($option_name);
$new_value = array_merge($current_value, $id_array);
update_option($option_name, $id_array);
}
}
Además, se ha añadido otra variable para que puedas tener diferentes nombres para la opción de base de datos y el nombre del shortcode.
