# Tùy biến hiển thị danh mục category wordpress (ok)

Để tùy biến can thiệp vào từng category bạn muốn hiển thị hoặc không muốn hiển thị trong danh sách categories bạn liệt kê ở sidebar widget thì chúng ta sử dụng tham số `walker` cũng giống với cách tùy biến với nav menu nhưng kế thừa class `Walker_Category`.

Walker là class đặc biệt cho việc hiển thị cấu trúc cây của menu, categories, pages, comments trong wordpress. Điển hình hàm `wp_list_categories()` có tham số walker giúp bạn tùy chỉnh bất kỳ dữ liệu danh mục nào bạn muốn hiển thị có kết hợp với template tags.

Đầu tiên, chúng ta tạo class kế thừa `Walker_Category`. Chép nội dung class sau vào functions.php hoặc viết vào plugin mới. Nhưng cho đơn giản bạn có thể thêm vào trong theme functions.php để có kết quả ngay.

```
class Post_Category_Walker extends Walker_Category {
  private $term_ids = array();
  function __construct( $post_id, $taxonomy )  {
    // fetch the list of term ids for the given post
    $this->term_ids = wp_get_post_terms( $post_id, $taxonomy, 'fields=ids' );
  }
  function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
    $display = false;
    $id = $element->term_id;
    if ( in_array( $id, $this->term_ids ) ) {
      // the current term is in the list
      $display = true;
    }
    elseif ( isset( $children_elements[ $id ] ) ) {
      // the current term has children
      foreach ( $children_elements[ $id ] as $child ) {
        if ( in_array( $child->term_id, $this->term_ids ) ) {
          // one of the term's children is in the list
          $display = true;
          // can stop searching now
          break;
        }
      }
    }
    if ( $display ) parent::display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output );
  }
}
```

Lưu ý: Tương tự như cách làm việc của Menu Walker. `Walker_Category` và `Walker_Nav_Menu` có kế thừa base class chung là `Walker`. Vì vậy có thể override các phương thức thuộc về Walker class như: display\_element, start\_lvl, end\_lvl, start\_el, end\_el.

ở đây chúng ta thấy có hàm `display_element()`, hàm này được gọi cho mỗi category và quyết định cho từng category được hiển thị hoặc không bằng cách gọi mặc định phương thức mẹ `parent::display_element` của nó. Hàm override này quét tất cả những categories, categories nào thuộc về post có chỉ định $id xác định qua constructor sẽ cho hiển thị bao gồm parent categories và cả subcategories.

Tạo đối tượng walker cho hàm hiển thị danh mục categories trong wordpress `wp_list_categorie`, ví dụ đưa vào hàm sau:

```
function walk_post_categories($post_id, $args = array()) {
  $args = wp_parse_args($args, array(
    'taxonomy' => 'category',
  ));
  $args['walker'] = new Post_Category_Walker($post_id, $args['taxonomy']);
  $output         = wp_list_categories($args);
  if ($output) {
    return $output;
  }
}
```

Để hiển thị các danh mục của bài viết theo cấu trúc tầng chúng ta truyền post vào hàm :

```
<?php walk_post_categories(123);?>
```

Đưa thêm tham số vào hàm wp\_list\_categories nếu muốn.

```
<?php walk_post_categories(123, 'show_count=1&title_li='); ?>
```

Hàm `start_lvl` có vai trò tạo thẻ html bao các categories con, thường là ul, ol tùy theo bạn thiết lập. Mặc định là tag **ul**. Chúng ta có thể hiển thị danh mục con bên dưới danh mục mẹ hoặc chỉ hiển thị danh mục mẹ với thuộc tính hierarchical.\
Do vậy để sử dụng phương thức `start_lvl` và `end_lvl` hãy chắc chắn có thiết lập thuộc tính “hierarchical=true”.

```
wp_list_categories(array('hierarchical'=>true));
```

Hàm `wp_list_categories` cũng cho phép loại bỏ wrap bao ngoài toàn bộ danh mục bằng cách khai báo thuộc tính ‘**title\_li**‘ với giá trị chuỗi rỗng.

```
wp_list_categories(array('title_li'=>''));
```

Kết quả chỉ còn các thẻ bao nội dung mỗi category, nếu style=”list” thì hàm wp\_list\_categories trả về sẽ như thế này.

```
<li class="cat-item cat-item-1"><a href="#" ><span>Item 1</span></a></li>
<li class="cat-item cat-item-4"><a href="#" ><span>Item 2</span></a></li>
<li class="cat-item cat-item-4"><a href="#" ><span>Item 3</span></a></li>
```

Tuy nhiên nếu có thiết lập tham số ‘title\_li’ thì kết quả có thêm thẻ bao **li** hoặc **ul** bên ngoài dữ liệu categories, khi Inspect Element trên chrome bạn sẽ thấy như sau:\
\
Không có cách nào loại bỏ với bắt đầu bằng thẻ li của wp\_list\_categories, nhưng bạn có thể dùng css tạo style cho thẻ li này.

![list-categories-wp](https://img.hoangweb.com/2014/09/list-categories-wp.png)

Tham khảo một số phương thức walker có thể dùng đến cho website của bạn, sẽ rất hữu ích khi bạn muốn chỉnh sửa HTML trong cấu trúc hiển thị dữ liệu mặc định category/Menu.

```
class hw_Walker_categories extends Walker_Category {
  function __construct() {}
  public function start_lvl(&$output, $depth = 0, $args = array()) {
    if ('list' != $args['style']) {
      return;
    }
    $indent = str_repeat("\t", $depth);
    $output .= "$indent<ul class='children'>\n";
  }
  public function end_lvl(&$output, $depth = 0, $args = array()) {
    if ('list' != $args['style']) {
      return;
    }
    $indent = str_repeat("\t", $depth);
    $output .= "$indent</ul>\n";
  }
  public function start_el(&$output, $category, $depth = 0, $args = array(), $id = 0) {
    /** This filter is documented in wp-includes/category-template.php */
    $cat_name = apply_filters(
      'list_cats',
      esc_attr($category->name),
      $category
    );
    $link = '<a href="' . esc_url(get_term_link($category)) . '" ';
    if ($args['use_desc_for_title'] && !empty($category->description)) {
      $link .= 'title="' . esc_attr(strip_tags(apply_filters('category_description', $category->description, $category))) . '"';
    }
    $link .= '>';
    $link .= $cat_name . '</a>';
    if (!empty($args['feed_image']) || !empty($args['feed'])) {
      $link .= ' ';
      if (empty($args['feed_image'])) {
        $link .= '(';
      }
      $link .= '<a href="' . esc_url(get_term_feed_link($category->term_id, $category->taxonomy, $args['feed_type'])) . '"';
      if (empty($args['feed'])) {
        $alt = ' alt="' . sprintf(__('Feed for all posts filed under %s'), $cat_name) . '"';
      } else {
        $alt  = ' alt="' . $args['feed'] . '"';
        $name = $args['feed'];
        $link .= empty($args['title']) ? '' : $args['title'];
      }
      $link .= '>';
      if (empty($args['feed_image'])) {
        $link .= $name;
      } else {
        $link .= "<img src='" . $args['feed_image'] . "'$alt" . ' />';
      }
      $link .= '</a>';
      if (empty($args['feed_image'])) {
        $link .= ')';
      }
    }
    if (!empty($args['show_count'])) {
      $link .= ' (' . number_format_i18n($category->count) . ')';
    }
    if ('list' == $args['style']) {
      $output .= "\t<li";
      $class = 'cat-item cat-item-' . $category->term_id;
      if (!empty($args['current_category'])) {
        $_current_category = get_term($args['current_category'], $category->taxonomy);
        if ($category->term_id == $args['current_category']) {
          $class .= ' current-cat';
        } elseif ($category->term_id == $_current_category->parent) {
          $class .= ' current-cat-parent';
        }
      }
      $output .= ' class="' . $class . '"';
      $output .= ">$link\n";
    } else {
      $output .= "\t$link<br />\n";
    }
  }
  public function end_el(&$output, $page, $depth = 0, $args = array()) {
    if ('list' != $args['style']) {
      return;
    }
    $output .= "</li>\n";
  }
}
```

&#x20;So sánh các phương thức này [tại đây](https://www.hoangweb.com/wordpress-site/custom-wordpress-menus-walker).

&#x20;Đối với category widget, wordpress cung cấp cho chúng ta hook `widget_categories_args` để thiết lập thêm tham số cho hàm wp\_list\_categories của category widget. Sau khi kéo widget category trên sidebar sẽ hiển thị ra website, chúng ta chèn đoạn code sau đây vào theme functions.php. Lưu ý là wordpress không có mọi tùy chỉnh nâng cao với widget này mà bạn phải code ngoài nhé.

```
function my_wp_list_categories($cat_args) {
  global $post;
  $tax                            = get_object_taxonomies($post);
  $cat_args['title_li']           = 'ABC';
  $cat_args['exclude']            = 1;
  $cat_args['use_desc_for_title'] = 0;
  $cat_args['walker']             = new Post_Category_Walker($post->ID, $tax[1]);
  return $cat_args;
}
add_filter('widget_categories_args', 'my_wp_list_categories', 10, 2);
```

Không hiểu sao categories widget mặc định trong wordpress không hỗ trợ đầy đủ walker, phương thức start\_lvl và end\_lvl không hoạt động. Mình thử với plugin Display Categories Widget thì hoạt động tốt. Phiên bản gốc hiện tại không có tùy chọn option Walker tuy nhiên mình đã can thiệp thêm cài đặt này cho phép bạn điền class Walker để sử dụng tính năng này. Sửa code plugin cũng rất đơn giản với nhưng bạn thành thạo PHP, nếu ai không biết thì liên hệ với mình nha.

Ngoài ra sử dụng filter “wp\_list\_categories” bạn có thể thêm, sửa, xóa toàn phần hiển thị HTML của hàm wp\_list\_categories.

```
add_filter('wp_list_categories','filter_wp_list_categories');
function filter_wp_list_categories($output){
	....
 	return $output;
}
```

Chú ý: nếu gặp lỗi ‘escape slashes’ sẩy ra với thẻ html giống thế này,

```
<li class=\"cat-item cat-item-5\">
  <a href=\"http://mysite/category/chinese-tea/\" title=\"View all...Chinese Tea\" rel=\"nofollow\">Chinese Tea</a>
</li>
```

Giải pháp sử lý loại bỏ slashes, trong php có hàm `stripslashes`, kết hợp với hàm tiện ích wordpress `wp_rel_nofollow`.

```
add_filter('wp_list_categories','esc_wp_rel_nofollow');

function esc_wp_rel_nofollow($output){
  ....
   return   stripslashes(wp_rel_nofollow($output));
}
```

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


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://learnphp.gitbook.io/learnphp/wordpress/tuy-bien-hien-thi-danh-muc-category-wordpress-ok.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
