Добавление иконок к пунктам меню wordpress

Всем привет. Я не так давно изучаю WP. Хочу добавить иконки к каждому пункту меню, но уже 2 день сижу и не знаю что с этим делать. Временно поставила плагин "menu image", но хочу сделать это без него используя код :) Что можно почитать или как можно реализовать это? Пример


Ответы (2 шт):

Автор решения: Valeh Salimov

Скорее всего не актуально, но может кому то поможет

Сразу стоит отметить, что я не стал добавлять выбор изображения. В моей задаче оптимальным было указать id SVG иконки из спрайта, которая будет вставляться инлайново с помощью <use>. Так у нас меньше заморочек и сохраняется гибкость в цветах и размерах, которые спокойно можно задать в CSS и менять при разных состояниях.
В любом случае думаю вы без особых проблем сможете аналогично добавить нужные вам дополнительные поля.

Рекомендую сначала посмотреть результат в прикрепленном скриншоте (внизу), чтобы лучше понимать код. Лучше всё скопировать в свой редактор

Первым делом используем хук wp_nav_menu_item_custom_fields. Добавляем всё в function.php

<? function vs_iconav_custom_fields($item_id, $item)
{
// Если кастомные поля вам нужны во всех меню - можете удалить создание массива элементов и условие if (in_array($item, $iconav_all_menu_items)) :. Не забудьте endif тоже удалить
  $iconav_all_menu_items = array(); //массив пунктов меню для которых будет возможность указать иконку
  $iconav_menu_ids = array(42, 50);// массив с id меню. Добавьте id меню в которых вам нужны кастомные поля. Например Главное меню id - 42, Меню футер id - 50
  // собираем элементы всех указанных меню в один массив
  foreach ($iconav_menu_ids as $id) {
     $iconav_all_menu_items = array_merge($iconav_all_menu_items, wp_get_nav_menu_items($id));
  }
  // если текущий элемент есть в нашем массиве - добавляем для него поля
  if (in_array($item, $iconav_all_menu_items)) :
    wp_nonce_field('iconav_meta_nonce', '_iconav_meta_nonce_name');
    // обратите внимание на _iconav_meta. По этому названию вы будете получать свои данные с полей. Вы можете назвать по своему например _customnav_meta, только не забудьте поменять везде название
    $iconav_meta = get_post_meta($item_id, '_iconav_meta', true); // получаем мета поля текущего элемента (пункта меню)
    // если метаполе существует и содержит данные, забираем их (В начале естественно они будут пустые)
    $icon = $iconav_meta && $iconav_meta['icon'] ? esc_attr($iconav_meta['icon']) : ''; // в моем случае название иконки
    $size = $iconav_meta && $iconav_meta['size'] ? esc_attr($iconav_meta['size']) : ''; // размер для иконки одним полем. По хорошему width и height надо будет сделать, но пока так. В CSS правлю если надо
    $disabled = $iconav_meta && $iconav_meta['disabled'] ? 'checked' : '';// это был просто чекбокс показывающий, что пункт меню пока недоступен
    // продумайте свой список переменных. К примеру из вашего скриншота это могли быть $menu_img $img_hover $img_size $img_position...
    // дальше пишем разметку, которая будет отображаться в пунктах меню. Смотрим на скрин для лучшего понимания
    //Я особо не заморачивался и просто под себя быстро всё корректировал лишь бы было. Возможно некоторые элементы лишние, не уверен насчет input hidden, в остальном вроде всё норм
    ?>
    <div class="field-icon_meta description-wide" style="margin: 5px 0;">
      <span class="description"><?php _e("Название иконки", 'custom-menu-meta'); ?></span>
      <br>
      <input type="hidden" class="nav-menu-id" value="<?php echo $item_id;?>" />

      <div class="logged-input-holder">
        <input type="text" name="icon_meta[<?php echo $item_id; ?>]" id="custom-menu-meta-for-<?php echo $item_id; ?>" value="<?php echo $icon; ?>"  style="width: 100%"/>
      </div>
      <span class="description" style="color: green"><?php _e("*svg иконка вставляется из sprite.svg", 'custom-menu-meta'); ?></span>
    </div>
    <br>
    <br>
    <div class="field_meta description-wide" style="margin: 5px 0;">
      <span class="description"><?php _e("Размер иконки (px)", 'custom-menu-meta'); ?></span>
      <br>
      <input type="hidden" class="nav-menu-id" value="<?php echo $item_id;?>" />

      <div class="logged-input-holder">
        <input type="text" name="size_meta[<?php echo $item_id; ?>]" id="size-meta-for-<?php echo $item_id; ?>" value="<?php echo $size ?>"  style="width: 30%; margin-right: 90px"/>

        <input type="checkbox" name="disabled_meta[<?php echo $item_id; ?>]" id="disabled-meta-for-<?php echo $item_id; ?>" <?php echo $disabled; ?>/>
        <label for="disabled-meta-for-<?php echo $item_id; ?>">Отключить пункт меню</label>
      </div>
    </div>

<?php
  endif;
}
// не забываем использовать хук со своей функцией. Внимательно с названием функции
add_action('wp_nav_menu_item_custom_fields', 'vs_iconav_custom_fields', 10, 2);

Теперь используем хук wp_update_nav_menu_item для обновления данных в наших метаполях после сохранения изменений в меню

function vs_iconav_update($menu_id, $menu_item_db_id)
{
  // Так понял проверяем, что мы авторизованы и обновляется меню с кастомными полями. Оставлю оригинал на инглише
  // Verify this came from our screen and with proper authorization.
  if (!isset($_POST['_iconav_meta_nonce_name']) || !wp_verify_nonce($_POST['_iconav_meta_nonce_name'], 'iconav_meta_nonce')) {
    return $menu_id;
  }
  // здесь проверяются данные именно с инпута по его name. Если при обновлении он был не пустой, берем все данные и обновляем
  // Вы можете проверять по любому важному для вас полю или по хорошему каждое поле проверять отдельно. В моем случае без иконки остальное неважно было
  if (isset($_POST['icon_meta'][$menu_item_db_id])) {
    // Соответственно здесь будет тот же список полей, который вы укажите в предыдущей функции и будете использовать в разметке
    $sanitized_data['icon'] = sanitize_text_field($_POST['icon_meta'][$menu_item_db_id]);
    $sanitized_data['size'] = sanitize_text_field($_POST['size_meta'][$menu_item_db_id]);
    $sanitized_data['disabled'] = sanitize_text_field($_POST['disabled_meta'][$menu_item_db_id]);
   // обновляем все поля. А вот и наше название _iconav_meta
    update_post_meta($menu_item_db_id, '_iconav_meta', $sanitized_data);
  } else {
    delete_post_meta($menu_item_db_id, '_iconav_meta');
  }
}
add_action('wp_update_nav_menu_item', 'vs_iconav_update', 10, 2); 

Вот и всё. По идее если вы скопируете весь код в ваш functions.php и укажете id своего меню, у вас уже должны будут появиться эти поля (id можно в адресной строке посмотреть, когда редактируете меню).

Использую я это при создании кастомного вывода меню с помощью Walker_Nav_Menu{}. Среди всего прочего кода меню, примеры которого вы легко можете найти, поля я получаю следующим образом

<?php
// Берем наши поля _iconav_meta
$iconav_meta = get_post_meta($item->ID, '_iconav_meta', true);
// Ну и все значения получаем так - $iconav_meta['название поля']
$icon_url = get_template_directory_uri() . '/img/icons/sprite.svg#' . $iconav_meta['icon'];
$size = $iconav_meta && $iconav_meta['size'] ? esc_attr($iconav_meta['size']) : '';

Результат. Кастомные поля в пункте меню, для указания иконки

P.S. Писал код давно, раньше чем этот вопрос появился и к сожалению первоисточник откуда взял пример не укажу. Не вникал во все тонкости работы, но вроде не сложно разобраться, постарался основные моменты описать. Да и вообще я больше фронтендер, сильно не ругайтесь)

Вероятно код будет не идеальный и всё такое, но он работает, использовал на нескольких проектах и буквально сейчас он понадобился. Собственно поэтому я здесь

→ Ссылка
Автор решения: Виталий

Вот тут описано полное решение задачи как добавить иконку в меню без плагина: https://i-love-web-it.com/wordpress/articles/dobavleniye-izobrazheniy-ikonok-k-punktam-menyu-v-wordpress-bez-plagina/

→ Ссылка