web-dev-qa-db-fra.com

Chargement conditionnel de JavaScript/CSS pour les codes courts

J'ai publié un plugin qui crée un shortcode et nécessite un fichier JavaScript et un fichier CSS à charger sur toute page contenant ce shortcode. Je pourrais simplement faire en sorte que le script/style soit chargé sur toutes les pages, mais ce n'est pas la meilleure pratique. Je veux seulement charger les fichiers sur les pages qui appellent le shortcode. J'ai trouvé deux méthodes pour le faire, mais les deux ont des problèmes.

Méthode 1 attribue la valeur true à un indicateur dans la fonction de gestionnaire de shortcode, puis vérifie cette valeur dans un rappel wp_footer. Si c'est vrai, il utilise wp_print_scripts() pour charger le code JavaScript. Le problème avec ceci est que cela ne fonctionne que pour JavaScript et pas CSS, car CSS doit être déclaré dans <head>, ce que vous ne pouvez faire que pendant un hook précoce comme init ou wp_head.

Méthode 2 tire très tôt et "regarde en avant" pour voir si le shortcode existe dans le contenu de la page en cours. J'aime cette méthode beaucoup mieux que la première, mais le problème qu'elle pose ne détecte pas si le modèle appelle do_shortcode().

Donc, je suis plutôt enclin à utiliser la deuxième méthode, puis à essayer de détecter si un modèle est attribué et, le cas échéant, à l’analyser pour le shortcode. Avant de faire cela, cependant, je voulais vérifier si quelqu'un connaissait une meilleure méthode.

Mise à jour: J'ai intégré la solution dans mon plugin. Si quelqu'un est curieux de le voir se développer dans un environnement réel, vous pouvez le télécharger ou le parcourir .

Mise à jour 2: À partir de WordPress 3.3, il est maintenant possible de appeler wp_enqueue_script() directement dans un rappel de shortcode , et le fichier JavaScript sera appelé dans le pied de page du document. C'est techniquement possible pour les fichiers CSS également, mais cela devrait être considéré comme une mauvaise pratique car la sortie de CSS en dehors de la balise <head> enfreint les spécifications du W3C, peut avoir un effet FOUC et obliger le navigateur à restituer la page.

37
Ian Dunn

Sur la base de ma propre expérience, j’ai utilisé une combinaison des méthodes 1 et 2 - l’architecture et les scripts de pied de page de 1, et la technique de "recherche prospective" de 2.

Pour l’avenir, j’utilise regex à la place de stripos; préférence personnelle, plus rapidement, et peut vérifier pour shortcode "malformé";

preg_match( '#\[ *shortcode([^\]])*\]#i', $content );

Si vous êtes préoccupé par le fait que les auteurs utilisent do_shortcode manuellement, je choisirais de leur demander de utiliser un appel d'action mettre en file d'attente votre style pré-enregistré manuellement.

UPDATE: Pour l'auteur paresseux qui n'a jamais RTFM, envoie un message pour mettre en évidence le erreur de ses manières;)

function my_shortcode()
{
    static $enqueued;
    if ( ! isset( $enqueued ) )
        $enqueued = wp_style_is( 'my_style', 'done' ); // cache it so we don't repeat if called over and over

    // do shortcode
    $output = '';

    if ( ! $enqueued )
        // you can output the message on first occurence only by wrapping it in the previous if
        $output .= <<<HTML
<p>Attention! You must enqueue the shortcode stylesheet yourself if calling <code>do_shortcode()</code> directly!</p>
<p>Use <code>wp_enqueue_style( 'my_style' );</code> before your <code>get_header()</code> call inside your template.</p>
HTML;

    return $output;
}
11
TheDeadMedic

Je réponds tardivement à cette question mais depuis qu'Ian a commencé ce fil sur la liste des wp-hackers aujourd'hui, cela m'a fait penser que cela valait la peine de répondre, d'autant plus que j'ai prévu d'ajouter une telle fonctionnalité à certains plugins que j'ai visités travaille sur.

Une approche à considérer consiste à vérifier, lors du chargement de la première page, si le shortcode est réellement utilisé, puis à enregistrer le statut d'utilisation du shortcode dans une clé méta de publication. Voici comment:

Comment faire étape par étape

  1. Définissez un indicateur $shortcode_used sur 'no'.
  2. Dans la fonction shortcode, définissez l'indicateur $shortcode_used sur 'yes'.
  3. Définissez la priorité 'the_content' du hook 12 après que WordPress a traité les codes abrégés et vérifiez la valeur méta de posta pour un '' à l'aide de la clé "_has_{$shortcode_name}_shortcode". (Une valeur de '' est renvoyée lorsqu'une clé méta de publication n'existe pas pour l'ID de publication.)
  4. Utilisez un point d'ancrage 'save_post' pour supprimer la publication meta en effaçant l'indicateur de persistance pour cette publication au cas où l'utilisateur modifierait l'utilisation du code court.
  5. Également dans le hook 'save_post', utilisez wp_remote_request() pour envoyer un HTTP GET non bloquant au permalien de la publication afin de déclencher le chargement de la première page et le paramétrage de l'indicateur de persistance.
  6. Enfin, définissez un 'wp_print_styles' et vérifiez dans la métrique de post pour une valeur de 'yes', 'no' ou '' en utilisant la clé "_has_{$shortcode_name}_shortcode". Si la valeur est 'no', ne servez pas l'externe. Si la valeur est 'yes' ou '', continuez et servez le serveur externe.

Et cela devrait le faire. J'ai écrit et testé un exemple de plug-in pour montrer comment tout cela fonctionne.

Exemple de code de plugin

Le plugin se réveille sur un shortcode [trigger-css] qui définit les éléments <h2> de la page en blanc sur rouge afin que vous puissiez facilement le voir fonctionner. Il suppose un sous-répertoire css contenant le fichier style.css contenant ce CSS:

/*
 * Filename: css/style.css
 */
h2 {
  color: white;
  background: red;
}

Et ci-dessous est le code dans un plugin de travail:

<?php
/**
 * Plugin Name: CSS on Shortcode
 * Description: Shows how to conditionally load a shortcode
 * Author: Mike Schinkel <[email protected]>
 */
class CSS_On_Shortcode {

  /**
   * @var CSS_On_Shortcode
   */
  private static $_this;

  /**
   * @var string 'yes'/'no' vs. true/false as get_post_meta() returns '' for false and not found.
   */
  var $shortcode_used = 'no';

  /**
   * @var string
   */
  var $HAS_SHORTCODE_KEY = '_has_trigger-css_shortcode';
  /**
   *
   */
  function __construct() {
    self::$_this = $this;
    add_shortcode( 'trigger-css', array( $this, 'do_shortcode' ) );
    add_filter( 'the_content', array( $this, 'the_content' ), 12 ); // AFTER WordPress' do_shortcode()
    add_action( 'save_post', array( $this, 'save_post' ) );
    add_action( 'wp_print_styles', array( $this, 'wp_print_styles' ) );
  }

  /**
   * @return CSS_On_Shortcode
   */
  function this() {
    return self::$_this;
  }

  /**
   * @param array $arguments
   * @param string $content
   * @return string
   */
  function do_shortcode( $arguments, $content ) {
    /**
     * If this shortcode is being used, capture the value so we can save to post_meta in the 'the_content' filter.
     */
    $this->shortcode_used = 'yes';
    return '<h2>THIS POST WILL ADD CSS TO MAKE H2 TAGS WHITE ON RED</h2>';
  }

  /**
   * Delete the 'has_shortcode' meta value so that it can be regenerated
   * on first page load in case shortcode use has changed.
   *
   * @param int $post_id
   */
  function save_post( $post_id ) {
    delete_post_meta( $post_id, $this->HAS_SHORTCODE_KEY );
    /**
     * Now load the post asynchronously via HTTP to pre-set the meta value for $this->HAS_SHORTCODE_KEY.
     */
    wp_remote_request( get_permalink( $post_id ), array( 'blocking' => false ) );
  }

  /**
   * @param array $args
   *
   * @return array
   */
  function wp_print_styles( $args ) {
    global $post;
    if ( 'no' != get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * Only bypass if set to 'no' as '' is unknown.
       */
      wp_enqueue_style( 'css-on-shortcode', plugins_url( 'css/style.css', __FILE__ ) );
    }
   }

  /**
   * @param string $content
   * @return string
   */
  function the_content( $content ) {
    global $post;
    if ( '' === get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
      /**
       * This is the first time the shortcode has ever been seen for this post.
       * Save a post_meta key so that next time we'll know this post uses this shortcode
       */
      update_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, $this->shortcode_used );
    }
    /**
     * Remove this filter now. We don't need it for this post again.
     */
    remove_filter( 'the_content', array( $this, 'the_content' ), 12 );
    return $content;
  }

}
new CSS_On_Shortcode();

Exemple de captures d'écran

Voici une série de captures d'écran

Post Editor basique, sans contenu

Affichage post, pas de contenu

Éditeur de messages de base avec [trigger-css] Shortcode

Affichage de poste avec [trigger-css] Shortcode

Pas sûr si c'est 100%

Je crois que ce qui précède devrait fonctionner dans presque tous les cas, mais comme je viens d'écrire ce code, je ne peux pas être sûr à 100%. Si vous pouvez trouver des situations où cela ne fonctionne pas, j'aimerais vraiment savoir si je peux corriger le code dans certains plugins auxquels j'ai ajouté ceci. Merci d'avance.

8
MikeSchinkel

Googling m'a trouvé un potentiel répondre . Je dis "potentiel", car cela a l'air bien, ça devrait marcher, mais je ne suis pas convaincu à 100% que c'est la meilleure façon de le faire:

add_action( 'wp_print_styles', 'yourplugin_include_css' );
function yourplugin_include_css() {
    // Check if shortcode exists in page or post content
    global $post;

    // I removed the end ' ] '... so it can accept args.
    if ( strstr( $post->post_content, '[yourshortcode ' ) ) {
        echo $csslink;
    }
}

Cela devrait pouvoir vérifier si la publication en cours utilise un shortcode et ajouter une feuille de style à l'élément <head> de manière appropriée. Mais je ne pense pas que cela fonctionnera pour une page d'index (c.-à-d. Plusieurs publications dans la boucle) ... Elle provient également d'un blog de 2 ans, je ne suis même pas sûr que cela fonctionne avec WP 3.1.X.

5
EAMann

En combinant la réponse de TheDeadMedic et le get_shortcode_regex () documentation (qui n’a pas trouvé mes codes abrégés), j’ai créé une fonction simple permettant de mettre en file d'attente les scripts de plusieurs codes abrégés. Comme wp_enqueue_script () dans les codes abrégés ne fait qu'ajouter au pied de page, cela peut être utile car il peut gérer les scripts d'en-tête et de pied de page.


function add_shortcode_scripts() {
    global $wp_query;   
    $posts = $wp_query->posts;
    $scripts = array(
        array(
            'handle' => 'map',
            'src' => 'http://maps.googleapis.com/maps/api/js?sensor=false',
            'deps' => '',
            'ver' => '3.0',
            'footer' => false
        ),
        array(
            'handle' => 'contact-form',
            'src' => get_template_directory_uri() . '/library/js/jquery.validate.min.js',
            'deps' => array( 'jquery' ),
            'ver' => '1.11.1',
            'footer' => true
        )   
    );

    foreach ( $posts as $post ) {
        foreach ( $scripts as $script ) {
            if ( preg_match( '#\[ *' . $script['handle'] . '([^\]])*\]#i', $post->post_content ) ) {
                // enqueue css and/or js
                if ( wp_script_is( $script['handle'], 'registered' ) ) {
                    return;
                } else {
                    wp_register_script( $script['handle'], $script['src'], $script['deps'], $script['ver'], $script['footer'] );
                    wp_enqueue_script( $script['handle'] );
                }
            }
        }
    }
}
add_action( 'wp', 'add_shortcode_scripts' );
2
Sean Michaud

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

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' );
1
zdenekca

Enfin, j’ai également trouvé une solution de chargement css conditionnel qui fonctionne pour mon plugin www.mapsmarker.com et j’aimerais partager avec vous. Il vérifie si mon shortcode est utilisé dans le fichier de modèle actuel et dans l'en-tête/footer.php et, dans l'affirmative, met la feuille de style nécessaire dans l'en-tête:

  function prefix_template_check_shortcode( $template ) {
    $searchterm = '[mapsmarker';
    $files = array( $template, get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'header.php', get_stylesheet_directory() . DIRECTORY_SEPARATOR . 'footer.php' );
    foreach( $files as $file ) {
        if( file_exists($file) ) {
            $contents = file_get_contents($file);
            if( strpos( $contents, $searchterm )  ) {
                wp_enqueue_style('
leafletmapsmarker', LEAFLET_PLUGIN_URL . 'leaflet-dist/leaflet.css');
                  break; 
            }
        }
    }
  return $template;
  }  
  add_action('template_include','prefix_template_check_shortcode' );
1
robertharm

Script Logic est un plugin WordPress qui vous donne un contrôle total sur tous les fichiers JavaScript et CSS. En utilisant ce plugin, vous pouvez conditionnellement charger le fichier CSS et JS uniquement sur les pages où cela est nécessaire.

http://wordpress.org/plugins/script-logic/

0
Tahir Yasin

parce que CSS doit être déclaré à l'intérieur de <head>

Pour les fichiers CSS, vous pouvez les charger dans la sortie de votre shortcode:

<style type="text/css">
  @import "path/to/your.css"; 
</style>

Définissez une constante ou quelque chose après cela, comme MY_CSS_LOADED (n'incluez le CSS que si la constante n'est pas définie).

Vos deux méthodes sont plus lentes que d'aller de cette façon.

Pour les fichiers JS, vous pouvez faire de même si le script que vous chargez est unique et ne comporte aucune dépendance extérieure. Si ce n'est pas le cas, chargez-le à l'intérieur du pied de page, mais utilisez la constante pour déterminer si vous devez le charger ou non ...

0
onetrickpony