【WordPress】ユーザーごとに編集可能な投稿タイプを制限する実装方法

【WordPress】ユーザーごとに編集可能な投稿タイプを制限する実装方法 WordPress

WordPressでは、複数の投稿タイプ(カスタム投稿タイプ含む)を扱うサイトで、特定のユーザーまたはユーザーグループに対して編集できる投稿タイプを制限したいケースがあります。本記事では、ユーザーごとに編集可能な投稿タイプを制限する方法について、実装例を交えて紹介します。

スポンサーリンク

なぜ投稿タイプの制限が必要なのか?

たとえば、地域団体や複数の管理担当者が投稿するサイトでは、それぞれに編集権限のある投稿タイプを限定することで、以下のようなメリットがあります。

  • 誤操作や意図しない編集の防止
  • 投稿の役割分担を明確化
  • セキュリティと管理性の向上

実装方針 pre_get_posts と current_user_can() を活用

基本的な実装方針としては、下記のステップで制御します。

  1. 特定ユーザーごとに編集可能な投稿タイプを定義
  2. 投稿一覧・編集画面の表示をフィルターで制御
  3. 投稿の保存・更新時にもフックを使って制限

ユーザーと投稿タイプのマッピングを定義

以下のように、ユーザーIDと編集許可された投稿タイプを配列で定義します。

functions.php:ユーザーIDごとの編集可能投稿タイプ
function get_user_allowed_post_types() {
  $user = wp_get_current_user();

  // ユーザーIDに応じた編集可能な投稿タイプ
  $user_post_type_permissions = array(
    2 => array('event', 'news'),     // ユーザーID 2 は event, news の編集が可能
    3 => array('custom_type'),       // ユーザーID 3 は custom_type のみ編集可能
    // 必要に応じて追加
  );

  return $user_post_type_permissions[$user->ID] ?? array();
}

投稿一覧・編集画面でアクセス制御する

管理画面上の投稿一覧に不要な投稿タイプが表示されないように制御します。

functions.php:許可されていない投稿タイプの一覧を空にする
add_action('pre_get_posts', function ($query) {
  if (!is_admin() || !$query->is_main_query()) return;

  $screen = get_current_screen();
  if (empty($screen->post_type)) return;

  $allowed = get_user_allowed_post_types();
  if (!in_array($screen->post_type, $allowed)) {
    // 投稿タイプが許可されていない場合、一覧に表示しない
    $query->set('post_type', 'none');
  }
});

投稿の編集・保存自体をブロックする

投稿編集URLを直接開いた場合でも制限をかける必要があります。

NG:post-new.phpで既定のpostタイプが判定漏れする
add_action('admin_init', function () {
  global $pagenow;

  if ($pagenow === 'post.php' || $pagenow === 'post-new.php') {
    $post_type = $_GET['post_type'] ?? get_post_type($_GET['post'] ?? null);
    if ($post_type) {
      $allowed = get_user_allowed_post_types();
      if (!in_array($post_type, $allowed)) {
        wp_die('この投稿タイプを編集する権限がありません。');
      }
    }
  }
});
// post-new.php でpost_type未指定(既定のpost)の場合、$post_typeが
// 判定できずチェックごとすり抜けてしまう
post-new.phpはpost_typeパラメータが省略されることがある
既定の投稿タイプ「投稿(post)」を新規作成する場合、post-new.phpのURLには?post_type=が付与されません。この場合$_GET['post_type']$_GET['post']も未設定のため投稿タイプを判定できず、if ($post_type)のチェックごとすり抜けてしまいます。postタイプを許可されていないユーザーでも、素のpost-new.phpにアクセスすれば通常の投稿を新規作成できてしまう抜け穴です。post-new.phppost_type未指定の場合は既定値'post'を明示的に補ってください。
OK:post-new.phpのpost_type未指定時にpostを補完
add_action('admin_init', function () {
  global $pagenow;

  if ($pagenow === 'post.php' || $pagenow === 'post-new.php') {
    if (isset($_GET['post_type'])) {
      $post_type = $_GET['post_type'];
    } elseif (isset($_GET['post'])) {
      $post_type = get_post_type((int) $_GET['post']);
    } elseif ($pagenow === 'post-new.php') {
      // post-new.php でpost_type未指定の場合は既定の投稿タイプ'post'
      $post_type = 'post';
    } else {
      $post_type = false;
    }

    if ($post_type) {
      $allowed = get_user_allowed_post_types();
      if (!in_array($post_type, $allowed)) {
        wp_die('この投稿タイプを編集する権限がありません。');
      }
    }
  }
});

その他の対策(REST APIやメニューの非表示)

必要に応じて、REST API や管理画面メニューからも該当投稿タイプを非表示にすることも可能です。

NG:組み込みの「投稿」メニューが非表示処理から漏れる
add_action('admin_menu', function () {
  $allowed = get_user_allowed_post_types();
  $post_types = get_post_types(['_builtin' => false], 'names');

  foreach ($post_types as $pt) {
    if (!in_array($pt, $allowed)) {
      remove_menu_page("edit.php?post_type=$pt");
    }
  }
});
// _builtin => false はカスタム投稿タイプのみが対象。組み込みの「投稿」メニューは
// 非表示にならない
_builtin => false はカスタム投稿タイプしか対象にならない
get_post_types(['_builtin' => false], 'names')は組み込みのpost/pageを除外してしまうため、ユーザーがpostを許可されていなくても管理メニューには「投稿」がそのまま表示され続けます。組み込みの投稿タイプも対象に含めるよう修正してください。
OK:postを含む全投稿タイプを対象にメニューを制御
add_action('admin_menu', function () {
  $allowed = get_user_allowed_post_types();
  // 組み込みの投稿・固定ページも含め、UIを持つ全投稿タイプを対象にする
  $post_types = get_post_types(['show_ui' => true], 'names');
  unset($post_types['attachment']); // メディアは対象外

  foreach ($post_types as $pt) {
    if (!in_array($pt, $allowed)) {
      if ($pt === 'post') {
        remove_menu_page('edit.php');
      } else {
        remove_menu_page("edit.php?post_type=$pt");
      }
    }
  }
});

よくある質問(FAQ)

Q特定のロールに対して編集できる投稿タイプを制限するには?
Amap_meta_capフィルターでedit_postsケイパビリティを処理し、対象ロールと投稿タイプの組み合わせを確認して許可/拒否を制御します。
Qエディターに記事の編集権限は与えつつカスタム投稿タイプは編集させないには?
Aカスタム投稿タイプのregister_post_type()でcapability_type=’custom’と設定し、そのカスタムケイパビリティをエディターロールには付与しないことで実現できます。
Qロールとケイパビリティを管理するプラグインはありますか?
AUser Role Editorプラグインが広く使われています。GUIでロールのケイパビリティを細かく設定できます。プラグインなしの場合はadd_role()・remove_cap()・add_cap()をfunctions.phpで実装します。

まとめ

ユーザーごとに編集可能な投稿タイプを制限することで、運用の混乱を防ぎ、セキュアで役割分担された管理画面を実現できます。

複数投稿タイプを運用する大規模サイトや組織サイトでは、こうした制御は非常に有効です。post-new.phpでの既定タイプの扱いと、組み込みの投稿タイプもメニュー制御の対象に含めることを忘れないようにしましょう。