We're frequently asked, as part of an eCommerce site, to add a block to a product display page that renders a listing of related products. From a practical standpoint, our criteria for defining a "related product" is oftentimes some sort of grouping or category based on a Taxonomy term, which is present on a Commerce Product type as a taxonomy term reference field.

Currently, there is no straightforward way to accomplish this using standard Views contextual filters, since the taxonomy related filters are designed to work from "nodes" and therefore do not take into consideration other entity types that may be in your data, such as Commerce Product types.

After working on this issue for a couple of different clients, we finally hit upon a solution that accomplishes this goal, using Views PHP and a php based contextual filter.

Our case study is as follows:

  1. You have a product type in your commerce store called "widgets", and on that product type you have a taxonomy term reference field that has been added, that has the machine name "field_product_group_reference".
  2. You have a product display for your "widgets" product type that displays information about your individual "widget" products, including the pricing and "add to cart button", etc.
  3. Below your product details on your product display page you wish to display a block that contains "related products", and those related products are other "widgets" in your product data that have the same taxonomy term in the "field_product_group_reference" field as the product being displayed by the product display node.

One way to accomplish this is to use a php based contextual filter to provide the taxonomy term id as a filter argument to your views result.

Step 1: Add a new View, with a block display

Add a new view, showing "Commerce Product" of type "Widgets" sorted by "unsorted", uncheck "Create a Page", and check "Create a block", giving your view a block title of "Related Products Block", displaying an "Unformatted list" of "Fields", and limit to "0" (unlimited) items per page.

Click "Continue & Edit"

Step 2: Add Product Display relationships

In our case, we wanted to display a list of products by the product display title, along with their related image from the product entity.

In the right hand column, click the 'Add' button to the right of "Relationships", and add the "Commerce Product: Referencing Node", and select the product reference field that you have added to your product display. This will allow you to add the title field from the Product Display for your widget to this block you are creating. In our case, this field is named "field_widget_product_reference". Require this relationship.

Step 3: Add fields to your display

In the left hand column, under "Fields", click "Add", and add the Commerce Product: Images field for your widgets (in our case, shown as "Appears in: commerce_product:widgets". Uncheck "Create a label", Select Formatter:Image, Image style: Thumbnail, and Link image to: nothing.

Under "Fields" click "Add", and add "Content:Title", set your relationship to "Node referencing products from field_widget_product_reference". Uncheck "create a label", and check "Link this field to the original piece of content".

Under "Fields" click "Add", and add the "Content: Nid", set your relationship to "Node referencing products from field_widget_product_reference". Uncheck "create a label", and check "Exclude from display".

Remove the "Commerce Product: Product ID field.

Step 4: Add your contextual filter

In the right hand column, next to "Contextual Filters" click "Add". Select "Commerce Product: Group (which is the taxonomy term vocabulary you want to use to select your "related products"), which in our case "Appears in "commerce_product:widgets".

In the group, "When the Filter Value is NOT available", select Provide default value, and choose Type " PHP code. IN the PHP contextual filter code textarea, add the following:

//Get the node entity for the current page
$node = menu_get_object();
if($node->type == 'widget_display') {
  //Gets product entity from product display node
  $nodeproduct = entity_metadata_wrapper('node', $node)->field_widget_product_reference->value();
  //Gets taxonomy ID from product entity
  $group = entity_metadata_wrapper('commerce_product',   $nodeproduct)->field_product_group->value()->tid;
  return $group;
}

The above code does the following:

  1. Uses a call to menu_get_object to generate a node object from our menu router item for the current page. Since we will display this block only on product display pages for widgets by either configuring our views block, or adding it to a context for product display pages for widgets, this "object" will be a node object for the widget being displayed.
  2. Creates an Entity Metadata object from our node, so that we can easily pull the value stored in the "field_widget_product_reference" field
  3. Creates an Entity Metadata object from our related product entity for the display, so that we can get the value of the taxonomy term id stored in the "field_product_group" field on our product entity.
  4. Returns the value of the 'field_product_group' taxonomy term id, to use as a filter for our view results

Step 5: Add a PHP based Filter to remove the current product from the view results (requires Views PHP)

Currently, our "related products" block will display all products with the taxonomy term id of our current product display page, including our "current product", which needs to be excluded. We accomplish this by adding a "Global: PHP" filter criteria.

In the left hand column, Click "Add" next to "Filter Criteria, and select "Global: PHP" as your filter. Check "Use setup code" and add the following:

$node = menu_get_object();
if($node->type == 'widget_display') {
  $static['nid'] = $node->nid;
}

Our filter needs to return a TRUE if we are excluding any of our views rows from our results, and FALSE if we are to include them in our results. By storing the node id of the widget display page we are viewing in the "static" variable in our setup, we make that available for evaluation for each of our initial view results.

Add the following code to the "Filter code" block:

if($row->nid != $static['nid']) {
return FALSE;
} else {
return TRUE;
}

Save your view.

This block is now available to be added to any product display page for widgets products on your site.