Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何知道菜单项是否有子项?_Php_Wordpress - Fatal编程技术网

Php 如何知道菜单项是否有子项?

Php 如何知道菜单项是否有子项?,php,wordpress,Php,Wordpress,我正在开发一个带有嵌套子菜单的wordpress主题。我需要使没有孩子的元素在视觉上与有孩子的元素不同。现在我有这个菜单,但这可能会改变: A a1 a2 B b1 b2 C 如你所见,A和B有孩子。C不需要-我需要它在CSS级别上有所不同 理想情况下,我希望a在a和B中有子类,而不是在C中 到目前为止,我已经成功地创建了一个“menuwalker”PHP类,可以实例化并传递给它。其构造函数如下所示: class My_Walker_Nav_Menu extends Walke

我正在开发一个带有嵌套子菜单的wordpress主题。我需要使没有孩子的元素在视觉上与有孩子的元素不同。现在我有这个菜单,但这可能会改变:

A
  a1
  a2
B
  b1
  b2
C
如你所见,A和B有孩子。C不需要-我需要它在CSS级别上有所不同

理想情况下,我希望a
在a和B中有子类,而不是在C中

到目前为止,我已经成功地创建了一个“menuwalker”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
    }
  }
}
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...
}
那么,我如何判断
$item
是否有子项,或者是叶子


编辑:这个问题是由Wordpress论坛上一个叫“keesiemeijer”的人回答的。我会让这笔赏金过期,以防他想要收回。否则,我会将自己的答案标记为有效。

将其添加到
functions.php
它会将“下拉”类添加到父类

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
    }
  }
}
性能更佳的新方式

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 );
旧版:在数据库上进行密集处理

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;
}
我问了一下,keesiemeijer指了指我,他们做了以下事情:

他们没有修改
开始元素
,而是修改了
显示元素
,添加了以下两行(第37-38行):

我留下前两行作为空间参考,也作为对本文其他答案的评论。wordpress似乎“试图”在
$args
中设置“has_children”属性,但它要么做得不对,要么以我不理解的方式。在任何情况下,
有子项
参数永远不会传递给
开始
(请参阅$args的示例变量转储)

这可能是我得到的Wordpress版本(3.2.1)上的一个bug,可能在最新版本中已经修复


无论如何,我在WordPress论坛上得到的答案是帮助我解决这个问题的,所以我认为这已经解决了。我将等待悬赏到期,以防keesiemeijer想把他的答案放在这里。

有一个简单的解决方案


如果不想增加硬查询或函数的开销,可以在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()
*@自3.0.0以来
*
*@param string$通过引用传递的输出。用于附加其他内容。
*@param object$item菜单项数据对象。
*@param int$菜单项的深度。用于填充。
*@param int$当前页面菜单项ID。
*@param对象$args
*@url:http://www.liyinqing.com
*/
类My_Nav_Walk扩展Walker_Nav_菜单{
函数开始(&$output、$item、$depth、$args){
全局$wp_查询;
$indent=($depth)?str_repeat(“\t”,$depth):”;
$class_name=$value='';
$classes=空($item->classes)?array():(array)$item->classes;
$classes[]=“菜单项-”。$item->ID;
$class_name=join(“”,应用_过滤器('nav_menu_css_class',数组_过滤器($classes),$item,$args));
$class_names='class=“”.esc_attr($class_names)。”;
$id=应用过滤器('nav_菜单项\u id','menu item-'。$item->id,$item,$args);
$id=strlen($id)?'id=“”.esc_attr($id)。“:”;
$output.=$indent.';
$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)。“:”;
//检查我们的custom has_children属性。以下是要点
如果($args->有子项){
$attributes.=“class=”菜单父项“;
}
$item_output=$args->before;
$item_输出='';
$item\u output.=$args->link\u before。应用\u过滤器('the\u title',$item->title,$item->ID)。$args->link\u before;
$item_输出='';
$item_output.=$args->after;
$output.=apply_filters('walker_nav_menu_start_el'、$item_output、$item、$depth、$args);
}
函数显示元素($element,&$children_elements,$max_depth,$depth=0,$args,&$output){
$id_field=$this->db_fields['id'];
如果(is_object($args[0]){/,这里是要点
$args[0]->has_children=!empty($children_elements[$element->$id_field]);
}
返回父元素::显示元素($element、$children\u elements、$max\u depth、$depth、$args、$output);
}

}将此添加到functions.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;
}

然后,在您的walker中,您可以检查$item->has_children是真是假

谢谢Start_el函数,我的函数会跟随该函数运行查询。 我有一个功能将计数子菜单的父菜单的ID

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_items函数的每个函数中,通过$item->menu_item_parent==0选择父菜单的ID

这对我来说很有效,而且非常简单。

Kikito's完成了这项任务,但不是以最可重用的方式。在我看来,更好的方法是这样的:

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
    }
  }
}
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提到的WordPress中未修补的bug:问题是
$args[0]
并不总是一个数组。这似乎是
Walker::display_element()
的典型预期类型,但实际上我们在这里处理的是
Walker\u Nav_Menu::display_element()
,在这种情况下,
args
最终作为标准对象类型而不是数组类型传入。因此,我们只需要使用对象表示法而不是数组表示法添加
has_children
元素。问题解决了![1]

添加
elseif
accoun
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...
}
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...
}
/**
 * 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;
 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 );
    }
    }
$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...
        }   
    }
}
   if(in_array('menu-item-has-children', $item->classes) && $depth != 0)
   {
       // Your Code
   }