Scripts / styles en file d'attente en présence d'un shortcode

54

Quel est le moyen idéal pour enregistrer / mettre en file d'attente des scripts et / ou des styles à utiliser dans des plugins?

J'ai récemment créé un plugin simple permettant d'ajouter l'avatar / gravatar de l'utilisateur avec un shortcode. J'ai différentes options de style pour afficher l'avatar (carré, rond, etc.) et j'ai décidé de mettre le css directement dans le shortcode lui-même.

Cependant, je réalise maintenant que ce n’est pas une bonne approche car il répète le css chaque fois que le shortcode est utilisé sur une page. J'ai vu plusieurs autres approches sur ce site et le codex wp en a même deux exemples. Il est donc difficile de savoir quelle approche est la plus cohérente et la plus rapide.

Voici les méthodes que je connais actuellement:

Méthode 1: Inclure directement dans le shortcode - C'est ce que je suis en train de faire dans le plug-in, mais cela ne semble pas bien car cela répète du code.

class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* simply enqueue or print the scripts/styles in the shortcode itself */
?>
<style type="text/css">

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

Méthode 2: Utiliser la classe pour la mise en file d'attente des scripts ou des styles de manière conditionnelle

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;
        // shortcode handling here
    }
    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();

Méthode 3: Utiliser 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' );

Méthode 4: Utiliser 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');
Bryan Willis
la source
Je pense que Method 4: Using has_shortcode();c'est mieux car cela garantira que les scripts et les styles seront chargés une seule fois si le contenu de la publication comporte un shortcode, indépendamment de ses multiples utilisations. Bien que cela puisse ne pas fonctionner pour les utilisations de shortcode dans les widgets ou dans la barre latérale, je ne suis pas certain. Si c'est pour un plugin, alors je ne vous recommanderais pas de lier les scripts avec shortcode car certains pourraient appeler votre fonction au lieu de shortcode pour obtenir le résultat souhaité.
Robert hue

Réponses:

45

J'ai trouvé un autre moyen qui fonctionne bien pour moi:

Voici un exemple de plugin utilisant cette méthode qui vous permet d’utiliser get_avatar en tant que shortcode. La feuille de style n'est mise en file d'attente que lorsque le shortcode est présent.

Utilisation (id par défaut pour l'utilisateur actuel):

[get_avatar id="" size="32" default="mystery" alt="Profile Photo" 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' );
}
jblanche
la source
J'ai oublié de poser cette question l'année dernière, mais j'avais déjà commencé à le faire de la même manière dans de nombreux cas. C'est un peu comme si on combinait les méthodes 1 et 2.
Bryan Willis
4
Cette méthode charge le CSS dans le pied de page, qui a sûrement des limites?
Jacob Raccuia
2
C'est absolument la bonne façon de faire cela. Utilisez cette méthode chaque fois que vous avez besoin de charger de manière conditionnelle un script ou une feuille de style lorsque le wp_enqueue_scriptsraccordement est déjà effectué. (Les codes courts sont analysés pendant the_contentune partie du the_postcrochet, ce qui signifie que la mise en file d'attente quand il est analysé est trop tardive à moins que vous n'ayez déjà enregistré le script)
JRad the Bad
26

Avant de commencer, je dois dire que css et js ne sont pas les mêmes.

La raison en est simple: bien que l'ajout de js au corps de la page (en pied de page) soit une solution courante et valable, css doit être placé dans la <head>section de la page: même si la majorité des navigateurs peuvent rendre le css correctement dans la page. corps, ce n'est pas un code HTML valide.

Quand un shortcode est rendu, la <head>section était déjà imprimée, cela signifie que js peut être ajouté sans problème sur le pied de page, mais css doit être ajouté avant le rendu du shortcode.

Les scripts

Si votre shortcode n'a besoin que de js, vous avez de la chance et pouvez simplement l'utiliser wp_enqueue_scriptdans le corps du rappel de shortcode:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

function my_handle_shortcode() {
  wp_enqueue_script( 'myshortcodejs', '/path/to/js/file.js' );
  // rest of code here...
}

Ce faisant, votre script est ajouté au pied de page et une seule fois, même si le shortcode est utilisé plusieurs fois dans la page.

modes

Si votre code a besoin de styles, vous devez agir avant que le shortcode ne soit réellement restitué.

Il y a d'autres façons de le faire:

  1. examinez tous les articles de la requête en cours et ajoutez les styles de shortcode si nécessaire. C'est ce que vous faites dans les méthodes 3 et 4 de l'OP. En fait, les deux méthodes font la même chose, mais ont has_shortcodeété ajoutées à WP 3.6, alors qu’elles get_shortcode_regexsont disponibles à partir de la version 2.5, utilisez-les get_shortcode_regexuniquement si vous souhaitez rendre votre plugin compatible avec les versions antérieures.

  2. toujours ajouter un style shortcode, dans toutes les pages

Problèmes

Le problème avec # 1 est la performance. Les regex sont des opérations assez lentes et lancer regex dans une boucle de toutes les publications peut ralentir la page de manière cohérente. De plus, il est assez commun dans les thèmes de ne montrer que les extraits de messages dans les archives et d'afficher le contenu complet avec des codes abrégés uniquement dans des vues uniques. Si cela se produit, lorsqu’une archive est affichée, votre plugin lancera une correspondance regex dans une boucle dans le but d’ajouter un style qui ne sera jamais utilisé: un double impact inutile sur les performances: ralentissement de la génération de la page + demande HTTP inutile supplémentaire.

Le problème avec # 2 est la performance, encore. Ajouter du style à toutes les pages signifie ajouter une requête HTTP supplémentaire pour toutes les pages, même si elles ne sont pas nécessaires. Même si le temps de génération de page côté serveur n'est pas affecté, le temps de rendu de page total sera appliqué à toutes les pages du site.

Alors, que doit faire un développeur de plugin?

Je pense que la meilleure chose à faire est d’ajouter une page d’options au plugin, dans laquelle les utilisateurs peuvent choisir si le shortcode doit être traité en vue unique ou même dans les archives. Dans les deux cas, il est préférable de fournir une autre option permettant de choisir les types de publication pour lesquels le code abrégé est activé.

De cette façon, il est possible d’accrocher "template_redirect"pour vérifier si la requête actuelle satisfait aux exigences et, dans ce cas, ajouter le style.

Si l'utilisateur choisit d'utiliser le shortcode uniquement dans les affichages uniques, c'est une bonne idée de vérifier si post a un shortcode: une fois qu'une seule expression régulière est requise, la page ne doit pas être ralentie autant.

Si l'utilisateur choisit d'utiliser le shortcode même dans les archives, j'éviterais alors d'exécuter regex pour toutes les publications si le nombre de publications est élevé et de simplement mettre en file d'attente le style si les exigences de la requête sont suffisantes.

Ce qu’il faut considérer comme "élevé" à cet égard devrait être d’utiliser des tests de performance ou, au lieu de cela, d’ajouter une autre option et de donner le choix aux utilisateurs.

gmazzap
la source
2
Il convient de noter ici que les <style>balises dans le corps du document sont maintenant valides selon les spécifications du W3C. w3.org/TR/html52/document-metadata.html#the-style-element
Isaac Lubow
5

Pour mon plugin, j'ai constaté que parfois les utilisateurs ont un générateur de thème qui a un shortcode stocké dans des méta-données post . Voici ce que j'utilise pour détecter si mon shortcode de plugin est présent dans les métadonnées post ou post actuelles :

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

       // determine whether this page contains "my_shortcode" 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' );
Zdenekca
la source
2

Je le fais:

class My_Shortcode {

    function __construct() {
        do_action('my_start_shortcode'); // call
....

et accrocher le crochet dans d'autres fonctions (ou d'autres plugins):

function wpse_3232_load_script(){
    wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
Wladimir Druzhaev
la source
1

J'ai découvert pour mon propre plugin, si le shortcode est présent dans le widget de texte.

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 is being used

        // enque my css and js
        /****** Enqueu RFNB  ******/
        wp_enqueue_style('css-mycss');
        wp_enqueue_script('js-myjs');

        // OPTIONAL ALLOW SHORTCODE TO WORK IN TEXT WIDGET
        add_filter( 'widget_text', 'shortcode_unautop');
        add_filter( 'widget_text', 'do_shortcode'); 

    }

  return $text;

}
add_filter('widget_text', 'check_shortcode');
Gino
la source
1

WordPress possède une fonction intégrée permettant de faire quelque chose en fonction d'un statut de présentation de Shortcode spécifique. Le nom de la fonction est has_shortcode(). Vous pouvez utiliser le code suivant pour mettre en file d'attente votre style et vos scripts.

Ici, j'ai utilisé le is_a( $post, 'WP_Post' )pour vérifier si l' $postobjet est de la WP_Postclasse et $post->post_contentle contenu de la publication.

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' );
}
Arif Rahman
la source
0

J'ai fait une combinaison de l'exemple de code de la page Wordpress pour has_shortcode () et de la réponse donnée par zndencka . J'ai remarqué que la fonction has_shortcode est ajoutée dans Wordpress 3.6, c'est pourquoi je vérifie d'abord si la fonction existe. Peut-être que cette vérification est un peu obsolète cependant, car il n’ya plus beaucoup d’utilisateurs en dessous de wordpress 3.6 selon wordpress leurs propres statistiques.

// This makes sure the styling is already enqueued in the header, so before the shortcode loads in the page/post
function enqueue_shortcode_header_script() {
    global $post;
    if ( function_exists( 'has_shortcode' ) ){  // is added in wordpress 3.6
        // Source: 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) ) { // Small percentage wordpress users are below 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');
Vasco
la source
0

Nous pouvons en effet charger sous condition des fichiers CSS et JS via un shortcode sans utiliser de fonctions trop élaborées :

Tout d’abord, supposons que nous avons enregistré tous nos fichiers CSS / JS précédemment (peut-être lorsqu’ils sont wp_enqueue_scriptsexécutés)

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

Ensuite, examinons notre fonction de shortcode:

function my_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'); }
  ...
}

Facile. Terminé. Ainsi, nous pouvons "charger sous condition" les fichiers css / js (uniquement lorsque [shortcode] est exécuté).

Considérons l'idéologie suivante:

  • Nous voulons charger certains fichiers CSS / JS (mais uniquement lorsque le shortcode est déclenché)
  • Peut-être que nous ne voulons pas que ces fichiers soient chargés sur chaque page, ou même si le shortcode n'est pas utilisé sur une page / une publication. (poids léger)
  • Nous pouvons accomplir cela en nous assurant que WP enregistre TOUS les fichiers css / js avant d'appeler le shortcode et avant la mise en file d'attente.
  • IE: Peut-être que pendant ma prep_css_and_js()fonction je charge TOUS les fichiers .css / .js qui se trouvent dans certains dossiers ...

Maintenant que WP les voit comme des scripts enregistrés, on peut les appeler, conditionnellement, en se basant sur une vérité de situations, y compris mais sans s'y limiter my_shortcode_func()

Avantages: (pas de MySQL, pas de fonctions avancées et pas de filtres nécessaires)

  • c'est "WP orthodix", élégant, chargement rapide, facile et simple
  • permet aux compilateurs / minificateurs de détecter de tels scripts
  • utilise les fonctions WP (wp_register_style / wp_register_script)
  • compatible avec plus de thèmes / plugins qui pourraient vouloir annuler l'enregistrement de ces scripts pour de nombreuses raisons.
  • ne déclenchera pas plusieurs fois
  • très peu de traitement ou de code est impliqué

Références:

Christian Žagarskas
la source