コンテンツにスキップ

コンテンツ制限機能 仕様書

作成日: 2025-12-29
ステータス: 仕様確定
プラグイン名: inportal-content-restriction


1. 概要

1.1 目的

北日本造船株式会社の社員と外部会社ユーザーで、閲覧可能なコンテンツ・機能を分けるためのアクセス制御機能。

1.2 対象ユーザー分類

分類 判定条件 備考
社内ユーザー ipa_company = 北日本造船㈱ 判定値は管理画面で変更可能
外部ユーザー 上記以外の全ユーザー グループ会社、協力会社など

1.3 前提条件

  • 未ログインユーザーは全コンテンツ閲覧不可(既存のサイトパスワード保護で対応済み)
  • ログイン済みユーザーのみが本機能の対象

2. 機能一覧

機能 説明
投稿/ページ単位の制限 投稿・固定ページごとに「社内のみ」設定
一括設定 投稿一覧画面で複数投稿を一括設定
メニュー項目の制限 ドロワーメニューの機能別表示/非表示
直接URLアクセス防止 制限コンテンツへの直接アクセス時はリダイレクト
管理画面設定 判定値・メニュー設定を管理画面で変更可能

3. 投稿/ページ単位の制限

3.1 設定方法

投稿編集画面

┌──────────────────────────────────────┐
│ 公開                                  │
├──────────────────────────────────────┤
│ ステータス: 公開済み                   │
│ 公開日: 2025年12月29日                │
│                                      │
│ ☑ 社内のみ表示                        │
│   (外部ユーザーには非表示になります)  │
└──────────────────────────────────────┘

投稿一覧画面

┌────────────────────────────────────────────────────────────────┐
│ 一括操作 ▼  [適用]    □ タイトル        公開範囲    日時      │
├────────────────────────────────────────────────────────────────┤
│ ☑ 社内のみに設定      □ 記事タイトル1   🔒社内のみ  12/28     │
│ ☐ 全員に公開          □ 記事タイトル2   🌐全員     12/27     │
│                       □ 記事タイトル3   🌐全員     12/26     │
└────────────────────────────────────────────────────────────────┘

3.2 データ構造

項目
メタキー _inportal_internal_only
制限あり 1
制限なし 空(メタなし)

3.3 表示制御ロジック

// 投稿クエリフィルター(一覧・検索結果)
add_action('pre_get_posts', function($query) {
    if (is_admin() || !$query->is_main_query()) return;

    $user_company = get_user_meta(get_current_user_id(), 'ipa_company', true);
    $internal_company = get_option('icr_internal_company', '北日本造船㈱');
    $is_internal = ($user_company === $internal_company);

    if (!$is_internal) {
        $meta_query = $query->get('meta_query') ?: [];
        $meta_query[] = [
            'relation' => 'OR',
            ['key' => '_inportal_internal_only', 'compare' => 'NOT EXISTS'],
            ['key' => '_inportal_internal_only', 'value' => '1', 'compare' => '!='],
        ];
        $query->set('meta_query', $meta_query);
    }
});

// 単一投稿アクセス制御
add_action('template_redirect', function() {
    if (!is_singular()) return;

    $post_id = get_queried_object_id();
    $is_internal_only = get_post_meta($post_id, '_inportal_internal_only', true);

    if ($is_internal_only === '1') {
        $user_company = get_user_meta(get_current_user_id(), 'ipa_company', true);
        $internal_company = get_option('icr_internal_company', '北日本造船㈱');

        if ($user_company !== $internal_company) {
            // 専用エラーページへリダイレクト
            wp_redirect(home_url('/?content_restricted=1'));
            exit;
        }
    }
});

3.4 エラーページ

制限コンテンツへの直接アクセス時は、専用のエラーページを表示:

┌──────────────────────────────────────────────────┐
│                                                  │
│              このページは表示できません            │
│                                                  │
│                [ホームへ戻る]                     │
│                                                  │
└──────────────────────────────────────────────────┘

※「アクセス権限がありません」のような表現は避け、柔らかい表現を使用

3.5 ホーム画面のUI要素制御

ドロワーメニューだけでなく、以下のホーム画面要素も制限対象:

要素 説明
ダッシュボードカード 出勤ボード、ポイント表示など
アクショングリッド 機能一覧のグリッドアイテム
ドロワーメニュー サイドメニューのリンク

すべての導線から制限機能を非表示にする


4. メニュー項目の制限

4.1 対象メニュー項目

ID メニュー項目 デフォルト設定 備考
home ホーム 全員
news お知らせ一覧 全員
board 出勤ボード 社内のみ
checkin チェックイン 社内のみ 将来拡張予定
reserve 会議室予約 社内のみ
times 社内報 社内のみ KITA Times
knowledge ナレッジヤード 社内のみ 外部リンク
point ポイント管理 全員
suggestion 目安箱 全員 新規追加
instagram 公式Instagram 全員 外部リンク

4.2 管理画面設定

設定 → コンテンツ制限
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

■ 基本設定

  社内ユーザーの判定値
  ┌────────────────────────────────────────────┐
  │ 北日本造船㈱                               │
  └────────────────────────────────────────────┘
  ※ユーザーメタ「ipa_company」の値と比較します

■ メニュー項目の公開設定

  ┌──────────────────────────────────────────────────────────┐
  │ 機能名              │ 社内のみ │ 全員   │                │
  ├──────────────────────────────────────────────────────────┤
  │ ホーム              │ ○       │ ●      │                │
  │ お知らせ一覧        │ ○       │ ●      │                │
  │ 出勤ボード          │ ●       │ ○      │                │
  │ チェックイン        │ ●       │ ○      │ ※将来拡張予定  │
  │ 会議室予約          │ ●       │ ○      │                │
  │ 社内報              │ ●       │ ○      │                │
  │ ナレッジヤード      │ ●       │ ○      │                │
  │ ポイント管理        │ ○       │ ●      │                │
  │ 目安箱              │ ○       │ ●      │                │
  │ 公式Instagram       │ ○       │ ●      │                │
  └──────────────────────────────────────────────────────────┘

                                        [変更を保存]

4.3 オプション構造

// wp_options テーブル
$options = [
    'icr_internal_company' => '北日本造船㈱',  // 社内判定値
    'icr_menu_restrictions' => [
        'home' => 'all',           // 'all' = 全員, 'internal' = 社内のみ
        'news' => 'all',
        'board' => 'internal',
        'checkin' => 'internal',
        'reserve' => 'internal',
        'times' => 'internal',
        'knowledge' => 'internal',
        'point' => 'all',
        'suggestion' => 'all',
        'instagram' => 'all',
    ],
];

4.4 テーマ側の実装

// template-parts/app-header.php

// プラグインからヘルパー関数を使用
$is_internal_user = icr_is_internal_user();
$menu_restrictions = get_option('icr_menu_restrictions', []);

// メニュー項目の表示判定
function icr_can_show_menu($menu_id) {
    $restrictions = get_option('icr_menu_restrictions', []);
    $restriction = $restrictions[$menu_id] ?? 'all';

    if ($restriction === 'all') {
        return true;
    }

    return icr_is_internal_user();
}

// 使用例
<?php if (icr_can_show_menu('board')): ?>
    <li class="app-drawer__item">
        <a href="<?php echo esc_url(home_url('/?ipa_board_view=1')); ?>" ...>
            出勤ボード
        </a>
    </li>
<?php endif; ?>

5. ヘルパー関数

プラグインが提供するグローバル関数:

/**
 * 現在のユーザーが社内ユーザーかどうか判定
 * 
 * @return bool
 */
function icr_is_internal_user(): bool {
    if (!is_user_logged_in()) {
        return false;
    }

    $user_company = get_user_meta(get_current_user_id(), 'ipa_company', true);
    $internal_company = get_option('icr_internal_company', '北日本造船㈱');

    return $user_company === $internal_company;
}

/**
 * 指定メニュー項目を表示してよいか判定
 * 
 * @param string $menu_id メニューID
 * @return bool
 */
function icr_can_show_menu(string $menu_id): bool {
    $restrictions = get_option('icr_menu_restrictions', []);
    $restriction = $restrictions[$menu_id] ?? 'all';

    if ($restriction === 'all') {
        return true;
    }

    return icr_is_internal_user();
}

/**
 * 指定投稿が社内のみかどうか判定
 * 
 * @param int $post_id 投稿ID
 * @return bool
 */
function icr_is_internal_only_post(int $post_id): bool {
    return get_post_meta($post_id, '_inportal_internal_only', true) === '1';
}

6. 将来拡張予定

6.1 チェックイン機能の分離

現在「チェックイン」は一つのメニュー項目ですが、将来的に以下のように分離予定:

場所タイプ 説明 公開設定
会議室 (room) 本社・工場の会議室 社内のみ
現場 (site) 作業現場・工場ゲート 全員

実装方針: 1. wp_locations テーブルに is_internal_only カラムを追加 2. 場所ごとに公開設定を持たせる 3. チェックイン画面で場所タイプ選択時にフィルタリング

6.2 カテゴリベースの制限

将来的に、投稿カテゴリ単位での制限も検討:

カテゴリ「社内報」 → 社内のみ
カテゴリ「お知らせ」 → 全員

7. 管理画面メニュー構成

設定
└── コンテンツ制限
    ├── 基本設定(社内判定値)
    └── メニュー制限設定

8. セキュリティ考慮事項

リスク 対策
直接URLアクセス template_redirect フックでリダイレクト
REST API アクセス 必要に応じてAPIにも同様のフィルター適用
キャッシュ問題 ユーザー別キャッシュ or キャッシュ無効化
検索結果漏洩 pre_get_posts で除外

9. テスト項目

  • [ ] 社内ユーザーで制限コンテンツが表示される
  • [ ] 外部ユーザーで制限コンテンツが非表示
  • [ ] 外部ユーザーで直接URLアクセス時にリダイレクト
  • [ ] 投稿編集画面でチェックボックスが機能する
  • [ ] 投稿一覧で一括設定が機能する
  • [ ] 管理画面で判定値を変更できる
  • [ ] 管理画面でメニュー制限を変更できる
  • [ ] ドロワーメニューで制限項目が非表示になる