有条件地加载快捷码的JavaScript/CSS

时间:2011-06-23 作者:Ian Dunn

我发布了一个插件,该插件创建了一个短代码,并要求在包含该短代码的任何页面上加载一个JavaScript文件和一个CSS文件。我可以在所有页面上加载脚本/样式,但这不是最佳做法。我只想在调用短代码的页面上加载文件。我找到了两种方法,但都有问题。

Method 1 在shortcode处理程序函数内将标志设置为true,然后在wp_footer 回调。如果这是真的,它使用wp_print_scripts() 加载JavaScript。问题是它只适用于JavaScript,而不适用于CSS,因为CSS应该在内部声明<head>, 你只能在像initwp_head.

Method 2 提前触发并“向前看”,以查看当前页面内容中是否存在短代码。我比第一种方法更喜欢这个方法,但它的问题是无法检测模板是否调用do_shortcode().

因此,我倾向于使用第二种方法,然后尝试检测是否分配了模板,如果是,则分析它的短代码。在我这么做之前,我想看看是否有人知道更好的方法。

Update: 我已经将解决方案集成到我的插件中。如果有人想在生活环境中看到它的丰满,你可以download itbrowse it.

Update 2: 从WordPress 3.3开始,现在可以call wp_enqueue_script() directly inside a shortcode callback, JavaScript文件将在文档的页脚中调用。这在技术上也适用于CSS文件,但应被视为一种不好的做法,因为在<head> 标记违反了W3C规范,可以使用FOUC大小写,并且可能会强制浏览器重新呈现页面。

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

根据我自己的经验,我使用了方法1和;2-1的架构和页脚脚本,以及2的“前瞻”技术。

尽管如此,为了展望未来,我使用regex代替stripos; 个人喜好,速度更快,可以检查“格式错误”的短代码;

preg_match( \'#\\[ *shortcode([^\\]])*\\]#i\', $content );
如果您担心作者使用do_shortcode 手动,我会选择指示他们使用动作调用手动将预先注册的样式排队。

UPDATE: 对于从不RTFM的懒惰作者,输出一条消息以突出显示error 他们的方式;)

function my_shortcode()
{
    static $enqueued;
    if ( ! isset( $enqueued ) )
        $enqueued = wp_style_is( \'my_style\', \'done\' ); // cache it so we don\'t repeat if called over and over

    // do shortcode
    $output = \'\';

    if ( ! $enqueued )
        // you can output the message on first occurence only by wrapping it in the previous if
        $output .= <<<HTML
<p>Attention! You must enqueue the shortcode stylesheet yourself if calling <code>do_shortcode()</code> directly!</p>
<p>Use <code>wp_enqueue_style( \'my_style\' );</code> before your <code>get_header()</code> call inside your template.</p>
HTML;

    return $output;
}

SO网友:MikeSchinkel

我回答这个问题迟到了,但自从Ian开始this thread 在今天的wp黑客名单上,这让我觉得值得回答,尤其是考虑到我一直计划在我正在开发的一些插件中添加这样的功能。

要考虑的一种方法是在第一个页面加载时检查是否实际使用了短代码,然后将短代码使用状态保存到post元键。方法如下:

如何逐步设置$shortcode_used 标记为\'no\'.$shortcode_used 标记为\'yes\'.\'the_content\' 挂钩优先级12 这是在WordPress处理短代码并检查post meta的\'\' 使用键"_has_{$shortcode_name}_shortcode". (值为\'\' 当贴子ID的贴子元键不存在时返回。)
  • 使用\'save_post\' 钩子删除帖子元,清除该帖子的持久性标志,以防用户更改短代码用法\'save_post\' 挂钩使用wp_remote_request() 要发送一个非阻塞HTTP GET到帖子自己的永久链接以触发第一页加载和持久性标志的设置\'wp_print_styles\' 并检查post meta的值\'yes\', \'no\'\'\' 使用键"_has_{$shortcode_name}_shortcode" . 如果值为\'no\' 不要为外部服务。如果值为\'yes\'\'\' 继续为外部服务

    插件代码示例[trigger-css] 设置<h2> 页面上的元素变为白色或红色,以便您可以轻松看到它的工作情况。它假定css 包含的子目录style.css 包含此CSS的文件:

    /*
     * Filename: css/style.css
     */
    h2 {
      color: white;
      background: red;
    }
    
    下面是一个工作插件中的代码:

    <?php
    /**
     * Plugin Name: CSS on Shortcode
     * Description: Shows how to conditionally load a shortcode
     * Author: Mike Schinkel <[email protected]>
     */
    class CSS_On_Shortcode {
    
      /**
       * @var CSS_On_Shortcode
       */
      private static $_this;
    
      /**
       * @var string \'yes\'/\'no\' vs. true/false as get_post_meta() returns \'\' for false and not found.
       */
      var $shortcode_used = \'no\';
    
      /**
       * @var string
       */
      var $HAS_SHORTCODE_KEY = \'_has_trigger-css_shortcode\';
      /**
       *
       */
      function __construct() {
        self::$_this = $this;
        add_shortcode( \'trigger-css\', array( $this, \'do_shortcode\' ) );
        add_filter( \'the_content\', array( $this, \'the_content\' ), 12 ); // AFTER WordPress\' do_shortcode()
        add_action( \'save_post\', array( $this, \'save_post\' ) );
        add_action( \'wp_print_styles\', array( $this, \'wp_print_styles\' ) );
      }
    
      /**
       * @return CSS_On_Shortcode
       */
      function this() {
        return self::$_this;
      }
    
      /**
       * @param array $arguments
       * @param string $content
       * @return string
       */
      function do_shortcode( $arguments, $content ) {
        /**
         * If this shortcode is being used, capture the value so we can save to post_meta in the \'the_content\' filter.
         */
        $this->shortcode_used = \'yes\';
        return \'<h2>THIS POST WILL ADD CSS TO MAKE H2 TAGS WHITE ON RED</h2>\';
      }
    
      /**
       * Delete the \'has_shortcode\' meta value so that it can be regenerated
       * on first page load in case shortcode use has changed.
       *
       * @param int $post_id
       */
      function save_post( $post_id ) {
        delete_post_meta( $post_id, $this->HAS_SHORTCODE_KEY );
        /**
         * Now load the post asynchronously via HTTP to pre-set the meta value for $this->HAS_SHORTCODE_KEY.
         */
        wp_remote_request( get_permalink( $post_id ), array( \'blocking\' => false ) );
      }
    
      /**
       * @param array $args
       *
       * @return array
       */
      function wp_print_styles( $args ) {
        global $post;
        if ( \'no\' != get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
          /**
           * Only bypass if set to \'no\' as \'\' is unknown.
           */
          wp_enqueue_style( \'css-on-shortcode\', plugins_url( \'css/style.css\', __FILE__ ) );
        }
       }
    
      /**
       * @param string $content
       * @return string
       */
      function the_content( $content ) {
        global $post;
        if ( \'\' === get_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, true ) ) {
          /**
           * This is the first time the shortcode has ever been seen for this post.
           * Save a post_meta key so that next time we\'ll know this post uses this shortcode
           */
          update_post_meta( $post->ID, $this->HAS_SHORTCODE_KEY, $this->shortcode_used );
        }
        /**
         * Remove this filter now. We don\'t need it for this post again.
         */
        remove_filter( \'the_content\', array( $this, \'the_content\' ), 12 );
        return $content;
      }
    
    }
    new CSS_On_Shortcode();
    
    示例屏幕截图这里是一系列屏幕截图

    基本帖子编辑器,无内容

    后期显示,无内容

    基本帖子编辑器[trigger-css] 短代码

    使用Post显示[trigger-css] 短代码

    我不确定它是否是100%

    我相信上面的方法在几乎所有情况下都应该有效,但由于我刚刚编写了这段代码,我不能100%确定。如果你能找到它不起作用的情况,我真的很想知道,这样我就可以修复我刚刚添加的一些插件中的代码。提前谢谢。

  • SO网友:EAMann

    谷歌搜索发现我有潜力answer. 我说“潜力”看起来不错,应该有用,但我不完全相信这是最好的方式:

    add_action( \'wp_print_styles\', \'yourplugin_include_css\' );
    function yourplugin_include_css() {
        // Check if shortcode exists in page or post content
        global $post;
    
        // I removed the end \' ] \'... so it can accept args.
        if ( strstr( $post->post_content, \'[yourshortcode \' ) ) {
            echo $csslink;
        }
    }
    
    这应该能够检查当前帖子是否使用了短代码,并将样式表添加到<head> 元素。但我认为它对索引(即循环中的多个帖子)页面不起作用。。。这也是一篇2年前的博客文章,所以我甚至不确定它是否能与WP 3.1一起使用。十、

    SO网友:Sean Michaud

    结合使用HeadMedic的答案和get\\u shortcode\\u regex()documentation (实际上没有找到我的短代码),我创建了一个简单的函数,用于将多个短代码的脚本排队。由于短代码中的wp\\u enqueue\\u script()只会添加到页脚,这会很有帮助,因为它可以处理页眉和页脚脚本。

    
    function add_shortcode_scripts() {
        global $wp_query;   
        $posts = $wp_query->posts;
        $scripts = array(
            array(
                \'handle\' => \'map\',
                \'src\' => \'http://maps.googleapis.com/maps/api/js?sensor=false\',
                \'deps\' => \'\',
                \'ver\' => \'3.0\',
                \'footer\' => false
            ),
            array(
                \'handle\' => \'contact-form\',
                \'src\' => get_template_directory_uri() . \'/library/js/jquery.validate.min.js\',
                \'deps\' => array( \'jquery\' ),
                \'ver\' => \'1.11.1\',
                \'footer\' => true
            )   
        );
    
        foreach ( $posts as $post ) {
            foreach ( $scripts as $script ) {
                if ( preg_match( \'#\\[ *\' . $script[\'handle\'] . \'([^\\]])*\\]#i\', $post->post_content ) ) {
                    // enqueue css and/or js
                    if ( wp_script_is( $script[\'handle\'], \'registered\' ) ) {
                        return;
                    } else {
                        wp_register_script( $script[\'handle\'], $script[\'src\'], $script[\'deps\'], $script[\'ver\'], $script[\'footer\'] );
                        wp_enqueue_script( $script[\'handle\'] );
                    }
                }
            }
        }
    }
    add_action( \'wp\', \'add_shortcode_scripts\' );
    

    SO网友:robertharm

    最后,我还找到了一个适用于我的插件的条件css加载解决方案www.mapsmarker.com 我想与你分享。它检查我的短代码是否在当前模板文件和页眉/页脚中使用。php,如果是,则将所需样式表列在标题中:

      function prefix_template_check_shortcode( $template ) {
        $searchterm = \'[mapsmarker\';
        $files = array( $template, get_stylesheet_directory() . DIRECTORY_SEPARATOR . \'header.php\', get_stylesheet_directory() . DIRECTORY_SEPARATOR . \'footer.php\' );
        foreach( $files as $file ) {
            if( file_exists($file) ) {
                $contents = file_get_contents($file);
                if( strpos( $contents, $searchterm )  ) {
                    wp_enqueue_style(\'
    leafletmapsmarker\', LEAFLET_PLUGIN_URL . \'leaflet-dist/leaflet.css\');
                      break; 
                }
            }
        }
      return $template;
      }  
      add_action(\'template_include\',\'prefix_template_check_shortcode\' );
    

    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网友:onetrickpony

    因为CSS应该在内部声明<head>

    对于CSS文件,您可以在快捷码输出中加载它们:

    <style type="text/css">
      @import "path/to/your.css"; 
    </style>
    
    在此之后设置一个常量或其他内容,如MY_CSS_LOADED (仅当未设置常量时才包括CSS)。

    你的两种方法都比这样慢。

    对于JS文件,如果加载的脚本是唯一的并且没有任何外部依赖项,则可以执行相同的操作。如果不是这种情况,请在页脚内加载它,但使用常量确定是否需要加载。。。

    结束

    相关推荐

    Nested Shortcode Detection

    如果您熟悉此代码<?php $pattern = get_shortcode_regex(); preg_match(\'/\'.$pattern.\'/s\', $posts[0]->post_content, $matches); if (is_array($matches) && $matches[2] == \'YOURSHORTCODE\') { //shortcode is being used }&#