はじめに
Cocoonでは、ボックスメニューやヘッダー・フッターモバイルボタンなど、メニューを作成する際にアイコンを設定することがあります。
従来はFont Awesomeのホームページから使用するアイコンを探し、クラス名を確認してWordPressのメニュー項目に手入力する必要がありました。
そこで、WordPressのメニュー編集画面にFont Awesome 5のアイコンパレットを追加し、一覧からアイコンを選択できるようにします。
アイコン名による検索や選択したアイコンのプレビューにも対応します。
この記事では、この方法について説明します。
完成イメージ


実装手順
以下のコードをfunctions.phpに追加します。
// メニュー項目に入力フォームを追加
add_action('wp_nav_menu_item_custom_fields', function ($item_id, $item) {
// Font Awesome 5 が無効の場合は処理対象外
if (!is_site_icon_font_font_awesome_5()) {
return;
}
// メニュー項目のクラス一覧を取得
$current = '';
$classes = array_values((array) $item->classes);
// 選択済みアイコンのクラスを取得
foreach ($classes as $index => $class) {
if (
in_array($class, ['fas', 'far', 'fab'], true)
&& isset($classes[$index + 1])
&& preg_match('/^fa-[a-z0-9-]+$/', $classes[$index + 1])
) {
$current = $class . ' ' . $classes[$index + 1];
break;
}
}
?>
<p class="description description-wide">
<button type="button" class="button my-fa-open">アイコンを選択</button>
<span class="my-fa-current"><?php if ($current) : ?><i class="<?php echo esc_attr($current); ?>" aria-hidden="true"></i><?php endif; ?></span>
</p>
<?php
}, 10, 2);
// アイコンパレットを管理画面に出力
add_action('admin_footer-nav-menus.php', function () {
// Font Awesome 5 が無効の場合は処理対象外
if (!is_site_icon_font_font_awesome_5()) {
return;
}
// アイコン一覧のキャッシュキーを設定
$cache_key = 'my_fa5_icon';
// キャッシュ済みのアイコン一覧を取得
$icons = get_transient($cache_key);
// キャッシュが存在しない場合はアイコン一覧を取得
if (false === $icons) {
$response = wp_remote_get('https://raw.githubusercontent.com/FortAwesome/Font-Awesome/5.x/metadata/icons.json', ['timeout' => 15]);
// 通信エラーまたは HTTP ステータスが 200 以外の場合は処理対象外
if (!is_wp_error($response) && 200 === wp_remote_retrieve_response_code($response)) {
// JSON データを連想配列として取得
$data = json_decode(wp_remote_retrieve_body($response), true);
// アイコンデータが配列の場合は処理を継続
if (is_array($data)) {
// アイコンスタイルとCSSクラスの対応を設定
$prefixes = ['brands' => 'fab', 'regular' => 'far', 'solid' => 'fas'];
// アイコン一覧を初期化
$icons = [];
// アイコン名とスタイルを取得
foreach ($data as $name => $item) {
// アイコンが対応する各スタイルを取得
foreach ((array) ($item['styles'] ?? []) as $style) {
// 対応するスタイルのアイコンを一覧に登録
if (isset($prefixes[$style])) {
$icons[] = $prefixes[$style] . ' fa-' . $name;
}
}
}
// 取得したアイコン一覧を30日間キャッシュに登録
set_transient($cache_key, $icons, 30 * DAY_IN_SECONDS);
}
}
// アイコン一覧を取得できない場合は空の配列を設定
if (!is_array($icons)) {
$icons = [];
}
}
?>
<style>
.my-fa-modal {
border: 0;
border-radius: 6px;
padding: 0;
width: min(900px, 94vw);
&::backdrop {
background: rgba(0, 0, 0, .6);
}
}
.my-fa-modal__panel {
box-sizing: border-box;
display: flex;
flex-direction: column;
gap: 12px;
max-height: 85vh;
padding: 20px;
}
.my-fa-modal__header {
align-items: center;
display: flex;
gap: 12px;
justify-content: space-between;
& h2 {
margin: 0;
}
}
.my-fa-modal__search {
box-sizing: border-box;
width: 100%;
}
.my-fa-modal__grid {
display: grid;
gap: 6px;
grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
min-height: 150px;
overflow-y: auto;
}
.my-fa-modal__icon {
align-items: center;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
display: flex;
flex-direction: column;
gap: 8px;
justify-content: center;
min-height: 80px;
padding: 8px 4px;
&:hover,
&:focus {
background: #f0f6fc;
border-color: #2271b1;
}
& i {
font-size: 24px;
}
& span {
font-size: 11px;
text-align: center;
}
}
.my-fa-current {
margin-left: 8px;
vertical-align: middle;
& i {
font-size: 20px;
}
}
</style>
<!-- アイコン選択用ダイアログを登録 -->
<dialog id="my-fa-modal" class="my-fa-modal" aria-labelledby="my-fa-modal-title">
<div class="my-fa-modal__panel">
<div class="my-fa-modal__header">
<h2 id="my-fa-modal-title">Font Awesome 5 アイコンパレット</h2>
<button type="button" class="button my-fa-modal__close">閉じる</button>
</div>
<!-- アイコン検索用の入力欄を登録 -->
<input type="search" class="my-fa-modal__search" placeholder="アイコン名で検索">
<!-- アイコン一覧をグリッド形式で登録 -->
<div class="my-fa-modal__grid">
<?php foreach ($icons as $class) : ?>
<button type="button" class="my-fa-modal__icon" data-class="<?php echo esc_attr($class); ?>">
<i class="<?php echo esc_attr($class); ?>" aria-hidden="true"></i>
<span><?php echo esc_html(substr($class, strpos($class, 'fa-') + 3)); ?></span>
</button>
<?php endforeach; ?>
</div>
</div>
</dialog>
<script>
jQuery(function ($) {
// ダイアログと検索欄、アイコン一覧を取得
var dialog = $('#my-fa-modal')[0];
var $search = $('.my-fa-modal__search');
var $icons = $('.my-fa-modal__icon');
// 編集対象のメニュー項目を初期化
var $item;
// アイコンパレットを開く
$(document).on('click', '.my-fa-open', function () {
// クリックしたボタンのメニュー項目を取得
$item = $(this).closest('.menu-item');
// 検索欄を初期化してアイコン一覧を更新
$search.val('').trigger('input');
// ダイアログを表示して検索欄にフォーカスを設定
dialog.showModal();
$search.trigger('focus');
});
// 閉じるボタンでパレットを閉じる
$('.my-fa-modal__close').on('click', function () {
dialog.close();
});
// 背景クリックでパレットを閉じる
$(dialog).on('click', function (event) {
// ダイアログ本体以外をクリックした場合は処理対象外
if (event.target === dialog) {
dialog.close();
}
});
// 検索文字列に一致するアイコンを表示
$search.on('input', function () {
// 検索文字列を取得して前後の空白を除去
var query = this.value.trim().toLowerCase();
// アイコンのクラス名と検索文字列を照合して表示状態を変更
$icons.each(function () {
$(this).toggle(this.dataset.class.indexOf(query) !== -1);
});
});
// 選択したアイコンをメニュー項目に設定
$('.my-fa-modal__grid').on('click', '.my-fa-modal__icon', function () {
// 編集対象のメニュー項目がない場合は処理対象外
if (!$item || !$item.length) {
dialog.close();
return;
}
// 選択したアイコンのクラスを取得
var iconClass = this.dataset.class;
// メニュー項目の CSS クラス入力欄を取得
var $input = $item.find('input[name^="menu-item-classes"]');
// CSS クラス入力欄がない場合は処理対象外
if (!$input.length) {
dialog.close();
return;
}
// 既存の CSS クラスからアイコン関連クラスを除外
var classes = $input.val().trim().split(/\s+/).filter(function (name) {
return name && !/^(?:fas|far|fab)$/.test(name) && !/^fa-[a-z0-9-]+$/.test(name);
});
// 選択したアイコンのクラスに置換
classes.push(iconClass);
$input.val(classes.join(' ')).trigger('change');
// 選択したアイコンをボタン横に表示
$item.find('.my-fa-current').html('<i class="' + iconClass + '" aria-hidden="true"></i>');
// アイコンパレットを閉じる
dialog.close();
});
});
</script>
<?php
});
さいごに
今回紹介した方法を使えば、WordPressのメニュー編集画面からFont Awesome 5のアイコンを検索・選択し、クラス名を手入力する手間を省けます。
選択したアイコンはプレビューで確認でき、アイコンの変更も簡単に行えます。
Cocoonのボックスメニューやヘッダー・フッターのモバイルボタンなど、メニューのアイコン設定を効率化したい場合に活用してください。

