问题描述

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

 Method 1 在短代码处理函数内设置一个标志为 true,然后检查 wp_footer 回调中的值。如果是这样,它使用 wp_print_scripts()加载 JavaScript 。这样做的问题是它只适用于 JavaScript 而不是 CSS,因为 CSS 应该在<head> 中声明,<head> 只能在 initwp_head 之类的早期挂钩中进行。

 Method 2 早点触发,「前进」,看看当前页面内容是否存在短码。我喜欢这种方法比第一个好多了,但是它的问题是它不会检测到模板是否调用 do_shortcode()

所以,我倾向于使用第二种方法,然后尝试检测是否分配一个模板,如果是,则解析它的短码。在我这样做之前,我想检查一下有没有人知道一个更好的方法。

更新:我将解决方案集成到我的插件中。如果任何人好奇看到它在现场环境中充满活力,可以使用 download itbrowse it

更新 2:从 WordPress 3.3 开始,现在可以直接在短码回调中调用 wp_enqueue_script(),并在文档的页脚中调用 JavaScript 文件。这在 CSS 文件上也是可行的,但是由于在<head> 标签之外输出 CSS 违反了 W3C 规范,因此可能会导致浏览器出现 re-render 页面。

最佳解决方案

根据我自己的经验,我使用了方法 1 和 2 – 1 的架构和脚注脚本,以及 2 的’look-ahead’ 技术。

对于 look-ahead,我使用正则表达式代替 stripos; 个人喜好,速度更快,可以检查’malformed’ 短码;

preg_match( '#[ *shortcode([^]])*]#i', $content );

如果您担心手动使用 do_shortcode 的作者,我会选择指示他们使用动作调用手动排列您的 pre-registered 样式。

更新:对于从来没有 RTFM 的懒惰作者,输出一个消息来突出显示他们的方式的错误;)

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

次佳解决方案

我迟早会回答这个问题,但是由于 Ian 在 wp-hackers 列表上启动了 this thread,所以让我觉得值得回答,特别是考虑到我一直在计划为我一直在开发的一些插件添加一个这样的功能。

一种考虑的方法是检查第一页加载,以查看是否实际使用了短码,然后将短码使用状态保存到后期元键。就是这样:

Step-by-Step How-To

  1. $shortcode_used 标志设置为'no'
  2. 在短码功能本身,将 $shortcode_used 标志设置为'yes'
  3. 设置一个'the_content'钩子优先级 12,这是在 WordPress 处理了短码之后,并使用"_has_{$shortcode_name}_shortcode"键检查''的后期元数据。 (当帖子 ID 不存在后期元键时,返回''的值) 。
  4. 使用'save_post'钩子删除后期元素清除该帖子的持久标志,以防用户更改短代码使用情况。
  5. 另外在'save_post'钩子中使用 wp_remote_request()发送一个 non-blocking HTTP GET 到自己的固定链接,以触发到第一页加载和持久标志的设置。
  6. 最后设置'wp_print_styles',并使用"_has_{$shortcode_name}_shortcode"键检查'yes''no'''的后期元数据。如果值为'no'不服务于外部。如果值为'yes''',则提供服务。

那应该这样做。我已经编写和测试了一个示例插件,以显示这一切如何工作。

示例插件代码

该插件在 [trigger-css]短代码上唤醒,该代码将页面上的<h2> 元素设置为 white-on-red,以便您可以轻松看到它的工作。它假定 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 <mike@newclarity.net>
 */
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]短码

后期显示与 [trigger-css]短码

不确定如果是 100%

我相信上述应该在几乎所有的情况下工作,但正如我刚写的这个代码,我不能 100%肯定。如果你可以找到它不工作的情况,我真的很想知道,所以我可以修复代码在一些我刚加入的插件。提前致谢。

第三种解决方案

谷歌发现我有潜力的 answer 。我说”potential” 在它看起来不错,应该工作,但我不是 100%说服它是最好的方法:

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.X 。

参考文献

注:本文内容整合自 Google/Baidu/Bing 辅助翻译的英文资料结果。如果您对结果不满意,可以加入我们改善翻译效果:薇晓朵技术论坛。