はじめに
WordPressで記事を書いていると、「1ページ目は誰でも読めるようにして、続きは知っている人だけに見せたい」と思うことはありませんか?
今回は、記事に改ページタグを入れるだけで、2ページ目以降に暗証番号の鍵がかかる仕組みを、functions.phpにコードを追加して作る方法を紹介します。プラグインは使いません。
コードをコピーして貼り付けるだけで使えるので、PHPに詳しくない方でも大丈夫です。できるだけ分かりやすく、1つずつ説明していきます。
この仕組みでできること
| 項目 | 内容 |
|---|---|
| 鍵がかかる場所 | 全記事の2ページ目以降 |
| 鍵をかける方法 | 本文に改ページタグ(<!–nextpage–>)を入れるだけ |
| 暗証番号 | サイト全体で共通の1つ |
| 暗証番号の設定場所 | 管理画面の「設定」→「ページ2パスワード」 |
| 解除が続く期間 | ブラウザを閉じるまで |
| 暗証番号を変更したとき | 解除済みの人も自動でロックに戻る |
WordPress標準の「パスワード保護」との違い
WordPressには、もともと記事ごとにパスワードをかける機能があります。今回の仕組みとは次のような違いがあります。
| 比較 | 標準のパスワード保護 | 今回の仕組み |
|---|---|---|
| 鍵がかかる範囲 | 記事全体 | 2ページ目以降だけ |
| パスワード | 記事ごとに設定 | 全記事共通で1つ |
| 設定する場所 | 記事の編集画面の「公開状態」 | 「設定」→「ページ2パスワード」 |
| タイトルの表示 | 「保護中:」が付く | そのまま |
| 1ページ目 | 読めない | 誰でも読める |
今回の仕組みでは、記事の編集画面で「パスワード保護」を設定する必要はありません。2つは別の機能なので、混ざらないように注意してください。
仕組みのイメージ
訪問者から見ると、次のような流れになります。
- 記事の1ページ目は普通に読める
- 「2ページ目」のリンクをクリックする
- 暗証番号の入力画面に移動する
- 正しい暗証番号を入れると、2ページ目に戻って続きが読める
- ブラウザを閉じるまでは、他の記事の2ページ目も入力なしで読める
暗証番号が合っていたかどうかは、ブラウザに保存されるCookie(クッキー)という小さなデータで覚えています。遊園地の再入場スタンプのようなものだと思ってください。スタンプがある人はそのまま入れて、ない人は入口で止められる、という仕組みです。
導入手順
手順1:functions.phpのバックアップを取る
functions.phpは、書き間違えるとサイトが真っ白になってしまうこともある大事なファイルです。作業の前に必ずバックアップを取っておきましょう。
FTPソフト(WinSCPなど)で、使っているテーマ(子テーマ推奨)のfunctions.phpをパソコンにダウンロードしておけばOKです。何かあっても、このファイルを上書きアップロードすれば元に戻せます。
手順2:functions.phpにコードを貼り付ける
子テーマのfunctions.phpの一番下に、次のコードを貼り付けて保存します。
/************************************
**2ページ目以降に鍵をかける
************************************/
// ① 管理画面にパスワード設定メニューを追加
add_action('admin_menu', function() {
add_options_page('ページ2パスワード設定', 'ページ2パスワード', 'manage_options', 'page2-password', function() {
if (isset($_POST['page2_password']) && check_admin_referer('save_page2_password')) {
update_option('page2_password', sanitize_text_field(wp_unslash($_POST['page2_password'])));
echo '<div class="updated"><p>保存しました</p></div>';
}
$pw = get_option('page2_password', '');
?>
<div class="wrap">
<h1>ページ2 パスワード設定</h1>
<form method="post">
<?php wp_nonce_field('save_page2_password'); ?>
<input type="text" name="page2_password" value="<?php echo esc_attr($pw); ?>">
<input type="submit" value="保存" class="button button-primary">
</form>
</div>
<?php
});
});
// ② 解除用Cookieの判定(暗証番号を変えると全員ロックに戻る)
function hiro_page2_token() {
$stored = get_option('page2_password', '');
return ($stored === '') ? '' : hash_hmac('sha256', $stored, wp_salt('auth'));
}
function hiro_page2_unlocked() {
$token = hiro_page2_token();
if ($token === '') return true; // 暗証番号が未設定ならロックしない
return isset($_COOKIE['page2_unlock']) && hash_equals($token, (string) $_COOKIE['page2_unlock']);
}
// ③ カスタムエンドポイントを登録
add_action('init', function() {
add_rewrite_rule('^page2-password/?$', 'index.php?page2_password_page=1', 'top');
});
add_filter('query_vars', function($vars) {
$vars[] = 'page2_password_page';
return $vars;
});
// ④ 全記事の2ページ目以降をブロック+暗証番号入力画面
add_action('template_redirect', function() {
// 暗証番号入力画面
if (get_query_var('page2_password_page')) {
nocache_headers();
$redirect = isset($_REQUEST['redirect']) ? wp_unslash($_REQUEST['redirect']) : '';
$redirect = wp_validate_redirect($redirect, home_url('/'));
$error = '';
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) {
$input = sanitize_text_field(wp_unslash($_POST['password']));
$stored = get_option('page2_password', '');
if ($stored !== '' && hash_equals($stored, $input)) {
setcookie('page2_unlock', hiro_page2_token(), 0, COOKIEPATH, COOKIE_DOMAIN, is_ssl(), true);
wp_safe_redirect($redirect);
exit;
}
$error = '暗証番号が違います';
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="robots" content="noindex">
<title>暗証番号を入力してください</title>
<style>
body { display:flex; justify-content:center; align-items:center; height:100vh; margin:0; font-family:sans-serif; background:#f5f5f5; }
.box { background:#fff; padding:40px; border-radius:8px; text-align:center; box-shadow:0 2px 10px rgba(0,0,0,0.1); }
input { padding:10px; border:1px solid #ccc; border-radius:4px; font-size:16px; }
button { margin-top:15px; padding:10px 25px; background:#0073aa; color:#fff; border:none; border-radius:4px; cursor:pointer; font-size:16px; }
.error { color:red; margin-top:10px; }
</style>
</head>
<body>
<div class="box">
<p>暗証番号を入力してください</p>
<form method="post" action="<?php echo esc_url(home_url('/page2-password/')); ?>">
<input type="hidden" name="redirect" value="<?php echo esc_attr($redirect); ?>">
<input type="password" name="password" placeholder="暗証番号"><br>
<?php if ($error !== ''): ?>
<p class="error"><?php echo esc_html($error); ?></p>
<?php endif; ?>
<button type="submit">確認</button>
</form>
</div>
</body>
</html>
<?php
exit;
}
// 全記事の2ページ目以降をブロック
if (is_singular('post') && (int) get_query_var('page') >= 2) {
nocache_headers();
if (!hiro_page2_unlocked()) {
$current_url = (is_ssl() ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
wp_safe_redirect(add_query_arg('redirect', rawurlencode($current_url), home_url('/page2-password/')));
exit;
}
}
});functions.phpの最初にある「<?php」の行より下に貼り付けてください。ファイルの最後に「?>」がある場合は、その上に貼り付けます。
手順3:パーマリンク設定を保存し直す
今回のコードでは「/page2-password/」という新しいURL(暗証番号の入力画面)を作っています。WordPressに新しいURLを覚えさせるために、次の操作をします。
- 管理画面の「設定」→「パーマリンク」を開く
- 何も変更せずに「変更を保存」ボタンを押す
これをしないと、暗証番号の入力画面が「ページが見つかりません」になることがあります。
手順4:暗証番号を設定する
- 管理画面の左メニューの「設定」にカーソルを合わせる
- 一番下あたりに出てくる「ページ2パスワード」をクリック
- 入力欄に暗証番号を入れて「保存」を押す
「保存しました」と表示されれば完了です。暗証番号が空欄のままだと鍵はかかりません。必ず設定してください。
手順5:記事に改ページタグを入れる
鍵をかけたい記事を開いて、隠したい部分のすぐ前に、次のタグを入れます。
<!--nextpage-->このタグより上が1ページ目(誰でも読める)、下が2ページ目(暗証番号が必要)になります。タグを2つ以上入れた場合は、3ページ目以降にもすべて鍵がかかります。
ブロックエディタの場合は「ページ区切り」ブロックを使っても同じです。クラシックエディタのテキストモードなら、タグを直接書き込みます。
手順6:動作を確認する
管理画面にログインしたままのブラウザだと、正しく確認できないことがあります。ブラウザのシークレットウィンドウ(プライベートウィンドウ)で確認するのがおすすめです。
| 確認すること | 正しい動き |
|---|---|
| 記事の1ページ目を開く | 普通に表示される |
| 2ページ目を開く | 暗証番号の入力画面に移動する |
| 間違った暗証番号を入れる | 「暗証番号が違います」と表示される |
| 正しい暗証番号を入れる | 2ページ目に戻って表示される |
| URLの末尾を「/3/」に変えて開く(3ページ目がある場合) | 解除前なら入力画面に移動する |
| ブラウザを閉じて開き直す | また暗証番号が必要になる |
シークレットウィンドウは、Chromeなら「Ctrl + Shift + N」で開けます。
コードの解説
貼り付けたコードは、大きく4つの部品でできています。
① 管理画面のメニュー
「設定」の中に「ページ2パスワード」というメニューを追加して、暗証番号を保存できるようにしています。保存した暗証番号は、WordPressのデータベースに「page2_password」という名前で記録されます。
「wp_nonce_field」と「check_admin_referer」は、第三者が勝手に暗証番号を書き換えるのを防ぐための合言葉チェックです。
② 解除済みかどうかの判定
暗証番号をそのままCookieに保存すると、他人に見られたときに危険です。そこで、暗証番号とサイト固有の秘密の鍵(wp_salt)を混ぜて、元に戻せない別の文字列(ハッシュ)に変換してから保存しています。
暗証番号を変更すると、この文字列も変わります。そのため、前の暗証番号で解除した人のCookieは使えなくなり、自動的にロックに戻ります。
③ 暗証番号の入力画面のURL
「あなたのサイト/page2-password/」というURLを新しく作り、そこにアクセスしたときに暗証番号の入力画面を出す準備をしています。手順3のパーマリンク保存が必要なのは、この部分のためです。
④ 鍵のチェックと入力画面
記事のページが表示される直前に、次のチェックをしています。
- 今開いているのは投稿記事の2ページ目以降か?
- その人は解除用のCookieを持っているか?
- 持っていなければ、暗証番号の入力画面へ移動させる
入力画面では、暗証番号が正しければCookieを渡して、元の記事ページに戻します。Cookieの有効期限を「0」にしているので、ブラウザを閉じると解除が終わります。
「nocache_headers」は、「このページは保存(キャッシュ)しないでね」とブラウザやサーバーに伝える命令です。これがないと、解除した人が見たページが保存されて、他の人にもそのまま見えてしまうおそれがあります。
最初に作ったコードから改善した点
実は、最初に作ったコードも普通に使う分には動いていました。ただ、見直してみると「鍵としての穴」や「サイト全体への影響」がいくつか見つかりました。
参考として、最初に作ったコードを載せておきます。こちらは改善前の古いコードなので、実際に使うときは手順2のコードを使ってください。
/************************************
**2ページ目に鍵をかける
************************************/
// ① セッション開始
add_action('init', function() {
if (session_status() === PHP_SESSION_NONE) session_start();
});
// ② 管理画面にパスワード設定メニューを追加
add_action('admin_menu', function() {
add_options_page('ページ2パスワード設定', 'ページ2パスワード', 'manage_options', 'page2-password', function() {
if (isset($_POST['page2_password']) && check_admin_referer('save_page2_password')) {
update_option('page2_password', sanitize_text_field($_POST['page2_password']));
echo '<div class="updated"><p>保存しました</p></div>';
}
$pw = get_option('page2_password', '');
?>
<div class="wrap">
<h1>ページ2 パスワード設定</h1>
<form method="post">
<?php wp_nonce_field('save_page2_password'); ?>
<input type="text" name="page2_password" value="<?php echo esc_attr($pw); ?>">
<input type="submit" value="保存" class="button button-primary">
</form>
</div>
<?php
});
});
// ③ カスタムエンドポイントを登録
add_action('init', function() {
add_rewrite_rule('^page2-password/?$', 'index.php?page2_password_page=1', 'top');
});
add_filter('query_vars', function($vars) {
$vars[] = 'page2_password_page';
return $vars;
});
// ④ 全記事の2ページ目をブロック+パスワード入力画面
add_action('template_redirect', function() {
// パスワード入力画面の処理
if (get_query_var('page2_password_page')) {
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['password'])) {
$input = sanitize_text_field($_POST['password']);
$stored = get_option('page2_password', '');
if ($input === $stored) {
$_SESSION['page2_unlocked'] = true;
$redirect = isset($_GET['redirect']) ? esc_url_raw($_GET['redirect']) : home_url();
wp_redirect($redirect);
exit;
} else {
$GLOBALS['page2_error'] = '暗証番号が違います';
}
}
$redirect = isset($_GET['redirect']) ? esc_url($_GET['redirect']) : home_url();
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>暗証番号を入力してください</title>
<style>
body { display:flex; justify-content:center; align-items:center; height:100vh; margin:0; font-family:sans-serif; background:#f5f5f5; }
.box { background:#fff; padding:40px; border-radius:8px; text-align:center; box-shadow:0 2px 10px rgba(0,0,0,0.1); }
input { padding:10px; border:1px solid #ccc; border-radius:4px; font-size:16px; }
button { margin-top:15px; padding:10px 25px; background:#0073aa; color:#fff; border:none; border-radius:4px; cursor:pointer; font-size:16px; }
.error { color:red; margin-top:10px; }
</style>
</head>
<body>
<div class="box">
<p>暗証番号を入力してください</p>
<form method="post" action="<?php echo home_url('/page2-password/?redirect=' . urlencode($redirect)); ?>">
<input type="password" name="password" placeholder="暗証番号"><br>
<?php if (!empty($GLOBALS['page2_error'])): ?>
<p class="error"><?php echo $GLOBALS['page2_error']; ?></p>
<?php endif; ?>
<button type="submit">確認</button>
</form>
</div>
</body>
</html>
<?php
exit;
}
// 全記事の2ページ目をブロック
if (is_singular('post') && get_query_var('page') == 2) {
if (empty($_SESSION['page2_unlocked'])) {
$current_url = (isset($_SERVER['HTTPS']) ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
wp_redirect(home_url('/page2-password/?redirect=' . urlencode($current_url)));
exit;
}
}
});このコードと比べて、手順2のコードでは次の点を改善しています。
| 最初のコードの問題 | 何が困るのか | 改善した内容 |
|---|---|---|
| 「ちょうど2ページ目」だけをチェックしていた | URLを「/3/」に書き換えるだけで3ページ目が読めてしまう | 「2ページ目以上」をチェックするように変更 |
| 全ページでPHPのセッションを開始していた | 全訪問者にセッション用Cookieが発行され、キャッシュが効きにくくなる。サイトヘルスで警告が出る | 暗証番号を入力した人にだけCookieを渡す方式に変更 |
| 入力後の移動先をチェックしていなかった | 細工したリンクで、入力後に外部の怪しいサイトへ飛ばされる可能性がある | 自分のサイト内にしか移動しない「wp_safe_redirect」に変更 |
| キャッシュ対策がなかった | 解除後のページがキャッシュされ、他の人にも見えるおそれがある | 「nocache_headers」を追加 |
| 暗証番号が未設定のときの処理がなかった | 空欄のまま「確認」を押すと解除できてしまう | 未設定のときは解除できないように変更 |
| 入力画面にスマホ用の設定がなかった | スマホで文字が小さく表示される | viewportの設定を追加 |
| 入力画面の検索エンジン対策がなかった | 入力画面が検索結果に出てしまう可能性がある | noindexを追加 |
特に影響が大きいのは、最初の2つです。「とりあえず動く」コードでも、一度見直してみると意外な穴が見つかるものですね。
よくあるトラブルと対処法
暗証番号の入力画面が「ページが見つかりません」になる
手順3の「パーマリンクの保存し直し」をしていない可能性があります。「設定」→「パーマリンク」を開いて、何も変えずに「変更を保存」を押してください。
2ページ目に鍵がかからない
次の順番で確認してみてください。
- 暗証番号が設定されているか(空欄だと鍵がかかりません)
- シークレットウィンドウで確認しているか
- 記事に改ページタグが入っているか
- キャッシュ系のプラグインやサーバーのページキャッシュが効いていないか
KUSANAGIなど、サーバー側でページキャッシュを使っている環境では、キャッシュが原因で鍵をすり抜けることがあります。その場合は、キャッシュを削除してから再度確認してみてください。
固定ページの2ページ目には鍵がかからない
このコードは「投稿記事」だけが対象です。固定ページにも鍵をかけたい場合は、コード内の「is_singular(‘post’)」を「is_singular()」に変更すると、固定ページやカスタム投稿にも鍵がかかるようになります。
コードを貼ったらサイトが真っ白になった
貼り付けミス(コードの一部が欠けている、貼り付け位置が違うなど)の可能性が高いです。手順1で取ったバックアップのfunctions.phpをFTPで上書きアップロードすれば元に戻ります。
注意点
この仕組みは、「続きは知っている人だけに見せたい」というお手軽な目隠しとして使うものです。次の点は覚えておいてください。
- 暗証番号は全記事で共通なので、一度誰かに広まると全記事の続きが読めてしまいます。広まったと感じたら、暗証番号を変更しましょう
- RSSフィードの設定が「全文」になっていると、フィードに続きの内容が含まれる場合があります。「設定」→「表示設定」で「抜粋」にしておくと安心です
- 有料記事や個人情報など、本格的に守りたい内容には、会員制プラグインなど専用の仕組みを使うことをおすすめします
まとめ
| やること | 場所 |
|---|---|
| コードを追加する | 子テーマのfunctions.php |
| パーマリンクを保存し直す | 「設定」→「パーマリンク」 |
| 暗証番号を決める | 「設定」→「ページ2パスワード」 |
| 鍵をかける | 記事本文に改ページタグを入れる |
一度コードを入れてしまえば、あとは記事に改ページタグを入れるだけで、2ページ目以降に鍵がかかるようになります。「ここから先は限定公開」という使い方ができるので、ぜひ試してみてください。





コメント