2017-04-15 54 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; 
} 

注:我有更多進一步分層次,並測試它工作正常。