【WordPress会員機能】WP-Membersプラグインで登録時にメール認証（ダブルオプトイン方式）を実装する方法

WordPressで会員サイトを構築するとなると、プラグインの候補がある程度絞られてきます。
中でも導入数が多く、日本語ドキュメントも充実しているのが、『[WP-Members Membership Plugin](https://ja.wordpress.org/plugins/wp-members/)』。
登録時のフィードのカスタマイズができることや、ユーザーによるプロイフィール編集ができるなど、基本的な会員機能が一通り備わっており、使い勝手が良いのですが、どうしても仕様上欲しかったのが、新規登録時のメール認証。

1. フォームに入力して新規登録
2. 確認メールが届く
3. メールにある本登録URLをクリック
4. 本登録完了

と言った、動きを実装するべく調べていたところ、公式サイトにドキュメントを発見。
[Send new user an activation link in the new registration email](https://rocketgeek.com/filter-hooks/send-new-user-an-activation-link-in-the-new-registration-email/)

しかし、この方法をそのまま実装してもいろいろ間違っているようで、うまく動きませんでした。
（メールに値を不要する際、フィールドにない値は取れないこと、['toggle']がnewmodとなっているが新規登録時はnewregでないとダメなど。あと、本登録してなくてもログイン出来るなど、あくまでサンプルレベルのソースでした。）

いろいろとカスタマイズを加えることで実装が実現しましたので、以下その内容をまとめます。

**2020/2/4 update wpmem_fieldsを利用し、jQueryを使わないでいける様改善しました**


##管理画面より、アクティベーションキー用のhiddenフォームを追加
管理画面、設定>WP-Membersを開き、フィールドタブ、フィールドの追加をクリックし、新しくフィールドを追加します。
<img width="638" alt="wp-members.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/229958/33993a80-9758-7da5-b1f4-99af5f126696.png">
今回は「activation_key」と言う名前にしています。値はなんでも構いません。

##function.phpにフィルター・アクションフックを記入

```php:function.php
/**
 * 各種設定が変更できるヘルパー関数
 * （設定やテキストの変更は全てこの関数でできます）
 */
function my_activation_key_settings() {
    $settings = array(
        'email_text'      => '本登録はこちら: ',// メールに含めるテキスト
        'return_url'      => home_url('/user/'),// 登録完了時のリダイレクト先
        'send_welcome'    => false,// 本登録時ウェルカムメールを送信するか
        'show_success'    => true,// 完了メッセージを表示するか
        'success_message' => '本登録が完了しました。<br>サイトをお楽しみください',// 完了メッセージ
        'send_notify'     => false,// ユーザー登録時に管理者へ通知メッセージを送信
    );  
    return $settings;
}

/**
 * 登録時にアクティベーションキーを作成
 */
add_filter( 'wpmem_fields', 'my_remove_reg_fields_filter', 10, 2 );
function my_remove_reg_fields_filter( $fields, $tag ) {
    if ( 'register' == $tag ) {
        // ランダムなキーを発行してフィールドにセット
        $key = md5( wp_generate_password());
        $fields['activation_key']["value"] = $key;
    }
    return $fields;
}

/**
 * 登録時メールにアクティベーションキーを追加
 */
add_filter( 'wpmem_email_filter', 'my_add_key_to_email', 10, 3 );
function my_add_key_to_email( $arr, $wpmem_fields, $field_data ) {
    $settings = my_activation_key_settings();
    $url = trailingslashit( $settings['return_url'] );
    // 新規登録に対してのみ実行
    if ( $arr['toggle'] == 'newreg' ) {
        // 保存されたキーを取得
        $key = get_user_meta( $arr['user_id'], 'activation_key', true );
        // メール本文にテキストを追加
        $arr['body'] = $arr['body'] . "\r\n"
            . $settings['email_text']
            . add_query_arg( 'activate', $key, $url );
        //ステータスを仮登録にする
        update_user_meta( $arr['user_id'], 'my_active', '0' );
	}
    return $arr;
}

/**
 * アクティベーションキーを確認・存在する場合は、ユーザーを検証してログインします。
 */
add_action( 'template_redirect', 'my_validate_key' );
function my_validate_key() {
    $settings = my_activation_key_settings();
    // アクティベーションキーをチェック
    if ( isset( $_GET['activate'] ) ) {
        // キーの対象となるユーザーアカウントを取得
        $users = get_users( array(
            'meta_key'    => 'activation_key',
            'meta_value'  => $_GET['activate'],
            'number'      => 1,
            'count_total' => false
        ) );
        if ( $users ) {
            foreach( $users as $user ) {
                // 指定されたアクティベーションキーが有効、ログイン実行
                wp_set_auth_cookie( $user->ID, true );
                wp_set_current_user( $user->ID );
                // activation_keyメタを削除し、アクティブに設定
                delete_user_meta( $user->ID, 'activation_key' );
                update_user_meta( $user->ID, 'my_active', '1' );
                if ( $settings['send_welcome'] ) {
                    // ヘルパー関数の値がtrueならウェルカムメールを送信
                    wpmem_inc_regemail( $user->ID, '', 2 );
                }
                if ( $settings['send_notify'] ) {
                    // ヘルパー関数の値がtrueなら通知メールを送信
                    global $wpmem;
                    wpmem_notify_admin( $user->ID, $wpmem->fields );
                }
                break;
            }
        }
    }
}

/**
 * 本登録完了メッセージ表示
 */
add_filter( 'the_content', 'my_show_thankyou_on_activation', 100 );
function my_show_thankyou_on_activation( $content ) {
    $settings = my_activation_key_settings();
    if ( $settings['show_success'] && isset( $_GET['activate'] ) ) {
        // 依存関係をロード
        $content = wpmem_inc_regmessage( '', $settings['success_message'] ) . $content;
    }
    return $content;
}

/**
 * ログイン実行時、アクティベーションしていないユーザーの場合強制ログアウト
 */
add_filter( 'wpmem_login_redirect', 'my_login_redirect', 10, 2 );
function my_login_redirect( $redirect_to, $user_id ) {
	$type = get_user_meta( $user_id, 'active', true );
	if($type != '1') {
		wp_logout();
	}
    // ログインページへリダイレクト
    return home_url( '/login/' );
}
```


以上で、メールにアクティベーションURLが届くようになりました。