「カテゴリーで絞り込んでから一括編集したいのに、できない…」

WordPressのカテゴリーのドロップダウンで絞り込んだ状態では、一括操作でカテゴリーを変更できないという制限があります。これはWordPressの仕様なのですが、代わりにカラムヘッダーをクリックしてソートできるようにすれば、同じカテゴリーの記事をまとめて選択→一括編集が可能になります。

この記事では、

  • 固定ページにもカテゴリー・タグを追加
  • カテゴリー管理画面にID列を追加
  • 投稿ページ・固定ページ一覧で「カテゴリー」「投稿者」「タグ」のカラムをクリックしてソート

functions.phpに追加するだけで使える実践的なカスタマイズコードを紹介します。

    完成イメージ

    カスタマイズ後は、投稿一覧・固定ページ一覧で「カテゴリー」「投稿者」「タグ」のヘッダーをクリックすると、昇順・降順でソートできるようになります。

    これにより、同じカテゴリーの記事がまとまって表示されるので、チェックボックスで選択→一括操作でカテゴリー変更、といった作業が効率的に行えます。

    実装コード(functions.php)

    以下のコードをテーマのfunctions.phpに追加してください。子テーマを使用している場合は、子テーマのfunctions.phpに追加することをおすすめします。

    <?php
    /**
     * WordPress管理画面カスタマイズ
     * - 投稿・固定ページ一覧のソート機能追加
     * - 固定ページへのカテゴリー・タグ追加
     * - カテゴリー一覧へのID列追加
     */
    
    /* ■カテゴリー・タグ設定
    ====================================== */
    /* 固定ページにカテゴリーとタグを追加 */
    function add_taxonomy_to_pages() {
        register_taxonomy_for_object_type('category', 'page');
        register_taxonomy_for_object_type('post_tag', 'page');
    }
    add_action('init', 'add_taxonomy_to_pages');
    
    /* カテゴリー・タグアーカイブに固定ページを含める */
    function add_page_to_archive($query) {
        if (!is_admin() && $query->is_main_query()) {
            if ($query->is_category() || $query->is_tag()) {
                $query->set('post_type', array('post', 'page'));
            }
        }
    }
    add_action('pre_get_posts', 'add_page_to_archive');
    
    /* カテゴリー一覧に「ID」列を追加 */
    function add_category_columns_id($columns) {
        $columns['category_id'] = 'ID';
        return $columns;
    }
    add_filter('manage_edit-category_columns', 'add_category_columns_id');
    
    /* ID列にデータを表示 */
    function show_category_id_column($content, $column_name, $term_id) {
        if ($column_name === 'category_id') {
            return $term_id;
        }
        return $content;
    }
    add_filter('manage_category_custom_column', 'show_category_id_column', 10, 3);
    
    /* ID列をソート可能にする */
    function make_category_id_sortable($columns) {
        $columns['category_id'] = 'term_id';
        return $columns;
    }
    add_filter('manage_edit-category_sortable_columns', 'make_category_id_sortable');
    
    
    /* ■投稿・固定ページ一覧のソート機能追加
    ====================================== */
    /* 投稿一覧のカラムをソート可能にする(カテゴリー・投稿者・タグ) */
    function make_post_columns_sortable($columns) {
        $columns['categories'] = 'category_name';
        $columns['author']     = 'author';
        $columns['tags']       = 'tag_name';
        return $columns;
    }
    add_filter('manage_edit-post_sortable_columns', 'make_post_columns_sortable');
    
    /* 固定ページ一覧のカラムをソート可能にする(カテゴリー・投稿者・タグ) */
    function make_page_columns_sortable($columns) {
        $columns['categories'] = 'category_name';
        $columns['author']     = 'author';
        $columns['tags']       = 'tag_name';
        return $columns;
    }
    add_filter('manage_edit-page_sortable_columns', 'make_page_columns_sortable');
    
    /* 固定ページ一覧にカテゴリー・タグカラムを追加 */
    function add_taxonomy_columns_to_pages($columns) {
        //authorの後ろにカテゴリーとタグを追加
        $new_columns = array();
        foreach ($columns as $key => $value) {
            $new_columns[$key] = $value;
            if ($key === 'author') {
                $new_columns['categories'] = 'カテゴリー';
                $new_columns['tags'] = 'タグ';
            }
        }
        return $new_columns;
    }
    add_filter('manage_pages_columns', 'add_taxonomy_columns_to_pages');
    
    /* 固定ページ一覧のカテゴリー・タグカラムにデータを表示 */
    function show_taxonomy_columns_on_pages($column_name, $post_id) {
        if ($column_name === 'categories') {
            $categories = get_the_category($post_id);
            if (!empty($categories)) {
                $cat_links = array();
                foreach ($categories as $cat) {
                    $cat_links[] = '<a href="' . esc_url(admin_url('edit.php?post_type=page&category_name=' . $cat->slug)) . '">' . esc_html($cat->name) . '</a>';
                }
                echo implode(', ', $cat_links);
            } else {
                echo '—';
            }
        }
        
        if ($column_name === 'tags') {
            $tags = get_the_tags($post_id);
            if (!empty($tags)) {
                $tag_links = array();
                foreach ($tags as $tag) {
                    $tag_links[] = '<a href="' . esc_url(admin_url('edit.php?post_type=page&tag=' . $tag->slug)) . '">' . esc_html($tag->name) . '</a>';
                }
                echo implode(', ', $tag_links);
            } else {
                echo '—';
            }
        }
    }
    add_action('manage_pages_custom_column', 'show_taxonomy_columns_on_pages', 10, 2);
    
    /* カテゴリー・タグでのソート処理(投稿・固定ページ共通) */
    function sort_posts_by_taxonomy($query) {
        if (!is_admin() || !$query->is_main_query()) {
            return;
        }
    
        $screen = get_current_screen();
        if (!$screen || !in_array($screen->id, array('edit-post', 'edit-page'), true)) {
            return;
        }
    
        $orderby = $query->get('orderby');
    
        //カテゴリーでソート
        if ($orderby === 'category_name') {
            add_filter('posts_clauses', 'sort_by_category_clauses');
        }
    
        //タグでソート
        if ($orderby === 'tag_name') {
            add_filter('posts_clauses', 'sort_by_tag_clauses');
        }
    }
    add_action('pre_get_posts', 'sort_posts_by_taxonomy');
    
    /* カテゴリーでソートするためのSQL句を追加 */
    function sort_by_category_clauses($clauses) {
        global $wpdb;
    
        $clauses['join'] .= " LEFT JOIN (
            SELECT object_id, GROUP_CONCAT(t.name ORDER BY t.name ASC SEPARATOR ', ') as category_names
            FROM {$wpdb->term_relationships} tr
            INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'category'
            INNER JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
            GROUP BY object_id
        ) as cat_sort ON {$wpdb->posts}.ID = cat_sort.object_id";
    
        $order = strtoupper(get_query_var('order')) === 'ASC' ? 'ASC' : 'DESC';
        $clauses['orderby'] = "COALESCE(cat_sort.category_names, '') {$order}, " . $clauses['orderby'];
    
        //フィルターを1回だけ実行
        remove_filter('posts_clauses', 'sort_by_category_clauses');
    
        return $clauses;
    }
    
    /* タグでソートするためのSQL句を追加 */
    function sort_by_tag_clauses($clauses) {
        global $wpdb;
    
        $clauses['join'] .= " LEFT JOIN (
            SELECT object_id, GROUP_CONCAT(t.name ORDER BY t.name ASC SEPARATOR ', ') as tag_names
            FROM {$wpdb->term_relationships} tr
            INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id AND tt.taxonomy = 'post_tag'
            INNER JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
            GROUP BY object_id
        ) as tag_sort ON {$wpdb->posts}.ID = tag_sort.object_id";
    
        $order = strtoupper(get_query_var('order')) === 'ASC' ? 'ASC' : 'DESC';
        $clauses['orderby'] = "COALESCE(tag_sort.tag_names, '') {$order}, " . $clauses['orderby'];
    
        //フィルターを1回だけ実行
        remove_filter('posts_clauses', 'sort_by_tag_clauses');
    
        return $clauses;
    }
    
    
    /* カテゴリー管理画面用のCSS */
    function admin_custom_styles() {
        $screen = get_current_screen();
        
        if ($screen && $screen->id === 'edit-category') {
            echo '<style>
                .fixed .column-posts { width: 94px; }
                .manage-column.column-category_id { width: 54px; }
            </style>';
        }
    }
    add_action('admin_head', 'admin_custom_styles');
    

    コードの解説

    1. 固定ページにカテゴリー・タグを追加

    register_taxonomy_for_object_type()を使って、固定ページ(page)にカテゴリーとタグを関連付けています。

    register_taxonomy_for_object_type('category', 'page');
    register_taxonomy_for_object_type('post_tag', 'page');
    

    これだけで固定ページの編集画面にカテゴリー・タグの選択UIが表示されるようになります。

    2. ソート可能カラムの登録

    manage_edit-{post_type}_sortable_columnsフィルターを使って、ソート可能なカラムを追加しています。

    $columns['categories'] = 'category_name';  // カテゴリーカラム
    $columns['author']     = 'author';         // 投稿者カラム
    $columns['tags']       = 'tag_name';       // タグカラム
    

    配列のキーがカラム名、値がソート時に使用するorderbyパラメータです。

    3. カテゴリー・タグのソート処理

    WordPressの標準機能では、カテゴリーやタグでのソートはサポートされていません。そのため、posts_clausesフィルターを使ってSQLクエリを直接カスタマイズしています。

    ポイントはGROUP_CONCATを使っている点です。1つの投稿に複数のカテゴリー・タグが設定されている場合、それらをカンマ区切りで連結した文字列としてソートします。

    GROUP_CONCAT(t.name ORDER BY t.name ASC SEPARATOR ', ')
    

    例えば、「API, PHP, WordPress」という3つのタグが付いた記事は、「API, PHP, WordPress」という文字列としてソートされます。

    カスタム投稿タイプに対応させるには

    カスタム投稿タイプ(例:product)にも同じ機能を追加したい場合は、以下のように変更してください。

    // ソート可能カラムの登録を追加
    add_filter('manage_edit-product_sortable_columns', 'make_post_columns_sortable');
    
    // ソート処理の対象画面を追加
    if (!$screen || !in_array($screen->id, array('edit-post', 'edit-page', 'edit-product'), true)) {
        return;
    }
    

    まとめ

    WordPressの管理画面は、少しのカスタマイズで大幅に使いやすくなります。特に記事数が増えてくると、カテゴリーやタグでのソート機能は作業効率に直結します。

    カテゴリーの絞り込みドロップダウンでは一括編集ができないという制限も、ソート機能があればカバーできます。ぜひ活用してみてください。