# How to display featured products on the homepage? (Sage 9 / WooCommerce)

**URL:** https://discourse.roots.io/t/how-to-display-featured-products-on-the-homepage-sage-9-woocommerce/13336
**Category:** sage
**Tags:** woocommerce, sage9
**Created:** 2018-08-14T14:36:30Z
**Posts:** 22

## Post 1 by @shaneparsons — 2018-08-14T14:36:30Z

Sorry if this isn’t the right place to ask, but I can’t find the help I need anywhere…

**How can I display featured products on my homepage?** The closest I got was with shortcodes… but the styling was all messed up (potentially bootstrap 4 / woo conflicts). My product pages and everything else look and work properly, so I can’t understand what’s going on.

Any form of help or guidance will be greatly appreciated.

P.S. I’m using this [sage-woo](https://github.com/hambos22/sage-woo) boilerplate for Sage 9 / WooCommerce.

---

## Post 2 by @alwaysblank — 2018-08-14T16:21:32Z

I haven’t used WooCommerce in a while, but IIRC products are just a post type, and “featured” is probably some sort of taxonomy, so is there any particular reason you can’t just grab them with a `get_posts()`?

---

## Post 3 by @shaneparsons — 2018-08-14T18:38:19Z

Thanks man, I was able to find a solution with that train of thought.

For anybody else who might stumble here… here’s what I used:

```
<div class="featured-products row">
  @php
      $args = array(
        'post_type' => 'product',
        'posts_per_page' => 12,
        'tax_query' => array(
          array(
            'taxonomy' => 'product_visibility',
            'field' => 'name',
            'terms' => 'featured',
          ),
        ),
      );
      $loop = new WP_Query($args);
      if ($loop->have_posts()) {
        while ($loop->have_posts()) : $loop->the_post();
          wc_get_template_part('content', 'product');
        endwhile;
      } else {
        echo __('No products found');
      }
      wp_reset_postdata();
  @endphp
</div>
```

---

## Post 4 by @mmirus — 2018-08-14T18:43:17Z

@shaneparsons if you want to clean things up, that would be a great candidate to move to your controller or a data filter.

---

## Post 5 by @shaneparsons — 2018-08-14T18:45:23Z

I do, but controllers and filters are unfamiliar territory for me… Any advice on where to start?

---

## Post 6 by @mmirus — 2018-08-14T18:49:31Z

@shaneparsons yep, I would just take a quick look at the docs and see if that gets you pointed in the right direction. If you still have questions after that go ahead and follow up here. Data filters will be the simplest place to start.

Using Sage’s data filters [https://roots.io/sage/docs/blade-templates/](https://roots.io/sage/docs/blade-templates/)  
Using Controller [https://github.com/soberwp/controller](https://github.com/soberwp/controller)

---

## Post 7 by @shaneparsons — 2018-08-14T19:07:01Z

Thank you @mmirus, I appreciate the guidance.

I’m having trouble understanding how to implement either of those concepts though, so I’ll likely just move along for the time being so I can finish the website on time.

In the meantime, if anybody has time and wishes to help me understand filters and controllers more, It’d definitely be good to know in the near future. [This link](https://allurewebsolutions.com/add-filter-function-sage-9) helped me a bit, but I still don’t fully understand how I’d convert my code above into it.

---

## Post 8 by @mmirus — 2018-08-14T19:46:08Z

This isn’t tested, but you’d do something roughly like this with the filter approach.

First, in `filters.php`, fetch your products and add them to the data that’s passed to your template:

```
add_filter('sage/template/front-page/data', function (array $data) {
    $args = array(
        'post_type' => 'product',
        'posts_per_page' => 12,
        'tax_query' => array(
            array(
                'taxonomy' => 'product_visibility',
                'field' => 'name',
                'terms' => 'featured',
            ),
        ),
    );
    $data['products'] = new WP_Query($args);
    return $data;
});
```

If your page doesn’t have the `front-page` class on the `body` element, replace `front-page` with the appropriate class.

Then in your Blade template:

```
@if (!$products->have_posts())
  {{ __('No products found') }}
@endif

@while ($products->have_posts()) @php $products->the_post() @endphp
  @php wc_get_template_part('content', 'product') @endphp
@endwhile
@php wp_reset_postdata() @endphp
```

@alwaysblank is a wizard when it comes to doing this stuff cleanly

---

## Post 9 by @alwaysblank — 2018-08-14T21:06:28Z

The use of WC here means I don’t have a lot of suggestions: I don’t really use WC unless I absolutely have to because it makes me grumpy. :frowning:

In this case I probably would have used a partial that expects certain data instead of WC’s templating system, so i could so something like this:

```
// app/filters.php
add_filter('sage/template/front-page/data', function (array $data) {
    $data['products'] = array_map( function ($product) {
        $featured_image_id = get_post_thumbnail_id($product->ID);
        return array(
            'name' => $product->post_title,
            'link' => get_permalink($product),
            'image' => $featured_image_id ? wp_get_attachment_image_src($featured_image_id, 'large') : false,
        );
    }, get_posts(array(
        'post_type' => 'product',
        'posts_per_page' => 12,
        'tax_query' => array(
            array(
                'taxonomy' => 'product_visibility',
                'field' => 'name',
                'terms' => 'featured',
            ),
        ),
    )));
    return $data;
});
```

```
// resources/views/front-page.blade.php
<div class="featured-products row">
    @foreach($products as $product)
        @include('products.featured', $product)
    @endforeach
</div>

// resources/views/products/featured.blade.php
<div class="featured-product">
    <h3>{{ $product['name'] }}</h3>
    <img src="{{ $product['image'][0] }}">
    <a href="{{ $product['link'] }}"></a>
</div>
```

---

## Post 10 by @shaneparsons — 2018-08-14T21:15:34Z

Wow, thanks for the elaborate examples @mmirus and @alwaysblank… Just looking through them helps clear up a lot of the confusion I had with filters.

I ran out of time today, but I’ll be testing these first thing tomorrow morning!

---

## Post 11 by @shaneparsons — 2018-08-15T13:45:14Z

Hmm, I’m getting the following errors:

Example #1:  
`Call to a member function have_posts() on null in ...`

Example #2:  
`Notice: Undefined variable: products in ...`  
`Warning: Invalid argument supplied for foreach() in ...`

It feels like filters.php and front-page.blade.php aren’t communicating with each other properly and `products` ends up being null/undefined… Any ideas why?

Edit: I tried deleting Controller as per [this discussion](https://discourse.roots.io/t/sage-9-passing-acf-data-via-blade-not-working/11641/6?u=shaneparsons), but that didn’t seem to fix it.

---

## Post 12 by @shaneparsons — 2018-08-15T14:11:00Z

Disregard the previous message, I figured it out… Here’s what I did:

- implemented [this example](https://discourse.roots.io/t/how-to-display-featured-products-on-the-homepage-sage-9-woocommerce/13336/8?u=shaneparsons)
  - note: [this example](https://discourse.roots.io/t/how-to-display-featured-products-on-the-homepage-sage-9-woocommerce/13336/9?u=shaneparsons) can also be used for more flexibilty

- changed the filter path from `sage/template/front-page/data` to `sage/template/home/data` to match my body class
- changed `WP_Query($args)` to `\WP_Query($args)`
- updated to `soberwp/controller: "dev-master#403c46b4b31706e42a767fca618b0829b852d26c"`
  - note: `"2.1.0"` will replace this once it is released

---

## Post 13 by @shaneparsons — 2018-08-15T15:15:57Z

It appears I spoke too soon… While deleting `soberwp/controller` fixed my filter issues, it appears to have broken my posts page (i.e. `Class 'App' not found`)… Is there a way to get filters and controllers to work in harmony? How should I go about fixing this?

---

## Post 14 by @alwaysblank — 2018-08-15T15:17:40Z

Which version of Controller are you using? The latest tagged version should fix this issue.

---

## Post 15 by @shaneparsons — 2018-08-15T15:19:18Z

I’m using the latest (2.0.1)

---

## Post 16 by @shaneparsons — 2018-08-15T15:44:28Z

I was able to convert the filter into a controller to overcome the issue in the meantime… but the conflict with filters is still a cause for concern. What does this mean for the default filters in filters.php? Are they working as intended?

---

## Post 17 by @alwaysblank — 2018-08-15T15:53:15Z

It looks like it hasn’t been tagged yet, but this commit should be 2.1.0 which I think fixes that problem: [https://github.com/soberwp/controller/commit/2ccaf4fb25c31cf0e5a70593a6a51433b2c784fc](https://github.com/soberwp/controller/commit/2ccaf4fb25c31cf0e5a70593a6a51433b2c784fc)

@withjacoby probably has better input re: Controller than I do though.

---

## Post 18 by @shaneparsons — 2018-08-15T16:17:04Z

Perfect! Until 2.1.0 is released, it seems like using dev-master fixes the issues.

---

## Post 19 by @alwaysblank — 2018-08-15T16:25:54Z

I’d recommend against defining `dev-master` in your `composer.json`, since it means that every time you run `composer update` it’ll pull whatever’s at the tip of the master branch—which may break your site. Instead, if the head of master is working for you I recommend locking it to that commit, i.e.:

```
"soberwp/controller": "dev-master#403c46b4b31706e42a767fca618b0829b852d26c"
```

Normally you can leave this kind of behavior to `composer.lock`, but when dealing w/ non-tagged stuff, this makes me feel a lot safer.

---

## Post 20 by @withjacoby — 2018-08-15T16:57:52Z

Tagging 2.1.0 this coming Sunday, but everything @alwaysblank said above is exactly right.

---

## Post 21 by @withjacoby — 2018-08-17T08:26:44Z

2.1.0 is tagged. [Changelog](https://github.com/soberwp/controller/blob/master/CHANGELOG.md)

---

## Post 22 by @keshy — 2018-09-01T16:22:25Z

Probably it’s better to use `wc_get_products()` instead of `get_posts()`. It’s the right way according to Woo and also here: [https://cfxdesign.com/create-a-custom-woocommerce-product-loop-the-right-way/](https://cfxdesign.com/create-a-custom-woocommerce-product-loop-the-right-way/)
