'Get WooCommerce product categories from WordPress

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?



Solution 1:[1]

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 2:[2]

You could also use wp_list_categories();

wp_list_categories( array('taxonomy' => 'product_cat', 'title_li'  => '') );

Solution 3:[3]

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 4:[4]

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 5:[5]

//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 6:[6]

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 7:[7]

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

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Xris Pap
Solution 2 Etienne Dupuis
Solution 3
Solution 4
Solution 5 Victor Hugo Soares Freitas
Solution 6 LifeInstructor
Solution 7 davide.taddei