[WordPress][プラグイン開発] 記事中のショートコードを保存時に書き換える

Development, WordPressWordPress

記事に挿入したショートコードを保存した時に書き換えてしまうプラグインサンプルを書きました。

[foo bar=”qux”] → 保存すると [foo bar=”qux” baz=”quux”] というような感じ。

なぜそんなことする必要があるのかというと、ショートコードの処理は毎回記事を表示するときに実行されるので、重たい処理はショートコードに含ませておこうというものです。

具体的には、Webサイトのスクリーンショットを表示 で作成したプラグインのショートコードが、Web サイトのタイトルを指定していないと毎回 Web サイトにアクセスするという動作をしているのに、今頃気付いたので、その解決策です。このプラグインは保存時にタイトルを取得するようアップデートしています。既存の記事は一度更新しないと毎回タイトル取得してしまいますが、プラグイン単体で良い感じにするのは思いつかなかったのでそのままです。

コード全体は jz5/wp-rewrite-shortcode-sample に置いてます。

ショートコード プラグインの作成

ショートコードのプラグイン作成は簡単です。add_shortcode でショートコードタグのフックを追加します。

[foo bar=”qux” baz=”quux”] というショートコードを書くと、(bar = qux, baz = quux) と表示するだけの簡単なものです。

<?php
// shortcode 処理
// [foo bar="qux" baz="quux"]
add_shortcode('foo', 'rewrite_shortcode_func');
function rewrite_shortcode_func($atts) {
// shortcode のパラメータ取得
extract(shortcode_atts(array(
'bar' => 'qux', // bar 既定値
'baz' => null // baz 既定値
), $atts));
return "(bar = $bar, baz = $baz)"; // shortcode の結果
}
?>

view raw
gistfile1.php
hosted with ❤ by GitHub

保存時に書き換える

サンプルとして、ショートコードの baz 属性が指定されていなかった場合は、プラグインで値を決め本文中に書き換えてから保存するようにします。

新規作成と更新時時に処理するため wp_insert_post_data というフィルターをフックします。

$data['post_content'] の内容を書き換えます。サンプルでは baz 属性を指定していなければ uniqid() の結果が付けたショートコードに書き換えられます。

ショートコード部分の取得などは、Shortcode API を使います。リファレンスだと詳細不明で実際の shortcodes.php のコードも読んでました。

<?php
// 保存時 shortcode の書き換え
add_filter('wp_insert_post_data', 'rewrite_shortcode_insert_post_data');
function rewrite_shortcode_insert_post_data($data) {
// foo shortcode がなければ書き換えなし
if (false === has_shortcode($data['post_content'], 'foo')) {
return $data;
}
// foo shortcode 部分の書き換え
$pattern = get_shortcode_regex();
// shortcode 部分を繰り返し取得して置換
$data['post_content'] = preg_replace_callback('/'. $pattern .'/s', function ($matches) {
// foo 以外の shortcode は書き換えなし
if ($matches[2] !== 'foo') {
return $matches[0];
}
// エスケープされた shortcode は書き換えなし
if ($matches[1] == '[' && $matches[6] == ']') {
return $matches[0];
}
// shortcode のパラメータ取得
$atts = shortcode_parse_atts(stripslashes($matches[3]));
// baz !== null (規定値以外)の場合も書き換えなし
if ($atts['baz'] !== null) {
return $matches[0];
}
// baz が既定値以外の場合 shortcode を書き換え
$atts['baz'] = uniqid();
$params = array();
foreach ($atts as $key => $val) {
$params[] = "$key=\"$val\"";
}
return '[foo ' . implode(' ', $params) . ']'; // 書き換えた shortcode
}, $data['post_content']);
return $data;
}
?>

view raw
gistfile1.php
hosted with ❤ by GitHub

has_shortcode

Function Reference/has shortcode « WordPress Codex

まず対象のショートコードが本文に含まれるか確認に使っています。

get_shortcode_regex

Function Reference/get shortcode regex « WordPress Codex

ショートコードを表す正規表現を返す関数。この正規表現自体は [foo] のような閉じタグ([/foo])がない場合はうまくショートコード部分を取れません(が、フィルターに渡される本文データの場合上記コードで意図した動作になります)。

下記の結果を使っています。

  • $matches[0]: ショートコード全体([foo bar=”qux” baz=”quux”])
  • $matches[2]: ショートコードタグ(foo)
  • $matches[3]: ショートコード属性部分(bar=”qux” baz=”quux”)
  • $matches[1], $matches[6]: ショートコードのエスケープ記述([[foo]])の場合は [ と ] が入る

shortcode_parse_atts

Function Reference/shortcode parse atts « WordPress Codex

ショートコード属性部分(bar=”qux” baz=”quux”)を連想配列に変換します。上記で得られた結果は stripslashes 関数を通してから指定します。