Добавить дополнительную кнопку в навигацию Bootstrap в WordPress Custom Walker

Я использую следующий код пользовательского средства навигации для WordPress для генерации начальной загрузки:

<?php


class NavWalker extends Walker_Nav_Menu {
  private $cpt; // Boolean, is current post a custom post type
  private $archive; // Stores the archive page for current URL

  public function __construct() {
    add_filter('nav_menu_css_class', array($this, 'cssClasses'), 10, 2);
    add_filter('nav_menu_link_attributes', array($this, 'filter_menu_link_atts'), 10, 3);
    add_filter('walker_nav_menu_start_el', array($this, 'filter_menu_item_output'), 10, 4);
    add_filter('nav_menu_item_id', '__return_null');
    $cpt           = get_post_type();
    $this->cpt     = in_array($cpt, get_post_types(array('_builtin' => false)));
    $this->archive = get_post_type_archive_link($cpt);
  }

  /**
  * @see Walker::start_lvl()
  * @since 3.0.0
  *
  * @param string $output Passed by reference. Used to append additional content.
  * @param int $depth Depth of page. Used for padding.
  */
  // @codingStandardsIgnoreStart
  public function start_lvl(&$output, $depth = 0, $args = array()) {
    parent::start_lvl($output, $depth, $args);
    $pos    = strrpos($output, '">', -1);
    $output = substr_replace($output, ' dropdown-menu depth'.$depth.'" role="menu">', $pos);
  }
  // @codingStandardsIgnoreEnd

  /**
   * Traverse elements to create list from elements.
   *
   * Display one element if the element doesn't have any children otherwise,
   * display the element and its children. Will only traverse up to the max
   * depth and no ignore elements under that depth.
   *
   * This method shouldn't be called directly, use the walk() method instead.
   *
   * @see Walker::start_el()
   * @since 2.5.0
   *
   * @param object $element Data object
   * @param array $children_elements List of elements to continue traversing.
   * @param int $max_depth Max depth to traverse.
   * @param int $depth Depth of current element.
   * @param array $args
   * @param string $output Passed by reference. Used to append additional content.
   * @return null Null on failure with no changes to parameters.
   */

  // @codingStandardsIgnoreStart
  public function display_element($element, &$children_elements, $max_depth, $depth, $args, &$output) {
    if (!$element) {
      return;
    }

    $id_field = $this->db_fields['id'];
    $this->has_children = !empty($children_elements[$element->$id_field]);

    parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);
  }
  // @codingStandardsIgnoreEnd

  public function cssClasses($classes, $item) {
    if ($this->has_children) {
      $classes[] = 'dropdown';
    }

    if ($item->menu_item_parent != 0) {
      $classes[] = 'dropdown-item';
    }

    if ($item->menu_item_parent == 0) {
      $classes[] = 'nav-item';
    }

    if (strcasecmp($item->attr_title, 'header') == 0) {
      $classes[] = 'dropdown-header';
    }

    $slug = sanitize_title($item->title);

    if ($this->cpt) {
      $classes = str_replace('current_page_parent', '', $classes);
      if (strcasecmp($this->archive, $item->url) === 0) {
        $classes[] = 'active';
      }
    }

    //$classes = preg_replace('/(current(-menu-|[-_]page[-_])(item|parent|ancestor))/', '', $classes);
    $classes = preg_replace('/^((menu|page)[-_\w+]+)+/', '', $classes);
    $classes[] = 'menu-' . $slug;
    $classes = array_unique($classes);

    return array_filter($classes, function ($element) {
      $element = trim($element);
      return !empty($element);
    });
  }

  /*
   * This filter is used to customize the <li> attributes.
   */
   // @codingStandardsIgnoreStart
  public function filter_menu_link_atts($atts, $item, $args) {

    if (is_object($args->walker)) { // Filter if custom walker
      $classes   = array();
      $classes[] = 'nav-link';

   /*
      if ($args->walker->has_children) {
        $atts['data-toggle']   = 'dropdown';
        $classes[]             = 'dropdown-toggle';
        $atts['aria-haspopup'] = 'true';
      }
      */

      if (strcasecmp($item->attr_title, 'disabled') == 0) {
        $classes[] = 'disabled';
      }

      if ($item->current == 1) {
        $classes[] = 'active';
      }

      if ($item->parent == 1) {
        $classes[] = 'active';
      }

      $atts['class'] = implode(' ', $classes);
    }

    return $atts;
  }
  // @codingStandardsIgnoreEnd

  /*
   * This filter is used to customize the <li> final output.
   */
   // @codingStandardsIgnoreStart
  public function filter_menu_item_output($item_output, $item, $depth, $args) {
    $indent = str_repeat("\t", $depth);

    if (strcasecmp($item->attr_title, 'divider') == 0 && $depth === 1) {
      $item_output .= $indent . '<li role="presentation" class="dropdown-divider">';
    } else if ((strcasecmp($item->attr_title, 'header') == 0 && $depth === 1) && $depth === 1) {
      $item_output = $indent . '<h6>' . esc_attr($item->title) . '</h6>';
    }

    $args->link_before = '';
    $args->link_after = '';

    return $indent . $item_output;
  }
  // @codingStandardsIgnoreEnd
}

Я также использую следующий код JS, чтобы открыть раскрывающийся список в навигации при наведении мыши:

 $('ul.nav li.dropdown.nav-item').hover(function() {
     $(this).find('.sub-menu.dropdown-menu.depth0').stop(true, true).delay(200).fadeIn(500);
   }, function() {
     $(this).find('.sub-menu.dropdown-menu.depth0').stop(true, true).delay(200).fadeOut(500);
   });

      $('li.dropdown.dropdown-item').hover(function() {
     $(this).find('.sub-menu.dropdown-menu.depth1').stop(true, true).delay(200).fadeIn(500);
   }, function() {
     $(this).find('.sub-menu.dropdown-menu.depth1').stop(true, true).delay(200).fadeOut(500);
   });

В этом случае у мобильного пользователя нет возможности открыть выпадающий список. Он всегда будет нажимать на ссылку. Это абсолютно нормально для меня. Мне просто нужна еще одна ссылка для мобильных пользователей (значок стрелки справа), чтобы они могли открыть раскрывающийся список.

Я просто не понимаю, где я должен добавить эту ссылку в пользовательский ходок.

1 ответ

Решение

Я нашел решение. Изменить этот код:

public function start_lvl(&$output, $depth = 0, $args = array()) {
     parent::start_lvl($output, $depth, $args);
     $pos    = strrpos($output, '">', -1);
     $output = substr_replace($output, ' dropdown-menu depth'.$depth.'" role="menu">', $pos);
}

к этому:

public function start_lvl(&$output, $depth = 0, $args = array()) {
    $indent = str_repeat("\t", $depth);
    $output .= "\n$indent<button class=\"btn btn-link btn-menu pull-xs-right hidden-lg-up\" data-toggle=\"dropdown\"><i class=\"icon-chevron-down\"></i></button>\n";

    parent::start_lvl($output, $depth, $args);
    $pos    = strrpos($output, '">', -1);
    $output = substr_replace($output, ' dropdown-menu depth'.$depth.'" role="menu">', $pos);
 }
Другие вопросы по тегам