Problem/Motivation

The "Show only deepest item levels" processor (ShowOnlyDeepestLevelItemsProcessor) is supposed to hide any facet result that has children, leaving only leaf-level items visible. It is not working with facets_exposed_filters, for two independent reasons:

  1. supportsFacet() is gated to facet_entity only. The processor's supportsFacet() hardcodes support to $facet->getFacetType() == 'facet_entity', with a @todo Support "facets_exposed_filter". comment acknowledging the gap. Any facet exposed as a Views filter via the Facets Exposed Filters submodule has facet_type == 'facets_exposed_filter' at runtime, so the processor is excluded from that facet's pipeline entirely — it never even appears as a configurable option on the Views filter's settings form.
  2. Processor ordering. Once the type restriction above is lifted, the processor still has no effect: it declares a default build stage weight of 40, while HierarchyProcessor — the processor that actually populates each result's children via setChildren() — declares a weight of 100. Processors run in ascending weight order, so ShowOnlyDeepestLevelItemsProcessor::build() runs before the hierarchy tree is built. Its check if (!empty($result->getChildren())) { unset($results[$id]); } always sees an empty children array, so no result is ever excluded.

Reweighting the processor to run after HierarchyProcessor is not sufficient by itself, and surfaces a third, previously-latent bug:

  1. build()'s removal logic discards children along with their parent. HierarchyProcessor::build() deliberately removes child results from the top-level results array once they are nested under their parent (its own code comment: "Remove children from primary level"). ShowOnlyDeepestLevelItemsProcessor::build() only ever removes a parent when it has children — it has no logic to promote that parent's children back into the flat results array in its place. Once the ordering bug (2) is fixed and the processor actually runs against a built hierarchy tree, it removes every parent correctly, but their children vanish along with them instead of surfacing as the intended "deepest level" items. Only fixing (1) and (2) together produces a facet that shows no results below the top level at all, worse than doing nothing.

Steps to reproduce

  1. Create a hierarchical taxonomy vocabulary with at least one parent term that has children.
  2. Create a Search API facet on that field, with "Use hierarchy" enabled and hierarchy type "Taxonomy."
  3. Expose the field as a Views filter via the Facets Exposed Filters submodule (facets_filter plugin). Observe: the "Show only deepest item levels" processor is not offered as a selectable processor on the filter's settings form at all (bug 1).
  4. Patch supportsFacet() only and add the processor to the filter's processor_configs at its default weight. Observe: parent and child terms all still display (bug 2, ordering).
  5. Additionally reweight the processor to run after hierarchy_processor, without changing build(). Observe: both parent and child terms disappear — only childless top-level terms remain (bug 3, children are not promoted after their parent is removed).

Proposed resolution

  • Update ShowOnlyDeepestLevelItemsProcessor::supportsFacet() to also allow facet_type == 'facets_exposed_filter', removing the @todo.
  • Change the processor's declared build stage weight from 40 to a value greater than HierarchyProcessor's 100 (e.g. 110), so it runs after the hierarchy tree is built and getChildren() is populated.
  • Rewrite build() to recursively descend into each result's children and collect only the leaves (results with no children of their own), rather than simply unsetting any result that has children. This requires no additional queries: it operates purely on the hierarchy tree HierarchyProcessor already built via a single batched getChildIds() call, which matters for taxonomies with large numbers of terms since that call is not batched into a single query internally.

Remaining tasks

  • Patch and manual testing against both a classic Facets block and a Facets Exposed Filters (Views) placement, across more than one level of hierarchy depth.
  • Confirm no other core/contrib processor depends on ShowOnlyDeepestLevelItemsProcessor running at its current weight of 40 relative to processors between weight 40 and 100 (e.g. CountLimitProcessor, ExcludeSpecifiedItemsProcessor, HideOnlyOneItemProcessor, all at weight 50) before finalizing the new weight value.

User interface changes

None. The processor becomes selectable in the Views exposed-filter processor settings form for facets of type facets_exposed_filter, where it was previously silently omitted.

API changes

None. The processor's plugin ID and configuration schema are unchanged. The plugin annotation's declared default weight, the supportsFacet() return condition, and the internal implementation of build() change; a new protected helper method is added. No public method signatures change.

Data model changes

None.

CommentFileSizeAuthor
#6 facets-3616544-3.0.3.patch1.95 KBckng

Issue fork facets-3616544

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

ckng created an issue. See original summary.

ckng’s picture

Issue summary: View changes

ckng changed the visibility of the branch 3616544-facetsexposedfilters-show-only to hidden.

ckng’s picture

Category: Feature request » Bug report
Status: Active » Needs review
ckng’s picture

StatusFileSize
new1.95 KB

Patch file against 3.0.3, in case anyone need it.
MR is against 3.0.x-dev.