「ナビゲーションメニュー」ウィジェットにドロップダウン表示を追加する方法

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

はじめに

以下の質問に回答します。

「ナビゲーションメニュー」ウィジェットには、ドロップダウン表示機能がありません。

そこで、「タグクラウド」ウィジェットに「ドロップダウンで表示」メニューを追加します。

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

完成イメージ

実装手順

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

// ウィジェットに設定メニューを追加
add_action('in_widget_form', function ($widget, $return, $instance) {
  if ($widget->id_base !== 'nav_menu') {
    return;
  }

  $dropdown = !empty($instance['dropdown']);

  ?>
  <p>
    <input type="checkbox" id="<?= $widget->get_field_id('dropdown'); ?>" class="widefat" name="<?= $widget->get_field_name('dropdown'); ?>" value="1" <?php checked($dropdown); ?>>
    <label for="<?= $widget->get_field_id('dropdown'); ?>">ドロップダウン形式で表示</label>
  </p>
  <?php
}, 10, 3);


// ウィジェットの入力データを更新
add_filter('widget_update_callback', function ($instance, $new_instance) {
  if (isset($new_instance['dropdown'])) {
    $instance['dropdown'] = !empty($new_instance['dropdown']) ? 1 : 0;
  }

  return $instance;
}, 10, 2);


// フロントエンド表示に反映
add_filter('widget_display_callback', function ($instance) {
  if (empty($instance['dropdown'])) {
    return $instance;
  }

  $nav_menu = !empty($instance['nav_menu']) ? wp_get_nav_menu_object($instance['nav_menu']) : false;
  if (!$nav_menu) {
    return $instance;
  }

  $menu_items = wp_get_nav_menu_items($nav_menu->term_id);
  if (!$menu_items) {
    return $instance;
  }

  $current_url = trailingslashit(home_url(add_query_arg([], $_SERVER['REQUEST_URI'])));

  // 現在の表示オブジェクトを取得
  $current_object = get_queried_object();

  /**
   * ナビゲーションメニュー項目を再帰的に<option>タグとして出力
   *
   * @param array $items wp_get_nav_menu_items() で取得したメニュー項目の配列
   * @param int $parent_id 親メニュー項目のID(デフォルト: 0)
   * @param int $depth 現在の階層の深さ(インデント用、デフォルト: 0)
   * @return void
   */
  $render_options = function ($items, $parent_id = 0, $depth = 0) use (&$render_options, $current_url, $current_object) {
    $indent_unit = '&nbsp;&nbsp;&nbsp;';

    foreach ($items as $item) {
      if ((int) $item->menu_item_parent !== (int) $parent_id) {
        continue;
      }

      $indent = str_repeat($indent_unit, $depth);

      // selectedを判定
      $is_taxonomy  = $item->type === 'taxonomy'  && isset($current_object->term_id)  && (int) $item->object_id === (int) $current_object->term_id;
      $is_post_type = $item->type === 'post_type' && isset($current_object->ID)       && (int) $item->object_id === (int) $current_object->ID;
      $is_custom    = $item->type === 'custom'    && trailingslashit($item->url) === $current_url;

      $selected = $is_taxonomy || $is_post_type || $is_custom;

      ?>
      <option value="<?= esc_url($item->url); ?>" <?php selected($selected); ?>>
        <?= $indent . esc_html($item->title); ?>
      </option>
      <?php
      // 子メニューを再帰的に出力
      $render_options($items, $item->ID, $depth + 1);
    }
  };

  ob_start();
  ?>
  <select onchange="if (this.value) window.location.href=this.value;">
    <option value="">メニューを選択</option>
    <?php $render_options($menu_items); ?>
  </select>
  <?php
  // ウィジェット出力を置き換え
  echo ob_get_clean();

  return false;
});

さいごに

今回紹介した方法を使えば、「ナビゲーションメニュー」を簡単に簡単にドロップダウン表示できます。
メニュー項目を動的に表示できるため、柔軟にカスタマイズすることも可能です。

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