1

currently My archive-product.php shows like this.

https://khaleejdev.com/kds/newtornetto/product-category/multilingual-digital-marketing/

Inside this there are 15 products and 3 subcategories (each subcategory has short description) 1st Sub category - 6 products 2nd Sub category - 4 products 3rd sub category - 5 products

currently there are only Products are pulled out inside the category and a short description of category.

what i want to achieve here is

  1. Category short description followed by
  2. 1st Sub category title and Short description followed by Products in it (6)
  3. 2nd Sub category title and Short description followed by Products in it (4)
  4. 3rd Sub category title and Short description followed by Products in it (5)

currently i have this code inside archive-product.php

<header class="woocommerce-products-header">
            <?php if ( apply_filters( 'woocommerce_show_page_title', true ) ) : ?>
                <h1 class="woocommerce-products-header__title page-title"><?php woocommerce_page_title(); ?></h1>
            <?php endif; ?>

            <?php
            /**
             * Hook: woocommerce_archive_description.
             *
             * @hooked woocommerce_taxonomy_archive_description - 10
             * @hooked woocommerce_product_archive_description - 10
             */
            do_action( 'woocommerce_archive_description' );


            ?>
            <?php 
         global $post;
        $args = array( 'taxonomy' => 'product_cat',);
        $terms = wp_get_post_terms($post->ID,'product_cat', $args);

            $count = count($terms); 
            if ($count > 0) {

                foreach ($terms as $term) {
                    echo '<div class="align-center text-justify">';
                    echo $term->description;
                    echo '</div>';

                }

            }

        ?>
        </header>
        <?php
        if ( woocommerce_product_loop() ) {

            /**
             * Hook: woocommerce_before_shop_loop.
             *
             * @hooked wc_print_notices - 10
             * @hooked woocommerce_result_count - 20
             * @hooked woocommerce_catalog_ordering - 30
             */
            do_action( 'woocommerce_before_shop_loop' );

            woocommerce_product_loop_start();

            if ( wc_get_loop_prop( 'total' ) ) {
                while ( have_posts() ) {
                    the_post();

                    /**
                     * Hook: woocommerce_shop_loop.
                     *
                     * @hooked WC_Structured_Data::generate_product_data() - 10
                     */
                    do_action( 'woocommerce_shop_loop' );

                    wc_get_template_part( 'content', 'product' );
                }
            }

            woocommerce_product_loop_end();

            /**
             * Hook: woocommerce_after_shop_loop.
             *
             * @hooked woocommerce_pagination - 10
             */
            do_action( 'woocommerce_after_shop_loop' );
        } else {
            /**
             * Hook: woocommerce_no_products_found.
             *
             * @hooked wc_no_products_found - 10
             */
            do_action( 'woocommerce_no_products_found' );
        }

        /**
         * Hook: woocommerce_after_main_content.
         *
         * @hooked woocommerce_output_content_wrapper_end - 10 (outputs closing divs for the content)
         */
        do_action( 'woocommerce_after_main_content' );

The desired format

The steps i explained should be like in image. Please help me to achieve it by customizing current archive-product.php

1

Lets see if this is helpfull. From your description you have/want the following setup:

-Category 
--Sub-Category-1
---Products of Sub-Category-1
--Sub-Category-2
---Products of Sub-Category-2
--Sub-Category-3
---Products of Sub-Category-3

OK, so you first need to get all top level categories. You can get them with something like this:

$top_categories_args = array(
    'taxonomy' => 'product_cat', // the taxonomy we want to get terms of
    'parent' => 0 // all top level cats with a parent of 0
);
$top_categories = get_terms( $top_categories_args );

With an foreach loop the iterate trough all top level cats:

foreach ($top_categories as $top_category) {

    $top_id = $top_category->term_id; // get term ID
    $top_slug = $top_category->slug; // get term slug
    $top_name = $top_category->name; // get term title
    $top_desc = $top_category->description; // get term description

    echo '<div class="'.$top_slug.'">';

    echo '<h2>'.$top_name.'</h2>';

    if ($top_desc) {
        echo '<p>'.$top_desc.'</p>';
    }

    // here we now need to get all the sub-categories

    echo '</div><!-- END top categories container -->';

}

Now we need an similar new get_terms query for the sub-categories: (should replace"// here we now need to get all the sub-categories")

// here we get all the sub categories of the current cat

$sub_categories_args = array(
    'taxonomy' => 'product_cat',
    'parent' => $top_id // we use the top_id from before to get only sub-cats
);
$sub_categories = get_terms( $sub_categories_args );

foreach ($sub_categories as $sub_category) {

    $sub_id = $sub_category->term_id;
    $sub_slug = $sub_category->slug;
    $sub_name = $sub_category->name;
    $sub_desc = $sub_category->description;

    echo '<div class="'.$top_slug.'-'.$sub_slug.'">';

    echo '<h3>'.$sub_name.'</h3>';

    if ($sub_desc) {
        echo '<p>'.$sub_desc.'</p>';
    }

    // here we now need to get all the products inside this sub-categories

    echo '</div><!-- END sub categories container -->';

}

And now, inside this sub-category code, you can now get the products with a query combined with a tax_query. (should replace"// here we now need to get all the products inside this sub-categories")

$products_args = array(
    'post_type'     => 'product', 
    'tax_query'     => array( 
        array(
            'taxonomy' => 'product_cat',
            'field'    => 'term_id', // we look for the ID, you could also use slug
            'terms'    => $sub_id, // get only products with the sub-cat ID
        ),
    ),
);
$products = new WP_Query( $products_args );

if ( $products->have_posts() ) { // only start if we hace some products

    // START some normal woocommerce loop

    woocommerce_product_loop_start();

    while ( $products->have_posts() ) : $products->the_post();

        wc_get_template_part( 'content', 'product' );

    endwhile; // end of the loop.

    woocommerce_product_loop_end();

    // END the normal woocommerce loop

    // Restore original post data, maybe not needed here (in a plugin it might be necessary)
    wp_reset_postdata();

} else { // if we have no products, show the default woocommerce no-product loop

    // no posts found
    wc_get_template( 'loop/no-products-found.php' );

}//END if $products

I created a gist here, with an complete product-archive.php and more details: product-archive.php


If you have some terms that you dont want to show, you can use exclude or exclude_tree, to disable them. For more options take a look at the codex page here.

// first we get all top-level categories
$top_categories_args = array(
    'taxonomy' => 'product_cat', // the taxonomy we want to get terms of
    'parent' => 0, // all top level cats with a parent of 0
    'hide_empty' => true,
    'exclude' => '11,23,99', // Array or comma/space-separated string of term ids to exclude.
    'exclude_tree' => '2,5,12' // Array or comma/space-separated string of term ids to exclude along with all of their descendant terms.
);

Also you can change the order of the terms with the default drag and drop function from WooCommerce. Just drag and drop the terms in the backend.

  • thanks for the answer , the current code pulls all category and sub categories inside it . But we are on the right track. here is the current look. Please compare with the image above. khaleejdev.com/kds/newtornetto/product-category/… we need to remove some parts. please help me by mentioning the code that needs to be removed to attain the look as image. – Nimesh Jun 18 '18 at 12:56
  • @Nimesh on the top of your page I see 2 categories which have no sub-categories, "Uncategorized" and "Export & Multichannel Services". To remove these, you can add an exclude argument with a list of ID´s from these. After this I think you need some CSS to put the description on the header image (if you need this). Will edit the answer. – LWS-Mo Jun 18 '18 at 13:38
  • 1
    So you want also to be able to view/open, for example, the "Multilingual Digital Marketing" Category, and only the 3 sub-categories (International Social Media, International Inbound marketing, International Marketing Automation) should be visible? Uh, than you need to different between is_shop() and is_product_category(). You could wrap the code you got now inside an is_shop() loop, and create a separate new loop for is_product_category(). Take a look at this, really quick and dirty Gist. – LWS-Mo Jun 18 '18 at 14:38
  • 1
    OK good, but keep in mind I just quickly thrown it together. The code could be cleaner, and you might want to work with not only archive-product.php but maybe use taxonomy-product_cat.php also. Maybe this will be cleaner. And you also need to tinker with the view of a sub-cats if you want. (maybe look if a parent exists and change the query accordingly). – LWS-Mo Jun 18 '18 at 14:55
  • 1
    If you have a category without sub-categories and the products should be shown, you can add an "else" statement to the "if ($terms)". Updated the quick and dirty Gist. – LWS-Mo Jun 20 '18 at 11:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.