WordPress パスワード保護ページの 投稿パスワード を「投稿別」に複数使えるようにする

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

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

ここでは照合の中にある「post_password_required」フィルターを使って 投稿別にパスワードを複数登録して照合する簡易版を作りました。
以下の「追加照合用コード」と「パスワード登録・編集」を使ってみてください。

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

 

追加照合用コード

投稿の編集画面 で、設定したパスワードで照合するようにしています。
また期限チェックも追加しています。パスワードが合っていても期限が過ぎていたらNGになります。

カスタムフィールドのパスワードで照合する

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

/**
 * カスタムフィールドのパスワードで認証する
 * 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_post_password_required( $required, $post ) {

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

	require_once ( ABSPATH . 'wp-includes/class-phpass.php' );

	// パスワードデータ読込
	$multi_postpass_data = maybe_unserialize( get_post_meta( $post->ID, 'multi_postpass', true ) );

	$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 ) ) {
					//期限チェック
					if ( strtotime( date_i18n( "Y/m/d" ) ) <= strtotime( $passdata[ 'postpass_kigen' ] ) ) {
						return false;
					}
				}
			}
		}
	}
	return $required;
}
add_filter( 'post_password_required', 'nendebcom_post_password_required', 10, 2 );

 



 

パスワード登録・編集

投稿ごとに パスワードを登録・編集できるフォームを追加します。

「投稿パスワード」を複数 追加できるようにするのと「期限」も登録できるようにします。

編集画面に「投稿パスワード」の項目を追加

宣言用・フォーム用・保存用 とありますのでセットで利用してください。
以下のコードを my-plugin.php に張り付けてみてください。

/**
 * 投稿の編集画面に「投稿パスワード」の項目を追加
 * Adds a box to the main column Multi Post Password
 *
 * License: GPLv2 or later
 */
function nendebcom_multi_postpass_meta_box() {
	add_meta_box( 'nendebcom_multi_postpass_area', '個別 投稿パスワード', 'nendebcom_multi_postpass_callback', 'post', 'advanced' );
}
add_action( 'add_meta_boxes', 'nendebcom_multi_postpass_meta_box' );



/**
 * Prints the box Multi Post Password.
 * 
 * @param WP_Post $post The object for the current post/page.
 * License: GPLv2 or later
 */
function nendebcom_multi_postpass_callback( $post ) {

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

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

	// 投稿パスワード取得(配列)
	$multi_postpass_data = maybe_unserialize( get_post_meta( $post->ID, 'multi_postpass', true ) );
	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 );

	// CSS
	echo '<style type="text/css">';
	echo '	div#multi_postpass{max-height: 200px;overflow: auto;}';
	echo '	table.multi_postpass_table tr.header{background: #f3f3f3 none repeat scroll 0 0;}';
	echo '	table.multi_postpass_table th{text-align: center;}';
	echo '	table.multi_postpass_table td input[type="text"]{width: 100%;}';
	echo '	table.multi_postpass_table td.kigen {width:15%;}';
	echo '	table.multi_postpass_table td.pass{width:30%;}';
	echo '	table.multi_postpass_table td.memo{width:40%;}';
	echo '	table.multi_postpass_table td.date{width:15%;text-align: center;}';
	echo '</style>';

	// 表示テーブル
	echo '<div id="multi_postpass">';
	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 '<input type="hidden" name="max_id" value="' . $tmp_max_id . '">';
	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 '</div>';
	echo ' ※パスワードを 空欄にして保存すると、その行は削除されます。';
}



/**
 * When the post is saved, saves our custom data Multi Post Password.
 *
 * @param int $post_id The ID of the post being saved.
 * License: GPLv2 or later
 */
function nendebcom_multi_postpass_save_meta_box_data( $post_id ) {

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

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

	// If this is an autosave, our form has not been submitted, so we don't want to do anything.
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return;
	}

	// Check the user's permissions.
	if ( isset( $_POST[ 'post_type' ] ) && 'post' == $_POST[ 'post_type' ] ) {
		if ( !current_user_can( 'edit_post', $post_id ) ) {
			return;
		}
	} else {
		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_post_meta( $post_id, 'multi_postpass', $multi_postpass_data );
}
add_action( 'save_post', 'nendebcom_multi_postpass_save_meta_box_data' );

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

 
 

あとがき

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

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

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

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

 
 

参考

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

関数リファレンス/add meta box – WordPress Codex 日本語版
http://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_meta_box