Cargar scripts solo si un shortcode o widget específico está presente
Necesitaba una forma de filtrar el contenido de una página/entrada antes de que se cargara para poder añadir scripts al encabezado si estaba presente un shortcode específico. Después de mucha búsqueda encontré esto en http://wpengineer.com
function tiene_mi_shortcode($posts) {
if ( empty($posts) )
return $posts;
$encontrado = false;
foreach ($posts as $post) {
if ( stripos($post->post_content, '[mi_shortcode') )
$encontrado = true;
break;
}
if ($encontrado){
$urljs = get_bloginfo( 'template_directory' ).IMP_JS;
wp_register_script('mi_script', $urljs.'miscript.js' );
wp_print_scripts('mi_script');
}
return $posts;
}
add_action('the_posts', 'tiene_mi_shortcode');
lo cual es absolutamente brillante e hizo exactamente lo que necesitaba.
Ahora necesito extenderlo un poco más y hacer lo mismo para las barras laterales. Puede ser por un tipo de widget específico, shortcode, fragmento de código o cualquier otra cosa que funcione para identificar cuándo se necesita cargar el script.
El problema es que no puedo descubrir cómo acceder al contenido de las barras laterales antes de que se cargue la barra lateral (el tema en cuestión tendrá varias barras laterales)

Puedes usar la función is_active_widget. Por ejemplo:
function check_widget() {
if( is_active_widget( '', '', 'search' ) ) { // comprueba si se usa el widget de búsqueda
wp_enqueue_script('my-script');
}
}
add_action( 'init', 'check_widget' );
Para cargar el script solo en la página donde se carga el widget, tendrás que agregar el código is_active_widget() en tu clase de widget. Por ejemplo, mira el widget predeterminado de comentarios recientes (wp-includes/default-widgets.php, línea 602):
class WP_Widget_Recent_Comments extends WP_Widget {
function WP_Widget_Recent_Comments() {
$widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'Los comentarios más recientes' ) );
$this->WP_Widget('recent-comments', __('Comentarios recientes'), $widget_ops);
$this->alt_option_name = 'widget_recent_comments';
if ( is_active_widget(false, false, $this->id_base) )
add_action( 'wp_head', array(&$this, 'recent_comments_style') );
add_action( 'comment_post', array(&$this, 'flush_widget_cache') );
add_action( 'transition_comment_status', array(&$this, 'flush_widget_cache') );
}

¿Se puede llamar ANTES de que se carguen los widgets? Para ser claro, esto debe ocurrir antes de que la página incluso se cargue. Mi código de ejemplo usa the_posts para filtrar el contenido en la página, pero eso no afecta las barras laterales/widgets.

Tu ejemplo en realidad no funciona. ¿Estoy pasando por alto algo obvio?

En realidad lo estaba. wp_enqueue_script no parece funcionar cuando se aplica a wp_head, pero wp_print_scripts sí. wp_enqueue_script sí funciona si se aplica a init de esta manera: add_action( 'init', 'check_widget' );

Sin embargo, carga los scripts en cada página del sitio, incluso si el widget solo está activo en una barra lateral. Por ejemplo, si tengo una barra lateral para páginas de blog y otra barra lateral para otras páginas. Agrego el widget de búsqueda a la barra lateral del blog y los scripts se cargan, pero también se cargan en páginas que no tienen la barra lateral del blog. Necesito poder cargar el script solo si el widget está presente en esa página.

Solo quería compartir una solución en la que trabajé que me permitió ser un poco más versátil con mi implementación. En lugar de hacer que la función verifique una variedad de shortcodes, la modifiqué para que busque un único shortcode que haga referencia a una función de script/estilo que necesite ser encolada. Esto funcionará tanto para métodos en otras clases (como plugins que podrían no hacer esto por sí mismos) como para funciones dentro del alcance. Solo coloca el siguiente código en functions.php y añade la siguiente sintaxis a cualquier página/post donde quieras CSS y JS específicos.
Sintaxis para Página/Post: [loadCSSandJS function="(clase->método/nombre de función)"]
Código para functions.php:
function page_specific_CSSandJS( $posts ) {
if ( empty( $posts ) )
return $posts;
foreach ($posts as $post) {
$returnValue = preg_match_all('#\[loadCSSandJS function="([A-z\-\>]+)"\]#i', $post->post_content, $types);
foreach($types[1] as $type) {
$items = explode("->",$type);
if (count($items) == 2) {
global $$items[0];
if( method_exists( $$items[0], $items[1] ))
add_action( 'wp_enqueue_scripts', array(&$$items[0], $items[1]) );
}
else if( !empty( $type ) && function_exists( $type ))
add_action( 'wp_enqueue_scripts', $type );
}
}
return $posts;
}
Esto también te permitirá añadir tantos como quieras en una página. Ten en cuenta que necesitas un método/función para cargar.

Con WordPress 4.7 existe otra forma de lograr esto en tu archivo functions.php
,
add_action( 'wp_enqueue_scripts', 'registrar_mi_script');
function registrar_mi_script(){
wp_register_script('mi-shortcode-js',$src, $dependency, $version, $inFooter);
}
primero registras tu script, que en realidad no se imprime en tu página a menos que lo encoles si se llama a tu shortcode,
add_filter( 'do_shortcode_tag','encolar_mi_script',10,3);
function encolar_mi_script($output, $tag, $attr){
if('myShortcode' != $tag){ //asegúrate de que es el shortcode correcto
return $output;
}
if(!isset($attr['id'])){ //incluso puedes verificar atributos específicos
return $output;
}
wp_enqueue_script('mi-shortcode-js'); //encola tu script para imprimirlo
return $output;
}
el do_shortcode_tag
fue introducido en WP 4.7 y se puede encontrar en las páginas de la nueva documentación para desarrolladores.

¡Gracias por compartir este consejo!
Me dio un poco de dolor de cabeza, porque al principio no funcionaba. Creo que hay un par de errores (quizás errores tipográficos) en el código anterior has_my_shortcode
y reescribí la función como se muestra a continuación:
function has_my_shortcode( $posts ) {
if ( empty($posts) )
return $posts;
$shortcode_found = false;
foreach ($posts as $post) {
if ( !( stripos($post->post_content, '[my-shortcode') === false ) ) {
$shortcode_found = true;
break;
}
}
if ( $shortcode_found ) {
$this->add_scripts();
$this->add_styles();
}
return $posts;
}
Creo que había dos problemas principales: el break
no estaba dentro del alcance de la sentencia if, y eso hacía que el bucle siempre se interrumpiera en la primera iteración. El otro problema era más sutil y difícil de descubrir. El código anterior no funciona si el shortcode es lo primero que se escribe en una publicación. Tuve que usar el operador ===
para resolver esto.
De todos modos, muchas gracias por compartir esta técnica, ayudó mucho.
