WordPressの固定ページ内で<script>タグを使用する際、ショートコードが正しく展開されないという問題に遭遇することがあります。この記事では、この問題の解決方法とレンタルサーバーに依存しない安全な実装方法を解説します。

問題の例

例えば、以下のようなショートコードを設定していたとします:

//shortcodes.php または functions.php
$urls = array(
'topthemeurl' => 'https://example.com/wp-content/themes/your-theme',
'commonsurl' => 'https://example.com/wp-content/themes/your-theme/commons'
);

function register_shortcodes() {
global $urls;

foreach ($urls as $key => $value) {
add_shortcode($key, function () use ($value) {
return $value;
});
}
}

固定ページ内で以下のように記述した場合:

<link rel="preload" href="https://code-plus.jp/gp/wp-content/themes/zaratan/js/script.js" as="script">
<script src="https://code-plus.jp/gp/wp-content/themes/zaratan/js/script.js"></script>

<link>タグではショートコードが正しく展開されますが、<script>タグでは展開されないという問題が発生します:

<!-- 結果(view-source) -->
<link rel="preload" href="https://example.com/wp-content/themes/your-theme/js/script.js" as="script">
<script src="https://code-plus.jp/gp/wp-content/themes/zaratan/js/script.js"></script>

解決方法1: DOMDocument を使用する方法


この問題を解決するには、functions.phpに以下のコードを追加します:

//scriptタグ内のショートコードを処理する
add_filter('the_content', 'process_shortcodes_in_script', 99);

function process_shortcodes_in_script($content) {
if (false === strpos($content, '<script')) {
return $content;
}

//DOMDocumentを使用してHTMLを解析
$dom = new DOMDocument();
//HTML5のタグを適切に処理するための設定
libxml_use_internal_errors(true);
$dom->loadHTML(mb_convert_encoding($content, 'HTML-ENTITIES', 'UTF-8'), LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
libxml_clear_errors();

//scriptタグを検索
$scripts = $dom->getElementsByTagName('script');

//各scriptタグに対して処理
foreach ($scripts as $script) {
//src属性を取得
$src = $script->getAttribute('src');
if ($src) {
//src属性内のショートコードを処理
$new_src = do_shortcode($src);
$script->setAttribute('src', $new_src);
}
}

//変更を適用したHTMLを返す
$new_content = $dom->saveHTML();

//余分なタグを削除
$new_content = preg_replace('/<(!DOCTYPE|html|body).*?>|<\/(html|body)>/', '', $new_content);

return $new_content;
}

注意点: この方法は一部のレンタルサーバー(カラフルボックスなど)では動作しますが、エックスサーバーやヘテムルなどの一部のサーバーでは、エラー処理が厳格なため動作しない場合があります。

解決方法2: 正規表現を使用する方法(サーバー互換性向上版)

より多くのレンタルサーバーで安定して動作する改良版コードを紹介します。この方法では、DOMDocumentではなく正規表現を使用しています:

/* ページ内の<script>タグでもショートコードを処理できるようにする */
function process_shortcodes_in_script($content) {
//高速チェック - scriptタグが無ければ処理しない
if (false === strpos($content, '<script')) {
return $content;
}

//正規表現を使用してscriptタグのsrc属性を見つけてショートコードを処理
$pattern = '/<script\s+[^>]*?src=(["\'])([^"\']*)\1[^>]*>/i';

return preg_replace_callback($pattern, function($matches) {
$src = $matches[2];
//ショートコードがある場合のみ処理
if (strpos($src, '[') !== false && strpos($src, ']') !== false) {
$processed_src = do_shortcode($src);
//属性値を更新
return str_replace($src, $processed_src, $matches[0]);
}
//ショートコードが無ければそのまま返す
return $matches[0];
}, $content);
}
add_filter('the_content', 'process_shortcodes_in_script', 99);

拡張: 複数の属性に対応した統合版


より幅広い用途に対応するため、scriptsrc属性だけでなく、他の属性(hrefonclickなど)でもショートコードを処理できる統合版コードを紹介します:

/* HTML要素の属性内のショートコードを処理する統合関数 */
function process_shortcodes_in_html_attributes($content) {
//高速チェック - ショートコードがなければ処理しない
if (false === strpos($content, '[')) {
return $content;
}

//処理する属性のリスト
$attributes = array('src', 'href', 'onclick', 'data-src');

//各属性に対して処理を行う
foreach ($attributes as $attr) {
//属性を含むタグを検索する正規表現
$pattern = '/(' . $attr . ')=(["\'])([^"\']*?)\2/i';

//コールバック関数で属性値内のショートコードを処理
$content = preg_replace_callback($pattern, function($matches) {
$attr_name = $matches[1]; //属性名
$quote = $matches[2]; //引用符 (' または ")
$attr_value = $matches[3]; //属性値

//ショートコードが含まれる場合のみ処理
if (strpos($attr_value, '[') !== false && strpos($attr_value, ']') !== false) {
$processed_value = do_shortcode($attr_value);
return $attr_name . '=' . $quote . $processed_value . $quote;
}

//ショートコードがなければそのまま返す
return $matches[0];
}, $content);
}

return $content;
}

//フィルターを追加
add_filter('the_content', 'process_shortcodes_in_html_attributes', 99);

$attributes 配列に処理したい属性名を追加するだけで、簡単に対象を拡張できます。例えば、data-*属性、srcsetaltなどを追加することも可能です。

使用例

このコードをfunctions.phpに追加後は、固定ページ内で以下のように記述できます:

<link rel="preload" href="https://code-plus.jp/gp/wp-content/themes/zaratan/js/script.js" as="script">
<script src="https://code-plus.jp/gp/wp-content/themes/zaratan/js/script.js"></script>
<a href="https://code-plus.jp/gp/wp-content/themes/zaratan/page.html">リンク</a>
<div data-src="https://code-plus.jp/gp/wp-content/themes/zaratan/commons/images/photo.jpg"></div>

全ての属性でショートコードが正しく展開されます。

レンタルサーバー別の動作状況

サーバー方法1 (DOMDocument)方法2 (正規表現)統合版
カラフルボックス
エックスサーバー
ヘテムル
ロリポップ
さくらインターネット

※ △は設定によって動作が異なる場合があることを示します

まとめ

正規表現を使用した方法2または統合版を使用することで、ほとんどのレンタルサーバーでWordPressの固定ページ内のHTML属性内でショートコードを使用できるようになります。これは特に以下のような場合に便利です:

  • テーマのディレクトリパスを動的に管理したい場合
  • マルチサイト環境でスクリプトのパスを柔軟に制御したい場合
  • 下層に別のWordPressをインストールしている場合のパス管理
  • JavaScriptファイルやリソースの参照を一元管理したい場合

安定性を重視する場合は、必ず方法2または統合版を使用することをお勧めします。