当前位置: 首页>>技术解读>>正文


存在短代码时排队脚本/样式

问题描述

注册/排队脚本和/或样式以在插件中使用的想法是什么?

我最近制作了一个插件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中所做的。实际上,这两种方法都做同样的事情,但是在VB 3.6中添加了has_shortcode,而从版本2.5开始可以使用get_shortcode_regex,因此只有在您希望使插件与旧版本兼容时才使用get_shortcode_regex

  2. 始终在所有页面中添加短代码样式

Issues

#1的问题是性能。正则表达式是相当慢的操作,并且在所有帖子的循环中启动正则表达式可能会一致地降低页面速度。此外,主题中非常常见的任务是仅在档案中显示摘录并仅在单个视图中显示包含短代码的完整内容。如果发生这种情况,当显示存档时,您的插件将在循环中启动正则表达式匹配,目的是添加永远不会使用的样式:不必要的双重性能影响:减慢页面生成+额外的不必要的HTTP请求

#2的问题再次出现在性能上。向所有页面添加样式意味着为所有页面添加额外的HTTP请求,即使在不需要时也是如此。即使服务器端页面生成时间不受影响,总页面呈现时间也会对所有网站页面都有影响。

那么,插件开发者应该做些什么呢?

我认为最好的办法是在插件中添加一个选项页面,用户可以选择是仅在单一视图中处理短代码,还是在归档中处理。在这两种情况下最好提供另一个选项来选择哪些帖子类型启用短代码。

以这种方式可以挂钩"template_redirect"以检查当前查询是否满足要求,并在这种情况下添加样式。

如果用户选择仅在单一帖子视图中使用短代码,最好检查帖子是否有短代码:一旦只需要一个正则表达式,它就不应该这么慢。

如果用户甚至在档案中选择使用短代码,那么如果帖子数量很高,我会避免为所有帖子运行正则表达式,如果查询符合要求,我会将样式排入队列。

在这方面考虑”high”应该考虑使用一些性能测试,或者作为替代方案,添加另一个选项并为用户提供选择。

第三种解决方案

对于我的插件,我发现有时用户有一个主题构建器,其中包含存储在后元数据中的短代码。以下是我用来检测我的插件短代码是否存在于当前帖子或后期元数据中的内容:

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

第四种方案

我这样做:

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

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/2071.html,转载请务必附带本地址声明。