問題描述

在插件中註冊/排隊腳本和/或樣式的想法是什麼?

我最近做了一個插件 simple plugin 添加用户頭像/ gravatar 與一個短碼。我有不同的風格選項,用於顯示頭像 (平方,圓形等),並決定將 CSS 直接放入短碼本身。

然而,我意識到現在這不是一個好的方法,因為它會重複 CSS 每次在一個頁面上使用短代碼。我在這個網站上看到過其他幾種方法,而 wp codex 甚至有兩個自己的例子,所以很難知道什麼方法是最一致和最快速的。

以下是我目前所知道的方法:

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

最佳解決方案

我找到了另一種對我有用的方式:

  • 初始化插件時,不要排列腳本和樣式,而是使用 wp_register_stylewp_register_script 註冊。

  • 接下來,您可以根據需要加載腳本/樣式。例如,當您使用 wp_enqueue_style("your_style")wp_enqueue_script("your_script")呈現短碼時。

這是一個使用此方法的示例插件,可以將 get_avatar 用作短碼。當短碼存在時,樣式表才會排隊。

用法 (id 默認為當前用户):

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

次佳解決方案

在開始回答之前,我不得不説,關於這個話題,css 和 js 是不一樣的。

原因很簡單:將 js 添加到頁面的主體 (頁腳) 是一個常見且有效的方法,css 需要放置在頁面的<head> 部分:即使大多數瀏覽器都可以正確地呈現 CSS 頁面正文,這是無效的 HTML 代碼。

當一個短代碼被渲染時,<head> 部分已經被打印了,這意味着可以在頁腳上添加沒有任何問題的 js,但是在渲染短代碼之前必須添加 CSS 。

Scripts

如果您的短代碼只需要 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...
}

這樣做你的腳本被添加到頁腳,只有一次,即使短碼在頁面中多次使用。

Styles

如果您編碼需要樣式,那麼您需要在執行短代碼實際呈現之前執行操作。

有不同的方式來做到這一點:

  1. 查看當前查詢中的所有帖子,如果需要,添加短代碼樣式。這是您在 OP 中的方法#3 和#4 中所做的。事實上,兩種方法都做同樣的事情,但是 WP 3.6 中添加了 has_shortcode,而 get_shortcode_regex 是從 2.5 版本開始使用的,所以只有在要使插件與舊版本兼容時才使用 get_shortcode_regex

  2. 總是添加短代碼樣式,在所有頁面

Issues

#1 的問題是性能。正則表達式運算速度非常慢,並且在所有帖子的循環中啓動正則表達式可能會一直拖慢頁面。此外,在主題中只顯示檔案中的摘錄並僅以奇異視圖顯示具有短碼的完整內容是一個非常常見的任務。如果發生這種情況,當顯示存檔時,您的插件將在循環中啓動正則表達式匹配,目的是添加永遠不會使用的樣式:不必要的雙重性能影響:減慢頁面生成+附加不必要的 HTTP 請求

#2 的問題是性能,再次。向所有頁面添加樣式意味着為所有頁面添加一個額外的 HTTP 請求,即使不需要。即使服務器端頁面生成時間不受影響,總頁面呈現時間也將用於所有站點頁面。

那麼插件開發人員應該做什麼呢?

我認為最好的做法是向插件添加一個選項頁面,用户可以選擇是否應該在單個視圖中處理短代碼,甚至在檔案中進行處理。在這兩種情況下,最好提供另一個選項來選擇哪個類型啓用短碼。

以這種方式可以鈎住"template_redirect"來檢查當前查詢是否滿足要求,在這種情況下添加樣式。

如果用户選擇使用短碼僅在單個的視圖中,是一個好主意,檢查 post 是否有短碼或不需要:只需要一個正則表達式,它不應該減慢頁面這麼多。

如果用户選擇在檔案中使用短碼,那麼如果帖子數量很多,我會避免為所有帖子運行正則表達式,如果查詢符合要求,則只需排入該樣式。

在這方面應該考慮什麼”high” 應該使用一些性能測試,或者作為替代,添加另一個選項並給用户選擇。

參考文獻

注:本文內容整合自 Google/Baidu/Bing 輔助翻譯的英文資料結果。如果您對結果不滿意,可以加入我們改善翻譯效果:薇曉朵技術論壇。