0

I have a shortcode that takes 1 argument for post category slug and returns and list of posts.

    //[list-products] creates the product table in the wholesale page, can be used to create a table list of any category

function list_products_func ( $atts ) {

$a = shortcode_atts( array (
  'category' => '',
), $atts);

  $args = array(
      'posts_per_page' => -1,
      'tax_query' => array(
          'relation' => 'AND',
          array(
              'taxonomy' => 'product_cat',
              'field' => 'slug',
              'terms' => $a['category']
          )
      ),
      'post_type' => 'product',
      'orderby' => 'title,'
  );

  $products = new WP_Query( $args );
  echo "<table>";
  while ( $products->have_posts() ) {
      $products->the_post();
    $product = new WC_Product(get_the_ID());
      ?>
          <tr class="product-list-item">
              <td><a href="<?php the_permalink(); ?>">
                  <?php the_title(); ?>
              </a></td>
              <td>
                  <?php echo get_the_excerpt(); ?>
              </td>
              <td>
                  <?php echo $product->get_price_html(); ?>
              </td>
          <td>
          <?php echo woocommerce_quantity_input(
            array(
                'min_value' => 1,
                'max_value' => $product->backorders_allowed() ? '' : $product->get_stock_quantity(),
            )); ?>
          </td>
          <td>
          <?php echo woocommerce_template_loop_add_to_cart(); ?>
          </td>
          </tr>
      <?php
  }
  echo "</table>";
}
add_shortcode ( 'list_products' , 'list_products_func' );

I'd like it to be able to take any number of categories and return the posts that match BOTH categories. In this use case, it is being used by a coffee distributor to show WooCommerce products that have a category of wholesale and one of their coffee subcategories distinct-well-defined or whatever.

The way it is used is [list-products CAT1 CAT2]

I tried just typing the shortcode with commas and hoping the code interpreted that correctly, but that didn't work.

Any help would be appreciated.

Update

It turns out I actually need it to filter products so it only shows products that have both categories, not showing all products in both categories.

0

2 Answers 2

1

Maybe you can make it so that you can use the shortcode like [list-products categories="1,2,3"], and then explode them as an array to insert them as your terms?

<?php
function list_products_func($atts) {

   $a = shortcode_atts(array(
      'categories' => '',
   ), $atts);

   // Check for multiple categories by comma
   if ( strpos( $a['categories'], ',' ) !== false ) {
      $terms = explode( $a['categories'] );
   } else {
      $terms = $a['categories'];
   }

   $args = array(
      'posts_per_page'  => -1,
      'tax_query'       => array(
         'relation'     => 'AND',
         array(
            'taxonomy'  => 'product_cat',
            'field'     => 'slug',
            'terms'     => $terms // Your exploded terms array 
         )
      ),
      'post_type' => 'product',
      'orderby'   => 'title,'
   );

   $products = new WP_Query($args);
   echo "<table>";
   while ($products->have_posts()) {

      $products->the_post();
      $product = new WC_Product(get_the_ID()); ?>
      <tr class="product-list-item">
         <td><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></td>
         <td><?php echo get_the_excerpt(); ?></td>
         <td><?php echo $product->get_price_html(); ?></td>
         <td>
            <?php echo woocommerce_quantity_input(
            array(
               'min_value' => 1,
               'max_value' => $product->backorders_allowed() ? '' : $product->get_stock_quantity(),
            )); ?>
         </td>
         <td><?php echo woocommerce_template_loop_add_to_cart(); ?></td>
      </tr>
      <?php

   }
   echo "</table>";
}
add_shortcode('list_products', 'list_products_func');
?>
3
  • That did it! Thanks. I realized that I also needed it to generate multiple tax_query arguments, so that the AND relation would actually work as a filter. In the code above, it just shows all products in both categories, where I wanted it to only show products in BOTH. Commented Jan 12, 2017 at 16:14
  • Your answer also helped me think about the rest of the problem in a much more productive way. Thanks! Commented Jan 12, 2017 at 16:20
  • Glad I could help!
    – Robbert
    Commented Jan 13, 2017 at 8:06
0

This is an answer to the second part of my question, which I didn't realize until after the accepted answer came in.

First, I added the accepted answer from Robbert and this little for loop to expand the tax_query arguments dynamically:

//Generates an array of tax_query arguments
  $query_args = array ();
  foreach ( $terms as $term ) {
    array_push( $query_args, array (
          'taxonomy' => 'product_cat',
              'field' => 'slug',
              'terms' => $term
          )
    );
  }

  $args = array(
      'posts_per_page' => -1,
      'tax_query' => array(
          'relation' => 'AND',
          $query_args
      ),
      'post_type' => 'product',
      'orderby' => 'title,'
  );

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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