Kolejkuj skrypty / style, gdy występuje krótki kod

54

Jaki jest pomysł na rejestrację / kolejkowanie skryptów i / lub stylów do użytku we wtyczkach?

Niedawno stworzyłem wtyczkę prostą wtyczkę, aby dodać awatar użytkownika / gravatar z krótkim kodem. Mam różne opcje wyświetlania awatara (kwadratowy, okrągły itp.) I postanowiłem umieścić css bezpośrednio w samym krótkim kodzie.

Zdaję sobie jednak sprawę, że nie jest to dobre podejście, ponieważ będzie powtarzać css za każdym razem, gdy na stronie zostanie użyty krótki kod. Widziałem kilka innych podejść na tej stronie, a kodeks wp ma nawet dwa własne przykłady, więc trudno jest ustalić, które podejście jest najbardziej spójne i najszybsze.

Oto metody, które obecnie znam:

Metoda 1: Uwzględnij bezpośrednio w krótkim kodzie - tak właśnie robię we wtyczce, ale nie wydaje się dobra, ponieważ powtarza kod.

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

Metoda 2: Użyj klasy do warunkowego kolejkowania skryptów lub stylów

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

Metoda 3: Używanie 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: Używanie 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
źródło
Myślę, że Method 4: Using has_shortcode();najlepiej, ponieważ zapewni to, że skrypty i style zostaną załadowane jeden raz, jeśli treść postu ma krótki kod, niezależnie od jego wielokrotnego użycia. Chociaż może nie działać w przypadku użycia krótkiego kodu w widżetach lub na pasku bocznym, nie jestem jednak pewien. Jeśli dotyczy wtyczki, nie polecam wiązania skryptów za pomocą shortcode, ponieważ niektórzy mogą wywołać twoją funkcję zamiast shortcode, aby uzyskać pożądany wynik.
Robert hue

Odpowiedzi:

45

Znalazłem inny sposób, który działa dla mnie dobrze:

Oto przykładowa wtyczka korzystająca z tej metody, która pozwala używać get_avatar jako shortcode. Arkusz stylów jest kolejkowany tylko wtedy, gdy występuje krótki kod.

Użycie (domyślnie id dla bieżącego użytkownika):

[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
źródło
Zapomniałem, że zadałem to pytanie w zeszłym roku, ale tak naprawdę zacząłem to robić w wielu przypadkach. To trochę jak połączenie metody 1 i 2.
Bryan Willis
4
Ta metoda ładuje CSS w stopce, która z pewnością ma ograniczenia?
Jacob Raccuia
1
Jest to absolutnie właściwy sposób na zrobienie tego. Użyj tej metody za każdym razem, gdy musisz warunkowo załadować skrypt lub arkusz stylów, gdy wp_enqueue_scriptshak już się pojawił. (Skróty są analizowane, podczas the_contentktórych jest częścią przechwytywania the_post, co oznacza, że ​​kolejkowanie podczas analizowania jest zbyt późne, chyba że skrypt został już zarejestrowany)
JRad the Bad
26

Przed rozpoczęciem odpowiedzi muszę powiedzieć, że w tym temacie css i js nie są takie same.

Powód jest prosty: podczas gdy dodawanie js do treści strony (w stopce) jest powszechną i prawidłową drogą, css musi być umieszczony w <head>sekcji strony: nawet jeśli większość przeglądarek potrafi poprawnie renderować css na stronie body, to nie jest poprawny kod HTML.

Gdy renderowany jest krótki kod, <head>sekcja została już wydrukowana, oznacza to, że można dodać js bez problemu w stopce, ale css musi zostać dodany przed renderowaniem krótkiego kodu.

Skrypty

Jeśli twój shortcode potrzebuje tylko js, ​​masz szczęście i możesz go użyć wp_enqueue_scriptw treści zwrotnej shortcode:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

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

W ten sposób skrypt zostanie dodany do stopki i tylko raz, nawet jeśli krótki kod zostanie użyty więcej niż jeden raz na stronie.

Style

Jeśli kod wymaga stylów, musisz działać, zanim skrót zostanie zrenderowany.

Można to zrobić na różne sposoby:

  1. spójrz na wszystkie posty w bieżącym zapytaniu i dodaj style krótkiego kodu, jeśli to konieczne. Tak właśnie postępujesz w metodzie nr 3 i nr 4 w OP. W rzeczywistości obie metody robią to samo, ale has_shortcodezostały dodane w WP 3.6, podczas gdy get_shortcode_regexsą dostępne od wersji 2.5, więc używaj get_shortcode_regextylko, jeśli chcesz, aby Twoja wtyczka była kompatybilna ze starszymi wersjami.

  2. zawsze dodawaj styl krótkiego kodu na wszystkich stronach

Zagadnienia

Problem z numerem 1 dotyczy wydajności. Regex to dość powolne operacje i uruchomienie wyrażenia regularnego w pętli wszystkich postów może konsekwentnie spowalniać stronę. Ponadto w motywach dość powszechne jest wyświetlanie tylko fragmentów postów w archiwach i wyświetlanie pełnej zawartości ze skrótami tylko w pojedynczych widokach. Jeśli tak się stanie, gdy zostanie wyświetlone archiwum, wtyczka uruchomi dopasowanie pętli regularnej w pętli w celu dodania stylu, który nigdy nie będzie używany: niepotrzebny wpływ na podwójną wydajność: spowolnienie generowania strony + dodatkowe niepotrzebne żądanie HTTP

Problem z nr 2 to znowu wydajność. Dodanie stylu do wszystkich stron oznacza dodanie dodatkowego żądania HTTP dla wszystkich stron, nawet jeśli nie jest to potrzebne. Nawet jeśli nie ma to wpływu na czas generowania strony po stronie serwera, całkowity czas renderowania strony się zmieni i dla wszystkich stron witryny.

Co powinien zrobić programista wtyczek?

Myślę, że najlepszą rzeczą jest dodanie strony wtyczki do opcji, w której użytkownicy mogą wybrać, czy shortcode powinien być obsługiwany tylko w widoku pojedynczym, czy nawet w archiwach. W obu przypadkach lepiej jest podać inną opcję wyboru, dla których typów postów włącz skrót.

W ten sposób można "template_redirect"przechwycić, czy bieżące zapytanie spełnia wymagania, i w takim przypadku dodać styl.

Jeśli użytkownik zdecyduje się używać shortcode tylko w pojedynczych widokach postów, dobrym pomysłem jest sprawdzenie, czy post ma shortcode, czy nie: gdy wymagany jest tylko jeden wyrażenie regularne, nie powinien on zbytnio spowalniać strony.

Jeśli użytkownik zdecyduje się na użycie shortcode nawet w archiwach, unikałbym uruchomienia wyrażenia regularnego dla wszystkich postów, jeśli liczba postów jest wysoka, i po prostu kolejkuje styl, jeśli zapytanie pasuje do wymagań.

To, co należy uznać za „wysokie” pod tym względem, to skorzystanie z niektórych testów wydajności lub, alternatywnie, dodanie innej opcji i wybór dla użytkowników.

gmazzap
źródło
2
Warto tutaj zauważyć, że <style>tagi w treści dokumentu są teraz prawidłowe zgodnie ze specyfikacją W3C. w3.org/TR/html52/document-metadata.html#the-style-element
Isaac Lubow
5

W przypadku mojej wtyczki stwierdziłem, że czasami użytkownicy mają narzędzie do tworzenia motywów, w którym krótki kod jest przechowywany w metadanych post . Oto, czego używam do wykrycia, czy mój krótki kod wtyczki jest obecny w bieżących postach lub metadanych :

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
źródło
2

Tak robię:

class My_Shortcode {

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

i złap haczyka w innych funkcjach (lub innych wtyczkach):

function wpse_3232_load_script(){
    wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
Władimir Druzhaev
źródło
1

Dowiedziałem się o własnej wtyczce, czy w widżecie tekstowym występuje krótki kod.

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
źródło
1

WordPress ma wbudowaną funkcję do robienia czegoś na podstawie określonego stanu prezentacji Shortcode. Nazwa funkcji to has_shortcode(). Możesz użyć następującego kodu, aby uporządkować swój styl i skrypty.

Tutaj użyłem is_a( $post, 'WP_Post' )do sprawdzenia, czy $postobiekt należy do WP_Postklasy i $post->post_contentsprawdziłem zawartość postu.

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
źródło
0

Zrobiłem kombinację przykładowego kodu ze strony Wordpress dla has_shortcode () i odpowiedzi udzielonej przez zndencka . Zauważyłem, że funkcja has_shortcode została dodana w Wordpress 3.6, dlatego najpierw sprawdzam, czy funkcja istnieje. Być może ta kontrola jest nieco przestarzała, ponieważ według wordpress nie ma wielu użytkowników poniżej wordpress 3.6 .

// 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
źródło
0

Rzeczywiście możemy warunkowo ładować pliki CSS i JS za pomocą krótkiego kodu, bez korzystania z nadmiernie skomplikowanych funkcji:

Po pierwsze, załóżmy, że wcześniej zarejestrowaliśmy wszystkie nasze pliki CSS / JS (być może po wp_enqueue_scriptsuruchomieniu)

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

Następnie sprawdźmy naszą funkcję 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'); }
  ...
}

Prosty. Gotowy. Ergo: możemy „warunkowo” ładować pliki css / js (tylko gdy działa [shortcode]).

Rozważmy następującą ideologię:

  • Chcemy załadować niektóre pliki CSS / JS (ale tylko po uruchomieniu krótkiego kodu)
  • Być może nie chcemy, aby te pliki ładowały się na każdej stronie lub w ogóle, jeśli krótki kod nie jest używany na stronie / postu. (lekki)
  • Możemy to osiągnąć, upewniając się, że WP rejestruje WSZYSTKIE pliki css / js przed wywołaniem krótkiego kodu i przed kolejką.
  • IE: Może podczas mojej prep_css_and_js()funkcji ładuję WSZYSTKIE pliki .css / .js, które znajdują się w określonych folderach ...

Teraz, gdy WP widzi je jako zarejestrowane skrypty, możemy rzeczywiście wywoływać je warunkowo, w oparciu o prawdziwość sytuacji, w tym między innymi my_shortcode_func()

Korzyści: (bez MySQL, bez zaawansowanych funkcji i bez filtrów)

  • to jest „WP orthodix”, eleganckie, szybkie ładowanie, łatwe i proste
  • pozwala kompilatorom / minifierom wykrywać takie skrypty
  • korzysta z funkcji WP (wp_register_style / wp_register_script)
  • kompatybilny z większą liczbą motywów / wtyczek, które mogą chcieć wyrejestrować te skrypty z wielu powodów.
  • nie uruchomi się wiele razy
  • zaangażowane jest bardzo mało przetwarzania lub kodu

Bibliografia:

Christian Žagarskas
źródło