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

方法1在shortcode处理函数中将标志设置为true,然后在wp_footer回调中检查该值。如果正确,它将使用wp_print_scripts()加载JavaScript。这样做的问题是,它仅适用于JavaScript而不适用于CSS,因为CSS应该在<head>内声明,您只能在像initwp_head这样的早期钩子中进行声明。

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

因此,我倾向于使用第二种方法,然后尝试检测是否分配了模板(如果已分配),则将其解析为简码。但是,在此之前,我想检查是否有人知道更好的方法。

更新:我已将解决方案集成到我的插件中。如果有人想看到它在实时环境中充实,可以下载或浏览它。

更新2:从WordPress 3.3开始,现在可以在简码回调中直接调用wp_enqueue_script(),并且JavaScript文件将在文档的页脚中调用。从技术上讲,这对于CSS文件也是可行的,但应将其视为一种不好的做法,因为在<head>标记之外输出CSS会违反W3C规范,可能会出现FOUC,并且可能会迫使浏览器重新呈现页面。

评论

我过去使用过方法1的一种变体。在页脚中为短代码加载JS,在线内为短代码加载CSS。它可以工作,但是有点黑。期待更好的解决方案。

内联CSS的主要问题是很难用其他样式覆盖,并且不使用wp_enqueue_styles()方法。

您有多少CSS?

多少行javascript?

javascript是简单的部分。最好的做法是在此处的“ Jedi”下:scribu.net/wordpress/optimal-script-loading.html

#1 楼

根据我自己的经验,我使用了方法1和2的组合-方法1的体系结构和页脚脚本,以及方法2的“预视”技术。

但是,我使用正则表达式代替stripos;个人喜好,速度更快,并且可以检查“格式错误”的短代码;

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


如果您担心手动使用do_shortcode的作者,我会选择指示他们使用

更新:对于从未使用过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;
}


评论


那是个很好的观点。理想情况下,我希望它能够在无需他们做任何其他事情的情况下工作-因为一半的时间他们可能不会先阅读FAQ,因此他们只会认为它已损坏-但我最终可能会这样做。我可以在每个页面上注册脚本,但是只有在我检测到短代码时才将它们排队。然后,假设当时执行还不算太晚,用户可以加入init并在需要的地方调用特定模板中的入队函数。此外,WP内置有get_shortcode_regex()。

–伊恩·邓恩
11年6月23日在18:54

如果用户擅长实现do_shortcode(),那么认为他们同样擅长遵循使短代码样式入队的说明是否合理?

–芯片Bennett
2011年6月23日19:16

的确如此,但是它将获得所有短代码的正则表达式,而不仅仅是您的正则表达式;)“我可以在每个页面上注册脚本”可能也是更好的方法!请注意,它们不需要挂接到init,只需在wp_head之前的任何位置。对于懒惰的开发人员,请在您的简码中检查wp_style_is('my_style_handle','done')。如果为假,请打印出一个可见的错误,指示他们如何操作。

–TheDeadMedic
2011年6月23日19:17



@Chip-我不担心他们没有能力按照说明进行操作,只是他们不会知道应该这样做,因为99%的时间您不需要执行任何其他操作。

–伊恩·邓恩
2011年6月23日22:05

@Ian我的想法是,将do_shortcode()添加到模板中已经在“做一些额外的事情”-并且愿意做其他事情的用户可能已经知道需要加入样式,否则将会更多愿意/可能遵循特别指示。

–芯片Bennett
2011年6月23日在23:03

#2 楼

我迟迟未回答此问题,但是自从Ian从今天在wp-hackers列表上启动此线程以来,它使我认为值得回答,特别是考虑到我正计划将这样的功能添加到我一直在研究的某些插件中。 br />
考虑的一种方法是检查第一页加载以查看是否实际使用了简码,然后将简码的使用状态保存到post meta键中。方法如下:

分步操作方法


$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'并使用键'yes'检查post meta的值'no'''"_has_{$shortcode_name}_shortcode"。如果值为'no',请不要为外部服务。如果值为'yes''',请继续为外部服务。

应该这样做。我已经编写并测试了一个示例插件,以显示所有插件的工作原理。

示例插件代码

该插件会在[trigger-css]短代码中唤醒,该代码会在插件上设置<h2>元素页面变成白底红字,这样您就可以轻松看到它的正常运行。假定其中包含带有CSS的css文件的style.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%
不确定
我相信以上内容几乎可以在所有情况下使用,但由于我只是编写了这段代码,所以我不能百分百确定。如果您发现无法正常工作的情况,那么我真的很想知道,这样我就可以修复一些我刚刚添加到其中的插件中的代码。提前谢谢。

评论


那么,使用您的方法的五个插件会在每次保存帖子时触发五个远程请求?我宁愿在post_content上使用正则表达式。那么小部件中的短代码呢?

– fuxia♦
13年1月2日于7:02



@toscho触发后加载实际上是可选的;只是为了确保用户不必在加载了外部组件的情况下看到首页加载。这也是一个非阻塞调用,因此从理论上讲您不会注意到它。对于我们的代码,我们在基类中进行操作,因此基类只能处理一次。我们可以钩住'pre_http_request'钩子,并在'save_post'钩子处于活动状态时禁用对同一URL的多次调用,但是我要等到w真正看到了这一点,不是吗?至于小部件,可以增强处理能力,但这不是我所看到的用例。

– MikeSchinkel
2013年1月2日7:59



@toscho-同样,您也不能确定短代码是否存在,因为另一个钩子可能会清除它。您可以确定的唯一方法是,是否确实触发了简码功能。因此,正则表达式方法并非100%可靠。

– MikeSchinkel
13年1月2日在8:03

我知道。没有为短代码注入CSS的防弹方法(使用