programing

Wordpress - 메뉴 항목에 하위 항목이 있는지 어떻게 알 수 있습니까?

newnotes 2023. 3. 6. 21:28
반응형

Wordpress - 메뉴 항목에 하위 항목이 있는지 어떻게 알 수 있습니까?

서브메뉴가 중첩된 워드프레스 테마를 개발하고 있습니다.아이가 없는 요소와 아이가 있는 요소를 시각적으로 다르게 만들어야 합니다.현재 이 메뉴가 있지만 변경될 수 있습니다.

A
  a1
  a2
B
  b1
  b2
C

보시다시피 A와 B는 아이가 있습니다.C는 필요 없습니다.CSS 레벨에서는 다른 것이 필요합니다.

이상적으로, 나는 그것을 가지고 싶다.has-childrenA a B 、 C 의 C 、 A a B 。

지금까지 저는 인스턴스화해서 wp_nav_menu로 전달할 수 있는 "Menu Walker" PHP 클래스를 만들었습니다.생성자는 다음과 같습니다.

class My_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el(&$output, $item, $depth, $args) {
    ...
    if(??? $item has children???) {
      // I know what to do here
    }
  }
}

어떻게 해야 요?$item이가있있 ,??? ????

편집: 이 질문은 Wordpress 포럼에서 "keeesiemeijer"라고 불리는 사람에 의해 답변되었습니다.만약 그가 그것을 되찾고 싶어 할 때를 대비해서 나는 이 현상금을 기한이 지난 상태로 둘 것이다.그렇지 않으면 내 답변이 유효하다고 표시되게 됩니다.

을 더하면 됩니다.functions.php에게 '해 줄 입니다.

퍼포먼스를 향상시키는 새로운 방법

function menu_set_dropdown( $sorted_menu_items, $args ) {
    $last_top = 0;
    foreach ( $sorted_menu_items as $key => $obj ) {
        // it is a top lv item?
        if ( 0 == $obj->menu_item_parent ) {
            // set the key of the parent
            $last_top = $key;
        } else {
            $sorted_menu_items[$last_top]->classes['dropdown'] = 'dropdown';
        }
    }
    return $sorted_menu_items;
}
add_filter( 'wp_nav_menu_objects', 'menu_set_dropdown', 10, 2 );

구식: DB에 집중

add_filter( 'nav_menu_css_class', 'check_for_submenu', 10, 2);
function check_for_submenu($classes, $item) {
    global $wpdb;
    $has_children = $wpdb->get_var("SELECT COUNT(meta_id) FROM wp_postmeta WHERE meta_key='_menu_item_menu_item_parent' AND meta_value='".$item->ID."'");
    if ($has_children > 0) array_push($classes,'dropdown'); // add the class dropdown to the current list
    return $classes;
}

간단한 사용방법:

설명:"Walker"를 사용하여 메뉴를 만듭니다.

$walker = new Nav_Walker;
wp_nav_menu(array(
        'container'=>'nav',
        'container_class'=>'menu',
        'menu_class'=>'list-unstyled list-inline',
        'walker'=>$walker
    ));

클래스 워커:

class Nav_Walker extends Walker_Nav_Menu
{ 
      public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
    {
        if($args->walker->has_children)
        {
            //code...
        }   
    }
}

walker 객체가 있습니다.var_dump($args)를 사용하면 더 많은 것을 볼 수 있습니다.난 내 프로젝트에 사용하고 있어!

을 사용하다 4.되어 Walker_Nav_Menu가 되었습니다.$has_children★★★★★★★★★★★★★★★★★★.

/**
 * Whether the current element has children or not.
 *
 * To be used in start_el().
 *
 * @since 4.0.0
 * @access protected
 * @var bool
 */
protected $has_children;

해킹을 할 는 없어요.function display_element(...)★★★★★★★★★★★★★★★★★★.

WordPress 포럼에서 질문했더니 Keesiemeijer가 다른 게시물을 가리키며 다음과 같이 답했습니다.

「 」를 변경하는 에,start_el라고 수정했습니다.display_element, 다음의 2 행(여기서는 37 ~38 행)을 추가합니다.

//display this element (THESE ARE NOT THE LINES)
if ( is_array( $args[0] ) )
  $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );

// THESE TWO ARE THE LINES:               
if( ! empty( $children_elements[$element->$id_field] ) )
  array_push($element->classes,'parent');

앞의 두 줄을 띄어쓰기로, 그리고 이 글의 다른 답변에 대한 코멘트로 남겨두었습니다.'자녀것 .$args말은has_children 「하지 않는다」로 넘어가지 .start_el(여기서 var_140달러 샘플 참조)

이것은 현재 보유하고 있는 Wordpress 버전(3.2.1)의 버그일 수 있으며 최신 버전에서 수정되었을 수 있습니다.

어쨌든, Wordpress 포럼에서 얻은 답변은 그것을 고치는 데 도움을 준 답변이기 때문에, 저는 이것이 해결되었다고 생각합니다.만약 Keesiemeijer가 여기에 그의 대답을 넣으려 한다면, 나는 현상금이 만료될 때까지 기다릴 것이다.

class My_Walker_Nav_Menu extends Walker_Nav_Menu {
  function start_el(&$output, $item, $depth, $args) {
    ...
    if($args['has_children']) {
      // I know what to do here
    }
  }
}

이 기능을 추가합니다.php

add_filter('wp_nav_menu_objects', 'menu_has_children', 10, 2);

function menu_has_children($sorted_menu_items, $args) {
    $parents = array();
    foreach ( $sorted_menu_items as $key => $obj )
            $parents[] = $obj->menu_item_parent;
    foreach ($sorted_menu_items as $key => $obj)
        $sorted_menu_items[$key]->has_children = (in_array($obj->ID, $parents)) ? true : false;
    return $sorted_menu_items;
}

그러면 워커에서 $item-> has_children이 참인지 거짓인지 확인할 수 있습니다.

Kikito의 답변은 요령을 달성하지만, 가장 재사용 가능한 방법은 아닙니다.제가 보기에 더 나은 접근 방식은 다음과 같습니다.

function display_element($element, &$children_elements, $max_depth, $depth=0, $args, &$output) {
    // the first few lines of the method...

    //display this element; handle either arrays or objects gracefully
    if ( is_array( $args[0] ) )
        $args[0]['has_children'] = ! empty( $children_elements[$element->$id_field] );

    elseif ( is_object($args[0]) )
        $args[0]->has_children =  ! empty( $children_elements[$element->$id_field] );

    // the rest of the method...
}

「」의 덮어쓰기Walker::display_element()옳은 조치이지만 두 가지 이유로 이 시점에서 단순히 클래스를 부가하는 것보다 문제의 근원적인 부분에 실제로 대처하는 것이 좋습니다.이 아니라 Kikito가 되지 않은 는 「Kikito」, 「Kikito」, 「WordPress」입니다.문제는$args[0]항상 배열은 아닙니다.은 일반적으로 .Walker::display_element() 있는 것은 ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」입니다Walker_Nav_Menu::display_element() 이 경우,args는 어레이 유형이 아닌 표준 개체 유형으로 전달됩니다.해서 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아,has_children요소를 배열 표기법 대신 개체 표기법을 사용합니다.[1 [1]

「」의 elseif일반적인 네비게이션 메뉴 케이스의 원인입니다.이것은 이 패치의 핵심 클래스로 만들 수 있는 것과 같은 형식입니다.이 시점에서 더 이상 확장하지 않아도 됩니다.다음 경우를 고려하기 위해 패치를 더 적용해야 할 것 같습니다.$args[0]배열도 객체도 아니지만, 그런 일이 일어날 거라고는 생각하지 않습니다.

번째, 여러 잘는 '', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '수업', '', '수업', '수업', '수업', '수업', '수업', '수업', '', '수업'start_el() 방법display_element()업업처처처처처혀혀고있있요요요요요요 。

as, 그, 지, 지, 지, 지, 지, as 、 as 、 as 、 as 、 as 、 as 。start_el()원하는 대로 커스텀 클래스를 추가하거나 요소를 완전히 무시하거나 커스텀 텍스트를 제공하거나 원하는 모든 것을 제공할 수 있습니다(내 경우 부모와 자녀에 따라 매우 구체적인 분류 요건을 가진 기존 Javascript 메뉴 구현을 검토하고 있기 때문에 아이가 있는 모든 것에 동일한 클래스를 추가할 수는 없습니다).바로 그렇기 때문에 이러한 우려의 분리가 중요한 것입니다.)내 코드:

function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0) {
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';
    $class_names = $value = '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $has_children = (is_object($args) && $args->has_children) || (is_array($args) &&  $args['has_children']);
    if ($has_children) {
        // do whatever you need to do
    }

    // everything else the method does...
}

[1] 이것은 물론 PHP와 같은 동적 유형의 언어에서 발생할 수 있는 함정 중 하나입니다.당신이 조심하기만 하면 그건 문제가 되지 않아요.WordPress 개발자들은 여기서 조심하지 않았다.

하드 쿼리 또는 함수의 오버헤드를 원하지 않는 경우 jQuery에서 다음을 수행할 수 있습니다.

(function() {
    // Add 'has_children' class to menus
    jQuery.each(jQuery('.menu-item').has('ul.sub-menu'), function() {
        jQuery(this).addClass('has_children');
    });
})();
    /**
     * @see My_Nav_Walk::start_el()
     * @since 3.0.0
     *
     * @param string $output Passed by reference. Used to append additional content.
     * @param object $item Menu item data object.
     * @param int $depth Depth of menu item. Used for padding.
     * @param int $current_page Menu item ID.
     * @param object $args
     * @url:http://www.liyinqing.com
     */
class My_Nav_Walk extends Walker_Nav_Menu {
    function start_el(&$output, $item, $depth, $args) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

    $class_names = $value = '';

    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;

    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
    $class_names = ' class="' . esc_attr( $class_names ) . '"';

    $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
    $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

    $output .= $indent . '<li' . $id . $value . $class_names .'>';

    $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
    $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
    $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
    $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

    // Check our custom has_children property.here is the points
    if ( $args->has_children ) {
      $attributes .= ' class="menu parent"';
    }

    $item_output = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
  }

  function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
    $id_field = $this->db_fields['id'];
    if ( is_object( $args[0] ) ) {/.here is the points
      $args[0]->has_children = ! empty( $children_elements[$element->$id_field] );
    }
    return parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
  }

}

이 질문은 구글 검색의 첫 번째 결과 중 하나이며, 다른 웹페이지에서 참조되고 있으며, 대부분의 답변이 구식이기 때문에 이 답변을 올리려고 합니다.

start_el()에는 $item 객체의 일부로 클래스가 있습니다.start_el()에 추가할 수 있습니다.

   if(in_array('menu-item-has-children', $item->classes) && $depth != 0)
   {
       // Your Code
   }

경우 $depth는 필요하지 않지만 삭제 시 첫 번째 항목(depth 0 항목)에 코드가 적용됩니다.

호환성 부분에 대해서는 WordPress 3.7(2013년 10월) menu-item-has-children 클래스가 추가되어 최신 WordPress 4.4(이 답변 게시 시점)에서 테스트했습니다.

의 핵심 기능을 다시 쓰는 대신Walker_Nav_Menu ★★★★★★★★★★★★★★★★★」Walker수업 방식은 그냥 좋은 구식 상속을 사용하자.

코드

class Has_Child_Walker_Nav_Menu extends Walker_Nav_Menu {
    public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {
        if ( ! $element ) {
            return;
        }
        $element->has_children = ! empty( $children_elements[ $element->{$this->db_fields['id']} ] );
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }
}

구조

  1. .Has_Child_Walker_Nav_Menu 계승하다Walker_Nav_Menu로부터 물려받은 것이다.Walker.
  2. 는 이이 the the the the the the the the 를 덮어씁니다.Walker->display_element()메뉴 항목 트리를 걷는 동안 각각의 메뉴 메뉴를 호출하는 첫 번째 방법이기 때문에 우리만의 기능을 가진 방법.
  3. 저희 회사에서는display_element(): 새 방법: " "has_children $element itema.k.a.k.a. 하면 이 속성을 사용할 수 .$itemstart_el() ★★★★★★★★★★★★★★★★★」end_el()즉, 이것은 "Methods", "Methods"에에도 전달됨을 합니다.start_el().
  4. ★★★★★★★★★의has_children는 같은 됩니다.Walker 속성 " " "has_children결정되어 있습니다.
  5. 는 지지 the 라고 부릅니다.display_element() parent(부모의 메서드)Walker_Nav_Menu 조부모님WalkerWalker_Nav_Menu없다display_element()★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★display_element()의 메서드Walker->display_element()★★★★★★ 。

바로 그거야!

, 이제 ★★★★★★★★★★★★★★★★★★.$item->has_children필터 등 필요한 곳이라면 어디서든 사용할 수 있습니다.

사용 예

메뉴판

wp_nav_menu(
    array(
        'theme_location'  => 'main_nav',
        'container_class' => 'main-nav',
        'walker'          => new Has_Child_Walker_Nav_Menu()
    )
);

필터

function my_menu_dropdown( $output, $item, $depth, $args ) {
    if ( $item->has_children ) {
        $output .= '<a href="#" class="expand-menu-toggle"><i class="fal fa-angle-down"></i></a>';
    }
    return $output;
}
add_filter( 'walker_nav_menu_start_el', 'my_menu_dropdown', 10, 4 );

Start_el 함수 덕분에 쿼리는 해당 함수에 따라 실행됩니다.부모 메뉴의 서브메뉴를 아이디로 카운트하는 기능이 있습니다.

function nav_count_children($parent_id){
    global $wpdb;
    $query = "SELECT COUNT(*) FROM $wpdb->postmeta 
            WHERE meta_key='_menu_item_menu_item_parent' 
            AND meta_value=$parent_id";
    $count_children = $wpdb->get_var( $query );
    return $count_children;
}

wp_get_nav_menu_parent 함수의 실행에서 $item-> menu_item_parent ==0으로 부모 메뉴의 ID를 선택합니다.

그것은 나에게 효과가 있고 매우 간단하다.

간단한 솔루션 소스가 있습니다.

function start_el(&$output, $item, $depth=0, $args=array()) {

  global $wpdb;
  $children_count = $wpdb->get_var(
    $wpdb->prepare("
      SELECT COUNT(*) FROM $wpdb->postmeta
      WHERE meta_key = %s
      AND meta_value = %d
    ", '_menu_item_menu_item_parent', $item->ID)
  );

  if( $children_count > 0 ) {
    // has children
    $classes[] = 'parent';
  }

  [...]

이 간단한 코드를 워커 클래스에서 사용합니다.

 class Description_Walker extends Walker_Nav_Menu
    {
    function start_el(  &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
    global $wp_query;
    ////

    ur code in this part 
    ///////
     $depth_classes = array(
        ( $depth == 0 ? 'nav-item' : 'nav-submenu-item' ),
        ( $depth >=2 ? 'sub-sub-menu-item' : '' ),
        ( $depth % 2 ? 'menu-item-odd' : 'menu-item-even' ),
        'menu-item-depth-' . $depth
    );
    $depth_class_names = esc_attr( implode( ' ', $depth_classes ) );

    // passed classes
    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $class_names = esc_attr( implode( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) ) );


     $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }
    }

언급URL : https://stackoverflow.com/questions/8448978/wordpress-how-do-i-know-if-a-menu-item-has-children

반응형