Php 如何知道菜单项是否有子项?
我正在开发一个带有嵌套子菜单的wordpress主题。我需要使没有孩子的元素在视觉上与有孩子的元素不同。现在我有这个菜单,但这可能会改变: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
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
}