Get WooCommerce product categories from WordPress

PhpWordpressWoocommerce

Php 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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTesterView Question on Stackoverflow
Solution 1 - PhpSuman.hassan95View Answer on Stackoverflow
Solution 2 - PhpXris PapView Answer on Stackoverflow
Solution 3 - PhpEtienne DupuisView Answer on Stackoverflow
Solution 4 - PhpAbdel Rahman KamhawyView Answer on Stackoverflow
Solution 5 - PhpMaciej KrawczykView Answer on Stackoverflow
Solution 6 - PhpVictor Hugo Soares FreitasView Answer on Stackoverflow
Solution 7 - PhpLifeInstructorView Answer on Stackoverflow
Solution 8 - Phpdavide.taddeiView Answer on Stackoverflow