Cocoon設定画面にキーワード検索機能を追加する方法

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

はじめに

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

Cocoonの設定項目は数多く、目的の項目を見つけるのが大変です。

そこで、Cocoon設定画面内でキーワードを検索し、該当するタブを赤色で表示します。

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

完成イメージ

実装手順

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

add_action('admin_enqueue_scripts', function ($hook_suffix) {
  $page_hook = get_plugin_page_hookname('theme-settings', '');

  if ($hook_suffix !== $page_hook) {
    return;
  }

  ob_start();
  ?>
  jQuery(function ($) {
    // 検索フォームを追加
    $('.admin-settings h1').after('<input type="text" id="hvn-key"><button type="button" id="hvn-button" class="button-primary">検索</button>');

    $('#hvn-button').on('click', function () {
      const key = $('#hvn-key').val().trim();

      // 既存の色をリセット
      $('.tab-label').css('background-color', '');

      // キーワードが空なら終了
      if (!key) {
        return;
      }

      // 各タブを検索
      $('[id*="tab"].metabox-holder').each(function () {
        const $content = $(this);
        const text = $content.text();

        // キーワードが見つからなければ次へ
        if (text.indexOf(key) === -1) {
          return;
        }

        // content → label に変換して対応するタブを取得
        const id = $content.attr('id');
        const labelId = '#' + id.replace('content', 'label');

        // 該当タブを強調
        $(labelId).css('background-color', '#ff0000');
      });
    });
  });
  <?php
  wp_add_inline_script('jquery', ob_get_clean(), 'after');
}, 999);

拡張:CSS Custom Highlight APIでテキストをハイライト表示する方法

前述のコードでは、文字を装飾するために<span class="highlight">などのタグでHTML構造を書き換える(DOM操作を行う)必要がありました。

しかし、管理画面やフォーム内でDOMを直接書き換えると、レイアウト崩れやイベントの破損、入力データの不具合を引き起こすリスクがあり、本文内のテキストハイライトには対応できませんでした。

今回のコードでは、「CSS Custom Highlight API」を採用により、DOM構造を変更しません。

これにより、管理画面のシステムやフォーム要素に悪影響を与えることなく、安全に本文内のキーワードまでピンポイントでハイライトできるよう改善されています。

完成イメージ

実装手順

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

add_action('admin_enqueue_scripts', function ($hook_suffix) {
  // 対象ページのフック名を取得
  $page_hook = get_plugin_page_hookname('theme-settings', '');

  if ($hook_suffix !== $page_hook) {
    return;
  }

  // CSS Custom Highlight APIのスタイルを追加
  wp_add_inline_style('wp-admin', '
    ::highlight(search-result) {
      background-color: #ff0000;
      color: #ffffff;
    }
  ');

  ob_start();
  ?>
  jQuery(function ($) {
    // 検索フォームを追加
    $('.admin-settings h1').after('<input type="text" id="hvn-key"><button type="button" id="hvn-button" class="button-primary">検索</button>');

    // 検索ボタンのクリック処理
    $('#hvn-button').on('click', function () {
      const key = $('#hvn-key').val().trim();

      // 既存のハイライトとタブの選択色を解除
      if (typeof CSS !== 'undefined' && CSS.highlights) {
        CSS.highlights.delete('search-result');
      }
      $('.tab-label').css('background-color', '');

      // 検索文字列が空なら処理しない
      if (!key) {
        return;
      }

      // 各タブの内容を検索
      $('[id*="tab"].metabox-holder').each(function () {
        const $content = $(this);
        const text = $content.text();

        // 検索文字列を含むタブを選択状態にする
        if (text.indexOf(key) !== -1) {
          const id = $content.attr('id');
          const labelId = '#' + id.replace('content', 'label');
          $(labelId).css('background-color', '#ff0000');
        }
      });

      // #tabs内のテキストを検索してハイライト
      if ($('#tabs').length && typeof CSS !== 'undefined' && CSS.highlights) {
        const ranges = [];
        const lowerKey = key.toLowerCase();

        /**
         * テキストノードから検索文字列の範囲を取得
         *
         * @param {Node} node 検索対象のノード
         * @return {void}
         */
        function findRanges(node) {
          if (node.nodeType === Node.TEXT_NODE) {
            const nodeText = node.nodeValue;
            const lowerNodeText = nodeText.toLowerCase();
            let startPos = 0;
            let index;

            // テキスト内のすべての一致箇所を取得
            while ((index = lowerNodeText.indexOf(lowerKey, startPos)) !== -1) {
              const range = new Range();
              range.setStart(node, index);
              range.setEnd(node, index + key.length);
              ranges.push(range);
              startPos = index + key.length;
            }
          } else if (node.nodeType === Node.ELEMENT_NODE && node.childNodes) {
            // 検索対象外の要素を除外
            const tagName = node.tagName.toUpperCase();

            if (
              tagName !== 'SCRIPT' &&
              tagName !== 'STYLE' &&
              tagName !== 'TEXTAREA' &&
              tagName !== 'INPUT'
            ) {
              // 子要素を再帰的に検索
              for (let i = 0; i < node.childNodes.length; i++) {
                findRanges(node.childNodes[i]);
              }
            }
          }
        }

        // #tabs内を検索
        findRanges($('#tabs')[0]);

        // 検索結果にハイライトを適用
        if (ranges.length > 0) {
          const searchHighlight = new Highlight(...ranges);
          CSS.highlights.set('search-result', searchHighlight);
        }
      }
    });
  });
  <?php
  wp_add_inline_script('jquery', ob_get_clean(), 'after');
}, 999);

さいごに

管理画面内の要素を操作するために、どのようにJavaScriptを実行するかを検討してみました。
ただし、実用性はあまり高くないため、あくまで参考としてご覧ください。

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