2017-04-15 118 views
0

该类设计为遍历WordPress菜单结构(嵌套数组/对象)以生成完成的菜单。虽然我的数据来源是WordPress,但我觉得这个问题属于SO而不是WP.SO,因为问题根植于PHP(适用于试图递归的任何人)。递归foreach()在循环时产生重复结果

出于某种原因,我在层次结构中看到重复的结果。另外,我注意到某些HTML元素没有正确关闭。看起来好像我已经正确地嵌套了一切,但结果就是你在这里看到的。

为了协助调试,我添加了一些*以直观地影响标记。也许你们知道我没有的东西。手指交叉并提前感谢您的意见!


我班

class Nav_Menu 
{ 
    public $wp_nav; 
    public $nested_nav; 
    public $recursion_depth = 0; 

    function __construct($menu, $args = array()) 
    { 
     $format = new Format; 

     if($menu) 
     { 
      $this->wp_nav = wp_get_nav_menu_items($menu, $args); 
      $this->nested_nav = $this->build_tree($this->wp_nav); 

      $output = $this->build_output($this->nested_nav); 
      $output_formatted = $format->HTML($output); 

      // echo $output; 
      echo $output_formatted; 
     } 
    } 

    private function build_output($menu = array()) 
    { 
     $output = '**'; 
     $output.= $this->recurse_menu($menu, $output); 

     return $output; 
    } 

    private function recurse_menu($menu = array(), $output) 
    { 
     global $post; 

     if(!empty($menu) && !empty($output)) 
     { 
      $this->recursion_depth++; 

      // ul classes 
      $classes_ul = array(); 
      $classes_ul[] = ($this->recursion_depth > 1 ? 'sub-menu' : ''); 
      $classes_ul[] = 'depth-' . $this->recursion_depth; 

      // process list wrappers 
      $output.= '<ul class="' . $this->process_classes($classes_ul) . '">'; 

      // loop through menu items 
      foreach($menu as $menu_key => $menu_val) 
      { 
       // process list items 
       $output.= '<li>' . $menu_val->title; 

       // if necessary, handle children and recurse 
       if(!empty($menu_val->children)) 
       { 
        // recurse, and call this again 
        $output.= $this->recurse_menu($menu_val->children, $output); 
       } 

       // process list items 
       $output.= '</li>'; 
      } 

      // process list wrappers 
      $output.= '</ul>'; 
     } 

     return $output; 
    } 

    private function process_classes($classes = array()) 
    { 
     if(!$classes) 
     { 
      return; 
     } 

     return trim(implode(' ', $classes)); 
    } 

    private function build_tree($elements = array(), $parent_id = 0) 
    { 
     $branch = array(); 
     foreach($elements as $element) 
     { 
      if ($element->menu_item_parent == $parent_id) 
      { 
       $children = $this->build_tree($elements, $element->ID); 
       if ($children) 
       { 
        $element->children = $children; 
       } 

       $branch[] = $element; 
      } 
     } 

     return $branch; 
    } 
} 

$mynav = new Nav_Menu('Test Menu'); 

输出结果

**** 
<ul class="depth-1"> 
    <li> 
     One** 
     <ul class="depth-1"> 
      <li> 
       One 
       <ul class="sub-menu depth-2"> 
        <li> 
         Sub One 
        </li> 
        <li> 
         Sub Two 
        </li> 
        <li> 
         Sub Three 
        </li> 
       </ul> 
      </li> 
      <li> 
       Two 
      </li> 
      <li> 
       Three** 
       <ul class="depth-1"> 
        <li> 
         One** 
         <ul class="depth-1"> 
          <li> 
           One 
           <ul class="sub-menu depth-2"> 
            <li> 
             Sub One 
            </li> 
            <li> 
             Sub Two 
            </li> 
            <li> 
             Sub Three 
            </li> 
           </ul> 
          </li> 
          <li> 
           Two 
          </li> 
          <li> 
           Three 
           <ul class="sub-menu depth-3"> 
            <li> 
             Sub One 
            </li> 
            <li> 
             Sub Two 
            </li> 
           </ul> 
          </li> 
          <li> 
           Four 
          </li> 
         </ul> 

的WordPress在后台菜单

WordPress navigation menu

+0

此外,echo'ing'$ output'而不是'$ output_formatted'产生相同的结果...只是连接在一起。我意识到你在这篇文章中错过了“格式”类,并且想要向所有人保证问题出在这里发布的代码上。 –

回答

0

如果有人知道原因,我愿意知道,所以我会保留现在选择一个答案。我的猜测是变量$output的某种奇怪的命名空间/范围问题。谁知道,我现在有点累了。

的修复得到一个合法的结构是这样的......


class Nav_Menu 
{ 
    public $wp_nav; 
    public $nested_nav; 
    public $recursion_depth = 0; 
    public $output = ''; 

    function __construct($menu, $args = array()) 
    { 
     $format = new Format; 

     if($menu) 
     { 
      $this->wp_nav = wp_get_nav_menu_items($menu, $args); 
      $this->nested_nav = $this->build_tree($this->wp_nav); 

      $this->build_output($this->nested_nav); 
      $output_formatted = $format->HTML($this->output); 

      // echo $this->output; 
      echo $output_formatted; 
     } 
    } 

    private function build_output($menu = array()) 
    { 
     $this->recurse_menu($menu); 
    } 

    private function recurse_menu($menu = array()) 
    { 
     global $post; 

     if(!empty($menu)) 
     { 
      $this->recursion_depth++; 

      // ul classes 
      $classes_ul = array(); 
      $classes_ul[] = ($this->recursion_depth > 1 ? 'sub-menu' : ''); 
      $classes_ul[] = 'depth-' . $this->recursion_depth; 

      // process list wrappers 
      $this->output.= '<ul class="' . $this->process_classes($classes_ul) . '">'; 

      // loop through menu items 
      foreach($menu as $menu_key => $menu_val) 
      { 
       // process list items 
       $this->output.= '<li>'; 
       $this->output.= $menu_val->title; 

       // if necessary, handle children and recurse 
       if(!empty($menu_val->children)) 
       { 
        // recurse, and call this again 
        $this->recurse_menu($menu_val->children); 
       } 

       // process list items 
       $this->output.= '</li>'; 
      } 

      // process list wrappers 
      $this->output.= '</ul>'; 
     } 
    } 

    private function process_classes($classes = array()) 
    { 
     if(!$classes) 
     { 
      return; 
     } 

     return trim(implode(' ', $classes)); 
    } 

    private function build_tree($elements = array(), $parent_id = 0) 
    { 
     $branch = array(); 
     foreach($elements as $element) 
     { 
      if ($element->menu_item_parent == $parent_id) 
      { 
       $children = $this->build_tree($elements, $element->ID); 
       if ($children) 
       { 
        $element->children = $children; 
       } 

       $branch[] = $element; 
      } 
     } 

     return $branch; 
    } 
} 

$mynav = new Nav_Menu('Test Menu'); exit; 

结果输出

<ul class="depth-1"> 
    <li> 
     One 
     <ul class="sub-menu depth-2"> 
      <li> 
       Sub One 
      </li> 
      <li> 
       Sub Two 
      </li> 
      <li> 
       Sub Three 
      </li> 
     </ul> 
    </li> 
    <li> 
     Two 
    </li> 
    <li> 
     Three 
     <ul class="sub-menu depth-3"> 
      <li> 
       Sub One 
      </li> 
      <li> 
       Sub Two 
      </li> 
     </ul> 
    </li> 
    <li> 
     Four 
    </li> 
</ul> 

我刚刚创建了一个私有变量的类,每次我需要将它作为存储位置引用离子,我只是追加它。和以前一样,但没有更多的必须通过$output下来一些疯狂的方法链。

如果有人有任何其他想法可以帮助社区,请分享!

0

更新您的build_output方法如下:

private function build_output($menu = array()) 
{ 
    $output = '<ul>'; 
    $output = $this->recurse_menu($menu, $output); 
    $output.= '</ul>'; 
    return $output; 
} 

更新您的recurse_menu方法如下:

private function recurse_menu($menu = array(), $output = '') 
{ 
    global $post; 
    if(!empty($menu)) 
     { 
     $this->recursion_depth++; 
     // ul classes 
     $classes_ul = array(); 
     $classes_ul[] = ($this->recursion_depth > 1 ? 'sub-menu' : ''); 
     $classes_ul[] = 'depth-' . $this->recursion_depth; 

     // loop through menu items 
     foreach($menu as $menu_key => $menu_val) 
     { 
      // if necessary, handle children and recurse 
      if(!empty($menu_val->children)) 
      { 
       // recurse, and call this again 
       $output.= '<li><a href="#">'.$menu_val->title.'</a><ul class="' . $this->process_classes($classes_ul) . '">'.$this->recurse_menu($menu_val->children).'</ul></li>'; 

      } 
      else { 
      $output.= '<li><a href="#">'.$menu_val->title.'</a></li>'; 
      } 

     } 
    } 

    return $output; 
} 

注:我有更多进一步分层次,并测试它工作正常。