Worked on this for a while as one of the facets for Drupal Commons would need to have future date ranges mixed in with a single catch-all past date range.

This patch adds in a tabledrag form on the facet configuration page that allows users to add a new date range, with a machine name that the facet uses for the query, a label that is displayed, and a starting and ending date range. Any facet that uses the date_range query type and widget that does not have any date ranges customized will automatically use the existing date ranges that exist currently in the module.

screenshot

This workflow works on both Core and Solr facets, and the logic has been built into each respective search variant's class.

This patch also adds in the functionality from #1878586: Add counts to date ranges by adding the count logic into the code as well.

An example usage of this is in the following screenshot, where the "Next year" facet under "Date" has been added through the UI provided in the patch.
screenshot

The only concern I would have is the AJAX handler that handles adding a temp row to the tabledrag table for the "add new date range" currently rebuilds the entire form, since the form uses a theme handler to build the tabledrag table.

Comments

jpontani’s picture

Updated patch to have date range counts for core search date range facets.

An example of this using core search (and the Faceted Navigation for Search module to have facets for core search):
screenshot

jpontani’s picture

Re-roll with a good amount of code cleanup.

nick_vh’s picture

+++ b/date_facets.moduleundefined
@@ -42,33 +46,185 @@ function date_facets_associate_widget(array &$facet_info) {
+    $build[$range_data['machine_name']] = array(

is $range_data[..] safe enough as identifier?

+++ b/date_facets.moduleundefined
@@ -42,33 +46,185 @@ function date_facets_associate_widget(array &$facet_info) {
+      '#markup' => $range_data['label'],

Same here, is label safe enough?

+++ b/date_facets.moduleundefined
@@ -42,33 +46,185 @@ function date_facets_associate_widget(array &$facet_info) {
+    array('data' => t('Name !required', array('!required' => '<span class="form-required" title="' . t('This field is required.') . '">*</span>'))),

I don't like html in a t() function, but I guess there's nothing we can do about it?

+++ b/date_facets.moduleundefined
@@ -42,33 +46,185 @@ function date_facets_associate_widget(array &$facet_info) {
+  drupal_add_tabledrag('facetapi-date-range-query-date-ranges', 'order', 'self', 'date-range-weight');
+  $rows = array();
+  foreach (element_children($form['widget']['widget_settings']['ranges']) as $range_key) {
+    $row = array();
+    unset($form['widget']['widget_settings']['ranges'][$range_key]['label']['#title']);
+    $row[] = drupal_render($form['widget']['widget_settings']['ranges'][$range_key]['label'])
+      . drupal_render($form['widget']['widget_settings']['ranges'][$range_key]['machine_name']);
+    foreach (array('date_range_start', 'date_range_end') as $element) {
+      $temp_row = '';
+      foreach (array('op', 'amount', 'unit') as $item) {
+        unset($form['widget']['widget_settings']['ranges'][$range_key][$element . '_' . $item]['#title']);
+        $temp_row .= drupal_render($form['widget']['widget_settings']['ranges'][$range_key][$element . '_' . $item]);
+      }
+      $row[] = $temp_row;

woa, very dense piece of code. Please add some commenting.

Also if you do a foreach, make sure the value exist and that it is iteratable. (is_array )

+++ b/date_facets.moduleundefined
@@ -42,33 +46,185 @@ function date_facets_associate_widget(array &$facet_info) {
+        form_set_error("ranges][$range_key][$element", t('!item is required.', array('!item' => '<em>' . $element . '</em>')));

There must be a reason, but why ! if % gives you these tags>

+++ b/lib/Drupal/Apachesolr/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -25,37 +25,55 @@ class Drupal_Apachesolr_Facetapi_QueryType_DateRangeQueryType extends FacetapiQu
+    ¶

whitespace issue

+++ b/lib/Drupal/Apachesolr/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -25,37 +25,55 @@ class Drupal_Apachesolr_Facetapi_QueryType_DateRangeQueryType extends FacetapiQu
+    $settings = $this->adapter->getFacetSettings($this->facet, facetapi_realm_load('block'));
+    $ranges = (isset($settings->settings['ranges']) ? $settings->settings['ranges'] : date_facets_default_ranges());
+    foreach (array_merge($ranges, date_facets_default_ranges()) as $range) {
+      list($start, $end) = $this->generateRange($range);
+      $query->addParam('facet.query', $this->facet['field'] . ":[$start TO $end]");

please add some more commenting to explain what you are doing here

+++ b/lib/Drupal/Apachesolr/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -25,37 +25,55 @@ class Drupal_Apachesolr_Facetapi_QueryType_DateRangeQueryType extends FacetapiQu
+  protected function generateRange($range) {

you might want to use SolrBaseQuery::validFilterValue to check if your generated timestring is a valid solr string

+++ b/lib/Drupal/Apachesolr/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -64,6 +82,24 @@ class Drupal_Apachesolr_Facetapi_QueryType_DateRangeQueryType extends FacetapiQu
-    return date_facets_get_ranges();
+    $settings = $this->adapter->getFacetSettings($this->facet, facetapi_realm_load('block'));
+    $ranges = (isset($settings->settings['ranges']) && !empty($settings->settings['ranges']) ? $settings->settings['ranges'] : date_facets_default_ranges());
+    $build = date_facets_get_ranges($ranges);
+    if ($response = apachesolr_static_response_cache($this->adapter->getSearcher())) {
+      $facet_global_settings = $this->adapter->getFacet($this->facet)->getSettings();
+      $values = (array) $response->facet_counts->facet_queries;

same here, some more explanation would be useful

+++ b/lib/Drupal/Search/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -16,6 +16,43 @@ class Drupal_Search_Facetapi_QueryType_DateRangeQueryType extends FacetapiQueryT
+  protected function generateRange($range = array()) {

doxygen

+++ b/lib/Drupal/Search/Facetapi/QueryType/DateRangeQueryType.phpundefined
@@ -88,10 +98,40 @@ class Drupal_Search_Facetapi_QueryType_DateRangeQueryType extends FacetapiQueryT
+      // Iterate over each date range to get a count of results for that item.
+      foreach ($ranges as $range) {
+        list($start, $end) = $this->generateRange($range);
+        $facet_query = clone $this->adapter->getFacetQueryExtender();
+        $query_info = $this->adapter->getQueryInfo($this->facet);
+        $facet_query->addFacetField($query_info);
+        foreach ($query_info['fields'] as $field_info) {
+          $facet_query->addFacetJoin($query_info, $field_info['table_alias']);
+          $field = $field_info['table_alias'] . '.' . $this->facet['field'];
+          $facet_query->condition($field, $start, '>=');
+          $facet_query->condition($field, $end, '<');

again, very dense. Make it a little more enjoyable to read and understand please ;-)

jpontani’s picture

is $range_data[..] safe enough as identifier?

I would say yes in this case, as the machine_name is run through Drupal's built in machine_name Form API validation, which only allows alphanumeric characters and underscores.

Same here, is label safe enough?

I actually missed over that, and it is now being run through check_plain()

As for the rest, I went through and commented and made some slight changes as you suggested.

cpliakas’s picture

Title: Customizable date ranges » Implement the ability to customize the date ranges via the UI
Category: task » feature
Priority: Normal » Major

The Search API integration work is complete, so bumping this up in priority since it is the next thing we should try to tackle.

nick_vh’s picture

StatusFileSize
new31.52 KB

Updated patch for the date facets, needs a facetapi change to be a little more clear for the users. Will post as soon as I have posted that patch

You'll need this patch : http://drupal.org/node/1984490#comment-7365696

cpliakas’s picture

Status: Needs review » Postponed
cpliakas’s picture

Status: Postponed » Active

Dependent issue is in Facet API is resolved, resuming work on this issue.

cpliakas’s picture

Status: Active » Needs work

Patch in #6 doesn't apply.

jos_s’s picture

When I apply this patch (from #4), I can configure new date ranges, but when I try to view them in my browser I get the following error message in my server log files:

PHP Fatal error: Cannot redeclare Drupal_Apachesolr_Facetapi_QueryType_DateRangeQueryType::generateRange()

Looks like a namespace problem. The protection function is declared twice in the patch.

jos_s’s picture

Would it also be possible to define fixed dates in the date ranges? I am working with historical data and would like to define date ranges from, say, year 1900 till now, years 1800 till 1899, years 1750 till 1799, etc.

I am not very good in php, but if someone could push me in the right direction I could try to implement this myself.

cpliakas’s picture

#1859074: Can't select multiple date ranges is potentially related as we support OR facets for dates and introduce custom ranges.

muschpusch’s picture

#6 doesn't apply and doesnt seems to be complete because it doesn't patch lib/Drupal/SearchApi/Facetapi/QueryType/DateRangeQueryType.php

Could you please re-roll the patch?

nick_vh’s picture

Status: Needs work » Needs review
StatusFileSize
new31.29 KB

Updated version

nick_vh’s picture

Status: Needs review » Fixed

Committed

eugene.ilyin’s picture

Status: Fixed » Needs work

date_facets/lib/Drupal/SearchApi/Facetapi/QueryType/DateRangeQueryType.php

this class also uses function date_facets_get_ranges, but now this function requires argument, and module will not works for SearchAPI

Need additional work.

eugene.ilyin’s picture

Status: Needs work » Needs review
StatusFileSize
new3.63 KB

Seems I adapted it for searchApi. But maybe need some additional testing and work. Everybody can use this patch. It also was commited into 7.x-1.x-dev

Also I have question - why you did so? Why range for DAY applyed for all types (HOUR, DAY, WEEK...)

      if ($range['date_range_end_op'] == 'NOW') {
        $end = REQUEST_TIME + (int) DATE_RANGE_UNIT_DAY;
      }
bennos’s picture

installed the dev version which includes above patch.

mayby my bug issue is related to this.
see
https://drupal.org/node/2065113

muschpusch’s picture

Status: Needs review » Needs work

the patch doesn't apply to current dev or latest beta. The module is kind of broken at the moment...

nick_vh’s picture

Status: Needs work » Fixed

This patch was committed. If you want to make a follow up, please create a new issue - it becomes too confusing other wise.

It works well with apachesolr and would want to fix it for search api but I need some help in getting there.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.