【WordPress】投稿一覧ページにカスタム並び順をドラッグ&ドロップで実装する方法

【WordPress】投稿一覧ページにカスタム並び順をドラッグ&ドロップで実装する方法 WordPress

WordPressでは通常、投稿一覧は公開日やタイトルなどで自動的に並びますが、管理画面で直感的に並び順を変更したいというケースもあります。特にカスタム投稿タイプでは「表示順を自由に変更したい」というニーズが高く、ドラッグ&ドロップによる並び替えが非常に便利です。

この記事では、管理画面でドラッグ&ドロップによる投稿の並び順を実装する方法を解説します。

スポンサーリンク

ステップ1:投稿に「menu_order」サポートを追加する

まず、対象の投稿タイプ(例:postやnews)にpage-attributesをサポートさせ、menu_orderで並び順を管理できるようにします。

functions.php:page-attributesサポートの追加
function add_menu_order_support() {
  add_post_type_support('post', 'page-attributes');
  // カスタム投稿タイプにも追加可能
  // add_post_type_support('news', 'page-attributes');
}
add_action('init', 'add_menu_order_support');

ステップ2:並び順を反映するための並び替え条件を指定

pre_get_postsフックを使い、管理画面での投稿一覧をmenu_orderによる並び順に変更します。

functions.php:管理画面でのソート順変更
function set_admin_order_by_menu_order($query) {
  if (is_admin() && $query->is_main_query() && $query->get('post_type') === 'post') {
    $query->set('orderby', 'menu_order');
    $query->set('order', 'ASC');
  }
}
add_action('pre_get_posts', 'set_admin_order_by_menu_order');

この処理により、投稿一覧がmenu_order順で表示されます。

ステップ3:管理画面にドラッグ&ドロップ機能を追加

以下のコードをfunctions.phpに追加して、JavaScriptによる並び替えUIを管理画面に挿入します。

functions.php:ドラッグ&ドロップ用スクリプトの読み込み
function enqueue_drag_drop_script($hook) {
  if ($hook !== 'edit.php') return;

  // edit.phpは全投稿タイプ共通のフックサフィックスのため、post以外の
  // 一覧画面に機能が漏れないよう投稿タイプも確認する
  $current_post_type = isset($_GET['post_type']) ? sanitize_key($_GET['post_type']) : 'post';
  if ($current_post_type !== 'post') return;

  wp_enqueue_script('jquery-ui-sortable');
  wp_enqueue_script('custom-order-script', get_stylesheet_directory_uri() . '/js/custom-order.js', array('jquery', 'jquery-ui-sortable'), null, true);

  // Ajax用データ
  wp_localize_script('custom-order-script', 'customOrderAjax', array(
    'ajax_url' => admin_url('admin-ajax.php'),
    'nonce'    => wp_create_nonce('custom_order_nonce'),
  ));
}
add_action('admin_enqueue_scripts', 'enqueue_drag_drop_script');
edit.phpは全投稿タイプ共通のフックサフィックス
admin_enqueue_scriptsで渡される$hookは、投稿タイプに関わらず一覧画面であれば常にedit.phpになります。投稿タイプの判定を省略すると、post専用のつもりで実装したドラッグ&ドロップ機能や並び替えAjaxが、固定ページやカスタム投稿タイプなど他の一覧画面にも読み込まれてしまいます。get_template_directory_uri()(親テーマのURLを返す関数)を使うと子テーマ環境で読み込みが404になる点もあわせて注意してください。正しくはget_stylesheet_directory_uri()を使います。

次に、テーマディレクトリにjs/custom-order.jsを作成し、以下のコードを記述します。

js/custom-order.js
jQuery(document).ready(function ($) {
  var $tbody = $('tbody');

  $tbody.sortable({
    items: 'tr',
    cursor: 'move',
    update: function () {
      var order = [];
      $tbody.find('tr').each(function (i, el) {
        var id = $(el).attr('id').replace('post-', '');
        order.push(id);
      });

      $.post(customOrderAjax.ajax_url, {
        action: 'save_custom_order',
        order: order,
        nonce: customOrderAjax.nonce
      });
    }
  });
});

ステップ4:並び順を保存するAjax処理を追加

Ajaxで送信された並び順を保存するため、functions.phpに以下の処理を追加します。

functions.php:並び順保存のAjaxハンドラー
function save_custom_order() {
  check_ajax_referer('custom_order_nonce', 'nonce');

  if (!current_user_can('edit_posts')) {
    wp_send_json_error('許可されていません');
  }

  $order = isset($_POST['order']) ? $_POST['order'] : array();

  foreach ($order as $menu_order => $post_id) {
    $post_id = intval($post_id);

    // 投稿ごとに編集権限を確認する(他人の投稿を書き換えられないようにする)
    if (!current_user_can('edit_post', $post_id)) {
      continue;
    }

    wp_update_post(array(
      'ID'         => $post_id,
      'menu_order' => intval($menu_order),
    ));
  }

  wp_send_json_success('並び順を更新しました');
}
add_action('wp_ajax_save_custom_order', 'save_custom_order');
投稿ごとの編集権限も確認する
current_user_can('edit_posts')は「投稿を編集する権限があるか」という包括的なチェックで、送信されたorder配列に含まれる個々の投稿IDに対する編集権限までは保証しません。このチェックだけでは、寄稿者(Contributor)権限のユーザーが他人の投稿や本来編集できないはずの投稿のmenu_orderを書き換えられてしまう可能性があります。ループ内でcurrent_user_can('edit_post', $post_id)を個別に確認し、権限がない投稿はスキップするようにしましょう。

ステップ5:並び順の見た目を調整する(オプション)

並び替えを明確にするため、管理画面の投稿一覧にIDやmenu_order列を追加すると便利です。

functions.php:順番列の追加(post専用)
function add_menu_order_column($columns) {
  $columns['order'] = '順番';
  return $columns;
}
add_filter('manage_post_posts_columns', 'add_menu_order_column');

function show_menu_order_column($column_name, $post_id) {
  if ($column_name === 'order') {
    echo get_post_field('menu_order', $post_id);
  }
}
add_action('manage_post_posts_custom_column', 'show_menu_order_column', 10, 2);

manage_posts_columnsmanage_posts_custom_columnは固定ページ以外のすべての投稿タイプに適用される汎用フックのため、postだけに限定したい場合は上記のようにpost専用のmanage_post_posts_columnsmanage_post_posts_custom_columnを使ってください。

関連記事

よくある質問(FAQ)

Q管理画面の記事一覧でドラッグ&ドロップの並び替えを実装するには?
AjQueryのSortableウィジェットで並び替えUIを実装し、orderの変更をAjaxで送信します。PHPハンドラーでwp_update_post()のmenu_orderを更新します。既存プラグインではSimple Custom Post Order等があります。
Q並び替えた順序をフロントエンドに反映するには?
Amenu_orderを保存した後、WP_Queryのorderby=menu_orderとorder=ASCでクエリします。フロントエンドのテンプレートまたはpre_get_postsフックで設定します。
Q並び替えをカテゴリーごとに独立して管理するには?
Amenu_orderはグローバルなためカテゴリーごとの独立した並び順にはカスタムメタデータが必要です。カテゴリーIDをキーにした配列を記事のpost_metaに保存する方法があります。

まとめ

WordPress管理画面でドラッグ&ドロップによる並び替えを実装することで、投稿の表示順を自由に制御できるようになります。とくにカスタム投稿タイプやトップページに表示する特定記事の順序管理に効果的です。

menu_orderを利用すれば、テンプレート側でも簡単に並び順を取得できるため、フロントと管理両面で一貫性のある出力が可能になります。投稿タイプの限定漏れやAjaxハンドラーの権限チェックに注意し、安全に実装しましょう。