この記事は最後に更新してから1年以上経過しています。
説明
ショートコードは投稿記事の閲覧時に動的に内容を変更できる優れもの。galleryやcaptionなどいくつかのショートコードが標準で組み込まれており、一部のプラグインではその機能を利用する手段としてショートコードが利用されている。
ショートコードは[tag-a /]のように記述する自己完結型と、[tag-b]コンテント[/tag-b]のように記述する囲み型に区別できる。ショートコードの中には、これら両方のタイプをサポートしているものもある。
ショートコードの処理は最後
ショートコードは、 the_content関数の同名のフィルターとして組み込まれている do_shortcode関数によって機能する。the_contentフィルターは、バージョン4.0の標準状態では次のようになっている。
フィルター関数 | 概要 | プライオリティ |
---|---|---|
WP_Embed:run_shortcode | ショートコードembedを処理 | 8 |
WP_Embed:autoembed | autoembedに対応したURLを処理 | 8 |
wptexturize | HTMLエンティティを一般的な文字に変換 | 10 |
convert_smilies | 絵文字を対応するimgタグに変換 | 10 |
convert_chars | HTML数値エンティティを変換 | 10 |
wpautop | 改行、pタグやbrタグを整頓 | 10 |
shortcode_unautop | pタグで囲まれたショートコードを調整 | 10 |
prepend_attachment | コンテント(本文)前に添付ファイル内容を追加 | 10 |
capital_P_dangit | 'Wordpress'を'WordPress'に変換など | 11 |
do_shortcode | ショートコードを処理 | 11 |
the_contentフィルターはこの表の上から下へ順番に処理を行う。最初にショートコードembed(埋め込み)が処理され、最後にショートコードを処理するdo_shortcode関数が呼び出されている。同じショートコードでも違うタイミングで処理されていることがわかる。
そこのpタグはいらない
さて前置きはこのへんにしておいて、本題に移っていこう。
今回、指定した条件にマッチする場合のみコンテントを表示するショートコードを作ってみたのだが、思い通りに表示にならなかった。ショートコードはアクセス日時によって表示内容を変更するもので、
function shortcode_period( $atts, $content='' ) {
extract( shortcode_atts( array(
'from' => '2000/1/1 0:00:00',
'to' => '2037/12/31 23:59:59'
), $atts ) );
$now_sec = strtotime( date_i18n( 'Y/m/d H:i:s' ) );
return ( $now_sec >= strtotime( $from ) && $now_sec <= strtotime( $to ) )? do_shortcode( $content ): '';
}
add_shortcode( 'period', 'shortcode_period' );
出力された内容を見てみると、(個人的には)余計なpタグがあり、しかも正しいペアになっていなかった。pタグ自体は我慢できても、正しいペアになっていないのは困る。そんなわけで、実際にどのような変換が行われているか比較してみた。
状況 | ケース1 | ケース2-1(10月22日閲覧) | ケース2-2(10月23日閲覧) |
---|---|---|---|
the_content実行前 | <h3>ショートコードについて</h3>\r\n[period to="2014/10/22 23:59:59"]22日まで[/period]\r\n[period from="2014/10/23 0:00:00"]23日から[/period] | <h3>ショートコードについて</h3>\r\n[period to="2014/10/22 23:59:59"]<div>22日まで</div>[/period]\r\n[period from="2014/10/23 0:00:00"]<div>23日から</div>[/period] | |
wpautop実行後 | <h3>ショートコードについて</h3>\n<p>[period to="2014/10/22 23:59:59"]22日まで[/period]<br />\n[period from="2014/10/23 0:00:00"]23日から[/period]</p>\n | <h3>ショートコードについて</h3>\n<p>[period to="2014/10/22 23:59:59"]\n<div>22日まで</div>\n<p>[/period]<br />\n[period from="2014/10/23 0:00:00"]\n<div>23日から</div>\n<p>[/period]</p>\n | |
do_shortcode実行後 | <h3>ショートコードについて</h3>\n<p>22日まで<br />\n</p>\n | <h3>ショートコードについて</h3>\n<p>\n<div>22日まで</div>\n<p><br />\n</p>\n | <h3>ショートコードについて</h3>\n<p><br />\n\n<div>23日から</div>\n<p></p>\n |
囲み型ショートコード内にdivタグ(pやsectionタグなども同様)を使用した場合、pタグが正しくペアにならないようだ。現状、pタグが正しくペアになっていないことで(ブラウザ次第ではあるが)表示が大きく乱れることは少なくなってきているが、HTMLバリデーションエラーのある状態は好ましくない。またbrタグによって行間が広くなるのも気になるところだ。
対処として、最初は remove_filter関数を使ってthe_contentフィルターからwpautop関数を削除することを考えたのだが、ショートコードembedと同じようにthe_contentフィルターでwpautop関数の前に希望するショートコードだけを処理することを考えてみた。
function run_shortcode_before_wpautop( $content ) {
global $shortcode_tags;
// 登録されているショートコードを退避して空に
$orig_shortcode_tags = $shortcode_tags;
remove_all_shortcodes();
// wpautop関数実行前に処理したショートコードをここで追加
add_shortcode( 'period', 'shortcode_period' );
$content = do_shortcode( $content );
// 退避したショートコードを元に戻す
$shortcode_tags = $orig_shortcode_tags;
return $content;
}
add_filter( 'the_content', 'run_shortcode_before_wpautop', 9 );
このコードはWP_Embedクラスのrun_shortcodeメソッドを流用したもので、the_contentフィルターとしてwpautop関数よりも優先度の高いプライオリティ値の9として登録している。この対応結果は次のようになり、意図した通りの結果を得ることができた。
状況 | ケース3-1(10月22日閲覧) | ケース3-2(10月23日閲覧) |
---|---|---|
the_content実行前 | <h3>ショートコードについて</h3>\r\n[period to="2014/10/22 23:59:59"]22日まで[/period]\r\n[period from="2014/10/23 0:00:00"]23日から[/period] | |
run_shortcode_before_wpautop実行後 | <h3>ショートコードについて</h3>\r\n<div>22日まで</div>\r\n | <h3>ショートコードについて</h3>\r\n\r\n<div>23日から</div> |
wpautop実行後 | <h3>ショートコードについて</h3>\n<div>22日まで</div>\n | <h3>ショートコードについて</h3>\n<div>23日から</div>\n |
do_shortcode実行後 | <h3>ショートコードについて</h3>\n<div>22日まで</div>\n | <h3>ショートコードについて</h3>\n<div>23日から</div>\n |
コンテントの中のショートコードを記述できるか
次の2点については後述のCodexに記載されているのだが、少しハマった経験があるのでここでも紹介しておく。
1点目は、囲み型ショートコードのコンテンツ内にショートコードを記述できる(許可する)かどうかである。例えば、次のような投稿内容で、ショートコードtag-aはspanタグで囲み、ショートコードtag-bはstrongタグで囲むものとしよう。
[tag-a][tag-b]コンテントの中のタグB[/tag-b][/tag-a][tag-b]単独のタグB[/tag-b]
ショートコードtag-aがコンテント内にショートコードを記述できない場合は、次の示す内容となる。
<span>[tag-b]コンテントの中のタグB[/tag-b]</span><strong>単独のタグB</strong>
これに対してショートコードtag-aがコンテント内にショートコードを記述できる場合には、次のような内容となる。
<span><p><span><strong>コンテントの中のタグB</strong></span><strong>単独のタグB</strong>
この2つの違いはショートコードの(ハンドラ)関数の記述にあり、コンテントを受け取るパラメータ$contentに対して do_shortcode関数を使用するかどうかで決まる。
/* コンテントのショートコードを許可しない */
function tag_a_func( $atts, $content='' ) {
return ''.$content.'';
}
/* コンテントのショートコードを許可する */
function tag_a_func( $atts, $content='' ) {
return ''.do_shortcode( $content ).'';
}
コンテントの中に同じ名前のショートコードは使えない
コンテントのショートコードを許可している場合で注意したいのが、同じ名前のショートコードを使用できないということだ。わかりやすく説明するために、先ほどの投稿内容を少し修正してみる(便宜上色分けする)。
[tag-a][tag-a]コンテントの中のタグ[/tag-a][/tag-a]
この場合の出力内容は、次のようになってしまう。
<span><span></span>コンテントの中のタグ</span>[/tag-a]
本来なら外側(赤)と内側(青)がそれぞれペアとして認識してほしいところだが、実際には赤の[tag-a]のペアとして青の[/tag-a]が適用されてしまうために起こっている。このことは既知の症状として認識されている(要はバグではない)。このようなことを回避するには、ショートコードのコンテントには同名のショートコードを使用しないことを徹底することだ。どうしても同じ機能のショートコードを使用しなければならない場合は、別名のショートコードを登録して使い分けることになる。
まとめ
というわけで、ショートコードを使うなら「Codex日本語版:ショートコード API」を必ず参照しておこう。
最終更新 : 2018年05月27日 10:46
関連
お勧め
add_shortcode(2018年5月27日 更新)
get_user_setting(2022年1月31日 更新)
have_posts(2018年5月27日 更新)
in_category(2018年5月27日 更新)
add_feed(2024年6月24日 更新)