Get WooCommerce product categories from WordPress
PhpWordpressWoocommercePhp Problem Overview
I am trying to get the product categories from WooCommerce through a function in my WordPress theme
function get_me_list_of($atts, $content = null)
{
$args = array( 'post_type' => 'product', 'posts_per_page' => 10, 'product_cat' => $atts[0]);
$loop = new WP_Query( $args );
echo '<h1 class="upp">Style '.$atts[0].'</h1>';
echo "<ul class='mylisting'>";
while ( $loop->have_posts() ) : $loop->the_post();
global $product;
echo '<li><a href="'.get_permalink().'">'.get_the_post_thumbnail($loop->post->ID, 'thumbnail').'</a></li>';
echo '<li><a href="'.get_permalink().'">'.$loop->post->post_title.'</a></li>';
echo '<li><a href="">'.get_categories().'</a></li>';
endwhile;
echo "</ul>";
wp_reset_query();
}
?>
The above code returns some products, but the product categories.
When I included echo '<li><a href="">'.get_categories().'</a></li>';
in the code above it returns as an array. How do I fix this?
How do i change this to get the product categories from WooCommerce?
Php Solutions
Solution 1 - Php
<?php
$taxonomy = 'product_cat';
$orderby = 'name';
$show_count = 0; // 1 for yes, 0 for no
$pad_counts = 0; // 1 for yes, 0 for no
$hierarchical = 1; // 1 for yes, 0 for no
$title = '';
$empty = 0;
$args = array(
'taxonomy' => $taxonomy,
'orderby' => $orderby,
'show_count' => $show_count,
'pad_counts' => $pad_counts,
'hierarchical' => $hierarchical,
'title_li' => $title,
'hide_empty' => $empty
);
$all_categories = get_categories( $args );
foreach ($all_categories as $cat) {
if($cat->category_parent == 0) {
$category_id = $cat->term_id;
echo '<br /><a href="'. get_term_link($cat->slug, 'product_cat') .'">'. $cat->name .'</a>';
$args2 = array(
'taxonomy' => $taxonomy,
'child_of' => 0,
'parent' => $category_id,
'orderby' => $orderby,
'show_count' => $show_count,
'pad_counts' => $pad_counts,
'hierarchical' => $hierarchical,
'title_li' => $title,
'hide_empty' => $empty
);
$sub_cats = get_categories( $args2 );
if($sub_cats) {
foreach($sub_cats as $sub_category) {
echo $sub_category->name ;
}
}
}
}
?>
This will list all the top level categories and subcategories under them hierarchically. do not use the inner query if you just want to display the top level categories. Style it as you like.
Solution 2 - Php
Improving Suman.hassan95's answer by adding a link to subcategory as well. Replace the following code:
$sub_cats = get_categories( $args2 );
if($sub_cats) {
foreach($sub_cats as $sub_category) {
echo $sub_category->name ;
}
}
with:
$sub_cats = get_categories( $args2 );
if($sub_cats) {
foreach($sub_cats as $sub_category) {
echo '<br/><a href="'. get_term_link($sub_category->slug, 'product_cat') .'">'. $sub_category->name .'</a>';
}
}
or if you also wish a counter for each subcategory, replace with this:
$sub_cats = get_categories( $args2 );
if($sub_cats) {
foreach($sub_cats as $sub_category) {
echo '<br/><a href="'. get_term_link($sub_category->slug, 'product_cat') .'">'. $sub_category->name .'</a>';
echo apply_filters( 'woocommerce_subcategory_count_html', ' <span class="cat-count">' . $sub_category->count . '</span>', $category );
}
}
Solution 3 - Php
You could also use wp_list_categories();
wp_list_categories( array('taxonomy' => 'product_cat', 'title_li' => '') );
Solution 4 - Php
In my opinion this is the simplest solution
$orderby = 'name';
$order = 'asc';
$hide_empty = false ;
$cat_args = array(
'orderby' => $orderby,
'order' => $order,
'hide_empty' => $hide_empty,
);
$product_categories = get_terms( 'product_cat', $cat_args );
if( !empty($product_categories) ){
echo '
<ul>';
foreach ($product_categories as $key => $category) {
echo '
<li>';
echo '<a href="'.get_term_link($category).'" >';
echo $category->name;
echo '</a>';
echo '</li>';
}
echo '</ul>
';
}
Solution 5 - Php
Efficient solution for getting all categories and sub-categories, no matter the depth.
/**
* Lists all product categories and sub-categories in a tree structure.
*
* @return array
*/
private function list_product_categories() {
$categories = get_terms(
array(
'taxonomy' => 'product_cat',
'orderby' => 'name',
'hide_empty' => false,
)
);
$categories = $this->treeify_terms($categories);
return $categories;
}
/**
* Converts a flat array of terms into a hierarchical tree structure.
*
* @param WP_Term[] $terms Terms to sort.
* @param integer $root_id Id of the term which is considered the root of the tree.
*
* @return array Returns an array of term data. Note the term data is an array, rather than
* term object.
*/
private function treeify_terms($terms, $root_id = 0) {
$tree = array();
foreach ($terms as $term) {
if ($term->parent === $root_id) {
array_push(
$tree,
array(
'name' => $term->name,
'slug' => $term->slug,
'id' => $term->term_id,
'count' => $term->count,
'children' => $this->treeify_terms($terms, $term->term_id),
)
);
}
}
return $tree;
}
It's also much more efficient than the current top answer as it uses only one query.
Solution 6 - Php
//Recursive function
function wc_loop_categories($parent = 0)
{
global $wpdb;
$query = "SELECT t.term_id AS ID, t.name AS title
FROM {$wpdb->prefix}terms AS t
LEFT JOIN {$wpdb->prefix}term_taxonomy AS ta
ON ta.term_id = t.term_id
WHERE ta.taxonomy='product_cat'
AND ta.parent=$parent
ORDER BY t.name ASC";
$cats = $wpdb->get_results($query);
foreach ($cats as $key => $cat) {
// get all sub_cats from current loop item
$cats[$key]->sub_cats = wc_loop_categories($cat->ID);
}
return $cats;
}
Solution 7 - Php
I have prepared the function that recursively creating menu and adding to object child element! masterCategoryId is the category rootId that recursion should work. FYI I did changes on Suman.hassan95 version.
function getWpCat($masterCategoryId = 3360, $returnCategories)
{
$taxonomy = 'product_cat';
$orderby = 'name';
$show_count = 1; // 1 for yes, 0 for no
$pad_counts = 1; // 1 for yes, 0 for no
$hierarchical = 1; // 1 for yes, 0 for no
$title = '';
$empty = 0;
$args = array(
'taxonomy' => $taxonomy,
'orderby' => $orderby,
'show_count' => $show_count,
'pad_counts' => $pad_counts,
'hierarchical' => $hierarchical,
'title_li' => $title,
'hide_empty' => $empty,
'parent' => $masterCategoryId
);
$all_categories = get_categories($args);
foreach ($all_categories as $cat) {
$returnCategories[$cat->slug] = $cat;
$child = get_categories(array(
'taxonomy' => $taxonomy,
'orderby' => $orderby,
'show_count' => $show_count,
'pad_counts' => $pad_counts,
'hierarchical' => $hierarchical,
'title_li' => $title,
'hide_empty' => $empty,
'parent' => $cat->cat_ID
));
if ( $child ) {
$returnCategories[$cat->slug]->child = getWpCat($cat->cat_ID, $returnCategories[$cat->slug]->child);
}
}
return $returnCategories;
}
$returnCategories = [];
$categories = getWpCat(3360, $returnCategories);
Solution 8 - Php
For better reading I suggest to use a class instead of a function, by the way with the following code you can manage unlimited subcategories:
class WoocommerceCategoriesDropdown
{
const PRODUCT_CAT = 'product_cat';
const NAME = 'name';
const SHOW_COUNT = 0;
const PAD_COUNTS = 0;
const HIERARCHICAL = 1;
const TITLE = '';
const HIDE_EMPTY = 0;
const INITIAL_LEVEL = 0;
private $all_categories;
private $currentCategory;
private $level;
public function __construct($currentCategory)
{
$this->level = self::INITIAL_LEVEL;
$this->currentCategory = $currentCategory;
$this->all_categories = get_categories($this->getRootCategoryQueryArgs());
}
public function render()
{
echo '<select class="category-list-dropdown">';
foreach ($this->all_categories as $cat) {
$this->level = 0;
if ($cat->category_parent == 0) {
echo '<option ' . $this->getSelected($cat) . ' data-link="' . get_term_link($cat->slug, self::PRODUCT_CAT) . '">' . $cat->name . '</option>';
$this->renderSubCategories($cat);
}
}
echo '</select>';
}
/**
* @return array
*/
private function getRootCategoryQueryArgs(): array
{
return [
'taxonomy' => self::PRODUCT_CAT,
'orderby' => self::NAME,
'show_count' => self::SHOW_COUNT,
'pad_counts' => self::PAD_COUNTS,
'hierarchical' => self::HIERARCHICAL,
'title_li' => self::TITLE,
'hide_empty' => self::HIDE_EMPTY,
];
}
/**
* @return array
*/
private function getSubCategoryQueryArgs($categoryId): array
{
$args2 = $this->getRootCategoryQueryArgs();
$args2['child_of'] = $categoryId;
$args2['parent'] = $categoryId;
return $args2;
}
/**
* @param $cat
*/
public function renderSubCategories($cat): void
{
$subCats = get_categories($this->getSubCategoryQueryArgs($cat->term_id));
if (!empty($subCats)) {
$this->level++;
foreach ($subCats as $subCategory) {
echo '<option ' . $this->getSelected($subCategory) . ' data-link="' . get_term_link($subCategory->slug, self::PRODUCT_CAT) . '">' . $this->getCategoryLevelSpacer() . $subCategory->name . '</option>';
$this->renderSubCategories($subCategory);
}
}
}
/**
* @param $cat
* @return string
*/
private function getSelected($cat): string
{
$selected = get_term_link($cat->slug, self::PRODUCT_CAT) === get_term_link($this->currentCategory->slug, self::PRODUCT_CAT) ? ' selected="selected" ' : '';
return $selected;
}
private function getCategoryLevelSpacer(): string
{
$spacer = '';
for ($i = 0; $i < $this->level; $i++) {
$spacer .= "-";
}
if (!empty($spacer)) {
$spacer = $spacer . " ";
}
return $spacer;
}
}
enter code here