Search code examples
wordpresswoocommerceproductshortcodestorefront

WooCommerce products shortcode outputs class="columns-x" twice


Just a vanilla call to product-category shortcode in functions.php is confusing me.

I'm trying to get a columns-3 of text sitting next to a columns-9 of products.

My code:

<div class="content">
  <div class="columns-3">
    <?php $home_kit = get_term(30, 'product_cat', ARRAY_A); ?>
    <h2 class="section-title"><?php echo $home_kit['name']; ?></h2>
    <p><?php echo $home_kit['description']; ?></p>
    <a href=" <?php echo get_category_link($home_kit['term_id']); ?>">All Products &raquo;</a>
  </div>
  <?php echo do_shortcode('[product_category category="home-kits" per_page="3" orderby="price" order="desc" columns="9"]'); ?>
</div>

The shortcode generates:

<div class="homepage-home-kit-category">
  <div class="content">
    <div class="columns-3">
     <h2...</h2>
     <p>...</p>
     <a ...</a>
    </div>
    <div class="woocommerce columns-9 ">
      <ul class="products columns-9">
        <li></li>
      </ul>
    </div>
  </div>
</div>

Note the repeat of the columns-9 on both the generated <div> and <ul>.

If both the <div> and <ul> have class columns-9 then I get 3/4 of the available 3/4.

Surely the class columns-9 only needs to be on either the WooComerce <div> or the <ul>.

How can I remove this addition from the <ul> element?

I am gratefull for the answers I received which are all valid and work well. I suppose my underlying problem is that I cannot see the usefulness of the product_category shortcode as it does not obey the columns parameter faithfully. Am I alone?


Solution

  • There are several options to remove/modify the columns-9 class from the <ul> element

    Solution 1 - Through the use of a filter hook.

    function filter_woocommerce_product_loop_start( $loop_start ) {
        // New output
        $loop_start = '<ul class="products">';
        
        return $loop_start;
    }
    add_filter( 'woocommerce_product_loop_start', 'filter_woocommerce_product_loop_start', 10, 1 );
    

    Solution 2 - Overwriting the template file.

    You could overwrite the templates/loop/loop-start.php template file

    • This template can be overridden by copying it to yourtheme/woocommerce/loop/loop-start.php.

    Replace

    <ul class="products columns-<?php echo esc_attr( wc_get_loop_prop( 'columns' ) ); ?>">
    

    With

    <ul class="products">
    

    Solution 3 - overwriting the existing function.

    Since woocommerce_product_loop_start uses function_exits, see: includes/wc-template-functions.php on line 1110-1134 @version 2.5.0

    More info: What's "function_exists" in Wordpress

    /**
     * Output the start of a product loop. By default this is a UL.
     *
     * @param bool $echo Should echo?.
     * @return string
     */
    function woocommerce_product_loop_start( $echo = true ) {
        $loop_start = '<ul class="products">';
    
        if ( $echo ) {
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo $loop_start;
        } else {
            return $loop_start;
        }
    }