存在简码时,排队脚本/样式


54

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

我最近制作了一个插件简单插件,以使用简码添加用户头像/ 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');

我认为这Method 4: Using has_shortcode();是最好的方法,因为它将确保如果帖子内容中包含短代码,则脚本和样式将加载一次,而不管短代码的多次使用如何。尽管它可能不适用于小部件或边栏中的简码,但是不确定。如果是用于插件,那么我不建议您将脚本与短代码绑定,因为有些脚本可能会调用您的函数而不是短代码来获得所需的输出。
罗伯特·休

Answers:


45

我发现了另一种对我有效的方法:

这是使用此方法的示例插件,可让您使用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' );
}

忘记我去年问过这个问题,但实际上我在很多情况下也已经开始这样做。这有点像合成方法1和2
布莱恩·威利斯

4
此方法将CSS加载到页脚中,这肯定有局限性吗?
Jacob Raccuia '17

1
这绝对是正确的方法。当wp_enqueue_scripts挂钩已经发生时,您需要有条件地加载脚本或样式表时,都可以使用此方法。(对短代码进行解析the_contentthe_post钩子的一部分,这意味着解析它时
进入队列

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. 查看当前查询中的所有帖子,并在需要时添加简码样式。这是您在OP中的方法3和方法4中所做的事情。实际上,这两种方法都具有相同的作用,但是has_shortcode是在WP 3.6中添加的,而get_shortcode_regex自2.5版以来才可用,因此get_shortcode_regex仅在希望使您的插件与旧版本兼容时才使用。

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

问题

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

#2的问题还是性能。向所有页面添加样式意味着即使在不需要时也为所有页面添加额外的HTTP请求。即使服务器端页面生成时间不受影响,总的页面渲染时间以及所有站点页面的时间也将受到影响。

那么,插件开发人员应该怎么做?

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

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

如果用户选择仅在单个帖子视图中使用短代码,则检查帖子是否包含短代码是一个好主意:一旦只需要一个正则表达式,它就不会减慢页面速度。

如果用户选择,即使在档案使用简码,那么我会避免为所有帖子运行正则表达式,如果帖子的数量是很高,只是排队的风格,如果查询适合要求。

在这方面认为“高”的应该使用一些性能测试来获得,或者作为替代,添加另一个选项并为用户提供选择。


2
在这里值得注意的是,<style>文档主体中的标签现在按照W3C规范有效。w3.org/TR/html52/document-metadata.html#the-style-element
Isaac Lubow

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

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具有内置功能,可根据特定的Shortcode呈现状态执行某些操作。函数名称为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的答案。我确实注意到在wordpress 3.6中添加了has_shortcode函数,这就是为什么我首先检查该函数是否存在的原因。不过也许检查有点过时了,因为根据wordpress自己的统计信息, 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');

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)
  • 与出于种种原因可能想要注销这些脚本的更多主题/插件兼容。
  • 不会多次触发
  • 很少涉及处理或代码

参考文献:

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.