WordPressで、ボタンをクリックすると画面全体を覆う別のコンテンツがふわっと表示される機能をショートコードで実装する方法を紹介します。
何かの補足事項を表示させたり、規約的なものを表示させる際に便利な機能かも知れません。
以下が主な仕様です。
- ボタンをクリックすると、画面全体にオーバーレイコンテンツを表示し、閉じるボタン、または、コンテンツ外の背景部分をクリックすると元のページに戻る
- 同一ページに複数のショートコードを使用しても問題なく動作するようにする(パラメーターでIDを任意に振る)
- ショートコードで囲んだ複数のブロックを表示する
1ページに1つという限定なら結構簡単に実装できますが、複数設置しても動くようにするというところを実装するのに結構苦労しました(泣)。
今回はこうしたコンテンツでよく使われるdivタグでのモーダル表示ではなく、dialogタグを使って表示させるようにしています
表示サンプル
百聞は一見に如かず、まずは動作デモをご覧ください(現在では確実に動作していますが、万が一動いていなかったらゴメンナサイ..)。
いろいろなコンテンツが表示されるようにしたものを3つ用意しましたので、今回のカスタマイズを行った場合にどのような感じで表示されるのか、どのような動きをするのかを確認ください。
本ページ掲載のコードを使用するときは
本ページで掲載しているコードは、以下に了承した上で使用ください
- コードは商用・非商用問わず自由に使っていただいて構いませんが、コード追加による不具合やトラブルが発生しても当方では一切責任を負いません
- コードは有効化しているテーマのfunctions.php、style.cssなどへ追加することで機能します。それらのファイルへの変更を行うことに不安のある方は使用しないでください
- コードは本ページの公開日時点で私の環境において動作したものです。WordPressバージョン他環境の違いによって動作しないことがあります
- コードは、セキュリティ、コードの正確さなどにおいて完全なものではありません。中には紹介するコードを簡略化するために省略している部分があるものもありますので、ご自身でコードを十分に検証し、必要な部分の編集を行った上で使用するようにしてください
- 掲載しているのは参考コードです。自身の環境に合わせるための編集はご自身で対応いただく必要があります(コメント欄等から質問いただいても基本回答は致しません)
- 掲載しているコードの転載を禁じます(SNSで紹介いただいたり、本ページへのリンクを張っていただくことは大歓迎です)
ダイアログコンテンツショートコードをサイトへ導入する手順
スクリプトとスタイルをインラインで読み込むための準備
今回紹介するコードでは、ページ内に複数のダイアログコンテンツショートコードを挿入できるよう、ショートコードの数分だけ、それぞれのidを付加したスクリプトとスタイルをインライン(HTML上に直接)で出力するようにしています(というかこの方法以外に複数に対応する方法が見つかりませんでした)。
そこで前準備として、インラインででスタイルとスクリプトを出力するためのターゲットとなるファイルを読み込ませる必要がありますから、まずはそれを準備します。
既にテーマカスタマイズなどで、独自のCSSファイルやJSファイルを読み込む措置をしている場合はこの作業は必要なく、次項のコード内でターゲットとなるCSSとJSのハンドルを変更すればOKです
wp_add_inline_scrip()で出力するスクリプトのターゲットとなるファイルを準備して読み込む
有効化しているテーマのルートディレクトリへ「dialog-modal.js」というファイルを挿入し、以下のコードをテーマのfunctions.phpへ追加してください。
/* wp_add_inline_scriptのターゲットとなるスクリプトの読み込み */
function pwcn_dialog_modal_script_include() {
wp_enqueue_script(
'pwcn-dialog-modal-js',
get_theme_file_uri('/dialog-modal.js'),
array('jquery'),
null,
array(
'strategy' => 'defer',
'in_footer' => true, // Note: This is the default value.
)
);
}
add_action( 'wp_enqueue_scripts', 'pwcn_dialog_modal_script_include');
wp_add_inline_style()で出力するスタイルのターゲットとなるファイルを準備して読み込む
有効化しているテーマのルートディレクトリへ「dialog-modal.css」というファイルを挿入し、以下のコードをテーマのfunctions.phpへ追加してください。
function pwcn_dialog_modal_style_include(){
//スタイルシートの登録
wp_enqueue_style(
'pwcn-dialog-modal-css',
get_theme_file_uri('/dialog-modal.css'),
array(),
null,
'all'
);
}
add_action('wp_enqueue_scripts','pwcn_dialog_modal_style_include');
テーマのfunctions.phpへコードを追加する
以下が今回の機能実装の主となるコードです。有効化しているテーマのfunctions.phpへ追加してください。
/*** dialogを使ったショートコード ***/
function pwcn_dialog_shortcode( $atts, $content = null ){
$atts = shortcode_atts( array(
'id' => '',
'opentext' => '',
'closetext' => '',
), $atts );
//idで半角英数字と「-」「_」以外は無視して認識する
$validated_id = preg_replace('/[^\w\-]/', '', $atts['id']);
// ショートコード内で別のショートコードの実行を許可
$content = do_shortcode( shortcode_unautop( $content ) );
//パラメーターの入力有無と変数化
$id = $validated_id;
$open = $atts['opentext'];
$close = $atts['closetext'];
if(empty($id)){
$modal_id = '';
} else {
$modal_id = sanitize_text_field($id);
}
if(empty($open)){
$open_text = __('画面を開く','');
} else {
$open_text = sanitize_text_field($open);
}
if(empty($close)){
$close_text = __('画面を閉じる','');
} else {
$close_text = sanitize_text_field($close);
}
//IDを変数化(複数挿入対応)
$open_btn = 'openButton_'.$modal_id;
$dialog_wrap = 'modalDialog_'.$modal_id;
$dialog_content = 'dialog_container_'.$modal_id;
$close_btn = 'closeButton_'.$modal_id;
$waitdata = 'waitDialogAnimation_'.$modal_id;
//スクリプトの読み込み
$script = "
document.addEventListener('DOMContentLoaded', function() {
//「開く」ボタンクリック時の動作
const ".$open_btn." = document.getElementById('".$open_btn."');
const ".$dialog_wrap." = document.getElementById('".$dialog_wrap."');
".$open_btn."?.addEventListener('click', () => {
".$dialog_wrap.".showModal();
document.documentElement.style.overflow = 'hidden';
});
//「閉じる」ボタンクリック時の動作
const ".$close_btn." = document.getElementById('".$close_btn."');
".$close_btn."?.addEventListener('click', () => {
".$dialog_wrap.".close();
document.documentElement.removeAttribute('style');
});
//モーダル画面外をクリックした時に閉じる動作
window.addEventListener('click', function(event) {
if (event.target === ".$dialog_wrap.") {
".$dialog_wrap.".close();
document.documentElement.removeAttribute('style');
}
});
});
";
add_action( 'wp_enqueue_scripts', function() use ($script) {
wp_add_inline_script(
'pwcn-dialog-modal-js',
$script
);
});
// スタイルの出力
if(wp_is_mobile()){
$css_pre ='
/* PWCN Dialog Style */
.dialog::backdrop {
backdrop-filter: blur(8px);
}
.dialog {
box-shadow: 0px 20px 36px 0px rgba(0, 0, 0, 0.6);
padding:0;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dialog {
height: 80%;
margin-top: 20%;
width: 100%;
}
.dialog[open] {
animation-name: fadeIn;
animation-fill-mode: forwards;
animation-duration: 0.5s;
animation-timing-function: ease-out;
}
.dialog-close-btn-'.$id.' {
position: fixed;
top:5%;
left: 50%;
transform: translateX(-50%);
}
button#'.$close_btn.' {
font-size: var(--wp--preset--font-size--medium);
padding: 4px 16px;
}
';
}else{
$css_pre ='
/* PWCN Dialog Style */
.dialog::backdrop {
backdrop-filter: blur(8px);
}
.dialog {
box-shadow: 0px 20px 36px 0px rgba(0, 0, 0, 0.6);
padding:0;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.dialog {
position: fixed;
inset:0;
margin:7% auto;
border: none;
height: min-content;
max-height: 80%;
width: max-content;
}
.dialog[open] {
animation-name: fadeIn;
animation-fill-mode: forwards;
animation-duration: 0.5s;
animation-timing-function: ease-out;
}
.dialog-close-btn-'.$id.' {
position: fixed;
top:7%;
left: 50%;
transform: translateX(-50%);
}
button#'.$close_btn.' {
font-size: var(--wp--preset--font-size--medium);
padding: 4px 16px;
}
';
};
// タブを除去
$css_deltab = preg_replace('/\t+/', '', $css_pre);
// 改行を除去
$css = str_replace(PHP_EOL, '', $css_deltab);
add_action( 'wp_enqueue_scripts', function() use ($css) {
wp_add_inline_style(
'pwcn-dialog-modal-css',
$css
);
});
// コンテンツを出力
//idパラメーターがあるかどうかで判断
if(!empty( $id )){
$content_before .= '';
$content_before .= '<button id="'.$open_btn.'">'.$open_text.'</button>';
$content_before .= '<dialog id="'.$dialog_wrap.'" class="dialog">';
$content_before .= '<div id="'.$dialog_content.'">';
$content_after = '';
$content_after .= '</div>';
$content_after .= '<div class="dialog-close-btn-'.$id.'">';
$content_after .= '<button id="'.$close_btn.'" type="button">';
$content_after .= '<span>'.$close_text.'</span>';
$content_after .= '</button>';
$content_after .= '</div>';
$content_after .= '</dialog>';
//囲みショートコードの本文前後に挿入される</p><p>を除去
$content = haup_remove_shortcode_paragraph($content);
//出力するコンテンツをまとめる
$output = '';
$output = $content_before .$content .$content_after;
}else{
$message_a = __('idパラメーターの設定がないため表示できません','');
$message_b = __('ここにはDialogショートコードが挿入されていますが、','');
$message_c = __('idパラメーターが指定されていないため動作していません(※idには半角英数字と「-」「_」のみが使用でき、それ以外の文字列は設定していても無視して動作するため、idにそれ以外の文字列しか使っていない場合はパラメーターなしと判定されます)','');
$message_d = __('※この警告メッセージは一般の訪問者にも表示されますのでご注意ください※','');
$output = '';
$output .= '<div style="border:3px solid #ff6900;text-align:center;padding:12px;">';
$output .= '<h3>'.$message_a.'</h3>';
$output .= '<p>'.$message_b.'</p>';
$output .= '<p>'.$message_c.'</p>';
$output .= '<p style="color:red";>'.$message_d.'</p>';
$output .= '</div>';
}
return $output;
}
add_shortcode('pwcn-dialog','pwcn_dialog_shortcode');
/*** 囲みショートコードで勝手に追加される</p><p>を除去する独自関数 ***/
function pwcn_remove_shortcode_paragraph($text = '') {
$tags = array("<p>", "</p>");
$text = str_replace($tags, "\n", $text);
$tags = array("<br>", "<br/>", "<br />");
$text = str_replace($tags, "", $text);
return apply_filters('the_content', $text);
}
ショートコードの使い方
以下のようにして別窓で表示させるブロック類をショートコードで囲んで使用します
[pwcn-dialog id="" opentext="" closetext=""]
この間に別窓で表示されるブロックを挿入
[/pwcn-dialog]
以下が各パラメーターの設定内容です。
パラメーター | 説明 |
---|---|
id | 一意のidを半角英数字と「-」「_」を使って入力します ※上記以外の文字は処理時に削除されます ※このパラメーターが未設定の場合には、ショートコードは動作せず、代わりに警告メッセージが表示されます(後述) |
opentext | 「画面を開く」の文字列を入力した文字列へ変更します |
closetext | 「画面を閉じる」の文字列を入力した文字列へ変更します |
幅の要素を持たないブロックのみで構成する場合の注意
「段落」「見出し」「テーブル」など、ブロックツールバーで「幅広」や「全幅」などの選択を行えないブロックのみでショートコード内を構成すると、最大で画面幅いっぱいまで内部コンテンツが広がってしまいます。
これは任意の幅で表示できるよう、プログラム内で内部コンテンツの幅に制限を設けていない仕様によるものです。
内部コンテンツの幅を指定したい場合には、幅の要素を持たないコンテンツをグループ化するなどして調整することで、目的の幅で表示できるようになりますのでいろいろと調整してください。
プログラム内の.dialogクラスのスタイルで「width:max-content」となっている部分を実数にすれば内部コンテンツの幅を制限することができますが、グループ化したブロックの幅が指定したものと異なってくる(制限によってそれ以上広がらない)という不都合が発生します。仕様としてそのような形でよければ、変更してください。
コードメモ
今回紹介しているコードのメモ、簡易説明です。
開閉の動作はJavaScriptで実装
ボタンクリックによるコンテンツの表示/閉じるボタンor背景クリックによるコンテンツの非表示の動作はJava Scriptで作成しています。
当初は自身が慣れていて、WordPressでは必ず読み込まれているjQueryで書いていて、もう少し凝った作りにしていたのですが、プラグインやコードによる高速化設定によって確実に動作しない現象が発生したため、読み込み順の影響を受けないJavaScriptで実装しています。
複数のコンテンツを作成できるようにする工夫
同一ページ内に複数のコンテンツを入れられるようにするため、それぞれのショートコードにidを設けて判別させるようにしています。
これにより、いくつショートコードを挿入しても別々に動作するようになっています。
ショートコードのパラメーターは原則他のプログラムへ渡して別のフックで有効にすることができないため、ショートコードフックのコールバックプログラムの中で完結できるよう、wp_add_inline_script()、wp_add_inline_style()を使っています(これによって前項のjQueryが不安定になるようです)。
プログラムについての補足事項
dialogタグの検索エンジン等での扱い
dialogタグというのは一時的に表示する警告や確認の表示に使われるHTMLタグであると認識しています。
今回dialogタグを使用したのは、位置の指定などをそれなりに正しく行う処理が他の方法に比べて圧倒的に少なくなることにメリットを感じたものであり、このHTMLタグが検索エンジンなどからどのように認識されるかは不明です。
HTML内にはソースが出力されているので、コンテンツの一部として認識されることは間違いありませんが、この機能で内部に含めたコンテンツがどのように評価されるかは分かりませんので了承の上使用ください。
スタイルの調整は最低限にしています
ボタンをクリックして表示される画面(窓)については、できるだけブロック指定の幅や高さが使えるよう、縦の開始位置の調整、画面の高さに対する窓の高さの割合、ボタン位置の調整のみを行っています。
これによって、いろいろな大きさの画面が作れますが、コンテンツ全体の高さが少ない(画面の高さが少ない)場合には、画面上部に寄った形で表示されることがあります。
また、幅の要素を持たないブロックのみで構成した場合には、窓の幅が不用意に小さくなることもあります。
この辺りはそれぞれの窓に対して調整をする必要があると思いますので、個別にスタイルを上書きする(コンテンツごとにid別でスタイルは出力されています)、または、コード内のスタイルコードを書き換えて全体をいい感じに調整いただく必要があります。
表示したコンテンツの隙間(余白)を排除しています
サンプルの通り、ボタンをクリックすると、ショートコード内に挿入したブロックが表示され、周囲はぼかすようにしています。
表示した窓(ダイアログボックス)については、余白(隙間)は一切なくなるようにしており、標準の背景色は白になります。
ショートコード内のコンテンツをグループ化してスタイル設定を行うことで、窓内に背景色、もしくは背景画像を使うことができます。
また、グループ化することで、グループ化ブロックのオプションが使えるようになるので、コンテンツの幅も調整できるようになります。
グループ化後幅の設定をしない場合は、サイトのグローバルスタイルの幅が適用されます(ブロックテーマの場合の話であり、クラシックテーマの場合の動作チェックはしていません)
余白の削除についてもう1つ、囲み型ショートコードでは、内部コンテンツの前後にpタグが挿入されてしまう現象が、古くから現象として発生しています。
これにより、上下にp(段落タグ)分の隙間ができてしまうのをコードの「//囲みショートコードの本文前後に挿入される</p><p>を除去」の部分と末尾のコールバック関数で防いでいます。
ただ、これにより、仕様上、ショートコード内のブロックに何もオプション設定をしていない段落タグがある場合のpタグも削除されるようになっています。
特にコンテンツの表示には問題はないと思いますが、ショーコード内の段落ブロックへ「文字」「色」などの装飾を加える等を行うことでタグの削除対象から外れ、HTML上でpタグを使って出力されるようになりますから、そのように措置を行ってください。
idパラメーターの扱いと、idが空だった時の処理について
冒頭の仕様で書いた通り、このコードでは、idパラメーターに異なる値を入れることで別のダイアログコンテンツと認識し、それぞれが別々に動作するようにしています。
これにより、同一ページ内に複数のダイアログコンテンツショートコードが存在している場合でも、idごとに別の動作をさせることができるようにしています。
確実にidを判別するため、idパラメーターには半角英数字と「-」「_」を使用する前提としています。
しかし、ショートコードのパラメーターでの入力値のチェックはできないため、処理時に上記の文字以外は削除するようにしています。
そのうえで、idが空と判定された場合には、ショートコードが動作しない代わりに以下の画面がフロントエンドに表示されるようにしています。

このコードでは、同一ページ内に同一IDのショートコードがあるかどうかの判別はしていません。同じidがある場合には思わぬ動作をするかも知れませんのでご注意ください
コード内の「//idで半角英数字と「-」「_」以外は無視して認識する」と「//idパラメーターがあるかどうかで判断」のところで判別と処理の切り分けをしています
ページ内へ複数のショートコードを使用した場合のHTML出力について
前項のように、このショートコードでは、idパラメーターごとに別々の動作をするようにしています。
これを実現させるため、idに応じたスクリプトとスタイルコードをHTML上へ出力するようにしています。
従って、例えば3つのショートコードをページ内に使用した場合には、ID部分のみが異なる似たスクリプトとスタイルコードが3つHTML上へ出力されます。
本ページのコードを使って10個程度のコンテンツを出力してみても、私が感じる限りでは特に表示速度への影響はないと感じましたが、使われる環境によるところが大きいため、複数設置して問題があるようでしたら、使用数を制限するなどの措置を取るようにしてください。
参考になったページ
今回の機能を実装するにあたって参考にさせていただいたページです。
コメントを残す