MENU

【WordPress×PHP】ショートコードを自作する方法を解説

【WordPress×PHP】ショートコードを自作する方法を解説
目次

はじめに

【WordPress×PHP】エスケープとセキュリティの基本(以下、第12回)では、値を安全に出力するためのエスケープを解説しました。

今回は、記事の中に[ ]で書くだけでPHPの処理を呼び出せるショートコードの作り方を解説します。ショートコードを自作すると、「毎年書き換えが必要な数字」や「期間が過ぎたら消したいお知らせ」のように、記事の中に直接書くと手間がかかる部分を、PHPに任せられるようになります。

このシリーズの全15回の構成は、第1回の記事の冒頭にまとめています。

ショートコードとは?

ショートコードは、記事の本文に[名前]の形で書いておくと、表示するときにPHPの処理結果に置き換わる仕組みです。SWELLにも、次のようなショートコードが用意されています(lib/shortcode.php)。

ショートコード働き
[spbr]スマホのときだけ改行する
[post_link id="123"]指定した記事のブログカードを表示する
[only_login] ~ [/only_login]ログイン中だけ、囲んだ部分を表示する

ショートコードの置き換えは、【WordPress×PHP】フィルターフックの仕組みと使い方(以下、第10回)で解説したthe_contentフィルターの中で行われています。ローカル環境でthe_contentに登録されている処理を調べると、優先度11にdo_shortcodeがありました。

ショートコードが置き換わる流れ。本文の[kurumico_years since="2016"]をthe_contentフィルターのdo_shortcodeが見つけ、登録した関数がreturnした「10年」に置き換わる

つまり、ショートコードを作るときにすることは、「この名前の[ ]が見つかったら、この関数を呼んでください」と登録することだけです。

いちばんシンプルなショートコードを作る

【WordPress×PHP】functions.phpの書き方では、フッターにサイトの運営年数を表示する関数を作りました。同じ「運営年数」を、記事の中で好きな場所に表示できるショートコードにしてみます。子テーマのfunctions.phpに、次のコードを追加します。

/**
 * [kurumico_years] で、2016年からの運営年数を表示する
 */
add_shortcode( 'kurumico_years', function() {
	$years = (int) current_time( 'Y' ) - 2016;
	return $years . '年';
} );

add_shortcode()の1つ目の引数がショートコードの名前、2つ目が呼び出す関数です。current_time( 'Y' )は、サイトのタイムゾーンでの今年の西暦を返します。

記事の中では、次のどちらかの方法で使います。

  • 段落ブロックの文章の中に、そのまま[kurumico_years]と書く
  • ブロックの追加で「ショートコード」ブロックを選び、[kurumico_years]と書く

段落ブロックに「運営歴は[kurumico_years]です」と書くと、2026年のローカル環境では「運営歴は10年です」と表示されました。年が変わると、記事を書き換えなくても数字が自動で変わります。

名前は英小文字とアンダースコアで、kurumico_のような自分用の接頭辞を付けましょう。ローカル環境では、大文字で[KURUMICO_YEARS]と書くと置き換わらず、同じ名前を2回登録すると後から登録したほうが有効になりました。SWELLやプラグインと名前が重なると、どちらかが動かなくなります。

表示する文字は「echo」ではなく「return」で返す

ショートコードの関数では、表示したい文字をechoせず、returnで返します。試しにechoで出力するショートコードを作り、段落ブロックに「前[ショートコード]後」と書いてみました。

// 悪い例:echoで出力している
add_shortcode( 'kurumico_echo', function() {
	echo 'ECHOで出力';
} );

結果は「前後」となり、「ECHOで出力」は本文のいちばん上(最初の段落より前)に表示されました。置き換えは、本文を文字列として組み立てている途中で行われるため、echoするとその時点ですぐに出力されてしまいます。第10回のフィルターと同じく、「returnで返す」と覚えておきましょう。

属性を受け取る

[post_link id="123"]のid="123"のように、ショートコードには属性を付けられます。属性は、関数の1つ目の引数に配列で届きます。先ほどのkurumico_yearsを、開始した年と単位を属性で変えられるようにしてみます。

/**
 * [kurumico_years since="2016" unit="年"] で、開始した年からの年数を表示する
 */
add_shortcode( 'kurumico_years', function( $atts ) {
	$atts = shortcode_atts(
		[
			'since' => '2016',  // 開始した年
			'unit'  => '年',    // 数字のあとに付ける文字
		],
		$atts,
		'kurumico_years'
	);

	$years = (int) current_time( 'Y' ) - (int) $atts['since'];

	return $years . esc_html( $atts['unit'] );
} );

shortcode_atts()は、1つ目の引数に書いた既定値と、記事に書かれた属性をまとめる関数です。ローカル環境で、いろいろな書き方を試した結果です。

記事に書いたもの表示
[kurumico_years]10年
[kurumico_years since="2020"]6年
[kurumico_years since="2020" unit=" years"]6 years
[kurumico_years Since="2020" color="red"]6年
属性が関数に届くまで。Since="2020" color="red"は$attsに小文字のsinceとcolorで届き、shortcode_attsで既定値とまとめるとsinceは2020、unitは既定値の年になり、colorは取り除かれる

$attsの中身も確かめると、大文字のSinceは小文字のsinceとして届き、値は"2020"・'2020'・2020のどれで書いても文字列の'2020'でした。[kurumico_years 2020]と名前なしで書くと、0 => '2020'と番号付きで届きました。

属性の値は、記事を書く人が自由に入力できる値なので、第12回のとおり表示するときはエスケープします。unitにHTMLのタグを入れてみると、タグとしては効かず文字のまま表示されました。

囲み型のショートコードを作る

[only_login]〜[/only_login]のように、開始タグと終了タグで文章を囲む囲み型のショートコードも作れます。囲まれた部分は、関数の2つ目の引数に文字列で届きます。

add_shortcode( 'kurumico_box', function( $atts, $content = null ) {
	return '<span class="kurumico-box">' . do_shortcode( $content ) . '</span>';
} );
囲み型ショートコードの受け取り方。開始タグの属性は第1引数の$attsに、タグの間の文字列は第2引数の$contentに届く。中のショートコードはdo_shortcodeを通すと置き換わる

ポイントはdo_shortcode()です。[kurumico_box]運営[kurumico_years]記念セール[/kurumico_box]と書いたとき、$contentをそのまま返すと[kurumico_years]は置き換わらずに表示されました。do_shortcode()を通すと「運営10年記念セール」になりました。

ブロックエディターで囲み型を使うときの注意

囲み型は、ブロックエディターでの書き方によって、出力されるHTMLが変わりました。ローカル環境で<div>を返す囲み型を試した結果です。

書き方結果
ショートコードブロックに1行で書く正しく出力された
開始タグと終了タグを別々のショートコードブロックにして、間に段落ブロックを置く</p>が余計に入り、HTMLが崩れた
段落ブロックの中に書く<p>の中に<div>が入った(HTMLとして正しくない形)
カスタムHTMLブロックに、段落ごと囲んで書く正しく出力された

1行の文章を囲むならショートコードブロック、複数の段落を囲むならカスタムHTMLブロックを使うと安全です。段落ブロックの中で使うショートコードは、<span>のように文章の途中に入れられるタグを返すようにしましょう。

SWELLのショートコードを読んでみる

SWELLのlib/shortcode.phpを開くと、ここまでの書き方がそのまま使われています(関数の定義を囲むif文などは省略しています)。

// 
:シンプルな単独型。HTMLをreturnで返している function spbr( $args ) { return '<br class="sp_">'; } add_shortcode( 'spbr', __NAMESPACE__ . '\spbr' ); // :囲み型。$contentをdo_shortcode()に通して返している function only_login( $args, $content = null ) { if ( is_user_logged_in() ) { return do_shortcode( shortcode_unautop( $content ) ); } return ''; } add_shortcode( 'only_login', __NAMESPACE__ . '\only_login' );

[only_login]では、ログインしていなければ空の文字列''を返して、囲んだ部分を表示しないようにしています。この形は、後の実務サンプルでも使います。

また、記事一覧を表示する[post_list]は、ob_start()とreturn ob_get_clean();で処理を挟んでいます。この間にechoされた内容は、画面に出力されず文字列として受け取れるため、echoで出力する関数もショートコードで使えます。

実務サンプル:期間限定のお知らせを表示する

セールやキャンペーンの紹介は、期間が終わったあとに直し忘れがちです。指定した期間だけ文章を表示するショートコードを作りましょう。子テーマのfunctions.phpに、次のコードを追加します。

/**
 * [kurumico_period start="2026-10-01" end="2026-10-31"]お知らせ文[/kurumico_period]
 * 指定した期間だけ、囲んだ文章を表示する
 */
add_shortcode( 'kurumico_period', function( $atts, $content = null ) {
	$atts = shortcode_atts(
		[
			'start' => '',  // 表示を始める日(空なら制限なし)
			'end'   => '',  // 表示を終える日(この日まで表示。空なら制限なし)
		],
		$atts,
		'kurumico_period'
	);

	$today = current_time( 'Y-m-d' );  // サイトのタイムゾーンでの今日の日付

	if ( $atts['start'] !== '' && $today < $atts['start'] ) {
		return '';  // まだ始まっていない
	}
	if ( $atts['end'] !== '' && $today > $atts['end'] ) {
		return '';  // もう終わった
	}

	return '<p class="kurumico-period">' . do_shortcode( $content ) . '</p>';
} );

子テーマのstyle.cssには、次のCSSを追加します。

.kurumico-period {
	padding: 1em 1.25em;
	background: #fff8e8;
	border-left: 4px solid #f0a020;
	border-radius: 4px;
}

2026年10月13日のローカル環境で、期間の違う3つのお知らせを、それぞれショートコードブロックに1行で書きました。

[kurumico_period end="2026-09-30"]【9月30日まで】9月の読書キャンペーン実施中です。[/kurumico_period]
[kurumico_period start="2026-10-01" end="2026-10-31"]【10月31日まで】Excel VBAの入門書が最大50%オフのセール中です。[/kurumico_period]
[kurumico_period start="2026-11-01"]【11月1日から】新しい連載を始めます。[/kurumico_period]

表示は次のとおりです。期間中の10月のお知らせだけが表示され、終わった9月と、まだ始まっていない11月のお知らせは表示されませんでした。

SWELLの記事ページ。オレンジの線が付いた枠で10月31日までのセールのお知らせだけが表示され、9月と11月のお知らせは表示されていない

開始日・終了日の当日も表示されました。コードのポイントは次のとおりです。

  • startとendの既定値は空。片方だけ書けば「この日から」「この日まで」になる
  • current_time( 'Y-m-d' )で、サイトのタイムゾーン(設定→一般)での今日の日付を取得している
  • 2026-10-13のような同じ形の日付どうしは、文字列のまま<や>で比べても前後を正しく判定できる
  • 期間外は空の文字列を返すので、空の枠が残らない
  • do_shortcode()を通しているので、お知らせ文の中に[kurumico_years]も書ける

よくある質問・エラー対処

Q. ショートコードが置き換わらず、[ ]のまま表示されます

→ そのショートコードが登録されていないときの表示です。次の点を確認しましょう。

  • 名前の打ち間違い(大文字・小文字の違いも含む)
  • functions.phpを編集した子テーマが有効になっているか
  • テーマを切り替えていないか(SWELLのショートコードは、SWELL以外のテーマでは[ ]のまま表示される)

また、ショートコードが置き換わるのはthe_contentフィルターを通る本文だけです。ローカル環境で記事タイトルに書いてみると、[ ]のまま表示されました。


Q. ショートコードそのものを、記事の中で説明として表示したいです

→ [[kurumico_years]]のように、[と]を2重にして書きます。ローカル環境では、置き換わらずに[kurumico_years]と表示されました。

インラインコード(<code>)の中に書いても、ショートコードは実行されます。この記事でも、SWELLのショートコードは2重にして書いています。なお、この書き方で1重になるのは、登録されているショートコードだけです。


Q. 期間限定のお知らせが、ずっと表示されない(または消えない)です

→ 日付は2026-10-01の形(ハイフン区切り)で書きます。ローカル環境でstart="2026/10/01" end="2026/10/31"とスラッシュで書くと、期間中なのに表示されませんでした。end="2026/10/01"だけを書くと、期間が過ぎても表示されたままでした。スラッシュ区切りの日付は、ハイフン区切りの日付と文字列として正しく比べられないためです。

キャッシュ系のプラグインを使っている場合は、日付が変わっても表示が切り替わらないことがあります。切り替わりのあとにキャッシュを削除しましょう。


Q. 終了タグを付け忘れたら、どうなりますか?

→ [kurumico_period end="2026-10-31"]お知らせと書くと単独型として処理され、空の枠の外に「お知らせ」が表示されました。


Q. テーマのテンプレートやフックの中で、ショートコードを使いたいです

→ echo do_shortcode( '[kurumico_years]' );のように、do_shortcode()に[ ]の文字列を渡します。ローカル環境で、フックの中に書いた結果が置き換わって表示されることを確かめました。

おわりに(まとめ)

まとめ

ショートコードを使うと、記事の中に[ ]で書くだけで、PHPの処理結果を好きな場所に表示できます。

  • ✅ add_shortcode()で、名前と呼び出す関数を登録する
  • ✅ 置き換えは、the_contentフィルターの優先度11で行われる
  • ✅ 表示する文字はechoせず、returnで返す
  • ✅ 属性はshortcode_atts()で既定値とまとめ、表示するときはエスケープする
  • ✅ 囲み型は第2引数で中身を受け取り、do_shortcode()に通して返す
  • ✅ 名前は英小文字+アンダースコアで、自分用の接頭辞を付ける

次回は、記事ごとに自由な値を保存できる「カスタムフィールド」と、その値を取り出すget_post_meta()を解説します。説します。

次回は、カスタムフィールドについて解説予定です。

この記事が、少しでも誰かのお役に立てれば幸いです。

関連記事

当サイトの記事で使用したVBAなどのサンプルをDLできます

この記事のサンプルはありません!

ダウンロードページへは下のカードをクリックすればジャンプできます。
よろしければご利用ください!


【CSS】テキスト関連プロパティについて基本解説|Webの基礎


よかったらシェアしてね!
  • URLをコピーしました!
目次