Ставить в очередь скрипты / стили при наличии шорткода

54

Каков идеальный способ регистрации / постановки в очередь скриптов и / или стилей для использования в плагинах?

Недавно я сделал плагин простым плагином для добавления пользователя аватар / граватар с коротким кодом. У меня есть разные варианты стилей для отображения аватара (квадрат, круг и т. Д.), И я решил поместить CSS непосредственно в сам шорткод.

Однако теперь я понимаю, что это не очень хороший подход, поскольку он будет повторять CSS каждый раз, когда шорткод используется на странице. Я видел несколько других подходов на этом сайте, и в кодексе wp даже есть два собственных примера, поэтому трудно понять, какой подход наиболее последовательный и быстрый.

Вот методы, которые я в настоящее время знаю:

Способ 1: включить непосредственно в шорткод - это то, что я сейчас делаю в плагине, но не очень хорошо, так как он повторяет код.

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

Способ 2. Использование класса для постановки в очередь скриптов или стилей условно

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

Способ 3: использование 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' );

Метод 4: Использование 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');
Брайан Уиллис
источник
Я думаю, что Method 4: Using has_shortcode();это лучше, потому что это гарантирует, что скрипты и стили будут загружаться один раз, если содержимое публикации имеет шорткод, независимо от многократного использования шорткода. Хотя это может не работать для использования шорткода в виджетах или на боковой панели, хотя не уверен. Если это для плагина, то я бы не рекомендовал вам связывать скрипты с шорткодом, потому что некоторые могут вызвать вашу функцию вместо шорткода, чтобы получить желаемый результат.
Роберт Хюэ,

Ответы:

45

Я нашел другой способ, который хорошо работает для меня:

Вот пример плагина, использующего этот метод, который позволяет вам использовать get_avatar в качестве шорткода. Таблица стилей ставится в очередь только при наличии шорткода.

Использование (идентификатор по умолчанию для текущего пользователя):

[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
источник
Забыл, я задал этот вопрос в прошлом году, но я действительно начал делать это так же во многих случаях. Это как комбинировать метод 1 и 2.
Брайан Уиллис
4
Этот метод загружает CSS в нижний колонтитул, который, безусловно, имеет ограничения?
Джейкоб Раккуя,
1
Это абсолютно правильный способ сделать это. Используйте этот метод каждый раз, когда вам нужно условно загрузить скрипт или таблицу стилей, когда wp_enqueue_scriptsперехват уже произошел. (Шорткоды анализируются, во время the_contentкоторых является частью the_postхука, то есть постановка в очередь, когда он анализируется, слишком поздно, если вы уже не зарегистрировали скрипт)
JRad the Bad
26

Прежде чем начать отвечать, я должен сказать, что в отношении этой темы css и js не совпадают.

Причина проста: хотя добавление js в тело страницы (в нижнем колонтитуле) является распространенным и правильным способом, CSS следует размещать в <head>разделе страницы: даже если большинство браузеров могут правильно отображать CSS на странице тело, это не правильный код HTML.

Когда визуализируется шорткод, <head>секция уже была напечатана, это означает, что js может быть добавлен без проблем в нижний колонтитул, но css должен быть добавлен до визуализации шорткода.

Сценарии

Если вашему шорткоду нужен только js, вам повезло, и вы можете просто использовать его wp_enqueue_scriptв теле обратного вызова шорткода:

add_shortcode( 'myshortcode', 'my_handle_shortcode' );

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

При этом ваш скрипт добавляется в нижний колонтитул и только один раз, даже если шорткод используется более одного раза на странице.

Стили

Если вашему коду нужны стили, вам нужно действовать до того, как шорткод будет действительно отображен.

Есть разные способы сделать это:

  1. посмотрите на все сообщения в текущем запросе и добавьте стили шорткода, если это необходимо. Это то, что вы делаете в методе № 3 и № 4 в ОП. На самом деле, оба эти метода делают одно и то же, но has_shortcodeбыли добавлены в WP 3.6, хотя get_shortcode_regexдоступны с версии 2.5, поэтому используйте их, get_shortcode_regexтолько если вы хотите, чтобы ваш плагин был совместим со старыми версиями.

  2. всегда добавлять стиль шорткода на всех страницах

вопросы

Проблема с # 1 - производительность. Регулярные выражения довольно медленные операции, и запуск регулярных выражений в цикле всех сообщений может последовательно замедлять работу страницы. Кроме того, в темах довольно распространено задание показывать только выдержку из архива и показывать полный контент с короткими кодами только в единственном виде. Если это произойдет, когда будет показан архив, ваш плагин запустит сопоставление регулярных выражений в цикле с целью добавления стиля, который никогда не будет использоваться: ненужное двойное влияние на производительность: замедление генерации страниц + дополнительный ненужный HTTP-запрос

Проблема с # 2 - это опять же производительность. Добавление стиля ко всем страницам означает добавление дополнительного HTTP-запроса для всех страниц, даже если он не нужен. Даже если это не повлияет на время создания страницы на стороне сервера, общее время отображения страницы будет одинаковым для всех страниц сайта.

Итак, что должен делать разработчик плагинов?

Я думаю, что лучше всего добавить страницу параметров в плагин, где пользователи могут выбирать, должен ли шорткод обрабатываться только в единственном представлении или даже в архивах. В обоих случаях лучше предоставить другую опцию, чтобы выбрать, для каких типов сообщений включить шорткод.

Таким образом можно подключить, "template_redirect"чтобы проверить, удовлетворяет ли текущий запрос требованиям, и в этом случае добавить стиль.

Если пользователь решает использовать шорткод только в отдельных записях, рекомендуется проверить, есть ли у шорткода пост или нет: если требуется только одно регулярное выражение, это не должно сильно замедлять страницу.

Если пользователь решит использовать шорткод даже в архивах, я бы не использовал regex для всех постов, если количество постов велико, и просто ставил бы в очередь стиль, если требования соответствовали требованиям.

Что следует считать «высоким» в этом отношении, можно получить с помощью некоторых тестов производительности или, в качестве альтернативы, добавить еще один вариант и дать выбор пользователям.

Gmazzap
источник
2
Здесь стоит отметить, что <style>теги в теле документа теперь действительны в соответствии со спецификацией W3C. w3.org/TR/html52/document-metadata.html#the-style-element
Исаак Любов,
5

Для моего плагина я обнаружил, что иногда у пользователей есть конструктор тем, у которого есть шорткод, сохраненный в метаданных поста . Вот что я использую, чтобы определить, присутствует ли мой шорткод плагина в текущем посте или метаданных поста :

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
источник
2

Я делаю так:

class My_Shortcode {

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

и перехватить хук в других функциях (или других плагинах):

function wpse_3232_load_script(){
    wp_enqueue_script('js-myjs');
}
add_action('my_start_shortcode','wpse_3232_load_script',10);
Владимир Дружаев
источник
1

Я выяснил для своего собственного плагина, присутствует ли шорткод в текстовом виджете.

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');
Джино
источник
1

В WordPress есть встроенная функция, позволяющая делать что-то на основе определенного шорткода, представляющего статус. Имя функции есть has_shortcode(). Вы можете использовать следующий код, чтобы поставить в очередь свой стиль и сценарии.

Здесь я использовал, is_a( $post, 'WP_Post' )чтобы проверить, принадлежит ли $postобъект WP_Postклассу, и я использовал, $post->post_contentчтобы проверить содержание сообщения.

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' );
}
Ариф Рахман
источник
0

Я сделал комбинацию кода примера со страницы Wordpress для has_shortcode () и ответа, который дал zndencka . Я заметил, что функция has_shortcode добавлена ​​в Wordpress 3.6, поэтому я сначала проверяю, существует ли эта функция. Возможно, эта проверка немного устарела, так как не так много пользователей из 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
источник
0

Мы действительно можем условно загружать файлы CSS и JS через шорткод, не используя чрезмерно сложные функции:

Во-первых, давайте предположим, что мы зарегистрировали все наши файлы CSS / JS ранее (возможно, при wp_enqueue_scriptsзапуске)

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

Далее, давайте рассмотрим нашу функцию шорткода:

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

Просто. Готово. Ergo: мы можем «условно загружать» файлы css / js (только при запуске [shortcode]).

Давайте рассмотрим следующую идеологию:

  • Мы хотим загрузить определенные файлы CSS / JS (но только когда запущен шорткод)
  • Возможно, мы не хотим, чтобы эти файлы загружались на каждой странице, или вообще, если шорткод не используется на странице / посте. (легкий вес)
  • Мы можем сделать это, убедившись, что WP регистрирует ВСЕ файлы css / js до вызова шорткода и до постановки в очередь.
  • IE: Может быть, во время prep_css_and_js()работы я загружаю ВСЕ файлы .css / .js, которые находятся в определенных папках ...

Теперь, когда WP видит их в качестве зарегистрированных сценариев, мы действительно можем назвать их, условно, исходя из множества ситуаций, включая, но не ограничиваясь my_shortcode_func()

Преимущества: (без MySQL, без расширенных функций и без фильтров)

  • это "WP orthodix", элегантный, быстрая загрузка, легко и просто
  • позволяет компиляторам / минификаторам обнаруживать такие скрипты
  • использует функции WP (wp_register_style / wp_register_script)
  • совместим с большим количеством тем / плагинов, которые могут захотеть отменить регистрацию этих скриптов по разным причинам.
  • не сработает несколько раз
  • очень мало обработки или кода

Рекомендации:

Кристиан Жагарскас
источник