プラグインなしで管理画面のメインナビゲーションのメニューを並び替える方法

Cocoonカスタマイズ集
この記事は約12分で読めます。
記事内に広告が含まれています。

はじめに

WordPressの管理画面を運用していると、メインナビゲーション(サイドバーにある)のメニューの順番がデフォルトのままで使いにくいと感じることはありませんか?
特にプラグインを多く導入するとメニューがどんどん増え、頻繁に使う「投稿」や「固定ページ」が埋もれてしまい、日々の更新作業にストレスがかかることも少なくありません。

そこで、プラグイン「Admin Menu Editor」などを使用せずに、ダッシュボードに管理メニューをドラッグ操作で並び替える機能を追加します。

この記事では、この方法について説明します。

完成イメージ

実装手順

以下のコードをfunctions.phpに追加します。

// 管理画面にメニューを追加
add_action('admin_menu', function () {
  add_submenu_page(
    'index.php',
    'メニュー並び替え',
    'メニュー並び替え',
    'manage_options',
    'menu_order',
    'render_menu_order'
  );
});


/**
 * 管理画面ページを出力
 *
 * @return void
 */
if (!function_exists('render_menu_order')):
function render_menu_order() {
  global $menu;

  ?>
  <div class="wrap menu-order">
    <!-- 画面の見出し -->
    <h1>メニュー並び替え設定</h1>
    <!-- 画面の説明文 -->
    <p>ドラッグ&ドロップで管理画面のメインナビゲーション(サイドバー)の並び順を変更できます。</p>

    <!-- メニュー並び替え用フォーム -->
    <form id="menu-order__form" class="menu-order__form" method="post" action="">
      <?php
      wp_nonce_field('menu_order_action', 'menu_order_nonce');
      ?>
      <!-- JSで取得したメニューの並び順(JSON文字列)を保持する隠し要素 -->
      <input type="hidden" id="menu-order__data" name="menu_order_data" value="">

      <!-- 並び替え可能なメニュー項目のリスト -->
      <ul id="menu-order__list" class="menu-order__list">
        <?php
        // メニュー項目を取得
        foreach ($menu as $item) {
          // タイトルのない項目を処理対象外
          if (empty($item[0])) {
            continue;
          }

          // メニュータイトルのHTMLタグを置換
          $title = wp_strip_all_tags($item[0]);
          // メニューのスラグを取得
          $slug = $item[2];
          ?>
          <!-- ドラッグ可能なリスト要素(スラグを属性に保持) -->
          <li class="menu-order__item" data-slug="<?php echo esc_attr($slug); ?>">
            <!-- ドラッグ用のハンドル領域 -->
            <div class="menu-order__handle">
              <!-- グリップアイコン -->
              <span class="menu-order__grip">⋮⋮</span>
              <!-- エスケープ処理してメニュータイトルを出力 -->
              <?php echo esc_html($title); ?>
            </div>
          </li>
          <?php
        }
        ?>
      </ul>

      <!-- 送信ボタンエリア -->
      <p class="menu-order__submit">
        <?php submit_button('設定を保存', 'primary', 'save_menu_order', false); ?>
        <input type="submit" name="reset_menu_order" id="menu-order__reset" class="button button-link-delete" value="初期にリセット" onclick="return confirm('並び順を初期化してもよろしいですか?');" />
      </p>
    </form>
  </div>
  <?php
}
endif;


// 管理画面用JS・CSSを追加
add_action('admin_enqueue_scripts', function () {
  if (($_GET['page'] ?? '') !== 'menu_order') {
    return;
  }

  ob_start();
  ?>
  .menu-order__list {
    background-color: #fff;
    border: 1px solid #ccd0d4;
    border-radius: 4px;
    max-width: 600px;
    margin-top: 20px;
    padding: 10px;
  }

  .menu-order__item {
    border: 1px solid #dcdcde;
    border-radius: 3px;
    margin-bottom: 8px;
  }

  .menu-order__item:last-child {
    margin-bottom: 0;
  }

  .menu-order__handle {
    align-items: center;
    background-color: #f6f7f7;
    cursor: move;
    display: flex;
    font-weight: bold;
    padding: 8px 12px;
  }

  .menu-order__grip {
    color: #8c8f94;
    letter-spacing: -1px;
    margin-right: 8px;
  }

  .menu-order__placeholder {
    background-color: #f0f6fc;
    border: 1px dashed #2271b1;
    border-radius: 3px;
    height: 36px;
    margin-bottom: 8px;
  }

  .menu-order__submit .button-link-delete {
    margin-left: 10px;
  }
  <?php
  wp_add_inline_style('wp-admin', ob_get_clean());

  ob_start();
  ?>
  jQuery(function ($) {
    // リストをドラッグ&ドロップで並び替え
    $('#menu-order__list').sortable({
      handle: '.menu-order__handle',
      items: '> .menu-order__item',
      axis: 'y',
      opacity: 0.7,
      placeholder: 'menu-order__placeholder',
      forcePlaceholderSize: true
    });

    // フォーム送信時の処理
    $('#menu-order__form').on('submit', function () {
      // リセットボタンの場合は順序収集をスキップ
      if ($(document.activeElement).attr('name') === 'reset_menu_order') {
        return true;
      }

      // 順序データを保持する配列を設定
      var orderData = [];

      // リスト項目からスラグを取得
      $('#menu-order__list > .menu-order__item').each(function () {
        // 配列にスラグを登録
        orderData.push($(this).data('slug'));
      });

      // 配列をJSON化して隠しフィールドに設定
      $('#menu-order__data').val(JSON.stringify(orderData));
    });
  });
  <?php

  wp_enqueue_script('jquery-ui-sortable');
  wp_add_inline_script('jquery-ui-sortable', ob_get_clean());
});


// 管理画面からの設定データ更新
add_action('admin_init', function () {
  // nonceチェック
  if (!isset($_POST['menu_order_nonce']) || !wp_verify_nonce($_POST['menu_order_nonce'], 'menu_order_action')) {
    return;
  }

  // 権限チェック
  if (!current_user_can('manage_options')) {
    return;
  }

  // リセット処理
  if (isset($_POST['reset_menu_order'])) {
    delete_option('my_menu_order');

    set_transient('my_admin_notice', [
      'type'    => 'success',
      'message' => 'メニューの並び順をリセットしました。',
    ], 30);

    wp_safe_redirect(admin_url('index.php?page=menu_order'));
    exit;
  }

  // POSTデータを取得
  if (empty($_POST['menu_order_data'])) {
    set_transient('my_admin_notice', [
      'type'    => 'error',
      'message' => 'データの保存に失敗しました。',
    ], 30);

    wp_safe_redirect(admin_url('index.php?page=menu_order'));
    exit;
  }

  // 送信されたJSON文字列をデコード
  $order = json_decode(stripslashes($_POST['menu_order_data']), true);

  // 配列であることを確認
  if (!is_array($order)) {
    set_transient('my_admin_notice', [
      'type'    => 'error',
      'message' => 'データの保存に失敗しました。',
    ], 30);

    wp_safe_redirect(admin_url('index.php?page=menu_order'));
    exit;
  }

  $sanitized_order = [];

  // 送信データをループ処理
  foreach ($order as $slug) {
    if (is_string($slug) && $slug !== '') {
      $sanitized_order[] = sanitize_text_field($slug);
    }
  }

  // 有効なデータを処理対象外
  if (empty($sanitized_order)) {
    set_transient('my_admin_notice', [
      'type'    => 'error',
      'message' => 'データの保存に失敗しました。',
    ], 30);

    wp_safe_redirect(admin_url('index.php?page=menu_order'));
    exit;
  }

  // 並び順をデータベースに登録
  update_option('my_menu_order', $sanitized_order);

  set_transient('my_admin_notice', [
    'type'    => 'success',
    'message' => 'メニューの並び順を保存しました。',
  ], 30);

  wp_safe_redirect(admin_url('index.php?page=menu_order'));
  exit;
});


// 通知メッセージを出力
add_action('admin_notices', function () {
  if ($notice = get_transient('my_admin_notice')) {
    echo '<div class="notice notice-' . esc_attr($notice['type']) . ' is-dismissible"><p>' . esc_html($notice['message']) . '</p></div>';
    delete_transient('my_admin_notice');
  }
});


// カスタムメニュー順序の有効化
add_filter('custom_menu_order', '__return_true');

// 管理メニューの表示順序を変更
add_filter('menu_order', function ($menu_order) {
  // データベースからカスタム順序設定を取得
  $custom_order = get_option('my_menu_order', []);

  if (empty($custom_order)) {
    return $menu_order;
  }

  // デフォルト順序のキーと値を反転して元の位置情報を保持
  $original_positions = array_flip($menu_order);

  // カスタム順序に基づいてソートを実行
  usort($menu_order, function ($a, $b) use ($custom_order, $original_positions) {
    // 項目のカスタム順序内での位置を取得
    $pos_a = array_search($a, $custom_order, true);
    $pos_b = array_search($b, $custom_order, true);

    if ($pos_a === false && $pos_b === false) {
      return $original_positions[$a] - $original_positions[$b];
    }

    if ($pos_a === false) {
      return 1;
    }

    if ($pos_b === false) {
      return -1;
    }

    return $pos_a - $pos_b;
  });

  return $menu_order;
});

さいごに

今回紹介した方法を使えば、プラグインを使わずに、管理画面のメインナビゲーションのメニューを自由にドラッグで並び替えることができます。
自分好みの順序で管理画面をカスタマイズできるため、作業効率の向上や画面の見やすさを大幅に改善できます。

タイトルとURLをコピーしました