How to combine two facet items in Facet API
How to change solr search query for one facet using these modules: Search API, Search API solr, facet API, Facet API bonus and some custom code.
I have configured these modules to have a search page showing content that you search for and a list of facet items that you can filter the search result on. In my case the facet items was an representation of node types that you could filter the search result with.
There are tons of blogpost how to do that, Search API solr documentation.
The facet item list can look like this (list of node types to filter search result on):
- Foo (22)- Bar (18)- Elit (10)- Ipsum (9)- Ultricies (5)- Mattis (2)- Quam (1)
What I wonted to achieve was to combine two facet items to one so the list would look like this:
- Foo and Bar (40)- Elit (10)- Ipsum (9)- Ultricies (5)- Mattis (2)- Quam (1)
The solution was using Search API hook hook_search_api_solr_query_alter(). I need to only change the query for the facet Item (node type) "Foo" and try to include (node type) "Bar" in the search query. So I fetched the facet item name by digging deep into the argument "$query".
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #007700">function </span><span style="color: #0000BB">YOUR_CUSTOM_MODULE_search_api_solr_query_alter</span><span style="color: #007700">(array &</span><span style="color: #0000BB">$call_args</span><span style="color: #007700">, </span><span style="color: #0000BB">SearchApiQueryInterface $query</span><span style="color: #007700">) {<br><br> </span><span style="color: #FF8000">// Fetching the facet name to change solr query on.<br> </span><span style="color: #0000BB">$facet_item </span><span style="color: #007700">= </span><span style="color: #0000BB">$query</span><span style="color: #007700">-></span><span style="color: #0000BB">getFilter</span><span style="color: #007700">()-></span><span style="color: #0000BB">getFilters</span><span style="color: #007700">();<br> if (!empty(</span><span style="color: #0000BB">$facet_item</span><span style="color: #007700">)) {<br> </span><span style="color: #0000BB">$facet_item </span><span style="color: #007700">= </span><span style="color: #0000BB">$facet_item</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">]-></span><span style="color: #0000BB">getFilters</span><span style="color: #007700">();<br><br> if (!empty(</span><span style="color: #0000BB">$facet_item</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">])) {<br> if (!empty(</span><span style="color: #0000BB">$facet_item</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #0000BB">1</span><span style="color: #007700">])) {<br> </span><span style="color: #0000BB">$facet_item </span><span style="color: #007700">= </span><span style="color: #0000BB">$facet_item</span><span style="color: #007700">[</span><span style="color: #0000BB">0</span><span style="color: #007700">][</span><span style="color: #0000BB">1</span><span style="color: #007700">];<br> </span><span style="color: #FF8000">// This is my facet item I wont to change solr query on "Foo" and also add node type "Bar" to the filter.<br> </span><span style="color: #007700">if (</span><span style="color: #0000BB">$facet_item </span><span style="color: #007700">=== </span><span style="color: #DD0000">'foo'</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">$call_args</span><span style="color: #007700">[</span><span style="color: #DD0000">'params'</span><span style="color: #007700">][</span><span style="color: #DD0000">'fq'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">] = </span><span style="color: #0000BB">$call_args</span><span style="color: #007700">[</span><span style="color: #DD0000">'params'</span><span style="color: #007700">][</span><span style="color: #DD0000">'fq'</span><span style="color: #007700">][</span><span style="color: #0000BB">0</span><span style="color: #007700">] . </span><span style="color: #DD0000">' OR ss_type:"bar"'</span><span style="color: #007700">;<br> }<br> }<br> }<br> }<br>}<br></span><span style="color: #0000BB">?></span></span>
We have now altered the solr query, but the list looks the same, the only differences now is that if you click on the "Foo" facet you will get "Foo" and "Bar" (node type) nodes in the search result.
To change the facet item list, I used drupal hook_facet_items_alter() provided by contrib module Facet API Bonus
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #007700">function </span><span style="color: #0000BB">YOUR_CUSTOM_MODULE_facet_items_alter</span><span style="color: #007700">(&</span><span style="color: #0000BB">$build</span><span style="color: #007700">, &</span><span style="color: #0000BB">$settings</span><span style="color: #007700">) {<br><br> if (</span><span style="color: #0000BB">$settings</span><span style="color: #007700">-></span><span style="color: #0000BB">facet </span><span style="color: #007700">== </span><span style="color: #DD0000">"type"</span><span style="color: #007700">) {<br><br> </span><span style="color: #FF8000">// Save this number to add on the combined facet item.<br> </span><span style="color: #0000BB">$number_of_bar </span><span style="color: #007700">= </span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'bar'</span><span style="color: #007700">][</span><span style="color: #DD0000">'#count'</span><span style="color: #007700">];<br><br> foreach(</span><span style="color: #0000BB">$build </span><span style="color: #007700">as </span><span style="color: #0000BB">$key </span><span style="color: #007700">=> </span><span style="color: #0000BB">$item</span><span style="color: #007700">) {<br> switch (</span><span style="color: #0000BB">$key</span><span style="color: #007700">) {<br> case </span><span style="color: #DD0000">'foo'</span><span style="color: #007700">:<br> </span><span style="color: #FF8000">// Change the title of facet item to represent two facet items<br> // (Foo & Bar).<br> </span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'foo'</span><span style="color: #007700">][</span><span style="color: #DD0000">"#markup"</span><span style="color: #007700">] = </span><span style="color: #0000BB">t</span><span style="color: #007700">(</span><span style="color: #DD0000">'Foo and Bar'</span><span style="color: #007700">);<br><br> </span><span style="color: #FF8000">// Smash the count of hits together.<br> </span><span style="color: #007700">if (</span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'foo'</span><span style="color: #007700">][</span><span style="color: #DD0000">'#count'</span><span style="color: #007700">] > </span><span style="color: #0000BB">0</span><span style="color: #007700">) {<br> </span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'foo'</span><span style="color: #007700">][</span><span style="color: #DD0000">'#count'</span><span style="color: #007700">] = </span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'foo'</span><span style="color: #007700">][</span><span style="color: #DD0000">'#count'</span><span style="color: #007700">] + </span><span style="color: #0000BB">$number_of_bar</span><span style="color: #007700">;<br> }<br> break;<br><br> </span><span style="color: #FF8000">// Remove this facet item now when Foo item will include this node type in the search result.<br> </span><span style="color: #007700">case </span><span style="color: #DD0000">'bar'</span><span style="color: #007700">:<br> unset(</span><span style="color: #0000BB">$build</span><span style="color: #007700">[</span><span style="color: #DD0000">'bar'</span><span style="color: #007700">]);<br> break;<br> }<br> }<br> }<br>}<br></span><span style="color: #0000BB">?></span></span>
After this should the list look like we want.
- Foo and Bar (40)- Elit (10)- Ipsum (9)- Ultricies (5)- Mattis (2)- Quam (1)
I also have a text printed out by Facet API submodule Current Search. This module lets you add blocks with text and tokens. In my case I added text when you searched and filtered to inform the user what he just searched for and/or filtered on. This could be done by adding existing tokens in the configuration of Current Search module configuration page "admin/config/search/current_search". The problem for me was that the token provided was the facet items that facet API created and not the one I changed. So I needed to change the token with text "Foo" to "Foo & Bar".
This can be accomplished by hook_tokens_alter().
<span style="color: #000000"><span style="color: #0000BB"><?php<br></span><span style="color: #007700">function </span><span style="color: #0000BB">YOUR_CUSTOM_MODULE_tokens_alter</span><span style="color: #007700">(array &</span><span style="color: #0000BB">$replacements</span><span style="color: #007700">, array </span><span style="color: #0000BB">$context</span><span style="color: #007700">) {<br><br> if (isset(</span><span style="color: #0000BB">$replacements</span><span style="color: #007700">[</span><span style="color: #DD0000">'facetapi_active:active-value'</span><span style="color: #007700">])) {<br> switch (</span><span style="color: #0000BB">$replacements</span><span style="color: #007700">[</span><span style="color: #DD0000">'[facetapi_active:active-value]'</span><span style="color: #007700">]) {<br><br> case </span><span style="color: #DD0000">'Foo'</span><span style="color: #007700">:<br> </span><span style="color: #0000BB">$replacements</span><span style="color: #007700">[</span><span style="color: #DD0000">'[facetapi_active:active-value]'</span><span style="color: #007700">] = </span><span style="color: #DD0000">'Foo and Bar'</span><span style="color: #007700">;<br> break;<br> }<br> }<br>}<br></span><span style="color: #0000BB">?></span></span>
And that's it.