Module: Spree::FiltersHelper

Defined in:
app/helpers/spree/filters_helper.rb

Instance Method Summary collapse

Instance Method Details

#default_storefront_filter_values_scopeObject



71
72
73
# File 'app/helpers/spree/filters_helper.rb', line 71

def default_storefront_filter_values_scope
  @default_storefront_filter_values_scope ||= Spree::OptionValue.for_products(products_for_filters_default_scope).distinct
end

#default_storefront_products_for_filtersObject



24
25
26
# File 'app/helpers/spree/filters_helper.rb', line 24

def default_storefront_products_for_filters
  @default_storefront_products_for_filters ||= products_for_filters_default_scope.unscope(:order)
end

#filter_form_fieldsObject



136
137
138
139
140
# File 'app/helpers/spree/filters_helper.rb', line 136

def filter_form_fields
  return '' if products_filters_params.blank?

  map_filters_params_to_form_fields(products_filters_params)
end

#filter_price_rangeObject



49
50
51
52
53
54
55
56
57
58
# File 'app/helpers/spree/filters_helper.rb', line 49

def filter_price_range
  @filter_price_range ||= begin
    product_ids = products_for_filters_scope(except_filters: [:price]).ids

    {
      min: Spree::Price.for_products(product_ids).minimum(:amount) || 0.to_d,
      max: Spree::Price.for_products(product_ids).maximum(:amount) || 0.to_d
    }
  end
end

#filter_stock_countObject



60
61
62
63
64
65
66
67
68
69
# File 'app/helpers/spree/filters_helper.rb', line 60

def filter_stock_count
  @filter_stock_count ||= begin
    products_scope = products_for_filters_scope(except_filters: [:purchasable, :out_of_stock])

    {
      in_stock: products_scope.in_stock.distinct.count,
      out_of_stock: products_scope.out_of_stock.distinct.count
    }
  end
end

#filter_taxon_idsObject



98
99
100
101
102
103
104
# File 'app/helpers/spree/filters_helper.rb', line 98

def filter_taxon_ids
  @filter_taxon_ids ||= Rails.cache.fetch([spree_base_cache_key, storefront_products_for_taxon_filters, @taxon], expires_in: 1.day) do
    scope = storefront_products_for_taxon_filters.joins(:classifications)
    scope = scope.in_taxon(@taxon).unscope(:order) if @taxon.present?
    scope.distinct.pluck(:taxon_id)
  end
end

#filter_taxons_for_taxonomy(taxonomy) ⇒ Object



106
107
108
109
110
111
112
# File 'app/helpers/spree/filters_helper.rb', line 106

def filter_taxons_for_taxonomy(taxonomy)
  taxon_depth = @taxon.present? ? @taxon.depth + 1 : 1

  taxonomy.taxons.where(depth: taxon_depth).order(:lft).find_all do |taxon|
    (taxon.cached_self_and_descendants_ids & filter_taxon_ids).any?
  end
end

#filter_values_for_filter(filter) ⇒ Object



83
84
85
86
87
88
89
90
91
92
# File 'app/helpers/spree/filters_helper.rb', line 83

def filter_values_for_filter(filter)
  selected = single_option_filter_selected?(filter.name)
  if filter.option_values.loaded?
    storefront_filter_values_ids = storefront_filter_values_scope(selected).pluck(:id)

    filter.option_values.find_all { |option_value| storefront_filter_values_ids.include?(option_value.id) }
  else
    filter.option_values.where(id: storefront_filter_values_scope(selected))
  end
end

#map_filters_params_to_form_fields(filters_params, prefix_key = nil) ⇒ Object



142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'app/helpers/spree/filters_helper.rb', line 142

def map_filters_params_to_form_fields(filters_params, prefix_key = nil)
  filters_params.to_h.map do |key, value|
    key = CGI.escapeHTML(key)
    key = [prefix_key, key].join('][') if prefix_key.present?

    if value.is_a?(Array)
      value.map do |v|
        v = CGI.escapeHTML(v)
        "<input type='hidden' name='filter[#{key}][]' value='#{v}' />"
      end.join
    elsif value.is_a?(Hash)
      map_filters_params_to_form_fields(value, key)
    else
      value = CGI.escapeHTML(value)
      "<input type='hidden' name='filter[#{key}]' value='#{value}' />"
    end
  end.join.html_safe
end

#price_filtered?Boolean

Returns:

  • (Boolean)


168
169
170
171
172
173
174
# File 'app/helpers/spree/filters_helper.rb', line 168

def price_filtered?
  min_price = permitted_products_params.dig(:filter, :min_price).presence
  max_price = permitted_products_params.dig(:filter, :max_price).presence

  (min_price.present? && min_price.to_d >= filter_price_range[:min]) ||
    (max_price.present? && max_price.to_d <= filter_price_range[:max])
end

#product_filters_aggregationsObject



28
29
30
31
32
33
34
# File 'app/helpers/spree/filters_helper.rb', line 28

def product_filters_aggregations
  @product_filters_aggregations ||= storefront_products_for_filters.
                                    joins(variants_including_master: :option_values).
                                    group("#{Spree::OptionValue.table_name}.id").
                                    distinct.
                                    count
end

#product_single_filter_aggregationsObject



36
37
38
39
40
41
42
# File 'app/helpers/spree/filters_helper.rb', line 36

def product_single_filter_aggregations
  @product_single_filter_aggregations ||= default_storefront_products_for_filters.
                                          joins(variants_including_master: :option_values).
                                          group("#{Spree::OptionValue.table_name}.id").
                                          distinct.
                                          count
end

#product_taxon_aggregationsObject



114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'app/helpers/spree/filters_helper.rb', line 114

def product_taxon_aggregations
  @product_taxon_aggregations ||= Rails.cache.fetch([spree_base_cache_key, storefront_products_for_taxon_filters, current_store.taxons], expires_in: 1.day) do
    current_store.taxons.
      joins(:classifications).
      where("#{Spree::Classification.table_name}.product_id" => storefront_products_for_taxon_filters.ids).
                                  group(
                                    "#{Spree::Taxon.table_name}.id",
                                    "#{Spree::Classification.table_name}.product_id"
                                  ).
      unscope(:order).
      count("#{Spree::Classification.table_name}.product_id")
  end
end

#products_count_for_filter(name, value_id) ⇒ Object



44
45
46
47
# File 'app/helpers/spree/filters_helper.rb', line 44

def products_count_for_filter(name, value_id)
  aggregations = single_option_filter_selected?(name) ? product_single_filter_aggregations : product_filters_aggregations
  aggregations.fetch(value_id, 0)
end

#products_count_for_taxon(taxon) ⇒ Object



128
129
130
131
132
133
134
# File 'app/helpers/spree/filters_helper.rb', line 128

def products_count_for_taxon(taxon)
  taxon_self_and_descendants_ids = taxon.cached_self_and_descendants_ids
  aggregations = product_taxon_aggregations.select { |key, _value| key[0].in?(taxon_self_and_descendants_ids) }

  # We want to count unique products across the taxon tree
  aggregations.uniq { |key, _value| key[1] }.sum(&:last)
end

#products_for_filters_default_scopeObject



3
4
5
6
7
8
# File 'app/helpers/spree/filters_helper.rb', line 3

def products_for_filters_default_scope
  scope = storefront_products_scope
  scope = scope.in_taxon(@taxon) if @taxon.present?
  scope = scope.search_by_name(params[:q].strip).unscope(:order) if params[:q].present?
  scope
end

#products_for_filters_scope(except_filters: []) ⇒ Object



10
11
12
13
14
15
16
17
18
# File 'app/helpers/spree/filters_helper.rb', line 10

def products_for_filters_scope(except_filters: [])
  products_finder = Spree::Dependencies.products_finder.constantize

  finder_params = default_products_finder_params
  finder_params[:filter] = finder_params[:filter].except(*except_filters) if except_filters.any?

  products = products_finder.new(scope: storefront_products_scope, params: finder_params).execute
  current_store.products.where(id: products.unscope(:order).ids)
end

#single_option_filter_selected?(filter_name) ⇒ Boolean

Returns:

  • (Boolean)


161
162
163
164
165
166
# File 'app/helpers/spree/filters_helper.rb', line 161

def single_option_filter_selected?(filter_name)
  options_filter = permitted_products_params.dig(:filter, :options) || {}

  !price_filtered? && !taxons_filtered? &&
    options_filter.keys.length == 1 && options_filter.key?(filter_name)
end

#storefront_filter_values_scope(filter_selected) ⇒ Object



75
76
77
78
79
80
81
# File 'app/helpers/spree/filters_helper.rb', line 75

def storefront_filter_values_scope(filter_selected)
  if filter_selected
    default_storefront_filter_values_scope
  else
    Spree::OptionValue.for_products(storefront_products_for_filters).distinct
  end
end

#storefront_products_for_filtersObject



20
21
22
# File 'app/helpers/spree/filters_helper.rb', line 20

def storefront_products_for_filters
  @storefront_products_for_filters ||= products_for_filters_scope
end

#storefront_products_for_taxon_filtersObject



94
95
96
# File 'app/helpers/spree/filters_helper.rb', line 94

def storefront_products_for_taxon_filters
  @storefront_products_for_taxon_filters ||= products_for_filters_scope(except_filters: [:taxons, :taxonomy_ids])
end

#taxons_filtered?Boolean

Returns:

  • (Boolean)


176
177
178
# File 'app/helpers/spree/filters_helper.rb', line 176

def taxons_filtered?
  permitted_products_params.dig(:filter, :taxon_ids)&.any?
end