В шаблон
PHP:
<?php
echo get_categories_product();
?>
в function
PHP:
function get_categories_product($categories_list = '', $parent_id = 0) {
$get_categories_product = get_terms('product_cat', [
'orderby' => 'name', // Поле для сортировки
'order' => 'ASC', // Направление сортировки
'hide_empty' => 1, // Скрывать пустые. 1 - да, 0 - нет.
'hierarchical' => 1,
'parent' => $parent_id
]);
if(count($get_categories_product) > 0) {
$categories_list .= ($parent_id == 0 ? '<ul class="main_categories_list">' : '<ul class="sub_categories_list sub_categories_list_'.$parent_id.'">');
foreach($get_categories_product as $categories_item) {
$categories_list .= '
<li>
<a href="'.esc_url(get_term_link((int)$categories_item->term_id)).'">'.esc_html($categories_item->name).'</a>
'.get_categories_product('', $categories_item->term_id).'
</li>
';
}
$categories_list .= '</ul>';
}
return $categories_list;
}
upd
ну и стилями потом обвернете, какими вам нравиться
Приведённый выше вариант не хорош: во вложенном рекурсивном цикле вызывается запрос к базе данных.
Ещё и с отсутствием контроля над рекурсией.
Именно за подобный подход ненавидят Вордпресс, а зря (его надо ненавидеть за совсем другое).
Я понимаю, что
@derealty взял его с просторов и немного доработал, и спасибо за подсказку куда двигаться.
Добавлю, что в ВП вывод
лишь категорий товаров штатными средствами решается проще:
PHP:
echo '<ul>'.wp_list_categories( array('taxonomy' => 'product_cat', 'title_li' => '', 'echo' => 0,'show_count'=>1) ).'</ul>'
Одна строчка — и у вас красивый вложенный список вдобавок с количеством товаров в скобках!
Однако у меня стояла задача полностью все категории с товарами опубликовать.
Мне удалось это сделать 3 функциями: одна вытягивает все категории (одним запросом к базе!), другая строит по ним дерево (рекурсивно), третья добавляет товары в категорию. Весь итог выводится через шорткод.
Корневые категории обозначил диском, вложенные кружком, товары нумерацией:
![Screenshot 2022-04-24 at 10-44-03 Sitemap — Тестовый.png Screenshot 2022-04-24 at 10-44-03 Sitemap — Тестовый.png](https://cdn.ucrack.com/data/attachments/4/4739-4e6317bfa35dfe9ce4a4228e3fc1e7a3.jpg)
Можно было бы ещё оптимизировать, вытянув все товары одним запросом. Но такой код при большом количестве товаров может положить сервер.
Публикую окончательный вариант, вдруг кому-то ещё пригодится.
PHP:
function get_products($category) {
if (empty($category)) return '';
$products = "<small><ol>\r\n";
$all_ids = get_posts( array(
'post_type' => 'product',
'numberposts' => -1,
'post_status' => 'publish',
'tax_query' => array(
array(
'taxonomy' => 'product_cat',
'field' => 'ID',
'terms' => $category,
//'operator' => 'IN',
)
),
));
foreach ( $all_ids as $id ) {
$products .= '<li><a href="'.site_url().'/product/'.$id->post_name.'/">'.$id->post_title."</a></li>\r\n";
}
$products .= "</ol></small>\r\n";
return $products;
}
function fn_category_tree($array, $parent, $show_products = false) {
$parent = (!empty($parent) ? $parent : 0);
$result='';
if (!empty($array)) foreach ($array as $key=>$value) {
if ($value->parent==$parent) {
$result .= '<li' . (($value->parent == 0) ? ' class="first_child" ' : '') . '>' .
' <a href="' . esc_url(get_term_link((int)$value->term_id)) . '" title="'.esc_html($value->description).'">'.esc_html($value->name).'</a>';
$result .= "\r\n";
if ($show_products) $result .= get_products($value->term_id);
if ($value->parent != $value->term_id) $result .= fn_category_tree($array, $value->term_id, $show_products);
$result .= "</li>\r\n";
}
}
if (!empty($result)) $result = '<ul style="'.($parent==0?'list-style-type:disc;':'list-style-type:circle;').'">'."\r\n".$result."</ul>\r\n";
return $result;
}
function get_categories_product($parent_id = 0) {
$categories = get_terms(
'product_cat',
array(
//'orderby' => 'name', // Поле для сортировки
//'order' => 'ASC', // Направление сортировки
'hide_empty' => 0, // Скрывать пустые. 1 - да, 0 - нет.
'hierarchical' => 1,
'parent' => $parent_id,
)
);
return fn_category_tree($categories,0,true);
}
add_shortcode('get_categories_product', 'get_categories_product');
Разумеется, код нужно добавить в functions.php текущей темы.
Замечание
Ссылка на товар у вас может быть другой, у меня такая — «'.site_url().'/product/'.$id->post_name.'/»
Здесь для универсальности можно было написать метод из вордпресса для возврата правильного адреса поста, но это увеличит количество запросов к базе, поэтому я сделал так.