Currently, there are no options for sorting facet links by the weight of taxonomy terms in the facet settings page. I am using Search API that supports hierarchical indexing of taxonomy terms as mentioned by cpliakas here, but it doesn't seem to make them to follow the order of taxonomy term weight.

I have been searching for solutions for awhile but nothing helps. Is it a feature that needs to be implemented by Facet API?

Sorry for my bad English, I hope you understand what I mean. Thanks!

Comments

cpliakas’s picture

This is an interesting use case, and I thinks a useful one as well. I am not sure if it will get into the core Facet API module, but the API should be flexible enough to support this. Trying to resolve the stable release blockers first, however I do want to try this out to see if the current API would allow for this. Would love to get feedback from other people's attempts as well.

Thanks,
Chris

cpliakas’s picture

Status: Active » Postponed

So looking at the current API this isn't possible without a lot of hacking. I think if we work on the issue posted at #1304820: Implement a hook that can alter facet data after it is returned from the server, then it would le pretty easy to add the taxonomy weight then filter by that value implementing hook_facetapi_sort_info() with a simple callback. Once I resolve the dependent issue I will post the taxonomy code here.

cpliakas’s picture

In addition, #1367964: Add requirements to sort info would also help this use case.

cpliakas’s picture

Status: Postponed » Needs work

First crack at this. With the patch applied at http://drupal.org/node/1304820#comment-5352346, the following code in a custom module named "mymodule" will allow you to sort facets by term weight. The requirements piece still has to be worked out, and I am also still deciding whether this should go in the core module or be implemented in contrib. I am leaning towards contrib.


/**
 * Implements hook_facetapi_facet_info_alter().
 */
function mymodule_facetapi_facet_info_alter(array &$facet_info, array $searcher_info) {
  foreach ($facet_info as $name => $facet) {
    if ($facet['field api name'] && ($field_info = field_info_field($facet['field api name']))) {
      // Only act on taxonomy term reference fields.
      if ('taxonomy_term_reference' == $field_info['type']) {
        $facet_info[$name]['alter callbacks'][] = 'mymodule_add_taxonomy_weights';
      }
    }
  }
}

/**
 * Alter callback that adds taxonomy weights to render array.
 */
function mymodule_add_taxonomy_weights(array &$build, FacetapiAdapter $adapter) {
  foreach (taxonomy_term_load_multiple(array_keys($build)) as $tid => $term) {
    $build[$tid]['#taxonomy_weight'] = $term->weight;
  }
}

/**
 * Implements hook_facetapi_sort_info().
 */
function mymodule_facetapi_sort_info() {
  $sorts = array();

  $sorts['taxonomy_weight'] = array(
    'label' => t('Taxonomy weight'),
    'callback' => 'mymodule_sort_taxonopmy',
    'description' => t('Sort by the taxonomy term weight.'),
    'weight' => -40,
  );

  return $sorts;
}

/**
 * Sorts by taxonomy weight.
 */
function mymodule_sort_taxonopmy(array $a, array $b) {
  $a_count = (isset($a['#taxonomy_weight'])) ? $a['#taxonomy_weight'] : 0;
  $b_count = (isset($b['#taxonomy_weight'])) ? $b['#taxonomy_weight'] : 0;
  if ($a_count == $b_count) {
    return 0;
  }
  return ($a_count < $b_count) ? -1 : 1;
}

foopang’s picture

@cpliakas, you are awesome! Thanks so much for your help! Appreciate your efforts on it:)

cpliakas’s picture

Title: Sort by the weight of taxonomy terms? » Add the ability to sort taxonomy facets by their term weight
cpliakas’s picture

Component: Code » Contrib
Status: Needs work » Needs review

This seems like a nice little contributed module. The code below works with the patches applied at #1304820: Implement a hook that can alter facet data after it is returned from the server and #1367964: Add requirements to sort info. Adding to the "Contrib" tag since this should be added outside of Facet API.


/**
 * @file
 * Adds an option to taxonomy facets to sort by term weight.
 */

/**
 * Tests whether a field is a term reference field.
 *
 * @param $field_name
 *   The machine readable name of the field.
 *
 * @return
 *   TRUE if the field is a term reference field.
 */
function mymodule_is_term_reference_field($field_name) {
  if ($field_name && ($field_info = field_info_field($field_name))) {
    return ('taxonomy_term_reference' == $field_info['type']);
  }
  else {
    return FALSE;
  }
}

/**
 * Implements hook_facetapi_facet_info_alter().
 */
function mymodule_facetapi_facet_info_alter(array &$facet_info, array $searcher_info) {
  foreach ($facet_info as $name => $facet) {
    // Only act on taxonomy term reference fields.
    if (mymodule_is_term_reference_field($facet['field api name'])) {
      $facet_info[$name]['alter callbacks'][] = 'mymodule_add_taxonomy_weights';
    }
  }
}

/**
 * Alter callback that adds taxonomy weights to render array.
 */
function mymodule_add_taxonomy_weights(array &$build, FacetapiAdapter $adapter) {
  foreach (taxonomy_term_load_multiple(array_keys($build)) as $tid => $term) {
    $build[$tid]['#taxonomy_weight'] = $term->weight;
  }
}

/**
 * Implements hook_facetapi_sort_info().
 */
function mymodule_facetapi_sort_info() {
  $sorts = array();

  $sorts['taxonomy_weight'] = array(
    'label' => t('Taxonomy weight'),
    'callback' => 'mymodule_sort_taxonopmy',
    'description' => t('Sort by the taxonomy term weight.'),
    'requirements' => array('mymodule_is_taxonomy_facet' => TRUE),
    'weight' => -40,
  );

  return $sorts;
}

/**
 * Checks whether the facet indexes taxonomy terms.
 *
 * @param array $realm
 *   The realm definition as returned by facetapi_realm_load().
 * @param array $facet
 *   The facet definition as returned by facetapi_facet_load().
 * @param $option
 *   If TRUE, the the requirements will pass if the facet indexes taxonomy
 *   terms. If FALSE, the facet must NOT index taxonomy terms in order to pass
 *   the requirements.
 *
 * @return
 *   TRUE if the hierarchical status matches $option, FALSE otherwise.
 */
function mymodule_is_taxonomy_facet(array $realm, array $facet, $option) {
  $is_taxonomy_facet = mymodule_is_term_reference_field($facet['field api name']);
  return ($option) ? $is_taxonomy_facet : !$is_taxonomy_facet;
}

/**
 * Sorts by taxonomy weight.
 */
function mymodule_sort_taxonopmy(array $a, array $b) {
  $a_count = (isset($a['#taxonomy_weight'])) ? $a['#taxonomy_weight'] : 0;
  $b_count = (isset($b['#taxonomy_weight'])) ? $b['#taxonomy_weight'] : 0;
  if ($a_count == $b_count) {
    return 0;
  }
  return ($a_count < $b_count) ? -1 : 1;
}

foopang’s picture

The contrib module works just perfectly. Thanks cpliakas!

cpliakas’s picture

Status: Needs review » Fixed

Thanks for testing. Marking as fixed. If someone decided to take this module on as their contrib, please post so multiple people don't create the same thing :-).

mrfelton’s picture

Code added to a sandbox project at http://drupal.org/sandbox/mrfelton/1377366

@cpliakas - I'm not really clear why in your code you were loading the field with field_info_field() based on $facet['field api name']. I found that $facet['field api name'] is always simply FALSE, so this wasn't working at all. I adjusted the code so that it instead just looks at the value of $facet['field type'] and ensures that it's is set to 'taxonomy_term' which seems to be the case for taxonomy term reference fields. With that adjustment, the module works great for me. If some others can confirm that the code in the sandbox project works for them, I'll promote the project to full project status and cut a release.

cpliakas’s picture

mrfelton,

Thanks for taking up this module! I appreciate you volunteering to maintain it.

In regards to the field type key, looking at the API documentation it isn't a key that is supported by Facet API and is probably custom to the search module you are using (Search API, right?). The field api name approach is the way that Facet API expects it to done, so I would recommend posting a bug report to the search module asking to utilize field api name. I don't mind posting the issue if you prefer.

Thanks again,
Chris

mrfelton’s picture

@cpliakas - yes, I'm using this in conjunction with Search API and its Solr integration. If you wouldn't mind posting the bug report over at Search API I'd appreciate that, since I'm sure that you would be able to give the most clear and concise report given your deeper understanding of the codebase.

- Tom

cpliakas’s picture

Thanks Tom. Issue posted at #1377734: The "field api name" key isn't being populated for facets containing field data. Since your setup is producing the error, I would be curious to see why this value is being not set. It looks like there is a small 8 line code snippet where this bug is being introduced, so it shouldn't take too much time to debug unless the issue is happening elsewhere. The link the the search_api_facetapi_facetapi_facet_info() function in the issue will point you directly to the code.

cpliakas’s picture

Also posted an issue #1379036: Resolve incompatibility with the Apache Solr Search Integration module with a patch that introduces a workaround to support both Apache Solr Search Integration and Search API with or without #1377734: The "field api name" key isn't being populated for facets containing field data resolved.

Status: Fixed » Closed (fixed)

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

Summit’s picture

Issue summary: View changes

Hi,
Is this contrib module https://www.drupal.org/node/1361284#comment-5384568 still necessary to sort facets?
greetings, Martijn

thePanz’s picture

@Summit: The module you need is now called FacetAPI Taxonomy Sort (https://www.drupal.org/project/facetapi_taxonomy_sort)