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


37

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

方法1は、ショートコードハンドラー関数内でフラグをtrueに設定し、wp_footerコールバック内でその値を確認します。trueの場合wp_print_scripts()、JavaScriptのロードに使用されます。これに伴う問題は、CSSが内部で宣言されなければならないので、それだけで、JavaScriptとCSSでないために働くということである<head>あなただけのような初期のフックの間に行うことができます、initまたはwp_head

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

したがって、私は2番目の方法を使用して、テンプレートが割り当てられているかどうかを検出し、割り当てられている場合はそれを解析してショートコードを取得しようとしています。しかし、その前に、誰かがより良い方法を知っているかどうかを確認したかったのです。

更新:ソリューションをプラグインに統合しました。誰かがそれがライブ環境で肉付けされているのを見たいと思うなら、それをダウンロードするか、それをブラウズすることができます

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


過去に方法1のバリエーションを使用しました。フッターのショートコードのJSを読み込み、インラインのショートコードのCSSを読み込みます。動作しますが、ハックです。より良いソリューションを楽しみにしています。
EAMann

インラインCSSの主な問題は、他のスタイルでオーバーライドすることが難しく、wp_enqueue_styles()メソッドを使用しないことです。
イアン・ダン

あなたはどれくらいのCSSを持っていますか?
-mfields

javascriptの行数は?
-mfields

2
JavaScriptは簡単な部分です。これを行うための最善のワットは、ここでは「ジェダイ」の下にある:scribu.net/wordpress/optimal-script-loading.html
mfields

回答:


11

私自身の経験に基づいて、方法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()が組み込まれています。
イアン・ダン

3
ユーザーがの実装do_shortcode()に熟達している場合、ショートコードスタイルをキューに登録するための指示に従うことに熟達していると想定するのは合理的ではないでしょうか?
チップベネット

1
確かに、それはあなただけのものではなく、すべてのショートコードの正規表現を取得します;)「スクリプトをすべてのページに登録できました」おそらくより良い方法です!彼らはにフックする必要はありませんinitどこでも前に、wp_head。怠け者の開発者の場合wp_style_is( 'my_style_handle', 'done' )は、ショートコードを確認してください。falseの場合、何をすべきかを指示する目に見えるエラーを出力します。
TheDeadMedic

@Chip- 99%の時間を余分に行う必要がないので、彼らが指示に従うことができないことを心配していません。
イアン・ダン

1
@Ian私の考えはdo_shortcode()、テンプレートへの追加はすでに「何か余分なことをする」ということでした-そして、その何かをするユーザーは、スタイルをキューに入れる必要性をすでに知っているか、またはもっと喜んで/可能性が高いでしょう特別な指示に従う。
チップベネット

8

私はこの質問に答えるのが遅れていますが、Ianが今日wp-hackersリストでこのスレッドを開始したので、特に私が取り組んでいるいくつかのプラグインにそのような機能を追加することを計画していることを考えると、答える価値があると思いました。

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

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

  1. $shortcode_usedフラグをに設定し'no'ます。
  2. ショートコード関数自体で$shortcode_usedフラグをに設定し'yes'ます。
  3. WordPressがショートコードを処理した後の'the_content'フックの優先順位12を設定''し、キーを使用するためにポストメタをチェックします"_has_{$shortcode_name}_shortcode"''投稿IDの投稿メタキーが存在しない場合、値が返されます。)
  4. 'save_post'フックを使用して、ユーザーがショートコードの使用を変更した場合に備えて、投稿の永続フラグをクリアする投稿メタを削除します。
  5. また、'save_post'フック内で、wp_remote_request()非ブロッキングHTTP GETを投稿の独自のパーマリンクに送信して、最初のページのロードと永続フラグの設定をトリガーします。
  6. 最後に設定'wp_print_styles'しての値をポストメタをチェックし'yes''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%かどうかわからない

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


あなたのアプローチを使用する5つのプラグインは、投稿が保存されるたびに5つのリモートリクエストをトリガーしますか?私はむしろ正規表現を使用しpost_contentます。ウィジェットのショートコードはどうですか?
FUXIA

@toschoポストロードのトリガーは実際にはオプションです。外部がロードされた状態で最初のページのロードをユーザーが見る必要がないようにするためだけにあります。ノンブロッキングコールでもあるため、理論上は気付かないはずです。このコードでは、基本クラスで1回だけ処理できるように、基本クラスで実行しています。フックをフックして'pre_http_request''save_post'フックがアクティブな間に同じURLへの複数の呼び出しを無効にすることもできますが、その必要性が実際にわかるまで待ちたいのです。ウィジェットに関しては、処理できるように拡張することもできますが、まだ見たユースケースではありません。
マイクシンケル

1
@toscho-また、別のフックがショートコードをクリアする可能性があるため、ショートコードがあることを確認できません。確認できる唯一の方法は、ショートコード関数が実際に起動するかどうかです。したがって、正規表現のアプローチは100%信頼できるものではありません。
マイクシンケル

知っている。ショートコード用にCSSを挿入する防弾の方法はありません(を使用する場合を除く<style>)。
FUXIA

私はこのソリューションに基づいた実装で作業しており、このメソッドは投稿/ページのプレビューのためにキューに入れないことを指摘したかっただけです。
mor7ifer

5

グーグルは私に潜在的な 答えを見つけました。私は「潜在的」と言っていますが、それは見栄えが良く、うまくいくはずですが、私はそれが最善の方法だと確信しているわけではありません:

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で機能するかどうかもわかりません。 。


ショートコードに引数がある場合、これは機能しません。本当に遅いこの方法を使用したい場合は、WPを使用get_shortcode_regex()して検索してください。
onetrickpony

私が言ったように、まだテストしていない「潜在的な」答え... :
EAMann

これは基本的に方法2と同じですが、do_shortcode()呼び出しのテンプレートをチェックしません。
イアン・ダン

なぜそれが必要なのでしょうか?あなたが呼び出す場合do_shortcode()、テンプレートに手動で、あなたはすでにあなたがショートを実行していることがわかっている
onetrickpony

ユーザーはショートコードを呼び出す人ではありません。これはプライベートプラグインではなく、分散プラグイン用です。
イアン・ダン

2

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

1

最後に、プラグイン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' );

ちょっとしたけれど、これは人々がheader.phpとfooter.phpを使用していると仮定していません。scribu.net/wordpress/theme-wrappers.htmlで説明されているようなテーマのラッピング方法はどうですか?または、テンプレートパーツを別の場所に保持するルートのようなテーマですか?
オリオンラッシュ

1

私のプラグインでは、ユーザーがポストメタデータに格納されたショートコードを持つテーマビルダーを持っていることがあります。プラグインショートコードが現在の投稿または投稿メタデータに存在するかどうかを検出するために使用しているものは次のとおりです。

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

0

CSSは内部で宣言する必要があるため <head>

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

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

この後、定数または何かを設定しMY_CSS_LOADEDます(定数が設定されていない場合のみCSSを含めます)。

どちらの方法も、この方法を使用するよりも時間がかかります。

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


3
<head>要素の外側にCSSをロードすることは適切なマークアップではありません。確かに、検証は単なるガイドラインですが、そのガイドラインに固執しようとしている場合、ショートコード出力内にスタイルシートをロードすることは悪い考えです。
EAMann

インラインCSSブロックは、私が覚えているXHTMLでも有効なマークアップです。他に受け入れられる代替手段がない場合、それらを使用しない理由はありません
-onetrickpony

1
W3Cの検証ツールによると:<style type="text/css"> The element named above was found in a context where it is not allowed. This could mean that you have incorrectly nested elements -- such as a "style" element in the "body" section instead of inside "head"。したがって、インラインスタイル(<element style="..."></element>)は有効ですが、インライン<style>要素は無効です。
EAMann

1
それをフィルター可能にし、他のプラグインやテーマが好きなようにできるようにします。空の文字列を返すようにフィルターを設定すると、何も出力されません。
-mfields

1
この実践に対する客観的な理由については言及しませんでした。とにかくそれは問題ではありません。ここには2つのオプションしか表示されません。CSS/スクリプトを常に読み込む(サイズを最適化する)、または条件付きインラインスタイル
onetrickpony

0

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

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


これは、プラグイン自体からエンキューを制御することに関するこの質問にはあまり関係ありません。このアプローチでは、ユーザーに別のプラグインをインストールするように依頼し、適切に構成する方法を理解する必要があります。
イアンダン14年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.