投稿・固定ページごとにCSSとJavaScriptを保存し、そのページを表示するときだけ読み込みます。
入力できるのはmanage_options・unfiltered_html・対象記事の編集権限を持つ利用者だけです。
一般の投稿者へJavaScript入力を開放する用途には使いません。
導入前の確認
子テーマのfunctions.phpをバックアップし、既存のPHP領域へ下記を追加します。
先頭の<?phpは既にある場合は重ねません。
テーマに同等の機能がある場合はそちらに統一し、二重出力を避けます。
旧版のadd_custom_code_meta_box、save_custom_code_meta_box_data、output_custom_css、output_custom_jsと対応するフックは撤去してから置き換えてください。
旧custom_css/custom_jsは自動移行しません。
旧入力を確認してから新しい欄にコピーします。
コードは入力者を信頼して実行する仕組みで、JSの安全性を自動判定するものではありません。
マルチサイトなどでunfiltered_htmlがない利用者には欄を表示しません。
入力欄・保存・公開側の読み込み
<?php
function waza_code_allowed($id) {
return current_user_can('manage_options') && current_user_can('unfiltered_html') && current_user_can('edit_post', $id);
}
function waza_code_valid($value) {
return is_string($value) && !preg_match('~</(?:script|style)~i', $value);
}
add_action('add_meta_boxes', function ($type, $post) {
if (!in_array($type, ['post', 'page'], true) || !waza_code_allowed($post->ID)) return;
add_meta_box('waza-page-code', '記事専用 CSS / JS', function ($post) {
wp_nonce_field('waza-code-' . $post->ID, 'waza_code_nonce');
foreach (['css', 'js'] as $kind) {
$value = get_post_meta($post->ID, '_waza_code_' . $kind, true);
echo '<p><label for="waza-code-' . esc_attr($kind) . '">' . esc_html(strtoupper($kind)) . '</label></p>';
echo '<textarea id="waza-code-' . esc_attr($kind) . '" name="waza_code_' . esc_attr($kind) . '" rows="8" style="width:100%">' . esc_textarea(is_string($value) ? $value : '') . '</textarea>';
}
echo '<p>タグを付けずにコードだけを入力します。script/style の終了タグを含む入力は保存されません。</p>';
}, $type, 'normal', 'default');
}, 10, 2);
function waza_code_save($id) {
if ((defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) || wp_is_post_revision($id) || wp_is_post_autosave($id)) return;
if (!in_array(get_post_type($id), ['post', 'page'], true) || !waza_code_allowed($id)) return;
if (!isset($_POST['waza_code_nonce']) || !is_string($_POST['waza_code_nonce']) || !wp_verify_nonce(wp_unslash($_POST['waza_code_nonce']), 'waza-code-' . $id)) return;
$values = [];
foreach (['css', 'js'] as $kind) {
$key = 'waza_code_' . $kind;
if (!isset($_POST[$key]) || !is_string($_POST[$key])) return;
$values[$kind] = wp_unslash($_POST[$key]);
if (!waza_code_valid($values[$kind])) return;
}
foreach ($values as $kind => $value) {
// update_post_meta() が外すスラッシュを補い、JSのバックスラッシュを保つ。
update_post_meta($id, '_waza_code_' . $kind, wp_slash($value));
}
}
add_action('save_post', 'waza_code_save');
function waza_code_enqueue() {
if (!is_singular(['post', 'page'])) return;
$id = get_queried_object_id();
$css = get_post_meta($id, '_waza_code_css', true);
$js = get_post_meta($id, '_waza_code_js', true);
if (waza_code_valid($css) && $css !== '') {
wp_register_style('waza-page-code', false);
wp_enqueue_style('waza-page-code');
wp_add_inline_style('waza-page-code', $css);
}
if (waza_code_valid($js) && $js !== '') {
wp_register_script('waza-page-code', false, [], null, true);
wp_enqueue_script('waza-page-code');
wp_add_inline_script('waza-page-code', $js);
}
}
add_action('wp_enqueue_scripts', 'waza_code_enqueue');
CSS・JSはタグを付けずに入力します。
終了タグを含む入力、片方の欄が欠けた送信、nonce不一致などは両方とも保存せず以前の値を維持します。
保存後に編集画面を再読み込みして値を確認してください。
nonceだけで権限を判断せず、保存時にも権限と投稿種別を確認します。
終了タグの検査は、CSSやJavaScriptの構文チェックではありません。
構文が誤っていてもこの検査を通る場合があるため、欄に値が保存されたことと公開ページで正常に動いたことは分けて確認します。
保存後も動かない場合は入力内容を確認し、JavaScriptではブラウザーのコンソールにエラーが出ていないかを調べてください。
バックスラッシュを含むコードはwp_unslashでフォームのスラッシュを外し、update_post_metaの仕様に合わせてwp_slashを付けて保存します。
公開側では対象記事IDを使い、JSはwp_add_inline_scriptでフッターに追加します。
テーマのwp_head・wp_footerが必要です。
動作確認用のボタン
記事のカスタムHTMLブロックへ次を入れ、CSS・JSは新しい入力欄へ別々に貼り付けます。
CSSはこのクラスを持つ要素だけに適用します。
ページ単位の読み込みでもbodyなどを指定すればページ全体へ作用する点に注意してください。
<button type="button" class="waza-code-test">動作を確認</button>.waza-code-test { border: 3px solid #a21d32; padding: .7em 1em; }document.querySelectorAll('.waza-code-test').forEach(function (button) {
button.addEventListener('click', function () {
button.textContent = 'JavaScriptが動作しました';
});
});ボタン部分の動く見本
次のボタンは上のCSS・JSと同じ動作を記事内で表示したものです。
管理画面のメタボックス保存を検証する見本ではありません。
実際に保存して確認した結果
| 確認した操作 | 結果 |
|---|---|
| 記事専用CSS・JSを入力して保存 | 再読み込み後も両欄を保持 |
| 公開側でボタンを操作 | PCのEnter・375px幅のSpaceで文字が変化 |
| JS欄に終了タグを入力して保存 | CSS・JSとも以前の値を保持 |
| 両欄を空にして保存 | 再読み込み後も空欄・公開側の追加枠と文字変更を解除 |
| コードを入れていない別の記事 | 専用CSS・JSの出力なし |
SWELL標準の「カスタムCSS & JS」と、このコードで追加する「記事専用 CSS / JS」は別の入力欄です。
この記事の実装を使う場合は「記事専用 CSS / JS」の欄へ入力し、同じコードを両方の欄へ重複して入れないでください。
2026年10月2日、WordPress 7.1.2・SWELL 2.19.0の単一サイトで管理者による保存を確認しました。
2026年10月4日の隔離環境での実HTTP出力では、コードを保存した個別ページにCSS・JSがそれぞれ1回出力され、その記事を含む一覧ページには出力されないことを確認しました。
一覧に記事本文や抜粋が表示されても、この記事専用コードが一覧へ引き継がれる仕組みではありません。
ビジュアルエディター本文の描画、マルチサイト、Pjaxとの組み合わせは未検証です。

確認と解除
保存後は編集画面を再読み込みして、CSS・JS両方の値が残っていることを先に確認します。
公開側では枠とボタンの文字変化を確認し、Tabで移動してEnterとSpaceでも操作します。
別の記事と一覧ページへの読み込み、PC・スマホの横はみ出しも導入環境で確認してください。
解除するときはCSS・JS両方の欄を空にして記事を更新します。
仕組み自体を外す場合は追加した関数とフックをまとめて削除し、functions.phpを元へ戻します。
保存済みメタ値は仕組みを外しても残りますが、このコードからは出力されません。
キャッシュを使う場合は更新後に対象ページのキャッシュも更新してください。
旧記事のGitHubサンプルとスクリーンショットは今回の権限チェック付き実装に同期していません。
本文のコードを使用してください。



