ウィジェット画面のウィジェット一覧の並び順を変更する方法

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

はじめに

外観→ウィジェットを開くと、使利用できるウィジェットの一覧が表示されます。
しかし、この順序はテーマやプラグインで登録された順のまま固定されており、管理画面での作業効率が悪く感じることがあります。

そこで、頻繁に操作するウィジェットをウィジェットエリアを先頭に表示できれば、目的の設定にすぐにアクセスできるようになります。

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

完成イメージ

実装手順

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

add_action('admin_enqueue_scripts', function ($hook_suffix) {
  if ($hook_suffix !== 'widgets.php') {
    return;
  }

  ob_start();
  ?>
  jQuery(function ($) {
    // ウィジェット一覧のコンテナ要素を取得
    const container = $('#widget-list');

    // 上部に配置するウィジェットのベースIDを指定
    const order = [
      'new_entries',
      'popular_entries',
      'categories'
    ];

    // 指定順序の逆順で処理し、対象要素を先頭へ移動
    order.slice().reverse().forEach(function (base) {
      // 指定したベースIDに一致するウィジェット要素を検索
      const el = container.find('[id*="_' + base + '-__i__"]');

      // 対象要素をコンテナの先頭へ移動
      if (el.length) {
        container.prepend(el);
      }
    });
  });
  <?php
  wp_add_inline_script('jquery', ob_get_clean());
});

拡張:ドラッグ&ドロップでウィジェットの表示順を変更する方法

先ほど紹介したコードでは、functions.php内の配列を書き換えることでウィジェットの並び順を固定していました。
しかし、管理者がその都度コードを編集するのは手間がかかります。

そこで、管理画面からドラッグ&ドロップで順序を変更し、その設定を保存できるようにする方法もあります。
この方法なら、ウィジェットを視覚的に並べ替え、保存ボタンで設定を保持し、必要に応じてリセットも可能です。

完成イメージ

実装手順

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

// ウィジェットページに追加
add_action('load-widgets.php', function () {
  $screen = get_current_screen();

  if ($screen->id !== 'widgets') {
    return;
  }

  $nonce_field = wp_nonce_field('widget_order_action', 'widget_order_nonce', true, false);

  ob_start();
  ?>
  <div class="widget-order">
    <form method="post" class="widget-order__form">
      <?= $nonce_field; ?>
      <p style="margin-bottom: 10px; color: #646970;">ドラッグ&ドロップでウィジェットの表示順を変更できます。</p>
      <ul class="widget-order__list"></ul>
      <div class="widget-order__actions">
        <button type="submit" name="save_widget_order" class="button button-primary">保存</button>
        <button type="submit" name="reset_widget_order" class="button button-link-delete">初期にリセット</button>
      </div>
    </form>
  </div>
  <?php
  $content = ob_get_clean();

  // ヘルプタブを画面に追加
  $screen->add_help_tab([
    'id'       => 'widget_order',
    'title'    => 'ウィジェット順序変更',
    'content'  => $content,
    'priority' => 999,
  ]);
});


// 設定データ更新
add_action('load-widgets.php', function () {
  if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    return;
  }

  // nonceチェック
  if (!isset($_POST['widget_order_nonce']) || !wp_verify_nonce($_POST['widget_order_nonce'], 'widget_order_action')) {
    return;
  }

  // 並び順の保存処理
  if (isset($_POST['save_widget_order'])) {
    $order = isset($_POST['widget_order']) ? array_map('sanitize_text_field', $_POST['widget_order']) : [];

    update_option('my_widget_order', $order);

    set_transient('my_admin_notice', '設定を保存しました。', 30);

    wp_safe_redirect(admin_url('widgets.php'));
    exit;
  }

  // 並び順のリセット処理
  if (isset($_POST['reset_widget_order'])) {
    delete_option('my_widget_order');

    set_transient('my_admin_notice', '初期状態にリセットしました。', 30);

    wp_safe_redirect(admin_url('widgets.php'));
    exit;
  }
});


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


// 管理画面用JS・CSSを追加
add_action('admin_enqueue_scripts', function ($hook_suffix) {
  if ($hook_suffix !== 'widgets.php') {
    return;
  }

  ob_start();
  ?>
  .widget-order__list {
    background-color: #fff;
    border: 1px solid #ccd0d4;
    border-radius: 4px;
    max-height: 300px;
    max-width: 400px;
    margin: 10px 0;
    overflow-y: auto;
    padding: 10px;
  }

  .widget-order__list li {
    align-items: center;
    background-color: #f6f7f7;
    border: 1px solid #dcdcde;
    border-radius: 3px;
    cursor: move;
    display: flex;
    margin: 0 0 5px;
    padding: 8px 12px;
  }

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

  .widget-order__actions {
    align-items: center;
    display: flex;
    gap: 10px;
    margin-top: 15px;
  }

  .widget-order__list .ui-state-highlight {
    background-color: #f0f6fc;
    border: 1px dashed #2271b1;
    border-radius: 3px;
    height: 36px;
    margin-bottom: 5px;
  }
  <?php
  wp_add_inline_style('wp-admin', ob_get_clean());

  ob_start();
  ?>
  jQuery(function ($) {
    var $list = $('.widget-order__list');

    /**
     * ウィジェット一覧をヘルプタブのリストに反映
     *
     * @return void
     */
    function loadWidgetsList() {
      $list.empty();
      var current = [];

      // 利用可能なウィジェットからIDとタイトルを取得
      $('#available-widgets .widget').each(function () {
        var id = $(this).attr('id');
        var name = $(this).find('.widget-title h3, .widget-title h4').text().trim();

        if (id && name) {
          current.push({ id: id, name: name });
        }
      });

      // 保存済み順序と現在のウィジェットから最終順序を決定
      var finalOrder = Array.isArray(widgetOrderSaved) && widgetOrderSaved.length
        ? widgetOrderSaved.filter(id => current.some(w => w.id === id))
        : current.map(w => w.id);

      // リスト要素を生成して追加
      finalOrder.forEach(function (id) {
        var w = current.find(w => w.id === id);

        if (w) {
          $list.append('<li class="ui-state-default" data-id="' + w.id + '"><span class="widget-order__grip">⋮⋮</span>' + w.name + '</li>');
        }
      });

      // jQuery UI Sortableを有効化
      $list.sortable({
        placeholder: 'ui-state-highlight',
        forcePlaceholderSize: true
      }).disableSelection();
    }

    // リストを初期化
    loadWidgetsList();

    // フォーム送信時の処理
    $('.widget-order__form').on('submit', function (e) {
      // リセットボタンが押された場合の確認ダイアログ
      if ($(document.activeElement).attr('name') === 'reset_widget_order') {
        if (!confirm('ウィジェットの並び順をデフォルトに戻しますか?')) {
          e.preventDefault();
          return;
        }
      }

      // 既存の隠し入力フィールドを削除
      $('.widget-order__list input.widget-order__hidden').remove();

      // 現在の並び順を隠しフィールドに設定
      $('.widget-order__list li').each(function () {
        $('<input>').attr({
          type: 'hidden',
          name: 'widget_order[]',
          value: $(this).data('id'),
          class: 'widget-order__hidden'
        }).appendTo('.widget-order__form');
      });
    });

    // 保存された並び順を利用可能なウィジェット一覧画面に反映
    if (Array.isArray(widgetOrderSaved) && widgetOrderSaved.length) {
      var container = $('#available-widgets #widget-list');

      widgetOrderSaved.forEach(function (id) {
        var widget = container.find(".widget[id='" + id + "']");

        if (widget.length) {
          widget.detach().appendTo(container);
        }
      });
    }
  });
  <?php

  $saved_order = get_option('my_widget_order', []);
  $saved_order_json = wp_json_encode($saved_order);

  wp_add_inline_script('admin-widgets', 'var widgetOrderSaved = ' . $saved_order_json . ';');
  wp_add_inline_script('admin-widgets', ob_get_clean());
});

さいごに

今回紹介した方法を使えば、管理画面で頻繁に利用するウィジェットエリアを先頭に配置でき、編集作業を効率的に進められます。
特に、Cocoonの新着記事ウィジェットや人気記事ウィジェットなど頻繁に操作するウィジェットを整理する場合に効果的です。

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