半ば放置ぎみだったミニコme!の開発を再開したことと、4月に控えている破滅派大リニューアルに向けてWordPressの会員制機能を作っているので、それについて情報をまとめておきます。メモなので、である調です。
前提:WordPressデフォルトのユーザーシステム
ユーザーの権限と種類を理解する
WordPressにはデフォルトで5種類のユーザー種別(管理者・編集者・投稿者・寄稿者・購読者)が存在する。これに「非登録ユーザー」を加えると、デフォルトで6種類のユーザーが存在することになる。
一人の人間がブログとして利用するだけであれば、管理者以外は必要ない。有料ブログなどを展開するのであれば、管理者・購読者・非登録ユーザーとなる。複数の投稿者が存在する場合(ニュースブログなど)は編集者・投稿者・非登録ユーザーとなり、これにゲスト等後者が加わる場合は寄稿者を利用する(もっとも、寄稿者にWordPressの管理画面をいじらせることは想定し辛いが)。登録ユーザーに対して特別な何かを提供する場合は「購読者」が役に立つ。
新規ユーザー登録の設定
管理画面で「設定 > 一般」で「誰でもユーザー登録ができるようにする」にチェックを入れれば、誰でも自由に登録できる。新規ユーザーのデフォルト権限も選べる。権限グループの詳細はCodexのユーザーの種類と権限にある。
なお、購読者ができることは「ログイン」および「プロフィールの編集」のみであるため、このままではあまり役にも立たない。プラグインの導入等を行うことではじめてユーザー登録が意味を持つ。
登録の流れと問題点
新規登録を可能にすると、ログインページ http://example.jp/wp-login.php に新規登録へのリンクが表われる。メールアドレスを入力して登録をするとパスワードが書かれたメールが届く。主な問題点は二つ。
- パスワードが平文で書かれているメールが届くので、セキュリティ的にちょっとアレ
- 大量のボットに襲われ、スパムアカウントが増加する
ユーザーの登録およびログインのカスタマイズ
ユーザー登録フローの改善
Theme My Loginというプラグインを利用する。日本語ファイルはWordPressプラグイン Theme My Login を日本語化しましたで公開されているが、ちょっと足りない部分もあるので、自力で日本語化してください。
Theme My Loginは下記の機能を持っている。
- 管理画面( http://example.jp/wp-admin 以下のページ)に入れる権限と入れない権限を選べる
- メールによる認証機能を使えるので、スパムアカウントが有効化しない(pendingという権限になり、ログインできないまま)。削除はしてくれない。
- パスワード喪失時、通常ならパスワードがメールで送られてくるが、「ユーザーにパスワードを入力させる > 承認メール送信 > 承認リンクを踏んでアカウント有効化」というフローが取れる。
- ユーザに対して送信するメール(登録時、パスワード変更時、etc)の文面を入力できる。
- ログインページをカスタマイズできる。ただし、表示されるフォーム自体は既存のものと同じなので、マークアップを変更することはできない。いま(2011-06-08時点)はできるっぽい。参考:Additional fields in register-form.phpそういうプラグインはあるのかもしれないけど、探してない。デモはこのサイトの「ログイン」を参照のこと。
商用でWordPressを使うときは、とりあえず「登録〜ログイン」までをこのプラグインに任せてしまうと楽だと思う。
ユーザーのログインをカスタマイズ
最近のWebサービスではユーザーのログイン名ではなく、メールアドレスでログインさせることが多い。WP Email Login というのがあるので、これを使うとメールアドレスでログインさせることができる。ただし、英語のメッセージがJavascriptにベタ書きされているので、これは要修正。上述のTheme My Loginではメールアドレスでもログインできることが判明。フォームのラベルだけ変えれば問題ないと思う。
退会をできるようにする
退会をできるようにするプラグインは一応あるっぽいけど、未検証。基本的には関数wp_delete_userで削除できる。ただし、この関数は管理画面専用なので、公開画面で使う場合は別途読み込む必要がある。
//関数の記載されたファイルを読み込み require_once ABSPATH."/wp-admin/includes/user.php"; //ID 10のユーザーを削除 wp_delete_user(10);
仮に登録していたユーザーが投稿(とそれに準ずるもの。カスタム投稿タイプも含む)を保持していた場合、その投稿を別のユーザーに割り当てることはできる。しかし、それ以外のユーザーに紐づく情報があった場合、単純にこの方法でユーザーを削除してしまうと、それらの情報が宙ぶらりんになってしまう。これについては後述する。
ユーザーの権限・登録情報に関するもの
ユーザーの権限を変更
Capability Managerというプラグインで権限を変更できる。
新しい権限グループを作ることもできるが、5個も10個も権限を作ったところでカオスになるだけだと思うので、デフォルトのをカスタマイズするのが楽だと思う。
ユーザーの権限を激しく変更
前述した権限グループは自作することもできるし、既存の権限グループに権限を追加することもできる。権限グループは実のところ、ただの配列である。WordPressの設定を保存するテーブルwp_optionsを覗いてみると、wp_user_rolesというオプション名で配列のままぶっ込まれている。
これを変更すれば権限も変わるのだが、それだとアップデートのときにどうなるのかわからないので、なるべくAPIを利用する。また、WordPressをカスタマイズするときは、データベースの中に入っているものをあまりいじらないようにした方がいい。
ユーザー権限はWP_Rolesというクラスが管理しているが、WordPressのいいところは「クラス? なにそれおいしいの? グローバル? 何がいけないの?」というレベルを脱していない人でもわりとなんとかなるところだ。
Ultimate Guide to Roles and Capabilitiesというエントリーにユーザー権限を司るクラスとその詳しい挙動が書いてあるが、細かいところはともかく、基本的にはグローバル変数$wp_rolesを呼び出し、add_capやremove_capメソッドを実行、その後current_user_can関数を使えばなんとかなる。
function customize_author_role(){ //グローバル変数を呼び出し global $wp_roles; //投稿者よ、墓に唾をかけろ! $wp_roles->add_cap("author", "i_spit_on_your_grave"); //投稿者がログインしている場合は... if(current_user_can("i_spit_on_your_grave")){ //ここで唾を吐く do_spit(); } } add_action("init", "customize_author_role"); // ※initフックより前だと、ユーザーオブジェクトが存在しない
ユーザーの権限をチェック
前述の通り、current_user_can関数が判定してくれる。
if(current_user_can("do_something")){ //なんか行う }
カスタマイズの拡張性を考えると、権限を利用することでユーザーの挙動を制限する方法が安心。
ユーザーの登録情報を変更
ユーザーには「コンタクトメソッド」という部分があって、デフォルトでは以下の4つ。
- Webサイト
- AIM
- Yahoo IM
- Jabber / Google Talk
下の3つはいらない子なので、これを消す。もし他に何か付け加えたいの方法がある場合(Twitterアカウントとか)は、以下の方法でできる。wpbeginner.comに書いてあった。もうちょっと汎用性を高くしたものをgistに置いてある。
/** * デフォルトのコンタクトフィールドを削除する * * @param array $contactmethods * @return array */ function hide_profile_fields( $contactmethods ) { unset($contactmethods['aim']); unset($contactmethods['jabber']); unset($contactmethods['yim']); return $contactmethods; } add_filter('user_contactmethods','hide_profile_fields',10,1); /** * デフォルトのプロフィール編集画面に新しいコンタクトフィールドを追加する * * @param array $contactmethods * @return array */ function original_profile_fields( $contactmethods ) { $contactmethods["twitter"] = "Twitter"; $contactmethods["facebook"] = "Facebook"; return $contactmethods; } add_filter('user_contactmethods','original_profile_fields',11,1);
ユーザーの登録情報に複雑な情報を追加
コンタクトメソッドではまかないきれない複雑な情報を追加したいときや、もうちょっと複雑な処理を行いたいときは、以下の方法を使う。
- ユーザーのプロフィール編集画面にフォームを追加
- ユーザーのプロフィール更新時にフォームのデータをDBに挿入
//自分のプロフィール編集画面にフォームを追加 function edit_profile_form(){ global $user_ID; //現在のユーザーIDを取得 //フォームを表示 echo '<input type="checkbox" name="pister_option" value="'.get_user_meta($user_ID, 'pister_option', true).'" />'; } add_action("profile_personal_options", "edit_profile_form"); //フォームを更新したときのアクション function update_profile(){ global $user_ID; //$_POSTデータを保存したりする update_user_meta($user_ID, "pister_option", $_POST["pister_option"]); } add_action("personal_options_update", "update_profile");
上記で紹介したのは、ユーザーが自分のプロフィールを更新する場合。管理者が他のユーザーの情報を更新するときにフォームを追加したい場合は、アクションフックがそれぞれ “profile_personal_options > edit_user_profile”, “personal_options_update > profile_update” となる。より詳しい情報はcodexのアクションフック一覧を参照のこと。
ただし、これは管理画面でのみ使える方法である。同時にフォームも作り込む必要があるケースがほとんどだと思われる(ラジオボタンを切り替えると必須項目が変わるとか)ので、がんばってほしい。
データのCRUD (Create, Read, Update, Delete) に関しては、*_user_meta系の関数(関数リファレンスの「ユーザーと投稿者の関数」を参照のこと)で可能。「SQL? それおいしいの?」というお気楽PHPerでも簡単に利用できる。
ユーザーの共有
複数のWordPress
WordPressは3.0からMultisiteという機能を持つようになり、複数のブログを運営できるようになった。しかし、デフォルトだとそのユーザーは自動で共有されず、手動で割り当てていくことになる。
WordPress.comのようなサイト(ブログホスティング)を作りたいならばそれでもいいが、二つのブログのユーザーを共有したい場合(ブログAの購読者=ブログBの購読者にしたい)は、それだと手間がかかりすぎる。たとえば、会員制ニュースサイトなどの場合が考えられる。
こういう場合はWordPressのユーザーテーブル共有機能を使う。WordPressのユーザー情報はwp_usersとwp_usermetaに保存されているので、同じテーブルを使えば、ブログAでのユーザー情報更新がすぐさまブログBにも反映されることとなる。
これを実現するプラグインが一応存在するが(Shared Users Reloaded)、基本的にはCodexに書かれている通り、カスタムユーザーテーブルを定義すればよい。(余談だが、wp-config.phpの編集の上級オプションの項は必読。)
ユーザーテーブルを共有したときの問題点はスレーブ(奴隷)であるブログBにおいて、ユーザーが「権限なし」となってしまうことである。つまり、ログインしても管理画面に入れなくなる。Shared Users Reloadedには、スレーブでの権限を割り当てる機能があるが、一人一人のユーザーを割り当てていかないといけない(ブログAの購読者をブログBの購読者にできない)。それにそもそも、「管理者」がいないとプラグインの設定ができないので、管理者については直接ユーザーテーブルを修正するしかない。
権限グループを同期するコードを書いたらgistにでも上げておく。基本的にはスレーブとなるブログの管理画面から同期するようなのがいいと思う。
WordPress+bbPressの連携
bbPressはプラグインではなく、単体のアプリケーションで、フォーラムを作成できる。bbPress側で親となるWordPressをインストール時に指定できるため、簡単。親となるWordPressにプラグインbbPress Integrationを入れればいい。
上級トピック:WordPressユーザーのバックエンド
ユーザー情報が保存されている場所
WordPressのユーザー情報は、前述の通り、wp_usersとwp_usermetaである。wp_usersのカラムはユーザー名とメール、パスワードなど最低限のものばかり。それ以外の情報はすべてwp_usermetaに保存されている。
ちなみに前述の権限はwp_capabilitiesとして、シリアライズされた配列の形でwp_usermetaにぶち込まれている。
もしそれ以外の情報が必要となる場合や、ECサイトのように増減の激しい情報(取引履歴など)がある場合は、専用テーブルを作成し、$wpdbなどを駆使する必要がある。
ユーザーの認証方法
WordPressは認証にセッションを使っていない。Cookieを使っている。ユーザーのログイン名とパスワードハッシュを登録している。これでログイン済みかどうかを判断している。ためしにCookieを無効にしてみると、ログインできないことがわかる。
携帯電話対応プラグインのKtai-StyleはCookie非対応端末(ほとんどのガラケー)の場合はこのCookieによるログイン認証をセッションに切り替えることで携帯電話でのログインを実現している。
セキュリティ的なリスクは徐々に改善されているし、どうせセッションログインでもCookieは使うので、あまり悩まない方がいい。とにかく、ひたすらUpToDateな状態に保つべし。
WordPressを会員専用サイトとした場合、Cookieを有効にしていないユーザーへの対処が必要となるが、wp_set_cookieなどのプラッガブル(上書き可能)な関数をオーバーライドして、なんとかするのが吉。
退会=データ削除?
上述したように、ユーザーの削除自体は可能だが、ユーザーデータをまるっと削除すると面倒なことも多々ある。wp_delete_userは投稿テーブルだけは他のユーザーに割り当てることで保護してくれる(投稿はデータにpost_authorという項目がある)が、自作のテーブルなどがユーザーIDを参照している場合はそうもいかない。
ある程度の規模を持ったWebサイトなら、取引履歴等はデータとして残しておきたいだろうし、個人情報とまではいかなくとも、せめて何県の何歳の人が買ったのかぐらいは知りたいはずだ。
この場合、delete_userなどの何も出来ない権限グループを用意した上で、メールアドレス、パスワードおよびクリティカルな個人情報をすべて削除し、権限を切り替えるというのがスマートだろう。
WordPressで会員制サイトを構築する際の注意点
- Eコマース系の大規模なプラグインを入れた場合、会員が必ずしもWordPressのユーザーではなかったりするので、注意する
- カスタマイズする場合は、出来る限り細切れに実装し、プラグインAPIを出来る限り使うこと
- ユーザー周りの関数はテンプレートタグとは別にけっこう沢山あるので、関数リファレンスを参照すること
おしまい。ミニコme!の完成をお楽しみに!