Caricare script solo se è presente un particolare shortcode o widget
Mi serviva un modo per filtrare il contenuto di una pagina/post prima che venisse caricato, così da poter aggiungere script all'header se era presente un determinato shortcode. Dopo lunghe ricerche ho trovato questo su http://wpengineer.com
function has_my_shortcode($posts) {
if ( empty($posts) )
return $posts;
$found = false;
foreach ($posts as $post) {
if ( stripos($post->post_content, '[my_shortcode') )
$found = true;
break;
}
if ($found){
$urljs = get_bloginfo( 'template_directory' ).IMP_JS;
wp_register_script('my_script', $urljs.'myscript.js' );
wp_print_scripts('my_script');
}
return $posts;
}
add_action('the_posts', 'has_my_shortcode');
che è assolutamente geniale e faceva esattamente quello che mi serviva.
Ora ho bisogno di estenderlo ulteriormente e fare lo stesso per le sidebar. Può essere per un particolare tipo di widget, shortcode, snippet di codice o qualsiasi altra cosa che possa funzionare per identificare quando lo script deve essere caricato.
Il problema è che non riesco a capire come accedere al contenuto delle sidebar prima che la sidebar venga caricata (il tema in questione avrà diverse sidebar)

Puoi utilizzare la funzione is_active_widget. Ad esempio:
function check_widget() {
if( is_active_widget( '', '', 'search' ) ) { // controlla se il widget di ricerca è utilizzato
wp_enqueue_script('my-script');
}
}
add_action( 'init', 'check_widget' );
Per caricare lo script solo nella pagina dove il widget è caricato, dovrai aggiungere il codice is_active_widget() nella tua classe del widget. Ad esempio, vedi il widget predefinito dei commenti recenti (wp-includes/default-widgets.php, riga 602):
class WP_Widget_Recent_Comments extends WP_Widget {
function WP_Widget_Recent_Comments() {
$widget_ops = array('classname' => 'widget_recent_comments', 'description' => __( 'I commenti più recenti' ) );
$this->WP_Widget('recent-comments', __('Commenti Recenti'), $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') );
}

Può essere chiamato PRIMA che i widget vengano caricati? Per essere chiari, questo deve avvenire prima ancora che la pagina venga caricata. Il mio codice di esempio utilizza the_posts per filtrare il contenuto della pagina, ma questo non include le sidebar/widgets.

Il tuo esempio in realtà non funziona. Mi sto perdendo qualcosa di ovvio?

In effetti lo ero. wp_enqueue_script non sembra funzionare quando applicato a wp_head, ma wp_print_scripts sì. wp_enqueue_script però funziona se applicato a init in questo modo: add_action( 'init', 'check_widget' );

Tuttavia carica gli script su ogni pagina del sito, anche se il widget è attivo solo in una sidebar. Ad esempio, se ho una sidebar per le pagine del blog e un'altra sidebar per le altre pagine. Aggiungo il widget di ricerca alla sidebar del blog e gli script vengono caricati, ma vengono caricati anche sulle pagine che non hanno la sidebar del blog. Ho bisogno di caricare lo script solo se il widget è presente su quella pagina.

Volevo condividere una soluzione su cui ho lavorato che mi ha permesso di essere più versatile nella mia implementazione. Invece di far controllare alla funzione una varietà di shortcode, l'ho modificata per cercare un singolo shortcode che fa riferimento a una funzione script/stile che deve essere accodata. Questo funzionerà sia per i metodi in altre classi (come plugin che potrebbero non gestirlo autonomamente) sia per funzioni nello scope. Basta inserire il codice qui sotto in functions.php e aggiungere la seguente sintassi a qualsiasi pagina/post dove vuoi CSS e JS specifici.
Sintassi Pagina/Post: [loadCSSandJS function="(nome classe->metodo/funzione)"]
Codice functions.php:
function page_specific_CSSandJS( $posts ) {
if ( empty( $posts ) )
return $posts;
foreach ($posts as $post) {
// Cerca tutti gli shortcode [loadCSSandJS] nel contenuto del post
$returnValue = preg_match_all('#\[loadCSSandJS function="([A-z\-\>]+)"\]#i', $post->post_content, $types);
// Elabora ogni funzione trovata
foreach($types[1] as $type) {
$items = explode("->",$type);
if (count($items) == 2) {
global $$items[0];
// Verifica se il metodo esiste nella classe
if( method_exists( $$items[0], $items[1] ))
// Aggiungi l'azione per accodare gli scripts
add_action( 'wp_enqueue_scripts', array(&$$items[0], $items[1]) );
}
else if( !empty( $type ) && function_exists( $type ))
// Aggiungi l'azione se la funzione esiste
add_action( 'wp_enqueue_scripts', $type );
}
}
return $posts;
}
Questo ti permetterà anche di aggiungere quanti shortcode vuoi in una pagina. Tieni presente che hai bisogno di un metodo/funzione da caricare.

Con WordPress 4.7 c'è un altro modo per ottenere questo risultato nel tuo file functions.php
,
add_action( 'wp_enqueue_scripts', 'register_my_script');
function register_my_script(){
wp_register_script('my-shortcode-js',$src, $dependency, $version, $inFooter);
}
per prima cosa registri il tuo script, che in realtà non viene stampato nella tua pagina a meno che non lo accodi se viene chiamato il tuo shortcode,
add_filter( 'do_shortcode_tag','enqueue_my_script',10,3);
function enqueue_my_script($output, $tag, $attr){
if('myShortcode' != $tag){ //assicurati che sia lo shortcode corretto
return $output;
}
if(!isset($attr['id'])){ //puoi anche verificare attributi specifici
return $output;
}
wp_enqueue_script('my-shortcode-js'); //accoda il tuo script per la stampa
return $output;
}
il do_shortcode_tag
è stato introdotto in WP 4.7 e può essere trovato nelle nuove pagine della documentazione per sviluppatori.

Grazie per aver condiviso questo suggerimento!
Mi ha causato un po' di mal di testa, perché all'inizio non funzionava. Penso ci siano un paio di errori (forse refusi) nel codice sopra has_my_shortcode
e ho riscritto la funzione come segue:
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;
}
Penso ci fossero due problemi principali: il break
non era nell'ambito dell'istruzione if, e questo causava l'interruzione del ciclo sempre alla prima iterazione. L'altro problema era più sottile e difficile da scoprire. Il codice sopra non funziona se lo shortcode è la prima cosa scritta in un post. Ho dovuto usare l'operatore ===
per risolvere questo.
Comunque, grazie mille per aver condiviso questa tecnica, è stata molto utile.
