Skip to content

会員管理 テーブル設計

項目内容
Issue#2594
親 Issue#2381 有料記事の体制を整える
関連 Issue#2390 決済・購読・アクセス制御
最終更新2026-07-04

1. 概要

有料記事 Phase 2(自サイト決済・アクセス制御)に向け、会員のプラン加入状態と有料記事の購入記録を管理するカスタムテーブルを定義する。

会員の実体(アカウント情報)は WordPress 標準ユーザー(wp_users / wp_usermeta)を利用し、本設計のカスタムテーブルは「プラン」「加入状態」「購入記録」など WordPress コアが持たないドメインデータのみを保持する。

2. WordPress 標準ユーザーを採用する理由

観点WordPress 標準ユーザー(採用)完全独自会員テーブル(不採用)
パスワード管理core の wp_hash_password / wp_check_password に委譲bcrypt/Argon2id 等を自前実装・保守が必要
セッション/Cookiewp_signon / wp_set_auth_cookie が提供セッション管理を自前実装
既存 WP エコシステムプラグイン・REST API・Capability との親和性が高いWP ユーザーと二重管理になり整合性が崩れやすい
実装コスト低(認証基盤は core 利用)高(セキュリティ監査対象が増える)
決済連携WooCommerce 等が WP ユーザー ID を前提とする決済プロバイダ連携時にユーザー ID マッピングが必要

結論: パスワード暗号化・ログインセッションは WordPress core に委譲し、会員ドメイン固有データのみカスタムテーブルで管理する。

3. ER 図

: wp_userspaid_article 投稿は WordPress コアテーブル(wp_posts 等)であり、DBML 正本のスコープ外。上図は論理関係の説明用。

DBML 正本: docs/design/テーブル定義/custom-tables.dbml

4. テーブル定義

4.1 db_member_plan_master(会員プラン/商品マスタ)

カラムNULLデフォルト説明
idbigintNOAUTO_INCREMENT主キー(MySQL では unsigned)
plan_keyvarchar(64)NOプラン識別子(例: paid_article_single
namevarchar(255)NO表示名
priceintNO0価格(円・税込想定、unsigned)
billing_cyclevarchar(32)NOone_time課金サイクル(下表参照)
is_activetinyintNO10: 非公開, 1: 公開
sort_orderintNO0表示順
created_atdatetimeNOCURRENT_TIMESTAMP作成日時
updated_atdatetimeNOON UPDATE更新日時

インデックス: uk_plan_key (plan_key) UNIQUE

billing_cycle の値:

用途
one_time単号購入(有料記事 1 号)
monthly月額サブスク
yearly年額サブスク

定数(実装時): DatabaseTableConstants::MEMBER_PLAN_MASTER = 'db_member_plan_master'

4.2 db_member_subscription(会員プラン加入状態)

カラムNULLデフォルト説明
idbigintNOAUTO_INCREMENT主キー
user_idbigintNOWordPress wp_users.ID(論理 Ref、DB FK なし)
plan_idbigintNOdb_member_plan_master.id
statusvarchar(32)NOactive加入状態(下表参照)
started_atdatetimeNO加入開始日時
expires_atdatetimeYESNULL失効日時(単号購入は NULL = 永久)
external_providervarchar(32)NOnone決済プロバイダ(none / stripe / woocommerce
external_subscription_idvarchar(255)YESNULLプロバイダ側サブスク ID(Webhook 連携用)
created_atdatetimeNOCURRENT_TIMESTAMP作成日時
updated_atdatetimeNOON UPDATE更新日時

インデックス:

  • idx_user_id (user_id)
  • idx_status (status)
  • idx_user_plan_status (user_id, plan_id, status)

status の値:

説明
active有効(閲覧権あり)
canceled解約済み(expires_at まで有効な場合あり)
expired失効
suspended管理者による一時停止

定数(実装時): DatabaseTableConstants::MEMBER_SUBSCRIPTION = 'db_member_subscription'

4.3 db_paid_article_purchase(有料記事単号購入記録)

カラムNULLデフォルト説明
idbigintNOAUTO_INCREMENT主キー
user_idbigintNOWordPress wp_users.ID
post_idbigintNOpaid_article CPT の投稿 ID
priceintNO0購入時の価格(円)
external_providervarchar(32)NOnone決済プロバイダ
external_transaction_idvarchar(255)YESNULLプロバイダ側取引 ID(Webhook 冪等キー)
purchased_atdatetimeNO購入完了日時
created_atdatetimeNOCURRENT_TIMESTAMP作成日時
updated_atdatetimeNOON UPDATE更新日時

インデックス:

  • uk_user_post (user_id, post_id) UNIQUE — 同一ユーザー・同一号の二重購入防止
  • idx_user_id (user_id)
  • idx_post_id (post_id)
  • uk_external_transaction_id (external_transaction_id) UNIQUE — Webhook 冪等キー(非 NULL 値の重複防止。MySQL では NULL は UNIQUE 比較対象外のため複数 NULL 可)

定数(実装時): DatabaseTableConstants::PAID_ARTICLE_PURCHASE = 'db_paid_article_purchase'

5. WordPress コアテーブルとの連携

5.1 論理参照の原則

本プロジェクトの DBML 方針に従い、DB レベルの外部キー制約は設けない。Repository 層で以下を担保する。

参照元カラム参照先整合性チェック(実装時)
user_idwp_users.IDユーザー存在確認(get_userdata() 等)
post_idwp_posts.IDpost_type = 'paid_article' かつ公開状態の確認
plan_iddb_member_plan_master.idマスタ存在確認 + is_active = 1

5.2 wp_usermeta で補完するデータ(設計上の候補)

カスタムテーブルに載せず、ユーザーメタで管理する軽量データの例:

meta_key用途
member_email_verifiedメール確認済みフラグ(0 / 1
member_email_verify_tokenメール確認用ワンタイムトークンの HMAC-SHA256(平文はメール/URL のみ。鍵は wp_salt( 'auth' )
member_terms_accepted_version同意済み利用規約バージョン(DB 現行 terms.version と一致で同意済み。空時フォールバックは MemberTermsConsentConstants::CURRENT_VERSION
member_terms_accepted_at利用規約同意日時(UNIX タイムスタンプ文字列)
member_registered_at会員登録日時(wp_users.user_registered でも可)

6. 購入記録とサブスクの使い分け

ユースケース使用テーブル備考
有料記事 1 号の購入db_paid_article_purchase永久アクセス(#2384 方針)
月額プレミアム会員db_member_subscriptionbilling_cycle = monthlyexpires_at で失効
全号アクセス権db_member_subscription特定プラン加入で全 paid_article を閲覧可

単号購入は db_paid_article_purchase で管理し、プラン加入型の権利は db_member_subscription で管理する。

7. 拡張ポイント

拡張対応方針
月額サブスクdb_member_plan_master.billing_cycle = monthly + db_member_subscription
返金db_paid_article_purchaserefunded_at 列追加、または status 列追加
ゲスト購入非推奨(#2384: WP ログイン必須推奨)。必要なら別テーブルで email 紐付け
ログイン試行監査ログイン試行監査テーブル-検討.md 参照
WooCommerce 連携external_provider = woocommerce、注文 ID を external_transaction_id に保存
Stripe Webhook 冪等uk_external_transaction_id UNIQUE 制約で二重付与防止(非 NULL 時のみ。external_provider = none 等で NULL の行は複数可)

8. 実装参照

レイヤーファイル例
定数core_src/Constants/DatabaseTableConstants.php
Installercore_src/Infrastructure/Database/MemberPlanMasterInstaller.php
Entitycore_src/Model/Entity/member_plan_master_entity/
Repositorycore_src/Model/Repository/member_plan_master_repository/
Interfacecore_src/Interface/repository/MemberPlanMasterRepositoryInterface.php
SQLcore_src/Model/Sql/member_plan_master/
DIcore_src/config/di/repositories.php

9. 関連ドキュメント