当存在快捷代码时将脚本/样式入队

时间:2014-10-18 作者:Bryan Willis

What is the idea way to register/enqueue scripts and/or styles for use in plugins?

我最近做了一个插件simple plugin 添加带有短代码的用户头像/坟墓者。我有不同的风格选项来显示化身(方形、圆形等),并决定将css直接放在短代码本身中。

然而,我现在意识到这不是一个好方法,因为每次在页面上使用短代码时,它都会重复css。我在这个网站上见过其他几种方法,wp codex甚至有两个自己的例子,所以很难知道哪种方法最一致、最快。

以下是我目前了解的方法:

Method 1: Include directly in shortcode - <这就是我目前在插件中所做的,但似乎并不好,因为它重复代码

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

Method 2: Use class for enqueueing scripts or styles conditionally

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

Method 3: Using 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\' );

Method 4: Using 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\');

10 个回复
最合适的回答,由SO网友:jblanche 整理而成

我找到了另一种适合我的方法:

初始化插件时,不要将脚本和样式排队,而是将它们注册到wp_register_stylewp_register_script.

接下来,您可以根据需要加载脚本/样式。例如,当使用wp_enqueue_style("your_style")wp_enqueue_script("your_script").

Here is an example plugin using this method that lets you use get_avatar in a shortcode. The stylesheet is only enqueued when the shortcode is present.

用法(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\' );
}

SO网友:gmazzap

在开始回答之前,我必须说,关于这个主题,css和js是不一样的。

原因很简单:虽然将js添加到页面主体(页脚)是一种常见且有效的方式,但css需要放置在<head> 页面部分:即使大多数浏览器可以在页面主体中正确呈现css,这也是无效的HTML代码。

渲染短代码时,<head> 节已打印,这意味着可以添加js,但页脚上没有任何问题,但必须添加cssbefore 将呈现短代码。

脚本

如果您的短代码只需要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...
}
这样,即使短代码在页面中使用了多次,脚本也只会添加到页脚中一次。

样式

如果您的代码需要样式,那么您需要在实际渲染短码之前执行操作。

有不同的方法可以做到这一点:查看当前查询中的所有帖子,并根据需要添加快捷码样式。这是您在OP中的方法#3和#4中所做的。事实上,这两种方法都做相同的事情,但是has_shortcode WP 3.6中添加了get_shortcode_regex 自版本2.5起可用,因此请使用get_shortcode_regex 仅当您希望使插件与旧版本兼容时。

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

问题#1的问题是性能。Regex是非常慢的操作,在所有帖子的循环中启动Regex可能会持续减慢页面速度。此外,在主题中,只显示存档中的帖子摘录,并仅在单数视图中使用短代码显示完整内容是一项非常常见的任务。如果出现这种情况,当显示归档文件时,插件将在循环中启动一个regex匹配,目的是添加一种永远不会使用的样式:不必要的双重性能影响:减缓页面生成速度+额外的不必要的HTTP请求

#2的问题还是性能。向所有页面添加样式意味着为所有页面添加额外的HTTP请求,即使不需要。即使服务器端页面生成时间不受影响,总页面呈现时间也会受到影响,并且对于所有站点页面。

那么,插件开发人员应该做什么呢

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

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

若用户选择只在单一的帖子视图中使用短代码,那个么检查帖子是否有短代码是一个好主意:一旦只需要一个正则表达式,它就不应该让页面速度降低这么多。

如果用户选择在归档文件中使用shortcode,那么如果帖子数量很大,我将避免对所有帖子运行regex,如果查询符合要求,则只需将样式排队即可。

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

SO网友:zdenekca

对于我的插件,我发现有时用户有一个主题生成器,其中存储了短代码post meta data. 下面是我用来检测当前post or post meta data:

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

SO网友:Wladimir Druzhaev

我这样做:

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

SO网友:Arif Rahman

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

SO网友:Simon

正如有人提到的,使用“has\\u shortcode”就可以了。这是一个我觉得很有帮助的例子(Source: Wordpress.org)

function wpdocs_shortcode_scripts() {
    global $post;
    if ( is_a( $post, \'WP_Post\' ) && has_shortcode( $post->post_content, \'wpdocs-shortcode\') ) {
        wp_enqueue_script( \'wpdocs-script\');
    }
}
add_action( \'wp_enqueue_scripts\', \'wpdocs_shortcode_scripts\');

SO网友:Gino

我确实为我自己的插件找到了短代码是否存在于文本小部件中。

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

SO网友:Vasco

我结合了Wordpress页面中的示例代码has_shortcode() 还有答案zndencka 给予。我注意到在Wordpress 3.6中添加了has\\u shortcode函数,所以我首先检查该函数是否存在。也许这个检查有点过时了,因为wordpress 3.6以下的用户已经不多了,根据wordpress their own stats.

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

SO网友:Christian Žagarskas

我们确实可以通过快捷码有条件地加载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 );
接下来,让我们检查一下我们的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\'); }
  ...
}
简单。完成。Ergo: we can "conditionally load" css/js files, (only when [shortcode] runs).

让我们考虑以下意识形态:

我们希望加载某些CSS/JS文件(但仅当触发了快捷码时)

  • 可能我们不希望在每个页面上加载这些文件,或者根本不希望在页面/帖子上使用快捷码。(轻量级)
  • 我们可以通过确保WP在调用短代码和排队之前注册所有css/js文件来实现这一点prep_css_and_js() 函数I全部加载。css/。某些文件夹中的js文件my_shortcode_func()

    优点:(无需MySQL,无需高级功能和过滤器)

    这是“WP正统”,优雅、快速加载,简单易用,允许编译器/缩微器检测此类脚本使用WP函数(WP\\u register\\u style/WP\\u register\\u script)

  • 与出于各种原因可能需要注销这些脚本的更多主题/插件兼容
  • 不会多次触发
  • 只涉及很少的处理或代码
  • SO网友:Amin Safsafi

    我使用WordPress 5.4版的OOP风格的代码,我不知道这是否会影响到为什么上面的解决方案都不适用于我,所以我提出了以下解决方案:

    public function enqueue_scripts() {
     global $post;
     //error_log( print_r( $post, true ) );
     //error_log( print_r(  $post->post_content, true ) );
     //error_log( print_r(  strpos($post->post_content, \'[YOUR_SHORTCODE]\'),true));
    
     if ( is_a( $post, \'WP_Post\' ) && strpos($post->post_content, \'[YOUR_SHORTCODE]\') ) 
     {
         wp_register_style(\'my-css\', $_css_url);
         wp_register_script(\'my-js\', $_js_url);
     }
    }
    
    希望这对别人有帮助。

    结束

    相关推荐

    OOP and WordPress shortcode

    我试图通过这种方式添加一个短代码class MyPlugin { function __construct() { $this->make_shortcode(); } function ShowMsg($cls, $lst4) { $data = shortcode_atts(array(\'phn\' => \'\', \'msg\' => \'\'), $atts);