web-dev-qa-db-ja.com

ショートコード用のJavaScript/CSSの条件付きロード

ショートコードを作成するプラグインをリリースしました。そのショートコードを含むページには、JavaScriptファイルとCSSファイルを読み込む必要があります。スクリプト/スタイルをすべてのページにロードすることもできますが、これはベストプラクティスではありません。ショートコードを呼び出すページにファイルをロードしたいだけです。これを行う方法は2つありますが、どちらにも問題があります。

方法1 は、ショートコードハンドラ関数内でフラグをtrueに設定してから、wp_footerコールバック内でその値を確認します。それが本当なら、JavaScriptをロードするのにwp_print_scripts()を使います。 CSSの<head>内で宣言する必要があるため、これはJavaScriptではなくCSSでしか機能しないという問題があります。これは、initwp_headのような初期のフック中にのみ実行できます。

方法2 は早めに起動され、現在のページのコンテンツにショートコードが存在するかどうかを確認するために「先読み」します。私はこの方法が最初の方法よりもはるかに優れているのですが、この方法ではテンプレートがdo_shortcode()を呼び出しても検出されません。

それで、私は2番目の方法を使って、それからテンプレートが割り当てられているかどうかを検出しようとしている、そしてもしそうなら、ショートコードのためにそれを解析することに傾いています。しかしそれをする前に、だれかがもっと良い方法を知っているかどうかを調べたかったのです。

更新: 私は自分のプラグインに解決策を統合しました。誰もがライブ環境でそれが完成するのを見たがっているのであれば、 ダウンロード または ブラウズ できます。

更新2: WordPress 3.3では、 ショートコードコールバック内で直接wp_enqueue_script()を呼び出す が可能になり、JavaScriptファイルはドキュメントのフッター内で呼び出されるようになりました。 CSSファイルでもこれは技術的には可能ですが、<head>タグの外側でCSSを出力するとW3Cの仕様に違反し、FOUCが無効になり、ブラウザにページの再レンダリングを強制する可能性があるため、悪い習慣と考えるべきです。

37
Ian Dunn

私自身の経験に基づいて、私は方法1と2の組み合わせ - 1のアーキテクチャとフッタースクリプト、および2の「先読み」手法を使用しました。

しかし先を見越して、私は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;
}
11
TheDeadMedic

私はこの質問に答えるのが遅れましたが、Ianが このスレッド 今日wp-hackersメーリングリストに載って以来、特に私がこれまで行ってきたいくつかのプラグインにそのような機能を追加する計画を考えて取りかかっている。

考慮すべきアプローチは、最初のページロードをチェックして、ショートコードが実際に使用されているかどうかを確認してから、ショートコードの使用状況をポストメタキーに保存することです。方法は次のとおりです。

ステップバイステップのハウツー

  1. $shortcode_usedフラグを'no'に設定します。
  2. ショートコード関数自体で$shortcode_usedフラグを'yes'に設定します。
  3. WordPressがショートコードを処理した後である'the_content'フック優先順位12を設定し、キー''を使用して"_has_{$shortcode_name}_shortcode"についてpost metaをチェックします。 (投稿IDに投稿メタキーが存在しない場合は、値''が返されます。)
  4. ユーザがショートコードの使用法を変更した場合に備えて、'save_post'フックを使用して投稿メタを削除し、その投稿の永続フラグをクリアします。
  5. また、'save_post'フックでは、wp_remote_request()を使用して、投稿の独自のパーマリンクにノンブロッキングHTTP GETを送信し、最初のページの読み込みと永続フラグの設定をトリガーします。
  6. 最後に'wp_print_styles'を設定し、キー'yes'を使って'no'''または"_has_{$shortcode_name}_shortcode"の値についてpost metaをチェックします。値が'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]ショートコード付きの基本的な投稿エディタ

[trigger-css]ショートコードでポストディスプレイ

100%かどうかわからない

私は上記のことはほとんどすべての場合にうまくいくはずだと思いますが、このコードを書いたばかりでは100%確信が持てません。うまく動かない状況が見つかったら、私が本当に知りたいのですが、これを追加したプラグインでコードを修正できます。前もって感謝します。

8
MikeSchinkel

グーグルは私に 潜在的な 答え を見つけた。私はそれがそうであるように私はそれがそうであるように「潜在的」と言います、働くべきです、しかし、私はそれがそれをする最も良い方法であると確信していません:

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.

5
EAMann

TheDeadMedicの答えとget_shortcode_regex() documentation (これは実際には私のショートコードを見つけることができませんでした)の組み合わせを使用して、複数のショートコード用のスクリプトをキューに入れるための簡単な関数を作成しました。ショートコード内のwp_enqueue_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' );
2
Sean Michaud

私のプラグインのために私は時々 ポストメタデータに保存されているショートコードを持っているテーマビルダーを持っていることを発見しました 。これが私のプラグインのショートコードが現在の postまたは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' );
1
zdenekca

最後に、私のプラグイン www.mapsmarker.com で動作する条件付きCSSローディングの解決策も見つけました。そしてあなたと共有したいと思います。私のショートコードが現在のテンプレートファイルとheader/footer.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' );
1
robertharm

スクリプトロジックは、すべてのJavaScriptおよびCSSファイルを完全に制御できるWordPressプラグインです。このプラグインを使用すると、必要に応じてCSSとJSファイルを条件付きでページにロードできます。

http://wordpress.org/plugins/script-logic/

0
Tahir Yasin

cSSは<head>の中で宣言されるべきだから

CSSファイルの場合は、ショートコードの出力内にそれらを読み込むことができます。

<style type="text/css">
  @import "path/to/your.css"; 
</style>

MY_CSS_LOADEDのように、定数かこれ以降に何かを設定してください(定数が設定されていない場合のみCSSを含めてください)。

どちらの方法も、この方法よりも遅くなります。

JSファイルの場合は、ロードしているスクリプトが一意で、外部の依存関係がない場合でも同じことができます。そうでない場合は、フッターの内側にロードしますが、ロードする必要があるかどうかを判断するために定数を使用します。

0
onetrickpony