WordPress パスワード保護ページの 投稿パスワード を「全記事共通」で複数使えるようにする


WordPress 4.7から「post_password_required」というアクションフィルターが追加されました。これを使って 1つしか設定できなかった パスワード保護ページの 投稿パスワードを複数登録して使えるようにできそうです。

WordPressでは 投稿にパスワードを設定すると 投稿ページは内容は表示されずに パスワード入力フォームが出てきます。
パスワードを入力して「確定(送信)」すると パスワードはwp-login.phpへ送られ クッキーに保存されてから投稿ページに戻され(リダイレクト)ます。
投稿ページでは クッキーのパスワードを照合して、合っていれば 投稿内容を表示します。

ここでは照合の中にある「post_password_required」フィルターを使って 全ての投稿パスワード記事 共通の投稿パスワードを登録して照合する簡易版を作りました。
今迄のパスワード保護ページで投稿パスワードがバラバラでもこの Tips を使えば 共通の投稿パスワード として使えます。

投稿ごとに個別の投稿パスワードを複数設定したい場合は以下の記事を参考にしてください。
WordPress パスワード保護ページの 投稿パスワード を「投稿別」に複数使えるようにする

 



 

コード

管理画面の設定→共通投稿パスワードで全てのパスワード保護の記事で有効な パスワードを複数設定します。

この仕組みを使うと、後で投稿パスワード入りの記事を追加しても自動で「共通 投稿パスワード」で閲覧する事ができます。
また期限チェックも追加しています。パスワードが合っていても期限が過ぎていたらNGになります。
※共通投稿パスワードを使わない投稿を設定できるようにもしています。

以下のコードを my-plugin.php に張り付けてみてください。

/**
 * 共通 投稿パスワード
 *
 * @since WordPress 4.7.0
 * License: GPLv2 or later
 */
if( is_admin() ){
	new nendebcom_Common_Multi_Post_Password();
}
class nendebcom_Common_Multi_Post_Password {

	/**
	 * Start up
	 */
	function __construct() {
		add_action( 'admin_menu', array( $this, 'admin_menu' ) );
	}

	/**
	 * Add options page
	 */
	function admin_menu () {
		add_options_page( 'common_multi_post_password', '共通投稿パスワード', 'edit_posts', __FILE__, array( $this, 'form' ) );
	}

	/**
	 * Saves Multi Post Password.
	 */
	function save_common_multi_post_password() {

		require_once ABSPATH . '/wp-includes/pluggable.php';

		// Check if our nonce is set.
		if ( !isset( $_POST[ 'admin_nendebcom_multi_postpass_nonce' ] ) ) {
			return;
		}

		// Verify that the nonce is valid.
		if ( !wp_verify_nonce( $_POST['admin_nendebcom_multi_postpass_nonce'], 'admin_nendebcom_multi_postpass_nonce' ) ) {
			return;
		}

		// Make sure that it is set.
		if ( !isset( $_POST['max_id'] ) ) {
			return;
		}

		// 登録パスワード数
		$max_id = isset( $_POST['max_id'] ) ? $_POST['max_id'] : 0;

		$multi_postpass_data = array();

		$j = 0;
		for ( $i = 0; $i <= $max_id; $i++ ) {
			$postpass_kigen	 = isset( $_POST[ 'postpass_kigen_' . $i ] ) ? sanitize_text_field( $_POST[ 'postpass_kigen_' . $i ] ) : '';
			$postpass_pass	 = isset( $_POST[ 'postpass_pass_' . $i ] )  ? sanitize_text_field( $_POST[ 'postpass_pass_' . $i ] ) : '';
			$postpass_memo	 = isset( $_POST[ 'postpass_memo_' . $i ] )  ? sanitize_text_field( $_POST[ 'postpass_memo_' . $i ] ) : '';
			$postpass_date	 = isset( $_POST[ 'postpass_date_' . $i ] )  ? sanitize_text_field( $_POST[ 'postpass_date_' . $i ] ) : current_time( 'timestamp' );

			// Postpass Max255文字
			$postpass_pass = substr( $postpass_pass, 0, 255 );

			if ( $postpass_pass ) {
				$multi_postpass_data[ $j ][ 'postpass_kigen' ]	 = $postpass_kigen;
				$multi_postpass_data[ $j ][ 'postpass_pass' ]	 = $postpass_pass;
				$multi_postpass_data[ $j ][ 'postpass_memo' ]	 = $postpass_memo;
				$multi_postpass_data[ $j ][ 'postpass_date' ]	 = $postpass_date;
				$j++;
			}
		}
		// Update the meta field in the database.
		update_option( 'multi_postpass', $multi_postpass_data );


		// 除外投稿パスワード
		$postpass_exclude_post = isset( $_POST['postpass_exclude_post'] ) ? $_POST['postpass_exclude_post'] : '';
		update_option( 'postpass_exclude_post', $postpass_exclude_post );

		return '保存しました。';
	}


	//プラグイン設定フォーム
	function form() {

		$save_valu = $this->save_common_multi_post_password();

		echo '<div class="wrap">';
		echo '<h1 class="wp-heading-inline">共通投稿パスワード</h1>';
		echo '<hr class="wp-header-end">';

		if( $save_valu ){
			echo '<div id="setting-error-settings_updated" class="updated settings-error notice is-dismissible">';
			echo '<p><strong>' . $save_valu . '</strong></p>';
			echo '</div>';
		}


		echo '<form method="post" action="">';

			// Add a nonce field so we can check for it later.
			wp_nonce_field( 'admin_nendebcom_multi_postpass_nonce', 'admin_nendebcom_multi_postpass_nonce' );

			// デフォルトパスワード期限 ( 今日から3カ月後 )
			$kijitsu = date( 'Y/m/d', strtotime( date( 'Y/m/d', strtotime( date_i18n( 'Y/m/d' ) . '+3 month' ) ) . ' -1 day' ) );

			// 投稿パスワード取得(配列)
			$multi_postpass_data = maybe_unserialize( get_option( 'multi_postpass', false ) );

			if ( !$multi_postpass_data ) {
				$multi_postpass_data = array();
			}else{
				//登録日でソート
				foreach ( $multi_postpass_data as $key => $value ){
					$key_id[$key] = $value['postpass_date'];
				}
				array_multisort ( $key_id , SORT_DESC , $multi_postpass_data );
			}

			// 登録パスワード数
			$tmp_max_id = count( $multi_postpass_data );

			echo '<input type="hidden" name="max_id" value="' . $tmp_max_id . '">';


			// CSS 表示テーブル用
			?>
			<style type="text/css">
				div#multi_postpass {
					background-color: #fff;
					padding: 10px;
					margin: 30px 0 0;
				}

				table.multi_postpass_table{
					width: 100%;
				}

				table.multi_postpass_table tr.header {
					background: #f3f3f3 none repeat scroll 0 0;
				}

				table.multi_postpass_table th {
					text-align: left;
					padding: 3px 5px;
				}

				table.multi_postpass_table td input[type="text"] {
					width: 100%;
				}

				table.multi_postpass_table td.kigen {
					width: 15%;
				}

				table.multi_postpass_table td.pass {
					width: 30%;
				}

				table.multi_postpass_table td.memo {
					width: 40%;
				}

				table.multi_postpass_table td.date {
					width: 15%;
					text-align: center;
				}
			</style>
			<?php

			// 表示テーブル
			echo '<div id="multi_postpass">';
			echo '全ての投稿パスワード記事で有効な ユーザー個別のパスワードを設定します。';
			echo '<table class="multi_postpass_table">';
			echo '<tr class="header">';
			echo '<th>期限</th>';
			echo '<th>パスワード</th>';
			echo '<th>メモ</th>';
			echo '<th>登録日</th>';
			echo '</tr>';

			//新規
			echo '<tr>';
			echo '<td class="kigen"><input type="text" name="postpass_kigen_' . $tmp_max_id . '" value="' . $kijitsu . '" size="10" autocomplete="off"></td>';
			echo '<td class="pass" ><input type="text" name="postpass_pass_'  . $tmp_max_id . '" value="" size="20" autocomplete="off"></td>';
			echo '<td class="memo" ><input type="text" name="postpass_memo_'  . $tmp_max_id . '" value="" size="60" autocomplete="off"></td>';
			echo '<td class="date">新規</td>';
			echo '</tr>';

			//修正・削除
			if ( !empty( $multi_postpass_data ) ) {

				$i = 0;
				foreach ( $multi_postpass_data as $data ) {
					echo '<tr>';
					echo '<td class="kigen"><input type="text" name="postpass_kigen_'  . $i . '" value="' . $data[ 'postpass_kigen' ] . '" size="10"></td>';
					echo '<td class="pass" ><input type="text" name="postpass_pass_'   . $i . '" value="' . $data[ 'postpass_pass' ] . '" size="20"></td>';
					echo '<td class="memo" ><input type="text" name="postpass_memo_'   . $i . '" value="' . $data[ 'postpass_memo' ] . '" size="60"></td>';
					echo '<td class="date" ><input type="hidden" name="postpass_date_' . $i . '" value="' . $data[ 'postpass_date' ] . '">' . date('Y/m/d', $data[ 'postpass_date' ] ) . '</td>';

					echo '</tr>';
					$i++;
				}
			}

			echo '</table>';
			echo ' ※パスワードを 空欄にして保存すると、その行は削除されます。';

			echo '<br>';
			echo '<br>';


			// 除外投稿パスワード取得
			$postpass_exclude_post = get_option( 'postpass_exclude_post', false );
			echo '<table class="multi_postpass_table">';
			echo '<tr class="header">';
			echo '<th>除外共通投稿パスワード</th>';
			echo '</tr>';
			echo '<tr>';
			echo '<td><input type="text" name="postpass_exclude_post" value="' . $postpass_exclude_post . '" autocomplete="off"></td>';
			echo '</tr>';
			echo '</table>';
			echo ' ※共通投稿パスワードを使わない投稿IDを入力してください。( post_id カンマ区切り )';


			echo '<p class="submit"><input type="submit" name="submit" id="submit" class="button-primary" value="変更を保存"  /></p>';
			echo '</div>';


		echo '</form>';
		echo '</div>';
	}
}


/**
 * オプションに入れた パスワードで認証する
 * Filters whether a post requires the user to supply a password.
 *
 * @since WordPress 4.7.0
 * post-template.php
 *
 * @param bool    $required Whether the user needs to supply a password. True if password has not been
 *                          provided or is incorrect, false if password has been supplied or is not required.
 * @param WP_Post $post     Post data.
 * License: GPLv2 or later
 */
function nendebcom_common_multi_post_password_required( $required, $post ) {

	if ( !$required ) {
		return $required;
	}

	// パスワードデータ読込
	$multi_postpass_data = maybe_unserialize( get_option( 'multi_postpass', false ) );
	// 除外投稿パスワード取得
	$postpass_exclude_post = get_option( 'postpass_exclude_post', false );
	$postpass_exclude_post_array = explode( ',', $postpass_exclude_post );

	$hasher = new PasswordHash( 8, true );

	// 追加照合
	$hash = isset( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) ? wp_unslash( $_COOKIE[ 'wp-postpass_' . COOKIEHASH ] ) : '';
	if ( 0 !== strpos( $hash, '$P$B' ) ) {
		$required = true;
	} else {
		if ( !empty( $multi_postpass_data ) ) {
			// パスワードチェック
			foreach ( $multi_postpass_data as $passdata ) {
				if ( $hasher->CheckPassword( $passdata[ 'postpass_pass' ], $hash ) ) {

					// 除外投稿ID
					foreach ( $postpass_exclude_post_array as $exclude_post_id ) {
						if( $exclude_post_id == $post->ID ){
							return $required;
						}
					}

					//期限チェック
					if ( strtotime( date_i18n( "Y/m/d" ) ) <= strtotime( $passdata[ 'postpass_kigen' ] ) ) {
						return false;
					}
				}
			}
		}
	}

	return $required;
}
add_filter( 'post_password_required', 'nendebcom_common_multi_post_password_required', 11, 2 );

※このフォームを触れる権限は「edit_posts」にしてますが、変更したい場合は add_options_pageの所で変更してください。
※投稿パスワードフォームのいちばん上の行が新規登録用になります。
※消したいパスワードがある場合、該当のパスワードを 空欄にして保存すると、その行は削除されます。
※デフォルトパスワード期限は使う用途で変更してください。
※WordPressの標準の投稿パスワード設定は必要です。これをしないと パスワード保護機能自体 動作しません。

 
 

あとがき

ここまで出来たら、運用しだいでいろいろなケースに対応できそうです。

また、WordPressの標準の投稿パスワードは、全て同じパスワードをいれて、スーパーユーザー用とか確認用とかに使ったらどうでしょうか?
そんな場合の全て同じパスワードを簡単に設定できる方法はこちらにあります。
パスワード保護ページの 投稿パスワード を 一括編集できるようにする

投稿ごとに個別の投稿パスワードを複数設定したい場合は以下の記事を参考にしてください。
WordPress パスワード保護ページの 投稿パスワード を「投稿別」に複数使えるようにする

あまりパスワード数が多くなると、使いにくくなりますので 実用的に変更しないといけません。
追加用の投稿パスワード情報は投稿ごとに 1つのカスタムフィールドにまとめて入るようにしてます。
もしかしたら パスワード情報を 新しい別のテーブルに持たせるようにした方が安心かもしれません。

 
 

参考

post_password_required | Hook | WordPress Developer Resources
https://developer.wordpress.org/reference/hooks/post_password_required/

管理メニューの追加 – WordPress Codex 日本語版
https://wpdocs.osdn.jp/%E7%AE%A1%E7%90%86%E3%83%A1%E3%83%8B%E3%83%A5%E3%83%BC%E3%81%AE%E8%BF%BD%E5%8A%A0

関数リファレンス/add options page – WordPress Codex 日本語版
https://wpdocs.osdn.jp/%E9%96%A2%E6%95%B0%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9/add_options_page

ユーザーの種類と権限 – WordPress Codex 日本語版
https://wpdocs.osdn.jp/%E3%83%A6%E3%83%BC%E3%82%B6%E3%83%BC%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E6%A8%A9%E9%99%90