Înregistrare Scripts / Styles când este prezent un shortcode

18 oct. 2014, 10:07:40
Vizualizări: 69.4K
Voturi: 87

Care este cea mai bună modalitate de a înregistra/încărca scripturi și/sau stiluri pentru utilizarea în plugin-uri?

Recent am creat un plugin simplu pentru a adăuga avatarul/gravatarul utilizatorului cu un shortcode. Am diferite opțiuni de stil pentru afișarea avatarului (pătrat, rotund etc.) și am decis să pun CSS-ul direct în shortcode.

Totuși, îmi dau seama acum că această abordare nu este bună deoarece va repeta CSS-ul de fiecare dată când shortcode-ul este utilizat într-o pagină. Am văzut mai multe abordări pe acest site și chiar codexul WP are două exemple proprii, așa că este greu de știut ce abordare este mai consistentă și mai rapidă.

Iată metodele de care sunt conștient în prezent:

Metoda 1: Include direct în shortcode - Aceasta este ce fac momentan în plugin, dar nu pare bine deoarece repetă codul.

class My_Shortcode {
function handle_shortcode( $atts, $content="" ) {
/* pur și simplu încarcă sau afișează scripturile/stilurile în shortcode-ul în sine */
?>
<style type="text/css">

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

Metoda 2: Folosește clasa pentru încărcarea condițională a scripturilor sau stilurilor

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;
        // manipularea shortcode-ului aici
    }
    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();

Metoda 3: Folosind 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' );

Metoda 4: Folosind 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
Comentarii

Cred că Method 4: Using has_shortcode(); este cea mai bună alegere deoarece va asigura că scripturile și stilurile se vor încărca o singură dată dacă conținutul postării conține shortcode, indiferent de utilizarea multiplă a acestuia. Totuși, s-ar putea să nu funcționeze pentru shortcode-urile folosite în widget-uri sau în bara laterală, nu sunt sigur. Dacă este vorba despre un plugin, atunci nu aș recomanda să legi scripturile de shortcode, deoarece unii utilizatori ar putea apela funcția ta în loc de shortcode pentru a obține rezultatul dorit.

Robert hue Robert hue
18 oct. 2014 10:46:54

Posibil duplicat al Cum să adaugi fișiere de stil doar pe paginile cu un anumit shortcode?

kontur kontur
30 mar. 2018 16:35:43

Metoda 4 este bună, dar există o problemă: poate crea dificultăți dacă shortcode-ul nu este adăugat direct în zona de conținut WP, ci în alte opțiuni ale unui plugin terță parte. Ar putea fi util să adaugi o verificare în funcția shortcode ! wp_style_is împreună cu metoda 4 și să încarci stilul acolo în cazul în care nu a fost adăugat în callback-ul anterior wp_enqueue_scripts.

Adeel Raza Adeel Raza
14 oct. 2020 13:23:43

Metoda 4 nu va funcționa dacă pagina solicitată este ceva precum pagina principală, pagina de index, iar primul post nu conține niciun shortcode. Restul postărilor nu vor afișa corect CSS-ul și JS-ul shortcode-ului.

vee vee
1 ian. 2023 21:17:19
Toate răspunsurile la întrebare 10
4
88

Am găsit o altă metodă care funcționează bine pentru mine:

Iată un exemplu de plugin care utilizează această metodă, permițându-vă să folosiți get_avatar într-un shortcode. Fișierul de stil este încărcat doar atunci când shortcode-ul este prezent.

Utilizare (id implică utilizatorul curent):

[get_avatar id="" size="32" default="mystery" alt="Poza de profil" 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 iun. 2015 15:28:58
Comentarii

Am uitat că am pus această întrebare anul trecut, dar de fapt am început să fac și eu în felul acesta în multe cazuri. E un fel de combinație între metoda 1 și 2.

Bryan Willis Bryan Willis
8 iul. 2015 20:36:53

Această metodă încarcă CSS-ul în footer, ceea ce cu siguranță are limitări?

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

Aceasta este cu siguranță metoda corectă de a face acest lucru. Folosește această metodă ori de câte ori ai nevoie să încarci condiționat un script sau o foaie de stil după ce hook-ul wp_enqueue_scripts a avut deja loc. (Shortcode-urile sunt parsate în timpul the_content, care face parte din hook-ul the_post, ceea ce înseamnă că încărcarea lor în momentul parsării este prea târziu, cu excepția cazului în care scriptul a fost deja înregistrat)

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

Acest lucru nu este util, deoarece creează FOUT atunci când stilul este încărcat în funcția shortcode-ului. Este mai bine să folosești metoda has_shortcode.

Adeel Raza Adeel Raza
14 oct. 2020 13:27:58
3
35

Înainte de a începe răspunsul, trebuie să menționez că în ceea ce privește acest subiect, CSS și JS nu sunt același lucru.

Motivul este simplu: în timp ce adăugarea JS în corpul paginii (în footer) este o metodă comună și validă, CSS trebuie plasat în secțiunea <head> a paginii: chiar dacă majoritatea browserelor pot afișa corect CSS în corpul paginii, acest lucru nu este un cod HTML valid.

Când un shortcode este randat, secțiunea <head> a fost deja afișată, ceea ce înseamnă că JS poate fi adăugat fără probleme în footer, dar CSS trebuie adăugat înainte ca shortcode-ul să fie randat.

Scripturi

Dacă shortcode-ul tău are nevoie doar de JS, ai noroc și poți folosi direct wp_enqueue_script în corpul funcției de callback a shortcode-ului:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

function my_handle_shortcode() {
  wp_enqueue_script( 'myshortcodejs', '/calea/către/fisier.js' );
  // restul codului aici...
}

Astfel, scriptul tău va fi adăugat în footer și doar o singură dată, chiar dacă shortcode-ul este folosit de mai multe ori în pagină.

Stiluri

Dacă codul tău necesită stiluri, atunci trebuie să acționezi înainte ca shortcode-ul să fie randat.

Există diferite metode pentru a face acest lucru:

  1. verifică toate articolele din interogarea curentă și adaugă stilurile shortcode-ului dacă este necesar. Aceasta este metoda pe care o folosești atât în metoda #3 cât și în #4 din OP. De fapt, ambele metode fac același lucru, dar has_shortcode a fost adăugat în WP 3.6, în timp ce get_shortcode_regex este disponibil începând cu versiunea 2.5, așa că folosește get_shortcode_regex doar dacă vrei să faci plugin-ul compatibil cu versiuni mai vechi.

  2. adaugă mereu stilurile shortcode-ului, în toate paginile

Probleme

Problema cu #1 este performanța. Expresiile regulate (regex) sunt operații destul de lente, iar rularea lor într-o buclă pentru toate articolele poate încetini semnificativ pagina. În plus, este o practică comună în teme să afișezi doar fragmentul articolului în arhive și conținutul complet cu shortcode-uri doar în vizualizările individuale. Dacă acest lucru se întâmplă, când este afișată o arhivă, plugin-ul tău va rula o potrivire regex într-o buclă cu scopul de a adăuga un stil care nu va fi niciodată folosit: un impact dublu și inutil asupra performanței: încetinirea generării paginii + cerere HTTP suplimentară inutilă.

Problema cu #2 este, din nou, performanța. Adăugarea stilului în toate paginile înseamnă o cerere HTTP suplimentară pentru toate paginile, chiar și atunci când nu este necesar. Chiar dacă timpul de generare al paginii pe server nu este afectat, timpul total de randare al paginii va fi afectat, și asta pentru toate paginile site-ului.

Deci, ce ar trebui să facă un dezvoltator de plugin-uri?

Cred că cel mai bine este să adaugi o pagină de opțiuni în plugin, unde utilizatorii pot alege dacă shortcode-ul ar trebui gestionat doar în vizualizări individuale sau și în arhive. În ambele cazuri, este mai bine să oferi o altă opțiune pentru a alege pentru care tipuri de postări să activezi shortcode-ul.

În acest fel, este posibil să folosești hook-ul "template_redirect" pentru a verifica dacă interogarea curentă îndeplinește cerințele și, în acest caz, să adaugi stilul.

Dacă utilizatorul alege să folosească shortcode-ul doar în vizualizări individuale de postări, este o idee bună să verifici dacă postarea conține shortcode-ul sau nu: deoarece este necesară doar o singură expresie regulată, aceasta nu ar trebui să încetinească prea mult pagina.

Dacă utilizatorul alege să folosească shortcode-ul și în arhive, atunci aș evita să rulez regex pentru toate postările dacă numărul acestora este mare și aș încărca stilul doar dacă interogarea îndeplinește cerințele.

Ceea ce considerăm "mare" în acest context ar trebui stabilit prin teste de performanță sau, ca alternativă, să adaugi o altă opțiune și să lași alegerea utilizatorilor.

18 oct. 2014 11:49:56
Comentarii

Este important de menționat că etichetele <style> în corpul documentului sunt acum valide conform specificației W3C. https://www.w3.org/TR/html52/document-metadata.html#the-style-element

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

@IsaacLubow În prezent (2023): Contexturi în care acest element poate fi utilizat: Într-un element noscript care este copil al unui element head. Am validat <style> în interiorul <body> pe https://validator.w3.org/nu/#textarea dar rezultatul este Eroare: Elementul style nu este permis ca descendent al elementului body în acest context.

vee vee
1 ian. 2023 20:53:56

Dar <link> în interiorul <body> trece de validare.

vee vee
1 ian. 2023 20:56:10
0
11

Pentru plugin-ul meu am descoperit că uneori utilizatorii au un constructor de teme care stochează shortcode-uri în metadatele postării. Iată ce folosesc pentru a detecta dacă shortcode-ul meu este prezent în postarea curentă sau în metadatele postării:

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

       // determină dacă această pagină conține shortcode-ul "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 are o funcție încorporată pentru a face ceva în funcție de starea de prezentare a unui anumit Shortcode. Numele funcției este has_shortcode(). Puteți utiliza următorul cod pentru a încărca stilurile și scripturile dumneavoastră.

Aici am folosit is_a( $post, 'WP_Post' ) pentru a verifica dacă obiectul $post este din clasa WP_Post și am folosit $post->post_content pentru a verifica conținutul postării.

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 oct. 2018 20:04:30
0

Eu fac asta:

class My_Shortcode {

    function __construct() {
        do_action('my_start_shortcode'); // apelează
....

și prind hook-ul în alte funcții (sau alte plugin-uri):

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

După cum a menționat cineva, utilizarea funcției 'has_shortcode' va rezolva problema. Iată exemplul pe care l-am găsit foarte util (Sursa: 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 ian. 2021 22:07:44
1

Putem încărca condiționat fișiere CSS și JS prin intermediul shortcode-urilor fără a folosi funcții prea elaborate:

Mai întâi, să presupunem că am înregistrat toate fișierele noastre CSS/JS anterior (poate când acțiunea wp_enqueue_scripts a rulat)

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 );

În continuare, să examinăm funcția noastră 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'); }
  ...
}

Simplu. Gata. Prin urmare: putem "încărca condiționat" fișiere css/js, (doar când shortcode-ul [shortcode] rulează).

Să luăm în considerare următoarea ideologie:

  • Vrem să încărcăm anumite fișiere CSS/JS (dar doar când shortcode-ul este declanșat)
  • Poate nu vrem ca aceste fișiere să se încarce pe fiecare pagină sau deloc dacă shortcode-ul nu este folosit pe o pagină/post. (ușor)
  • Putem realiza acest lucru asigurându-ne că WP înregistrează TOATE fișierele css/js înainte de apelarea shortcode-ului și înainte de a fi adăugate în coadă.
  • Adică: Poate în funcția mea prep_css_and_js() încarc TOATE fișierele .css/.js care se află în anumite foldere...

Acum că WP le vede ca scripturi înregistrate, le putem apela, condiționat, pe baza unei varietăți de situații, inclusiv dar nu limitat la my_shortcode_func()

Beneficii: (fără MySQL, fără funcții avansate și fără filtre necesare)

  • acest lucru este "ortodox WP", elegant, rapid, ușor și simplu
  • permite compilatoarelor/minificatoarelor să detecteze astfel de scripturi
  • folosește funcțiile WP (wp_register_style/wp_register_script)
  • compatibil cu mai multe teme/plugin-uri care ar putea dori să dezînregistreze acele scripturi din diverse motive.
  • nu se va declanșa de mai multe ori
  • foarte puțină procesare sau cod este implicat

Referințe:

16 sept. 2019 00:00:38
Comentarii

Această metodă încarcă stilurile sub subsol. De obicei, este mai bine să le plasați în head.

leclaeli leclaeli
8 mai 2024 23:24:14
0

Am descoperit pentru propriul meu plugin, cum să verific dacă shortcode-ul este prezent în widget-ul text.

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] ) )
    {
        // shortcode-ul meu este folosit

        // încarcă fișierele css și js
        /****** Încărcare RFNB  ******/
        wp_enqueue_style('css-mycss');
        wp_enqueue_script('js-myjs');

        // OPȚIONAL PERMITE FUNCȚIONAREA SHORTCODE ÎN WIDGET-UL TEXT
        add_filter( 'widget_text', 'shortcode_unautop');
        add_filter( 'widget_text', 'do_shortcode'); 

    }

  return $text;

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

Am făcut o combinație între codul exemplu de pe pagina WordPress pentru has_shortcode() și răspunsul dat de zndencka. Am observat că funcția has_shortcode a fost adăugată în WordPress 3.6, de aceea verific mai întâi dacă funcția există. Poate că această verificare este puțin învechită, deoarece nu mai sunt mulți utilizatori cu versiuni sub WordPress 3.6, conform statisticilor oficiale WordPress.

// Acest cod asigură că stilizarea este deja încărcată în header, înainte ca shortcode-ul să se încarce în pagină/post
function enqueue_shortcode_header_script() {
    global $post;
    if ( function_exists( 'has_shortcode' ) ){  // a fost adăugată în WordPress 3.6
        // Sursă: 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) ) { // Un procent mic de utilizatori WordPress sunt sub 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

Eu folosesc WordPress Versiunea 5.4 cu stilul OOP de cod și nu știu dacă acest lucru afectează motivul pentru care niciuna din soluțiile de mai sus nu a funcționat pentru mine, așa că am venit cu această soluție:

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);
 }
}

Sper că acest lucru ajută pe cineva.

14 apr. 2020 18:02:52