diff --git a/module/VuFind/src/VuFind/Search/Base/Params.php b/module/VuFind/src/VuFind/Search/Base/Params.php
index fa5defef2d76ef6217cca6514ae4350bd5b686af..7f59bd02d5abf5ab53b19c19ed3f4ca356b132aa 100644
--- a/module/VuFind/src/VuFind/Search/Base/Params.php
+++ b/module/VuFind/src/VuFind/Search/Base/Params.php
@@ -955,6 +955,9 @@ class Params implements ServiceLocatorAwareInterface
             if ($firstChar == '-') {
                 $operator = 'NOT';
                 $field = substr($field, 1);
+            } else if ($firstChar == '~') {
+                $operator = 'OR';
+                $field = substr($field, 1);
             } else {
                 $operator = 'AND';
             }
diff --git a/module/VuFind/src/VuFind/Search/Solr/Params.php b/module/VuFind/src/VuFind/Search/Solr/Params.php
index 0e36fcbd414f925adf739986358df58c6b0b2511..b3df70047c6141c95460e783dd6278f90c0756f1 100644
--- a/module/VuFind/src/VuFind/Search/Solr/Params.php
+++ b/module/VuFind/src/VuFind/Search/Solr/Params.php
@@ -95,18 +95,32 @@ class Params extends \VuFind\Search\Base\Params
     {
         // Define Filter Query
         $filterQuery = $this->getOptions()->getHiddenFilters();
+        $orFilters = array();
         foreach ($this->filterList as $field => $filter) {
+            if ($orFacet = (substr($field, 0, 1) == '~')) {
+                $field = substr($field, 1);
+            }
             foreach ($filter as $value) {
                 // Special case -- allow trailing wildcards and ranges:
                 if (substr($value, -1) == '*'
                     || preg_match('/\[[^\]]+\s+TO\s+[^\]]+\]/', $value)
                 ) {
-                    $filterQuery[] = $field.':'.$value;
+                    $q = $field.':'.$value;
+                } else {
+                    $q = $field.':"'.addcslashes($value, '"\\').'"';
+                }
+                if ($orFacet) {
+                    $orFilters[$field] = isset($orFilters[$field])
+                        ? $orFilters[$field] : array();
+                    $orFilters[$field][] = $q;
                 } else {
-                    $filterQuery[] = $field.':"'.addcslashes($value, '"\\').'"';
+                    $filterQuery[] = $q;
                 }
             }
         }
+        foreach ($orFilters as $field => $parts) {
+            $filterQuery[] = $field . ':(' . implode(' OR ', $parts) . ')';
+        }
         return $filterQuery;
     }
 
diff --git a/module/VuFind/src/VuFind/Search/Summon/Params.php b/module/VuFind/src/VuFind/Search/Summon/Params.php
index ef348c0aec93327ad9442924c9f08cf06625c680..4cd61a468091153cdf3dcb418f5d4ace1686ee2a 100644
--- a/module/VuFind/src/VuFind/Search/Summon/Params.php
+++ b/module/VuFind/src/VuFind/Search/Summon/Params.php
@@ -211,6 +211,8 @@ class Params extends \VuFind\Search\Base\Params
         // Which filters should be applied to our query?
         $filterList = $this->getFilterList();
         if (!empty($filterList)) {
+            $orFacets = array();
+
             // Loop through all filters and add appropriate values to request:
             foreach ($filterList as $filterArray) {
                 foreach ($filterArray as $filt) {
@@ -232,6 +234,11 @@ class Params extends \VuFind\Search\Base\Params
                         $to = SummonQuery::escapeParam($range['to']);
                         $params
                             ->add('rangeFilters', "{$filt['field']},{$from}:{$to}");
+                    } else if ($filt['operator'] == 'OR') {
+                        // Special case -- OR facets:
+                        $orFacets[$filt['field']] = isset($orFacets[$filt['field']])
+                            ? $orFacets[$filt['field']] : array();
+                        $orFacets[$filt['field']][] = $safeValue;
                     } else {
                         // Standard case:
                         $fq = "{$filt['field']},{$safeValue}";
@@ -241,6 +248,13 @@ class Params extends \VuFind\Search\Base\Params
                         $params->add('filters', $fq);
                     }
                 }
+
+                // Deal with OR facets:
+                foreach ($orFacets as $field => $values) {
+                    $params->add(
+                        'groupFilters', $field . ',or,' . implode(',', $values)
+                    );
+                }
             }
         }
     }
diff --git a/module/VuFind/src/VuFind/Search/UrlQueryHelper.php b/module/VuFind/src/VuFind/Search/UrlQueryHelper.php
index 8df3e3e2d57fc8415b046f68c32667bd0cef8cf0..275bdb97cc5f0ee81c98888629faa59dde520a2b 100644
--- a/module/VuFind/src/VuFind/Search/UrlQueryHelper.php
+++ b/module/VuFind/src/VuFind/Search/UrlQueryHelper.php
@@ -297,6 +297,8 @@ class UrlQueryHelper
         // Account for operators:
         if ($operator == 'NOT') {
             $field = '-' . $field;
+        } else if ($operator == 'OR') {
+            $field = '~' . $field;
         }
 
         // Remove the filter:
diff --git a/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php b/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php
index ab506b4eece19ae6a98c9603237648f0ecc52f0e..d1ef8fd603603ed91032053bb008ea618a3edd9d 100644
--- a/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php
+++ b/module/VuFindSearch/src/VuFindSearch/Backend/Summon/Backend.php
@@ -328,14 +328,11 @@ class Backend implements BackendInterface
 
         // Convert the options:
         $options = array();
+        // Most parameters need to be flattened from array format, but a few
+        // should remain as arrays:
+        $arraySettings = array('facets', 'filters', 'groupFilters', 'rangeFilters');
         foreach ($params as $key => $param) {
-            // Most parameters need to be flattened from array format, but a few
-            // should remain as arrays:
-            if (in_array($key, array('facets', 'filters', 'rangeFilters'))) {
-                $options[$key] = $param;
-            } else {
-                $options[$key] = $param[0];
-            }
+            $options[$key] = in_array($key, $arraySettings) ? $param : $param[0];
         }
 
         return new SummonQuery($query, $options);
diff --git a/themes/blueprint/templates/Recommend/SideFacets.phtml b/themes/blueprint/templates/Recommend/SideFacets.phtml
index 55bed4b78e3b4f9a06acb6ec1f6ea58c419196e5..5eeb7962fd1fd0e7f1c327135e84659a6b189b7e 100644
--- a/themes/blueprint/templates/Recommend/SideFacets.phtml
+++ b/themes/blueprint/templates/Recommend/SideFacets.phtml
@@ -16,7 +16,7 @@
     <strong><?=$this->transEsc('Remove Filters')?></strong>
     <ul class="filters">
     <? foreach ($filterList as $field => $filters): ?>
-      <? foreach ($filters as $filter): ?>
+      <? foreach ($filters as $i => $filter): ?>
         <?
             if (isset($filter['specialType']) && $filter['specialType'] == 'keyword') {
                 $removeLink = $this->currentPath().$results->getUrlQuery()->replaceTerm($filter['value'], '');
@@ -27,7 +27,7 @@
         ?>
         <li>
           <a href="<?=$removeLink?>"><img src="<?=$this->imageLink('silk/delete.png')?>" alt="Delete"/></a>
-          <a href="<?=$removeLink?>"><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a>
+          <a href="<?=$removeLink?>"><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; if ($filter['operator'] == 'OR' && $i > 0) echo $this->transEsc('OR') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a>
         </li>
       <? endforeach; ?>
     <? endforeach; ?>
diff --git a/themes/jquerymobile/templates/Recommend/SideFacets.phtml b/themes/jquerymobile/templates/Recommend/SideFacets.phtml
index 91ed4b99df31524c605bed2cff747f2d7dc6cdaa..bb69c5fefddcf713148cda17727420f8d5784bed 100644
--- a/themes/jquerymobile/templates/Recommend/SideFacets.phtml
+++ b/themes/jquerymobile/templates/Recommend/SideFacets.phtml
@@ -3,13 +3,13 @@
   <ul class="filters" data-role="listview" data-inset="true" data-dividertheme="e">
     <li data-role="list-divider"><?=$this->transEsc('adv_search_filters')?></li>
     <? $i = 0; foreach ($filterList as $field => $filters): ?>
-      <? foreach ($filters as $filter): ?>
+      <? foreach ($filters as $j => $filter): ?>
         <?
             $removeLink = $this->currentPath().$results->getUrlQuery()->removeFacet($filter['field'], $filter['value'], true, $filter['operator']);
             if ($filter['displayText'] == '[* TO *]') $filter['displayText'] = $this->translate('filter_wildcard');
         ?>
         <li data-icon="minus">
-          <a data-icon="minus" rel="external" href="<?=$removeLink?>"><?=$i++ > 0 ? $this->transEsc("AND") . ' ' : ''?><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a>
+          <a data-icon="minus" rel="external" href="<?=$removeLink?>"><?=($i++ > 0 && ($j == 0 || $filter['operator'] != 'OR')) ? $this->transEsc("AND") . ' ' : ''?><? if ($filter['operator'] == 'NOT') echo $this->transEsc('NOT') . ' '; if ($filter['operator'] == 'OR' && $j > 0) echo $this->transEsc('OR') . ' '; ?><?=$this->transEsc($field)?>: <?=$this->escapeHtml($filter['displayText'])?></a>
         </li>
       <? endforeach; ?>
     <? endforeach; ?>