Skip to content

Using FacetWP with post to post relations

September 7th, 2018 WordPress Tips Making coffee the old fashioned way

On a client site some posts have a relationship with other posts, set in meta fields. The client wanted to have a category filter for products on a brand page. In this blog I will explain what I did to achieve this.

The Relationship

Let me first explain what the post to post relationship is.

There are two Custom Post Types: Brand and Product. Products can have exactly one brand, and these are stored in a custom field made with Advanced Custom Fields.

The Requirement

The client was showing all products of a brand on the brand page. This was the initial requirement, but as we all know, requirements can change. And so did this one. The client wants visitors to be able to filter the products by category. This allows them to better find a product they want, for example a desk, a chair or a separator wall.

The solution in words

When a client tells me about a requirement, or a change, I immediately start to browse through my known plugins library in my head, and fire up my code engine. Also in my head. 🤯

I made up the following:

  • Use FacetWP

  • Create a taxonomy product-category for product

  • Create a facet based on the product-category

  • Create a FacetWP template to show the products

  • Done

Well, that looks easy, and in the end it was, but I had some struggles to get it right. The brand page only shows products of that brand. So I thought it would be handy to create a FacetWP template file in which I try to limit the WP query to only get products of the shown brand. And that’s where the s^%# hit the fan. But hey, making mistakes equals learning.

The solution in code

The FacetWP template for this case is pretty simple. Just a default loop, with some code on how to show posts (products in this case). This file is stored in the root directory of the theme as facetwp-products.php so FacetWP can find it.

3echo '<div class="products">';
4while ( have_posts() ) {
5 the_post();
6 echo '<div class="product">';
7 echo '<div class="product-image"><a title="' . get_the_title() .
8 '" href="' . get_the_permalink() . '">' .
9 get_the_post_thumbnail( get_the_ID(), 'rectangle-landscape' ) .
10 '<h2 class="product-title">' . get_the_title() . '</h2></a></div>';
11 echo '</div>';
13echo '</div>';

The template and facets are loaded in the page template for brands. And that’s done with this code:

3// Add brand collection to single-brand with facets and facet template
4add_action( 'genesis_entry_content', 'nstrm_add_brand_products', 15 );
5function nstrm_add_brand_products() {
6 if ( is_singular( 'brand' ) ) {
7 // load facets
8 echo facetwp_display( 'facet', 'productcategory' );
10 // load default template
11 echo facetwp_display( 'template', 'products' );
12 }

The above code is used in a Genesis theme, but can be used in other themes as well.

When we stop after these steps, products will be shown and the facets will be active (if product-categories have been assigned to products). But, all products will be shown, and not just the products that belong on this brand page.

Adding brand awareness

We need to make sure FacetWP is aware that it should only show products that have the product-category set to the brand of the currently active brand page. This is where the facetwp_query_args filter comes in handy. We need to add some arguments to the query, being the brand. To do that we need the brand id.

On a ‘normal’ page or post, it;s easy to get the post ID. But, when using FacetWP, which uses AJAX calls, the post ID can sometimes not be present. So, we need to help FacetWP by adding the post ID to the page in a little snippet of JavaScript, and use that in the facetwp_query_args filter function.

2// facetwp - pass current post_id to FacetWP
3add_action( 'wp_head', function () {
4 if ( is_singular( 'brand' ) ) {
5 global $post;
6 ?><script>
7 (function ($) {
8 $(document).on('facetwp-refresh', function () {
9 FWP_HTTP.post_id = '&lt;?php echo $post->ID; ?>';
10 });
11 })(jQuery);
12 </script>
13 &lt;?php
14 }
15}, 100 );

And let’s create the filter function so we can use the brand id in the query that FacetWP uses.

3//facetwp - add facetwp_query_args filter for limiting products by brand
4add_filter( 'facetwp_query_args', function ( $query_args, $class ) {
6 // get post_id from Ajax request
7 $post_id = (int) $class->http_params[ 'post_id' ];
8 if ( empty( $post_id ) ) {
9 $post_id = get_queried_object_id();
10 }
12 $query_args[ 'meta_key' ] = 'merk';
13 $query_args[ 'meta_value' ] = $post_id;
14 $query_args[ 'posts_per_page' ] = '-1';
16 return $query_args;
17}, 10, 2 );

That’s it. Happy coding and thanks for reading. If you have any remarks or questions, please let me know in the comments.

Featured image by rawpixel on Unsplash

About Marcel Bootsman

Marcel discovered the web in 1995. Since then he has paid attention to and worked with lots of technologies and founded his own WordPress oriented business in 2009.

Currently Marcel is Marketing Manager for the Dutch Market at Kinsta where he helps Kinsta's client base grow in the Managed WordPress and Application & Database hosting arena.

You can contact Marcel on a diverse range of online platforms. Please see the Connect section on the homepage for the details.