Tự code menu đa cấp cho themes WordPress

Tự code menu đa cấp cho themes WordPress

Menu là một thành phần không thể thiếu trong một website. WordPress có hỗ trợ chúng ta thêm rất nhiều menu vào các vị trí tùy chỉnh, tuy nhiên nó phải được themes hỗ trợ. Trong bài viết Hướng dẫn cách tạo menu trong WordPress đơn giản mình đã có trình bày cách lấy và tạo menu theo vị trí rồi, tuy nhiên với cách đó thì bạn không thể sử dụng tính năng kéo thụt lùi vào trên custom của WordPress được, trong bài này mình sẽ hướng dẫn bạn cách để có thể thực hiện được việc này.

Trong lập trình, người ta sẽ sử dụng các giải thuật đệ quy để giải quyết các công việc theo vòng lặp nhưng có lựa chọn. Menu đa cấp cũng vậy, thực tế thì menu đa cấp và một vòng lặp có lựa chọn, nó có thể được hình thành từ sự kết hợp của nhiều vòng lặp, nhiều hàm điều kiện khác nhau.

Nhiều trường hợp viết đệ quy menu đa cấp người ta thường truy vấn rất nhiều lần, tạo ra nhiều bộ dữ liệu khác nhau để ghép lại, nhưng cách làm đó sẽ không hay, làm tốn tài nguyên và làm server khổ sở vì truy vấn, Tuy nhiên trong WordPress bạn không nên làm thế, thay vì vậy thì mình thường tải dữ liệu menu một lần thôi và cho nó vào một biến sau đó sử dụng kết hợp hàm lặp foreach và if để hiển thị menu đa cấp. Nhưng trước tiên mình cần phân tích dữ liệu trả về và lấy ra các trường cần thiết đã.

Phân tích dữ liệu trả về của hàm menu

Mình sẽ sử dụng hàm menu được viết như bữa trước, hàm này có dạng như thế này:

<?php 
  $menuLocations = get_nav_menu_locations(); 
  $menuID = $menuLocations['main-nav']; 
  $primaryNav = wp_get_nav_menu_items($menuID); 
  foreach ( $primaryNav as $navItem ) {
     echo '<li class="menu-item menu-item-type-post_type menu-item-object-page"> <a href="'.$navItem->url.'" title="'.$navItem->title.'">'.$navItem->title.'</a> </li>';
  }
?>

Hàm trên sẽ lấy dữ liệu menu của main-nav, là một vị trí mà mình đã tạo ở file function. Bạn có thể xem lại bài Hướng dẫn cách tạo menu trong WordPress đơn giản trên blog của mình để biết các tạo, ở đây mình sẽ không nói lại nữa.

Bây giờ bạn bỏ hàm foreach đi và thay thành đoạn code như thế này

<?php 
   $menuLocations = get_nav_menu_locations(); 
   $menuID = $menuLocations['main-nav']; 
   $primaryNav = wp_get_nav_menu_items($menuID); 
   echo var_dump($primaryNav);
 ?>

Mình đã thay nó bằng hàm var_dump: đây là hàm hiển thị cấu trúc của một biến, một đối tượng,… nó sẽ cho mình thấy được các trường dữ liệu và dữ liệu của biến đó đang lưu trữ.

Bên trên là một phần của mảng mà mình show ra bằng hàm var_dump, nhìn cũng hãi thật menu mình chỉ cần cái title và url là đủ thế mà nó làm hẳn mấy chục trường vậy đó. Để làm menu đa cấp bạn cần chú ý thêm 2 trường nữa đó là ID và menu_item_parent. Trường ID là trường để xác định thôi, còn trường menu_item_parent là trường để xem nó là con của thằng nào (con của ID nào).

Thật ra cái này các bạn có thể tự tìm kiếm trên Google cũng ra đầy chứ cần gì đến hàm var_dump, nhưng nếu bạn là người thích tìm hiểu thì bạn nên làm như thế này, vừa nhanh hơn mà vừa có thể biết thêm nhiều thứ. Thật ra mình cũng ngạt nhiên vì nó quá nhiều trường như thế này, sau này nếu có ý tưởng gì mình có thể sử dụng các trường này để mở rộng.

Tóm lại, ngoài 2 trường title và url ra mình sẽ sử dụng trường ID và menu_item_parent để phục vụ việc tạo ra menu đa cấp.

Tạo menu đa cấp trong WordPress

Hàm lặp dưới đây sẽ giúp bạn lấy ra 3 cấp menu. Thật ra người ta viết một hàm để truyền vào tham số ID nhằm lấy ra các danh sách con và gọi lại nhưng nhu cầu hiển thị quá nhiều cấp (thường trên 5) là rất hiếm nên mình không làm như vậy, thay vì vì mình sẽ sử dụng 3 hàm lặp để lấy ra 3 cấp, các bạn có thể thêm theo cấu trúc dưới.

<ul id="menu-1" class="nav">
 <?php 
  $menuLocations = get_nav_menu_locations(); 
  $menuID = $menuLocations['main-nav']; 
  $primaryNav = wp_get_nav_menu_items($menuID); 
  $id_parent =0;
  foreach ( $primaryNav as $navItem ) {
    if($navItem -> menu_item_parent == $id_parent){
        echo '<li class="menu-item'.$navItem ->ID.'"> <a href="'.$navItem->url.'" title="'.$navItem->title.'">'.$navItem->title.'</a>'; 
        $sub="";
        foreach ( $primaryNav as $navItem2 ) { 
           if($navItem2 -> menu_item_parent == $navItem ->ID){
           $sub .= '<li class="menu-item'.$navItem2 ->ID.'"> <a href="'.$navItem2->url.'" title="'.$navItem2->title.'">'.$navItem2->title.'</a>';
           $sub2="";
           foreach ( $primaryNav as $navItem3 ) { 
              if($navItem3 -> menu_item_parent == $navItem2 ->ID){
              $sub2 .= '<li class="menu-item'.$navItem3 ->ID.'"> <a href="'.$navItem3->url.'" title="'.$navItem3->title.'">'.$navItem3->title.'</a></li>';
           } 
        }
        $sub .= '<ul>'.$sub2.'</ul>'; 
        $sub .= '</li>';
        } 
      }
      echo '<ul>'.$sub.'</ul>';
      echo '</li>';
    }
  }
 ?>
 </ul>

Với cách trên bạn dễ dàng chèn các class cần thiết để custom phù hợp với theme của mình. Đây là đoạn code mình dùng cho theme của mình, mặc dù 3 cấp mà mình chỉ có dùng 2 cấp à.

Chúc bạn thành công.