Drupal Commerce - How to set up Search API to search SKUs with and without dashes
So, you've built your Drupal Commerce site and are now setting up Search. You probably aren't going to use Drupal core's search since it won't give you enough control over what and how search results are returned. You are going to set up your own search server and index using Search API.
In this example, I am using Solr Search with Acquia Search for Search API. It doesn't matter how you have your index and server set up - as long as you can index your Commerce Products and Product displays, the custom module that I will describe shortly should work. For my setup, I have downloaded and enabled the following modules.
- Search API - provides a framework for easily creating searches on any entity known to Drupal, using any kind of search engine.
- Commerce Search API - provides Commerce-specific Search API integration.
- Search Views - integrates Search API with Views, enabling users to create views with searches as filters or arguments. This is included as part of the Search API module.
- Solr Search - provides a Solr backend for the Search API module.
- Acquia Search for Search API - allows Search API Solr to connect to the Acquia Search service. It requires the Acquia Connector module and a valid subscription.
The whats and hows of getting Search API set up on Acquia are described pretty well in Acquia's docs on using the Search API Module so I'm not going to run through them here. I'm also going to assume you've got Commerce Search API set up and that you have successfully indexed your products and any other desired fields associated with your product displays. Commerce Guys have a good screencast on how to set up Commerce Search if you need more help. So, you should see your Server and Index set up at admin/config/search/search_api
as well as your fully indexed product displays at admin/config/search/search_api/index/product_display:
When editing the product display fields (as provided by the Commerce Search API module at admin/config/search/search_api/index/product_display/fields), you will likely have selected fields such as SKU (in my case, field_pd_sku is the Product Display product reference field):
and also how the Commerce Product SKU property relates to the Product display product reference field:
Congrats - getting this far is a big accomplishment! But let's say that you want users to be able to search SKUs both with and without dashes - not an unreasonable request. Luckily this is pretty easy to implement with a small custom module. This excellent blog post on adding a custom field to Search API Solr index was key to me figuring out how to do this. In this example the custom module is called gls_search (you'll want to change the name to something more appropriate to your project), but I'll assume you're all set on making a custom module in terms of generating the .info and .module files (if not, read this drupal.org document on creating a custom module). In the gls_search.module file, first we will implement a
hook_entity_property_info_alter():
/** * Implements hook_entity_property_info_alter(). */ function gls_search_entity_property_info_alter(&$info) { $info['commerce_product']['properties']['sku_without_dashes'] = array( 'type' => 'text', 'label' => t('SKU without dashes'), 'getter callback' => 'gls_search_sku_without_dashes', ); }
So, what's going on in this function? We are using a hook provided by Entity API to create an additional property of the product display - in this case, sku_without_dashes. This hook allows modules to alter metadata about entity properties. If you have debugging set up, it can be useful to understanding what exactly this means. Try adding the above hook, and then view the fields that are being indexed in your product display at /admin/config/search/search_api/index/product_display/fields. If you start your debugger, clear cache, and put a break statement in your new function, you'll see the following. Alternatively if you don't have debugging set up, add a dmp($item) using the devel module. This hook is only called when clearing cache as far as I can tell.
If you inspect the $info array that we are altering in our function, you will see that the new property, sku_without_dashes has been added at the bottom. This is just metainfo about the commerce_product, so it won't contain the values for the various fields (like title, sku, description etc).
If you just added this function alone, you would see that this property has now been added to the list of available fields at admin/config/search/search_api/index/product_display/fields:
However, there is no data associated with this field - next we need to write the getter callback function to create the SKUs without dashes:
/** * Getter callback for sku_without_dashes property. */ function gls_search_sku_without_dashes($item) { // Get SKU for a given product. $sku = $item->sku; // Check to make sure SKU has dashes. if (strpos($sku, '-') !== FALSE) { // Cleanup SKU to remove dashes. $sku_without_dashes = preg_replace('/-/', '', $sku); // Return SKU without dashes. return $sku_without_dashes; } // If SKU doesn't contain dashes, return original SKU. else { return $sku; } }
I hope the comments clarify what is going on here, but I'll walk through the individual steps quickly. First, we will use the information that is contained in the $info array to access our SKU:
// Get SKU for a given product. $sku = $item->sku;
Next we make sure we are only doing this if the SKU already has dashes - if it doesn't have dashes, we will get an error. The strpos PHP function finds the first position of a character in a given string. This function returns FALSE if the character isn't found, so that's why we want to check to make sure there is a dash.
// Check to make sure SKU has dashes. if (strpos($sku, '-') !== FALSE) {
So, if a dash is found, we will look through the SKU and remove all occurences of the dash using the PHP function preg_replace. This function performs a regex search and replaces any found occurrences, but in our case it's very simple since we are only looking for a '-'.
// Cleanup SKU to remove dashes. $sku_without_dashes = preg_replace('/-/', '', $sku);
We'll then return our SKU without dashes now that we have reformatted the SKU.
// Return SKU without dashes. return $sku_without_dashes;
Finally, we will return the unaltered SKU if no dashes were found in the first place.
} // If SKU doesn't contain dashes, return original SKU. else { return $sku; }
OK, now we need to add this field to our search index, and set it to Fulltext. Once you have done this, you will need to re-index your site to include this new field. Then try searching with and without a dash in the same SKU - hopefully it works for you.