Google Crisis Response(Google)
災害に関する情報源や、行方不明者情報の収集と検索を行う『パーソンファインダー』を初めとするツールの提供が行われています。

2008年3月14日 金曜日

管理者なのに新規にページが公開できない原因

Filed under: WordPress,ハック
時間:1時10分
投稿者:よしとも
AddClips 経由でソーシャルブックマークに登録

 先週の記事でも書きましたように、Google AdSense の規約変更のためにプライバシーポリシーの掲載が必要となりました。いろいろと考えて自力で作ったのですが、なぜか肝心のページの公開ができません。

 公開するには、ステータスを「公開」にすればいいはずですが、私の場合はなぜかその項目が表示されていません。その部分のコードを探して確認してみることに。久しぶりのハックです。バージョンは ME2.1.3。ME2.0 からアップグレードしてあります。

解析編

 ページ編集画面のアドレスからファイルを推測したどっていくと、wp-admin/edit-page-form.php に該当箇所が見つかりました。

  1. <fieldset class="dbx-box">
  2. <h3 class="dbx-handle"><?php _e('Page Status') ?></h3>
  3. <div class="dbx-content"><?php if ( current_user_can('publish_pages') ) : ?>
  4. <label for="post_status_publish" class="selectit"><input id="post_status_publish" name="post_status" type="radio" value="publish" <?php checked($post->post_status, 'publish'); checked($post->post_status, 'future'); ?> /> <?php _e('Published') ?></label>
  5. <?php endif; ?>
  6.       <label for="post_status_draft" class="selectit"><input id="post_status_draft" name="post_status" type="radio" value="draft" <?php checked($post->post_status, 'draft'); ?> /> <?php _e('Draft') ?></label>
  7.       <label for="post_status_private" class="selectit"><input id="post_status_private" name="post_status" type="radio" value="private" <?php checked($post->post_status, 'private'); ?> /> <?php _e('Private') ?></label></div>
  8. </fieldset>

 63行目が公開とする項目で、62行目のところで権限の有無によって処理を分岐しているようです。管理者アカウントで作業しているので権限がないとは思えないのですが。

 今度は条件式に使われている関数 current_user_can() を調べます。まずは定義場所を見つける必要があります。ファイル群から検索という方法でもいいのですが、試しに Google で検索してみることに。キーワードは「WordPress current_user_can」。
 capabilities.php というファイルにあるという情報が見つかりました。コアファイルの置かれているところを探してみると、wp-includes/ にありました。

  1. // Capability checking wrapper around the global $current_user object.
  2. function current_user_can($capability) {
  3.     $current_user = wp_get_current_user();
  4.  
  5.     $args = array_slice(func_get_args(), 1);
  6.     $args = array_merge(array($capability), $args);
  7.  
  8.     if ( empty($current_user) )
  9.         return false;
  10.  
  11.     return call_user_func_array(array(&$current_user, 'has_cap'), $args);
  12. }

 446行目で wp_get_current_user() が返す値を変数に入れています。変数の値を調べてみると、クラス WP_User のインスタンスが入っていました。このクラスも、capabilities.php に定義があります。長いのでコードは省略します。

 448行目の処理は、この関数の2番目以降の引数を要素として持つ配列を取得しています。今回引数は1つだけなので、当然この行の直後では $args は要素を持たない配列です。449行では配列の結合をしていて、変数 $args には array('publish_pages') に相当する値が入ります。

 454行目では、コールバック処理の結果を返しています。変数 $current_user にはクラス WP_User のインスタンスが入っていますので、コールバック関数は WP_User のメンバ関数 has_cap() と言うことになります。定義は次のようになっています。

  1. //has_cap(capability_or_role_name) or
  2.     //has_cap('edit_post', post_id)
  3.     function has_cap($cap) {
  4.         if ( is_numeric($cap) )
  5.             $cap = $this->translate_level_to_cap($cap);
  6.  
  7.         $args = array_slice(func_get_args(), 1);
  8.         $args = array_merge(array($cap, $this->ID), $args);
  9.         $caps = call_user_func_array('map_meta_cap', $args);
  10.         // Must have ALL requested caps
  11.         $capabilities = apply_filters('user_has_cap', $this->allcaps, $caps, $args);
  12.         foreach ($caps as $cap) {
  13.             //echo "Checking cap $cap<br/>";
  14.             if(empty($capabilities[$cap]) || !$capabilities[$cap])
  15.                 return false;
  16.         }
  17.  
  18.         return true;
  19.     }

 引数 $cap には、コールバックで渡された文字列 publish_pages が入ります。数値ではないので、262行目の処理は行われません。264行目と265行目は、current_user_can() の場合と同じですね。$this->ID は、ログイン中のユーザーのID(ログインIDではなく、データベーステーブルの主キー)が入っています。

 266行目で再びコールバックです。この段階 $args には array(‘publish_pages’, ユーザーID) が入っているので、map_meta_cap('publish_pages', ユーザーID) ということをしていることになります。

 関数の定義は、285行目から442行目にかけて記述されています。これもかなり長いですが、やっていることは第一引数の値で switch 分岐処理をしているだけです。publish_pages のところはないので、default 節で次のように処理をしているだけです。

  1. default:
  2.         // If no meta caps match, return the original cap.
  3.         $caps[] = $cap;

 そして、その戻り値は予想通り array('publish_pages') でした。

 268行目。プラグイン作成ではおなじみの、apply_filters が使われています。以前にもこの関数のハックに挑んだことがありますが、ややこしくて苦手です。面倒なので $capabilities の中身を見てみるだけに。連想配列になっていて、ユーザステータスを記録しているようです。$capabilities['publish_pages'] はありませんでした。

 269~273行目では、値がないか Not true のものが見つかったら false でリターンするという処理です。値がないので false になってしまいます。

解決編

 すっかり弱ってしまいました。散々調べ続けて、わかったのは間違いなくページを公開する権限がないことだけ。(仕組みがわかって勉強になったというのもありますけど・・・)

 方向を変えて、publish_pages について調べてみることに。「WordPress publish_pages」と検索。WordPress Japan のフォーラムに、よく似た不具合のスレッドを発見。

 そこからリンクされているページを見ると、データベースに記録されているシステム設定に問題がある模様。どれどれと確認してみると、$capabilities の内容によく似たデータが。そして、そこには publish_pages はありませんでした。2.0 からアップグレードするときに、スクリプトが修正してくれなかっただけなのではないでしょうか。実際、プラグインチェック用に新規インストールした 2.1 のほうでは次のような内容で、そこにはちゃんと publish_pages があります。

  1. a:5:{s:13:"administrator";a:2:{s:4:"name";s:27:"管理人 - (Administrator)";s:12:"capabilities";a:47:{s:13:"switch_themes";b:1;s:11:"edit_themes";b:1;s:16:"activate_plugins";b:1;s:12:"edit_plugins";b:1;s:10:"edit_users";b:1;s:10:"edit_files";b:1;s:14:"manage_options";b:1;s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:6:"import";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:8:"level_10";b:1;s:7:"level_9";b:1;s:7:"level_8";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;s:12:"delete_users";b:1;s:12:"create_users";b:1;}}s:6:"editor";a:2:{s:4:"name";s:20:"編集者 - (Editor)";s:12:"capabilities";a:34:{s:17:"moderate_comments";b:1;s:17:"manage_categories";b:1;s:12:"manage_links";b:1;s:12:"upload_files";b:1;s:15:"unfiltered_html";b:1;s:10:"edit_posts";b:1;s:17:"edit_others_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:10:"edit_pages";b:1;s:4:"read";b:1;s:7:"level_7";b:1;s:7:"level_6";b:1;s:7:"level_5";b:1;s:7:"level_4";b:1;s:7:"level_3";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:17:"edit_others_pages";b:1;s:20:"edit_published_pages";b:1;s:13:"publish_pages";b:1;s:12:"delete_pages";b:1;s:19:"delete_others_pages";b:1;s:22:"delete_published_pages";b:1;s:12:"delete_posts";b:1;s:19:"delete_others_posts";b:1;s:22:"delete_published_posts";b:1;s:20:"delete_private_posts";b:1;s:18:"edit_private_posts";b:1;s:18:"read_private_posts";b:1;s:20:"delete_private_pages";b:1;s:18:"edit_private_pages";b:1;s:18:"read_private_pages";b:1;}}s:6:"author";a:2:{s:4:"name";s:20:"投稿者 - (Author)";s:12:"capabilities";a:10:{s:12:"upload_files";b:1;s:10:"edit_posts";b:1;s:20:"edit_published_posts";b:1;s:13:"publish_posts";b:1;s:4:"read";b:1;s:7:"level_2";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;s:22:"delete_published_posts";b:1;}}s:11:"contributor";a:2:{s:4:"name";s:25:"寄稿者 - (Contributor)";s:12:"capabilities";a:5:{s:10:"edit_posts";b:1;s:4:"read";b:1;s:7:"level_1";b:1;s:7:"level_0";b:1;s:12:"delete_posts";b:1;}}s:10:"subscriber";a:2:{s:4:"name";s:24:"購読者 - (Subscriber)";s:12:"capabilities";a:2:{s:4:"read";b:1;s:7:"level_0";b:1;}}}

 思い切ってデータを差し替えてみると、見事公開の選択肢が表示されるように。これで、やっとプライバシーポリシーの公開ができます。

Comments (0)

HTML convert time: 0.194 sec. Powered by

Images is enhanced with WordPress Lightbox JS by Zeo