Caricare Script / Stili quando è presente uno shortcode

18 ott 2014, 10:07:40
Visualizzazioni: 69.4K
Voti: 87

Qual è il modo migliore per registrare/accodare script e/o stili nei plugin?

Recentemente ho creato un plugin semplice per aggiungere l'avatar/gravatar dell'utente con uno shortcode. Ho diverse opzioni di stile per visualizzare l'avatar (quadrato, rotondo, ecc.) e ho deciso di inserire il css direttamente nello shortcode stesso.

Tuttavia, ora mi rendo conto che questo non è un buon approccio poiché ripeterà il css ogni volta che lo shortcode viene utilizzato in una pagina. Ho visto diversi altri approcci su questo sito e il codex wp ha persino due esempi propri, quindi è difficile sapere quale approccio sia più coerente e veloce.

Ecco i metodi di cui sono attualmente a conoscenza:

Metodo 1: Inclusione diretta nello shortcode - Questo è quello che sto facendo attualmente nel plugin, ma non sembra buono poiché ripete il codice.

class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* semplicemente accoda o stampa gli script/stili direttamente nello shortcode */
?>
<style type="text/css">

</style>
<?php
    return "$content";
     }
}
add_shortcode( 'myshortcode', array( 'My_Shortcode', 'handle_shortcode' ) );

Metodo 2: Utilizzo della classe per accodare script o stili condizionalmente

class My_Shortcode {
    static $add_script;
    static function init() {
        add_shortcode('myshortcode', array(__CLASS__, 'handle_shortcode'));
        add_action('init', array(__CLASS__, 'register_script'));
        add_action('wp_footer', array(__CLASS__, 'print_script'));
    }
    static function handle_shortcode($atts) {
        self::$add_script = true;
        // gestione shortcode qui
    }
    static function register_script() {
        wp_register_script('my-script', plugins_url('my-script.js', __FILE__), array('jquery'), '1.0', true);
    }
    static function print_script() {
        if ( ! self::$add_script )
            return;
        wp_print_scripts('my-script');
    }
}
My_Shortcode::init();

Metodo 3: Utilizzo di get_shortcode_regex();

function your_prefix_detect_shortcode() {

    global $wp_query;   
    $posts = $wp_query->posts;
    $pattern = get_shortcode_regex();

    foreach ($posts as $post){
        if (   preg_match_all( '/'. $pattern .'/s', $post->post_content, $matches )
            && array_key_exists( 2, $matches )
            && in_array( 'myshortcode', $matches[2] ) )
        {
            // css/js 
            break;  
        }    
    }
}
add_action( 'wp', 'your_prefix_detect_shortcode' );

Metodo 4: Utilizzo di has_shortcode();

function custom_shortcode_scripts() {
    global $post;
    if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'myshortcode') ) {
        wp_enqueue_script( 'my-script');
    }
}
add_action( 'wp_enqueue_scripts', 'custom_shortcode_scripts');
4
Commenti

Penso che il Method 4: Using has_shortcode(); sia il migliore perché garantisce che gli script e gli stili vengano caricati una sola volta se il contenuto del post ha lo shortcode, indipendentemente dall'uso multiplo dello shortcode. Anche se potrebbe non funzionare per gli shortcode utilizzati nei widget o nella sidebar, non ne sono sicuro. Se si tratta di un plugin, non ti consiglierei di legare gli script allo shortcode perché alcuni potrebbero chiamare la tua funzione invece dello shortcode per ottenere l'output desiderato.

Robert hue Robert hue
18 ott 2014 10:46:54

Possibile duplicato di Come aggiungere fogli di stile solo alle pagine con shortcode specifico?

kontur kontur
30 mar 2018 16:35:43

Il metodo 4 è buono ma c'è un problema: può creare inconvenienti se lo shortcode non viene aggiunto direttamente all'area dei contenuti di WP ma tramite opzioni di altri plugin di terze parti. Può essere utile aggiungere un controllo nella funzione dello shortcode ! wp_style_is insieme al metodo 4 e accodare lo stile lì nel caso non sia stato aggiunto nel precedente callback wp_enqueue_scripts

Adeel Raza Adeel Raza
14 ott 2020 13:23:43

Il metodo 4 non funzionerà se la pagina richiesta è qualcosa come la home, la pagina indice e il primo post non contiene shortcode. Tutti gli altri post non visualizzeranno correttamente il CSS e JS degli shortcode.

vee vee
1 gen 2023 21:17:19
Tutte le risposte alla domanda 10
4
88

Ho trovato un altro metodo che funziona bene per me:

Ecco un esempio di plugin che utilizza questo metodo e ti permette di usare get_avatar in uno shortcode. Il foglio di stile viene accodato solo quando è presente lo shortcode.

Utilizzo (l'id di default è l'utente corrente):

[get_avatar id="" size="32" default="mystery" alt="Foto Profilo" class="round"]

function wpse_165754_avatar_shortcode_wp_enqueue_scripts() {
    wp_register_style( 'get-avatar-style', plugins_url( '/css/style.css', __FILE__ ), array(), '1.0.0', 'all' );
}

add_action( 'wp_enqueue_scripts', 'wpse_165754_avatar_shortcode_wp_enqueue_scripts' );
if ( function_exists( 'get_avatar' ) ) {
    function wpse_165754_user_avatar_shortcode( $attributes ) {

        global $current_user;
        get_currentuserinfo();

        extract( shortcode_atts(
                     array(
                         "id"      => $current_user->ID,
                         "size"    => 32,
                         "default" => 'mystery',
                         "alt"     => '',
                         "class"   => '',
                     ), $attributes, 'get_avatar' ) );
        
        $get_avatar = get_avatar( $id, $size, $default, $alt );

        wp_enqueue_style( 'get-avatar-style' );

        return '<span class="get_avatar ' . $class . '">' . $get_avatar . '</span>';
    }

    add_shortcode( 'get_avatar', 'wpse_165754_user_avatar_shortcode' );
}
15 giu 2015 15:28:58
Commenti

Ho dimenticato di aver fatto questa domanda l'anno scorso, ma in realtà avevo già iniziato a fare così in molti casi. È un po' come combinare il metodo 1 e il 2.

Bryan Willis Bryan Willis
8 lug 2015 20:36:53

Questo metodo carica il CSS nel footer, il che sicuramente ha delle limitazioni?

Jacob Raccuia Jacob Raccuia
21 apr 2017 16:26:32

Questo è assolutamente il modo giusto per farlo. Usa questo metodo ogni volta che hai bisogno di caricare condizionalmente uno script o un foglio di stile quando l'hook wp_enqueue_scripts è già avvenuto. (Gli shortcode vengono analizzati durante the_content che fa parte dell'hook the_post, il che significa che accodarli quando vengono analizzati è troppo tardi a meno che non hai già registrato lo script)

JRad the Bad JRad the Bad
21 apr 2019 00:56:49

Questo non è utile in quanto crea FOUT quando lo stile viene caricato nella funzione dello shortcode. È meglio utilizzare il metodo has_shortcode.

Adeel Raza Adeel Raza
14 ott 2020 13:27:58
3
35

Prima di iniziare a rispondere, devo dire che riguardo a questo argomento CSS e JS non sono la stessa cosa.

Il motivo è semplice: mentre aggiungere JS nel corpo della pagina (nel footer) è un modo comune e valido di procedere, il CSS deve essere posizionato nella sezione <head> della pagina: anche se la maggior parte dei browser può visualizzare correttamente il CSS nel corpo della pagina, non è un codice HTML valido.

Quando uno shortcode viene renderizzato, la sezione <head> è già stata stampata, il che significa che JS può essere aggiunto senza problemi nel footer, ma il CSS deve essere aggiunto prima che lo shortcode venga renderizzato.

Script

Se il tuo shortcode necessita solo di JS, sei fortunato e puoi semplicemente usare wp_enqueue_script nel corpo della callback dello shortcode:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

function my_handle_shortcode() {
  wp_enqueue_script( 'myshortcodejs', '/percorso/al/file/js.js' );
  // resto del codice qui...
}

In questo modo il tuo script viene aggiunto nel footer e solo una volta, anche se lo shortcode è utilizzato più volte nella pagina.

Stili

Se il tuo codice necessita di stili, allora devi agire prima che lo shortcode venga effettivamente renderizzato.

Ci sono diversi modi per farlo:

  1. esamina tutti i post nella query corrente e aggiungi gli stili dello shortcode se necessario. Questo è ciò che fai sia nel metodo #3 che #4 nell'OP. In effetti, entrambi i metodi fanno la stessa cosa, ma has_shortcode è stato aggiunto in WP 3.6, mentre get_shortcode_regex è disponibile dalla versione 2.5, quindi usa get_shortcode_regex solo se vuoi rendere il tuo plugin compatibile con versioni più vecchie.

  2. aggiungi sempre lo stile dello shortcode, in tutte le pagine

Problemi

Il problema con #1 è la performance. Le regex sono operazioni piuttosto lente e lanciare regex in un loop di tutti i post può rallentare consistentemente la pagina. Inoltre, è un compito abbastanza comune nei temi mostrare solo l'estratto del post negli archivi e mostrare il contenuto completo con gli shortcode solo nelle visualizzazioni singole. Se ciò accade, quando viene mostrato un archivio, il tuo plugin lancerà un matching di regex in un loop con l'obiettivo di aggiungere uno stile che non verrà mai utilizzato: un doppio impatto sulla performance non necessario: rallentamento della generazione della pagina + richiesta HTTP aggiuntiva non necessaria.

Il problema con #2 è ancora la performance. Aggiungere stili a tutte le pagine significa aggiungere una richiesta HTTP aggiuntiva per tutte le pagine, anche quando non è necessario. Anche se il tempo di generazione della pagina lato server non è influenzato, il tempo totale di rendering della pagina lo sarà, e per tutte le pagine del sito.

Quindi, cosa dovrebbe fare uno sviluppatore di plugin?

Penso che la cosa migliore da fare sia aggiungere una pagina di opzioni al plugin, dove gli utenti possono scegliere se lo shortcode debba essere gestito solo nelle visualizzazioni singole o anche negli archivi. In entrambi i casi è meglio fornire un'altra opzione per scegliere per quali tipi di post abilitare lo shortcode.

In questo modo è possibile agganciarsi a "template_redirect" per verificare se la query corrente soddisfa i requisiti e in quel caso aggiungere lo stile.

Se l'utente sceglie di usare lo shortcode solo nelle visualizzazioni singole dei post, è una buona idea verificare se il post ha lo shortcode o meno: visto che è richiesta solo una regex, non dovrebbe rallentare troppo la pagina.

Se l'utente sceglie di usare lo shortcode anche negli archivi, allora eviterei di eseguire regex per tutti i post se il numero di post è elevato e aggiungerei semplicemente lo stile se la query soddisfa i requisiti.

Cosa considerare "elevato" in questo caso dovrebbe essere determinato tramite alcuni test di performance o, in alternativa, aggiungere un'altra opzione e dare la scelta agli utenti.

18 ott 2014 11:49:56
Commenti

Vale la pena notare qui che i tag <style> nel body del documento sono ora validi secondo le specifiche W3C. https://www.w3.org/TR/html52/document-metadata.html#the-style-element

Isaac Lubow Isaac Lubow
17 nov 2018 00:30:40

@IsaacLubow Attualmente (2023): Contesti in cui questo elemento può essere usato: In un elemento noscript che è figlio di un elemento head. Ho validato <style> all'interno di <body> su https://validator.w3.org/nu/#textarea ma il risultato è Errore: Elemento style non consentito come figlio dell'elemento body in questo contesto.

vee vee
1 gen 2023 20:53:56

Ma <link> all'interno di <body> supera la validazione.

vee vee
1 gen 2023 20:56:10
0
11

Per il mio plugin ho scoperto che a volte gli utenti hanno un tema builder che memorizza gli shortcode nei metadati del post. Ecco cosa utilizzo per rilevare se lo shortcode del mio plugin è presente nell'attuale post o nei metadati del post:

function abcd_load_my_shorcode_resources() {
       global $post, $wpdb;

       // determina se questa pagina contiene lo shortcode "my_shortcode"
       $shortcode_found = false;
       if ( has_shortcode($post->post_content, 'my_shortcode') ) {
          $shortcode_found = true;
       } else if ( isset($post->ID) ) {
          $result = $wpdb->get_var( $wpdb->prepare(
            "SELECT count(*) FROM $wpdb->postmeta " .
            "WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'", $post->ID ) );
          $shortcode_found = ! empty( $result );
       }

       if ( $shortcode_found ) {
          wp_enqueue_script(...);
          wp_enqueue_style(...);
       }
}
add_action( 'wp_enqueue_scripts', 'abcd_load_my_shorcode_resources' );
6 nov 2015 02:18:02
0

WordPress ha una funzione integrata per eseguire azioni in base alla presenza di un determinato Shortcode. Il nome della funzione è has_shortcode(). Puoi utilizzare il seguente codice per accodare i tuoi stili e script.

Qui ho usato is_a( $post, 'WP_Post' ) per verificare se l'oggetto $post appartiene alla classe WP_Post e ho utilizzato $post->post_content per controllare il contenuto del post.

if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'shortcode_tag') ) {
    wp_enqueue_style( 'handle', get_template_directory_uri() . '/your_file_filename.css' );
}
7 ott 2018 20:04:30
0

Faccio così:

class My_Shortcode {

    function __construct() {
        do_action('my_start_shortcode'); // chiama l'azione
....

e intercetto l'hook in altre funzioni (o altri plugin):

function wpse_3232_load_script(){
    wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
8 ago 2017 12:51:20
0

Come qualcuno ha menzionato, usare 'has_shortcode' funzionerà. Ecco l'esempio che ho trovato molto utile (Fonte: Wordpress.org)

function wpdocs_shortcode_scripts() {
    global $post;
    if ( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'wpdocs-shortcode') ) {
        wp_enqueue_script( 'wpdocs-script');
    }
}
add_action( 'wp_enqueue_scripts', 'wpdocs_shortcode_scripts');
27 gen 2021 22:07:44
1

Possiamo infatti caricare condizionalmente file CSS e JS tramite shortcode senza utilizzare funzioni eccessivamente elaborate:

Innanzitutto, supponiamo di aver registrato tutti i nostri file CSS/JS precedentemente (magari quando è stato eseguito wp_enqueue_scripts)

function prep_css_e_js() {
     wp_register_style('my-css', $_css_url);
     wp_register_script('my-js', $_js_url);
}
add_action( 'wp_enqueue_scripts', 'prep_css_e_js', 5 );

Successivamente, esaminiamo la nostra funzione dello shortcode:

function mio_shortcode_func( $atts, $content = null ) {
  if( ! wp_style_is( "my-css", $list = 'enqueued' ) ) { wp_enqueue_style('my-css'); }
  if( ! wp_script_is( "my-js", $list = 'enqueued' ) ) { wp_enqueue_script('my-js'); }
  ...
}

Semplice. Fatto. Ergo: possiamo "caricare condizionalmente" file css/js, (solo quando viene eseguito [shortcode]).

Consideriamo la seguente ideologia:

  • Vogliamo caricare determinati file CSS/JS (ma solo quando viene attivato lo shortcode)
  • Forse non vogliamo che quei file vengano caricati su ogni pagina, o del tutto se lo shortcode non viene utilizzato in una pagina/post. (leggero)
  • Possiamo ottenere questo risultato assicurandoci che WP registri TUTTI i file css/js prima di chiamare lo shortcode e prima dell'enqueue.
  • IE: Magari durante la mia funzione prep_css_e_js() carico TUTTI i file .css/.js che si trovano in determinate cartelle...

Ora che WP li vede come script registrati, possiamo effettivamente chiamarli, condizionalmente, in base a una varietà di situazioni, tra cui ma non limitato a mio_shortcode_func()

Vantaggi: (nessun MySQL, nessuna funzione avanzata e nessun filtro necessario)

  • è "ortodosso per WP", elegante, a caricamento veloce, facile e semplice
  • consente ai compilatori/minifier di rilevare tali script
  • utilizza le funzioni WP (wp_register_style/wp_register_script)
  • compatibile con più temi/plugin che potrebbero voler deregistrare quegli script per una varietà di motivi.
  • non si attiverà più volte
  • viene coinvolto pochissimo codice o elaborazione

Riferimenti:

16 set 2019 00:00:38
Commenti

Questo metodo carica gli stili sotto il footer. Di solito è meglio inserirli nell'head.

leclaeli leclaeli
8 mag 2024 23:24:14
0

Ho scoperto per il mio plugin, se lo shortcode è presente nel widget di testo.

function check_shortcode($text) {

  $pattern = get_shortcode_regex();

   if (   preg_match_all( '/'. $pattern .'/s', $text, $matches )
        && array_key_exists( 2, $matches )
        && in_array( 'myshortcode', $matches[2] ) )
    {
        // myshortcode è in uso

        // carica i miei file css e js
        /****** Carica RFNB  ******/
        wp_enqueue_style('css-mycss');
        wp_enqueue_script('js-myjs');

        // OPZIONALE PERMETTI AGLI SHORTCODE DI FUNZIONARE NEL WIDGET DI TESTO
        add_filter( 'widget_text', 'shortcode_unautop');
        add_filter( 'widget_text', 'do_shortcode'); 

    }

  return $text;

}
add_filter('widget_text', 'check_shortcode');
21 dic 2016 18:33:31
0

Ho combinato il codice di esempio dalla pagina di Wordpress per has_shortcode() e la risposta data da zndencka. Ho notato che la funzione has_shortcode è stata aggiunta in Wordpress 3.6, motivo per cui controllo prima se la funzione esiste. Forse questo controllo è un po' obsoleto, dato che non ci sono molti utenti con versioni inferiori a Wordpress 3.6 secondo le statistiche ufficiali di Wordpress.

// Questo assicura che lo stile sia già accodato nell'header, prima che lo shortcode venga caricato nella pagina/post
function enqueue_shortcode_header_script() {
    global $post;
    if ( function_exists( 'has_shortcode' ) ){  // aggiunto in wordpress 3.6
        // Fonte: https://codex.wordpress.org/Function_Reference/has_shortcode
        if( is_a( $post, 'WP_Post' ) && has_shortcode( $post->post_content, 'my_shortcode') ) {
            wp_enqueue_style( 'shortcode-css' );
        }
    }
    else if ( isset($post->ID) ) { // Piccola percentuale di utenti wordpress è sotto la 3.6 https://wordpress.org/about/stats/
        global $wpdb;
        $result = $wpdb->get_var(
          $wpdb->prepare(
              "SELECT count(*) FROM $wpdb->postmeta " .
              "WHERE post_id = %d and meta_value LIKE '%%my_shortcode%%'",
               $post->ID )
        );
        if (!empty( $result )) { wp_enqueue_style( 'shortcode-css' ); }
    }
}
add_action( 'wp_enqueue_scripts', 'enqueue_shortcode_header_script');
12 apr 2019 16:35:39
0

Utilizzo WordPress versione 5.4 con uno stile di codice OOP, non so se questo influisce sul motivo per cui nessuna delle soluzioni sopra indicate ha funzionato per me, quindi ho trovato questa soluzione:

public function enqueue_scripts() {
 global $post;
 //error_log( print_r( $post, true ) );
 //error_log( print_r(  $post->post_content, true ) );
 //error_log( print_r(  strpos($post->post_content, '[YOUR_SHORTCODE]'),true));

 if ( is_a( $post, 'WP_Post' ) && strpos($post->post_content, '[YOUR_SHORTCODE]') ) 
 {
     wp_register_style('my-css', $_css_url);
     wp_register_script('my-js', $_js_url);
 }
}

Spero che questo possa aiutare qualcuno.

14 apr 2020 18:02:52