WordPress のショートコードの作り方:add_shortcode の基本と、広告・記事のリンクを出す例(echo で上に出る・下書きの題が出る問題も直す)

概要説明

functions.php で WordPress のオリジナルのショートコードを作る方法。add_shortcode の基本の形と、AdSense の広告・投稿 ID から記事の URL やリンクを出す例を紹介。echo だと広告が本文の上に出る・下書きや非公開の題が見えてしまう、という前の書き方の問題も試した結果つきで。

ショートコードは、記事の中に [名前] と書くと、決めた内容に置きかわるしくみです。

functions.php に「中身を返す関数」を作り、add_shortcode() で名前を付けて登録します。

functions.php
/*----------------------------------------------------
 ショートコード:[my_hello name="山田"] 基本の形
----------------------------------------------------*/
function my_shortcode_hello( $atts ) {
	$atts = shortcode_atts( array( 'name' => 'ゲスト' ), $atts, 'my_hello' );
	return 'こんにちは、' . esc_html( $atts['name'] ) . 'さん';
}
add_shortcode( 'my_hello', 'my_shortcode_hello' );
[my_hello]
→ こんにちは、ゲストさん

[my_hello name="山田"]
→ こんにちは、山田さん
書き方 役目
add_shortcode( 'my_hello', '関数名' ) [my_hello] と書いたところで、関数を呼ぶように登録する
関数の $atts [my_hello name="山田"] の name のような、書いた値が入る
shortcode_atts( 決まりの値, $atts, 名前 ) 書かれなかった値に決まりの値を入れる。3 つ目に名前を入れると、ほかのプラグインからも値を変えられる
return で返す 返した文字が、[my_hello] のところに入る。echo で出すと、本文の上に出てしまう
esc_html()・esc_url() 書かれた値や記事の題を出すときに、HTML として動かないようにする
my_ を付けた名前 [ad] や [link] のような短い名前は、プラグインとぶつかりやすい

例:Google AdSense の広告を記事の中に出す [my_ad]

functions.php
/*----------------------------------------------------
 ショートコード:[my_ad] 記事の中に広告を出す
----------------------------------------------------*/
function my_shortcode_ad() {
	static $script_done = false;

	$client = 'ca-pub-0000000000000000'; // 自分のサイト運営者 ID
	$slot   = '0000000000';              // 広告ユニットの ID

	$html = '';
	if ( ! $script_done ) {
		// 広告を読み込む script は、ページに 1 回だけ出す
		$html       .= '<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=' . esc_attr( $client ) . '" crossorigin="anonymous"></script>';
		$script_done = true;
	}
	$html .= '<ins class="adsbygoogle" style="display:block; text-align:center;" data-ad-layout="in-article" data-ad-format="fluid"'
		. ' data-ad-client="' . esc_attr( $client ) . '" data-ad-slot="' . esc_attr( $slot ) . '"></ins>'
		. '<script>(adsbygoogle = window.adsbygoogle || []).push({});</script>';

	return $html; // echo ではなく return で返す
}
add_shortcode( 'my_ad', 'my_shortcode_ad' );
書き方 役目
$client・$slot AdSense の画面でもらった、サイト運営者 ID と広告ユニットの ID を入れる
static $script_done 広告を何個入れても、広告を読み込む script は 1 回だけ出す
esc_attr() ID を HTML の属性に入れるときの決まりの書き方
return $html [my_ad] を書いたところに広告が入る
[my_ad]

記事の中の、広告を出したいところに書きます。

前はこの記事で、広告のコードを echo で出していました。この書き方だと、[ad] を本文の途中に書いても、広告は本文のいちばん上に出ます。ショートコードの関数は、出したい文字を return で返します。

例:投稿 ID から記事の URL を出す [my_link]

2 つのショートコードで使う「公開中の記事だけを取り出す」関数を先に作り、それを使って URL を返します。

functions.php
/*----------------------------------------------------
 公開中の記事だけを取り出す([my_link]・[my_linka] で使う)
----------------------------------------------------*/
function my_shortcode_public_post( $id ) {
	$id = absint( $id );
	if ( ! $id ) {
		return null; // get_post( 0 ) は今の記事を返すので、0 は「なし」にする
	}
	$post = get_post( $id );
	if ( ! $post || 'publish' !== get_post_status( $post ) || post_password_required( $post ) ) {
		return null; // 下書き・非公開・パスワード付きは出さない
	}
	return $post;
}

/*----------------------------------------------------
 ショートコード:[my_link id="123"] 記事の URL を出す
----------------------------------------------------*/
function my_shortcode_link( $atts ) {
	$atts = shortcode_atts( array( 'id' => 0 ), $atts, 'my_link' );
	$post = my_shortcode_public_post( $atts['id'] );
	if ( ! $post ) {
		return '';
	}
	return esc_url( get_permalink( $post ) );
}
add_shortcode( 'my_link', 'my_shortcode_link' );
書き方 役目
absint( $id ) 書かれた ID を 0 以上の数にする。数でないときは 0
0 は null を返す get_post( 0 ) や get_permalink( 0 ) は「今の記事」を返すので、ID がないときに今の記事の URL が出ないようにする
get_post_status() が publish 公開中の記事だけを出す
post_password_required() パスワード付きの記事は出さない
esc_url() URL を出すときの決まりの書き方
[my_link id="92"]

→ https://functions.fs-create.net/archives/92

例:投稿 ID から記事へのリンク(a タグ)を出す [my_linka]

functions.php
/*----------------------------------------------------
 ショートコード:[my_linka id="123" text="文字"] 記事へのリンク(a タグ)を出す
----------------------------------------------------*/
function my_shortcode_linka( $atts ) {
	$atts = shortcode_atts( array( 'id' => 0, 'text' => '' ), $atts, 'my_linka' );
	$post = my_shortcode_public_post( $atts['id'] );
	if ( ! $post ) {
		return '';
	}
	$text = '' !== $atts['text'] ? $atts['text'] : get_the_title( $post );
	return '<a href="' . esc_url( get_permalink( $post ) ) . '">' . esc_html( wp_strip_all_tags( $text ) ) . '</a>';
}
add_shortcode( 'my_linka', 'my_shortcode_linka' );
書き方 役目
text の値 書いたときは、記事の題の代わりにその文字をリンクにする
wp_strip_all_tags() 題に入った <br> などのタグを外す
esc_html() リンクの文字を、HTML として動かないようにする
[my_linka id="92"]
→ <a href="https://functions.fs-create.net/archives/92">記事の題</a>

[my_linka id="92" text="こちら"]
→ <a href="https://functions.fs-create.net/archives/92">こちら</a>

前の書き方との違い

ところ 前の書き方 今の書き方
広告の出し方 echo で出していたので、本文のいちばん上に出た return で返すので、書いたところに出る
広告の script 広告の数だけ、同じ script を読み込んだ 1 回だけ
下書き・非公開の記事の ID だれが見ても、題と URL が出た 何も出さない
id を書き忘れたとき 今の記事の URL が出て、PHP の警告(Undefined array key "id")も出た 何も出さない
ない ID のとき 中身のない <a href=""></a> が出た 何も出さない
題の文字 そのまま出していた タグを外して、esc_html() で出す
extract() 使っていた(どの変数ができるか見えにくく、今はすすめられていない) 使わない

確かめた結果

このサイトの作業環境(WordPress 7.1.3・PHP 8.3)で、試しの記事(公開・下書き・非公開)を作り、ログインしていない訪問者として表示して試しました。試しの記事は、終わったあとに消しました。

試したこと 今の書き方 前の書き方
[my_hello name="山田"] こんにちは、山田さん —
「前の文 [広告] 後の文」 2 つの文のあいだに広告が入った 広告が文より先に出た(267 文字)
広告を 3 つ入れる 広告 3 つ・script 1 つ —
公開中の記事の ID URL・リンクが出た URL・リンクが出た
下書きの記事の ID 何も出ない 下書きの題と URL が出た
非公開の記事の ID 何も出ない 「非公開: 」付きの題と URL が出た
id なし 何も出ない 今の記事の URL と警告
ない ID・数でない ID 何も出ない 空のリンク
text に <script> を入れる タグが外れて文字だけ —

PHP のテンプレートからショートコードを使う

テーマのテンプレート
<?php echo do_shortcode( '[my_ad]' ); ?>
<?php echo do_shortcode( '[my_linka id="92"]' ); ?>

<?php // 自分で作った関数なら、直接呼ぶほうが速い ?>
<?php echo my_shortcode_linka( array( 'id' => 92 ) ); ?>

do_shortcode() に文字を渡すと、ショートコードを置きかえた結果が返ります。

自分で作ったショートコードなら、関数を直接呼んでも同じ結果になり、文字を調べる手間がないぶん速くなります。

参考(WordPress の公式の説明)

関連機能

  1. WordPress の記事の何番目の見出しの前に広告や文を差し込む:the_content で 1 つ目・2 つ目・最後の h3 を数える

  2. WordPress に画像の大きさを足す add_image_size:切り抜く・切り抜かないの違いと使い方

  3. WordPress パンくずリスト表示用のショートコード

サイドバー

よく使うカスタマイズ

最近の記事

Profile

PAGE TOP