投稿日:2023年6月22日
先日、Twitterから下記のようなご相談がありました。
数種類のメンバーシップ会員ページを作り、ユーザー自身が上位ユーザーにプラン変更できるようにしたい。
また、上位の会員は下位ページを見ることができるようにしたい。
下位ユーザーは全ての上位プランを見る(選択できる)ことはできず、ある階層になったら上位のプランを見れる(選択できる)ようにしたい。
分かりやすいように図にしてみました。

▲ユーザー一覧
Aプランユーザー閲覧可能なのはAプランページのみ。B、Cプランに変更することができますが、最上位のD、Eプランには変更ができません。最上位のD、Eプランがあることも分かりません。BプランユーザーA、Bプランページを見ることができ、Cプランに変更することができますが、最上位のD、Eプランには変更ができません。最上位のD、Eプランがあることも分かりません。CプランユーザーA、B、Cプランページを見ることができ、D、Eプランに変更することができます。Cプランユーザーがさらに上位のD、Eプランを選択できるようになります。DプランユーザーA、B、C、Dプランページを見ることができ、Eプランに変更することができます。EプランユーザーA、B、C、D、Eプランページ、全てのページを見ることができます。

▲会員制サイトの構築、メンバーシップページの作成にはWordPress プラグイン WP-Members を使うのが定石です。
使い方は過去の記事 でも取り上げてますので、そちらも参考にしてください。
設定 > Members と辿りオプションなどを設定します。
今回は下図のような設定にしました。

▲「異なるメンバーシッププロダクトの生成を有効化します」がメンバーシップの有効化です。

▲メニューのメンバーシップから作成するプランを新規追加して行きます。
上図は、Eプランを最上位の親に設定しています。

▲右側の「メンバーシップ属性」が親を決める項目になります。
AプランはBプランを、BプランはCプランを、CプランはDプランを、DプランはEプランを親にすることによってメンバーシップの階層が作られます。
「メンバーシップ登録時にデフォルトとして割り当てる(オプション)」にチェックを入れておくと登録時にAプランユーザーとして登録されます。
続いて各メンバーシップが閲覧制限できる固定ページを作成します。

▲固定ページ、Aプランページ。
右側の固定ページ制限でAプランを選択します。
Aプランユーザーにしか閲覧できない制限になりますが、先ほどのメンバーシップでの階層により、全てのユーザーが閲覧可能なページになります。
もちろんAプランユーザーはBプラン以降のページは見ることはできません。
ショートコードはB、Cが選択できるプルダウンメニューとCのみ選択できるボタンをContact Form 7で作成し、JavaScriptで条件に応じて表示、非表示を切り替える仕様にします。
フォームではなく、ボタンクリックだけでユーザー変更できるようにしてしまうと、変更した際に管理者が気づきません。
管理者とユーザーにメール通知が届くように Contact Form 7 を使用しました。
以下、Bプラン以降の固定ページです。




Contact Form 7の設定です。

▲プラダウンメニュー2種類と、ボタン2種類です。

▲プルダウンメニューです。
ユーザーネームとメールアドレスをデータベースから取得して、そのユーザーにメールを送る仕様にしています。
取得したテキストフレームはhideenで非表示にしています。
メール送信に必要な項目ですが、必須にしてないのでメールタグにエラーが表示されてしまいます。
が、メールはちゃんと送信されます。
div要素、id値formWrap
を条件によって表示、非表示を切り替えます。

▲ボタンのフォーム。

▲メールの設定です。
メール(2)を使用することでユーザーにも送ることができるようになります。
前述したようにhiddenで非表示にし、必須項目にしてないためエラーが表示されています。
メール送信はちゃんとされます。

▲届いたメールです。

▲WP-Membersはデータベースに上図のような状態で保存します。
umeta_idカラムの38〜43がWP-Membersが保存するフィールドになります。
42の_wpmem_products_a_plan 。これがメンバーシップの保存状態です。
a_planの部分をSQLなどで書き換えれば変更が可能になります。
43も関係していると思いますが、プラグイン自体からメンバーシップを変更しても反映されませんでした。なんでしょうね???
上で紹介したプルダウンやボタンクリックでPHPに記載したSQLを走らせ、メンバーシップを変更する仕様にしてます。
最後に変更するアクションのYouTube動画を掲載しておきます。
JavaScript(JQuery)、PHP、SQLを駆使してカスタマイズしてみました。
ある項目を含むフィールドから、同じ行のフィールドを取得するSQL文を作るのに苦労しました。
取得した内容は、SQLインジェクション対策、プリペアドステートメントの「?」プレースホルダを使うなどセキュリティ対策にも配慮し、(当たり前ですが)想定していた動作に結びつき手応えを感じています。
おそらくフォロワーさんはこの動作で満足していただけると思います。
ソースコードは正式なオファーが来てから掲載したいと思います。
最後まで読んでいただきありがとうございました。