Reefine is an ExpressionEngine add-on that allows the user to search, filter and refine channel entries (eg products) on your site. It is aimed at ecommerce sites but can be used for sorting any kind of data stored in channel entries.
Support the development of this project by becoming a sponsor or hire me for your software project
- Reefine - ExpressionEngine addon
* Table of Contents
- Documentation Versions
- Installation
- Hello world
- Parameters
- parse
- channel
- url
- url_output
- theme
- method
- author_id
- disable_search
- disable_multiple_selected_groups
- fix_pagination
- site
- search:field name
- category
- category_url
- fixed_order
- show_expired
- show_future_entries
- status
- filter:fields
- filter:filter group name
- filter:filter group:type
- filter:filter group:fields
- filter:filter group:label
- filter:filter group:locale
- filter:filter group:show_empty_filters
- filter:filter group:custom_titles
- filter:filter group:custom_values
- filter:filter group:default
- filter:filter group:delimiter
- filter:_filter group:_join
- filter:_filter group:_orderby
- filter:_filter group:_sort
- filter:filter group:category_group
- filter:filter group:show_separate_only
- Single Variables
- {entries} Variable Pair
- {list_groups} Variable Pair
- {list_groups} » {filters} Variable Pair
- {list_groups} » {filters} » {filter_id}
- {list_groups} » {filters} » {filter_value}
- {list_groups} » {filters} » {filter_title}
- {list_groups} » {filters} » {url}
- {list_groups} » {filters} » {filter_quantity}
- {list_groups} » {filters} » {filter_active}
- {list_groups} » {filters} » {filter_active_class}
- {list_groups} » {filters} » {filter_active_boolean}
- {tree_groups} Variable Pair
- {tree_groups} » {filters}
- {tree_groups} » {filters} » {has_active_subfilters}
- {tree_groups} » {filters} » {has_active_subfilters_class}
- {tree_groups} » {filters} » {subfilters_1}
- {tree_groups} » {filters} » {subfilters_1} » {subfilters_2}
- {tree_groups} » {filters} » {subfilters_1} » {subfilters_2} » {subfilters_3} ...
- {number_range_groups} Variable Pair
- {search_groups} Variable Pair
- {active_groups} Variable Pair
- {filter_groups} Variable Pair
- Change Log
- Compatibility
- About Reefine
- Tips and Tricks
- Known Issues
- Code Samples
Make sure your system meets the minimum requirements:
- ExpressionEngine 2.4.0 or later
- PHP 5
First download and extract the Reefine ZIP file. There are folders, ee2, ee3, ee4 and ee5.
- Download and extract the ee2 folder in the Reefine ZIP file.
- Upload the third_party/reefine folder to system/expressionengine/third_party/
- Upload the themes/third_party/reefine folder to themes/third_party/
- Install the module in Add-Ons → Modules
- Check the ee2/docs folder for more instructions on Reefine 1.x
- Download and extract the Reefine ZIP file. Go into the ee3/ee4/ee5 folder depending on your ExpressionEngine version
- Upload the /system/user/addons/reefine folder to /system/user/addons/reefine
- Upload the /themes/user/reefine folder to /themes/user/reefine
- Click Developer → Add-on Manager. Scroll down to "Third Party Add-Ons" and click install next to Reefine.
This is a small tutorial to create a clothing shop filter. View a live demo.
- Create a Channel called "clothes"
- Create a Field group called "clothes"
- Add a field with short name "size" with the type "select dropdown" and add values Small, Medium, and Large.
- Add three more fields with short names "product_type", "colour" and "price" with the type "text"
- Add another field with short name "product_image" with type "file".
- Associate the field group with the channel you created.
- Add some entries to your channel, ensure that you add an image to product_image and the price field contains just a number, the other fields can be anything you want.
- Create a new template in a template group. (eg shop/search )
- Paste following code into template (Github Gist). Then go to your template and see the results.
This must be set to inward for the {entries} tag works correctly.
parse="inward"
Important: This is required for Reefine to work properly
Specify a list of channels to search through, seperated by pipe |.
channel="food|clothes|cutlery"
This specifies the structure of your url. It must show where each filter group goes in the url. The filter group is specified in curly braces. Each filter group must be seperated by characters that are unlikely to appear in the filter.
This example will produce an url of mypage followed by a search for title and then colour. For example if the user filters by title mugs and colour red it will produce /mypage/mugs/red
fields="title|colour" url="mypage/{title}/{colour}"
If the user does not specify a title it will replace it with the text "any". You can override this behaviour by specifying the any text after a pipe. For example this will produce mypage/any-title/any-colour if no filters are selected.
url="mypage/{title|any-title}/{colour|any-colour}"
If the user searches by multiple filters for a filter group you can also specify the text that will join them. By default it is "-or-" (for join="or" filter groups), or "-and-" (for join="and" filter groups). This applies to filter groups of type text only. For example this will product mypage/mugs/red-otherwise-green/ if the user filters by title mugs and colour red or green.
url="mypage/{title|any-title}/{colour|any-colour|-otherwise-}"
For filters of the type number_range the url by default is "any" for no filter, "-to-" as a seperator between the range of values, "at-least-" if only the min value is specified and "at-most-" if only the max value is specified. You can override these using these pipe seperated values:
url="mypage/{title}/{colour}/{price|any|-to-|at-least-|at-most-}"
You don't need to seperate filter groups by a slash you can use any text you want. This will produce urls such as buy-some-delightful-things-today or buy-some-green-mugs-today
url="buy-some-{colour|delightful}-{title|things}-today"
Important: If you are using method="url" (default) then this is required and all filter groups must be specified in the url.
Default: same as "url" parameter
Use this if you need to specify a different url for output to links. This is useful if you want to link to a new page on filtering or if you're using a language indicator in the first segment that isn't sent through to expressionengine. Reefine will still use the "url" parameter to get the current filter values.
url="/{colour}/{price}" url_output="/shop/{colour}/{price}"
You can specify a theme to use which will output the filters selectors to save you having to create them yourself. Themes are found in the /themes/third_party/reefine folder. Reefine comes with the themes "shop" and "form". The "form" theme is compatible with all methods whereas the "shop" theme is compatible with all methods except for method="post".
theme="shop"
You can create your own themes by copying the theme from the /themes/third_party/reefine folder, and then reference your new theme using the directory name. For example /themes/third_party/reefine/mytheme would be:
theme="mytheme"
The theme parameter is optional - you can specify all html & css in the template itself. See the code samples for an idea of how this works.
Default: url
This is the method by which the user can interact with Reefine. The supported methods are url, ajax, get and post. The method must be supported by your theme / template code. The existing themes "shop" and "form" will read the method used and adapt accordingly. If you are using your own theme or template code you should note the following:
method="url"
(default) allows the user to filter by using links. You must provide the url parameter for this to be used. You can use links with filter url or a form. If you are using a form it will automatically redirect to the correct URL when the form is submitted, you will also need to add<input type="hidden" name="form\_post" value="yes"/>
which fixes a problem where the user can submit a form with no filters selected.method="ajax"
will support returning Reefine as an AJAX request. You can use a form or filter the url links. If you add ajax_request=1 to the get/post request it will return just the form on it's own without the rest of the template. If you are using just template code to or making your own theme from scratch you will need to use javascript / jQuery to handle the AJAX request. Refer to themes/third_party/reefine/shop/ajax.js or themes/third_party/reefine/form/ajax.js for examples.method="get"
will allow for submitting the request via the GET method (so it appears in the URL eg http://www.example.com/products?colour=red ). You can use a form <form method="get" ...> or by using filter the url links.method="post"
will allow for submitting the request via POST eg <form methd="POST" ... >. Unless you have disabled secure forms you will need to add to your form as well. This method does not support filter the url links, you will need to use a form.
Pipe separate list of author IDs. This parameter can restrict the entries shown to just these author IDs.
author_id="1|3"
Default: no
You can add the parameter disable_search="yes" which will make Reefine ignore any filter values in the URL or post. This is useful for showing all filter options on a subpage. For example if you are on the product's page (http://www.example.com/products/items/red-trousers) you don't want Reefine to pick up the segments "items/red-trousers" so you add disable_search="yes" to ignore them:
<nav> {exp:reefine channel="clothes" parse="inward" theme="shop" disable_search="yes"
filter:fields="title|product_type|size|colour|price" filter:price:type="number_range"
url="/products/{product_type}/{size}/{colour}/{price}/{title}"}
{/exp:reefine} </nav>
<article>{exp:channel:entries channel="clothes"} <h1>{title}</h1> <p>{content}</p> {/exp:channel:entries}</article>
Default: no
Make it so users can only select one filter group at a time (useful for performance problems).
disable_multiple_selected_groups="yes"
Default: no
If you're using Structure and/or freebie you may find the pagination doesn't work correctly. Set this to yes to try and fix this.
fix_pagination="yes"
Specify the site ID if using Multi site manager.
site="1"
You can search by a particular field value or the title. This works in the same way as the channel:entries tag. Please refer to the documentation on search:field_name for channel entries in the ExpressionEngine documentation. Additionally you can use this to search the title with search:title="abc".
search:colour="red"
This parameter will limit all your entries to a particular category by it's category ID. You can include multiple categories seperated by pipe "|".
category="2|3"
You can also exclude categories using not:
category="not 2|3"
This parameter will limit all your entries to a particular category. This uses the category url title.
category_url="{segment_2}"
Pipe separated lists of entry ids that will allow you specify the exact order of the entry_ids go in. You will need to put this in the fixed_order for {exp:channel:entries} for example:
{exp:reefine fixed_order="1|2|3|4" ...snip...}
{entries}
{exp:channel:entries entry_id="{entry_ids}" fixed_order="{entry_ids}" dynamic="no" } ... snip ... {/exp:channel:entries}
{/entries}
{/exp:reefine}
Default: no
Show expired entries. You will also need to add this to your {exp:channel:entries} tag.
show_expired="yes"
Default: no
Show entries with an entry date that is in the future. You will also need to add this to your {exp:channel:entries} tag.
show_future_entries="yes"
Default: open
This will limit the entries by their status. Multiple statuses are seperated by a pipe character "|".
status="featured|on_offer"
Important: The containing exp:channel:entries tag will also need to have the same status tag, otherwise the filter and search results will differ.
Pipe | seperated list of fields to filter by. For each field it will assume some defaults, such as specifying "title" will assume type is "search", a checkboxes/multiselect field will assume delimiter="|". You can then change some of attributes of the filter by referencing filter:field name:... as below. Each field will then be a filter group.
filter:fields="title|product_type|colour"
You can specify extra information about filter groups by using a parameter in the format filter:filter group name:variable. Some examples:
filter:search:fields="title|product_type|colour"
filter:search:category_group="3"
filter:search:type="search"`
filter:price:fields="price"
filter:price:type="number_range"
filter:colour:fields="colour"
filter:colour:delimiter="|"
filter:colour:label="Paint Colour"
filter:colour:join="or"
filter:colour:orderby="active"
Default: list
Specify the different filter group types which enables different features of Reefine. For example:
filter:price:type="number_range"
filter:search:type="search"
filter:colour:type="list"
Note: Not related to the field types in ExpressionEngine.
This is the default method. It will show a list of all possible value of the fields specified with the quantity. Also see {list_groups}
Search is for text searches with a text box. It will search each word individually. Also see {search_groups}
filter:search:fields="title|product_type|colour"
filter:search:type="search"
The number range allows the user to specify a minimum and maximum value to filter by. This is useful for price ranges. It will output extra information in the filter variables pair and the tag {number_range_groups}
filter:price:fields="price"
filter:price:type="number_range"
This type will allow the user to filter the entries by a list of months. This example if for a channel with the Date fields event_from (the date the event starts) and event_to (the date the event ends, this is useful in case the event covers more than one month). Also notice the filter:month:where_after parameter will hide all months that have passed. You can also use where_before to hide months in the future. The fields entry_date and expiration_date are also supported.
filter:month:type="month_list"
filter:month:fields="event_from|event_to"
filter:month:where_after="{current_time}"
This type will show categories with subcategories in a tree format, much like how ExpressionEngine shows them in the control panel. Also see {tree_groups}
filter:genre:category_group="2"
filter:genre:type="tree"
Pipe | seperated list of fields to filter by. Also includes title, entry_date, expiration_date and status.
filter:search:fields="title|product_type|colour"
Important: If one of the fields is of type checkboxes or multiselect list you must specify filter:filter group:delimiter="|"
The label for the filter group.
filter:colour:label="Paint Colour"
Default: Server's default locale
Applies to number_range
groups only. Locale in which the number would be formatted (locale name, e.g. en_CA). This effects how the number is parsed and displayed. This does not effect how the number appears in the URL.
filter:price:locale="de_DE"
Whether to output filters that have no matches in the current search. Value can be yes or no, default is "no".
filter:colour:show_empty_filters="yes"
For making a filter group with fixed values or adding some hard coded values to a filter group. This is usful for creating ways for the user to change orderby or number of pages. You can then use {active_filter_values} to access the selected value. Text is pipe separated and each item in custom_values has the repsective title in custom_titles, i.e. the first item in custom_values (eg title) has the title of the first item in custom_titles (eg Product Name) and so on.
filter:orderby:custom_titles="Product Name|The Price"
filter:orderby:custom_values="title|price"
filter:orderby:default="price"
filter:orderby:show_separate_only="yes"
filter:orderby:join="none"
Default selected value for this filter group. If using categories this would be the category short name.
filter:postage:default="first_class"
This is the delimiter to use for fields that contain more than one value. By default ExpressionEngine uses the pipe character |. You should specify filter:filter group:delimiter="|" when the filter group contains a field that is a checkboxes or multiselect.
filter:store:delimiter="|"
Possible options are:
- or (default)
- and
- none
This allows you specify how multiple filters are treated. If the join is or reefine will show an entry if it matches at least one filter in the filter group. If the join is and reefine will show an entry if it matches all filters in the filter group. If the join is none reefine will only allow the user to select one filter for that filter group.
filter:colour:join="or"
This specifies the order that the filters are displayed in the filter group. Possible values are:
- value (default, order alphabetically by the text value of the filter)
- quantity (order by the quantity of matching entries for filter, most to least)
- active (put active filters at top and order the rest alphabetically)
- active_quantity (put active filters at top and order the rest by quantity)
You can also specify a pipe "|" seperated list of filter values to set your own custom order.
filter:colour:orderby="active_quantity"
filter:city:orderby="london|bristol|cheltenham|plymouth"
Default: asc
This specifies the direction of order that the filters are displayed in the filter group. It can be "asc" for ascending or "desc" for decending.
filter:colour:sort="desc"
Filter by categories by specifying a category group. This is a pipe | seperated list of category IDs. In the same way the fields parameters works you can specify a list of categories. For example if I have a category group for departments with the ID 2 I can filter by the departments.
filter:department:category_group="2"
Default: no
Exclude this filter from the showing up in the tags for flexible filter groups, that combine filter groups (i.e. {list_groups}, {number_range_groups}, {search_groups}, {active_groups} and {filter_groups}). To show this filter you would need to specify it specifically, see Complete example using separate filters.
filter:department:show_separate_only="yes"
Number of active filters across all filter groups.
{if total_active_filters > 0}You have selected a filter{/if}
Total number of matching entries
{if total_entries == 0} No entries found. {/if}
Query string of current search, useful for pagination if you're using method="get" as ExpressionEngine does not add the querystring onto {auto_path} in pagination.
{paginate}
{if next_page}
<a href="{auto_path}?{querystring}">Next page</a>
{/if}
{/paginate}
Where the magic happens. This variable pair will contain your channel entries code to display the results
A pipe | seperated list of entry IDs that match the current filters. You can use this in a channel entries tag to output your results. If no entries are found {entry_ids} will be -1.
{exp:channel:entries entry_id="{entry_ids}" dynamic="no" orderby="title" status="not closed" limit="10" paginate="yes"}
<frameset>
<img src="{product_image}" alt="{title}"/><br />
<a href="/products/{url_title}">{title}</a><br />
<strong>£{price}</strong>
</frameset>
{paginate}<p class="paging">Page {current_page} of {total_pages} pages {pagination_links}</p>{/paginate}
{/exp:channel:entries}
Total number of matching entries
{if total_entries == 0} No entries found. {/if}
This variable pair will contain your list of filters for all the filter groups of type "list". Here is an example from the "shop" theme:
{list_groups}
<h3 class="group_{group_name}">{label}</h3>
<ul>
{filters}
<li class="{filter_active_class}" aria-selected="{filter_active_boolean}">
<a href="{url}">{filter_title} ({filter_quantity})</a>
</li>
{/filters}
</ul>
{/list_groups}
The filter group name that is derived from filter:group name tag or the EE field name. Can be used for css classes.
{list_groups}<div class="filter_{group_name}">...</div>{/list_groups}
Filter group label to display to user.
{list_groups}<h2>{label}</h2>....{/list_groups}
Filter group type (list, number_range, search)
{list_groups}{if type=="number_range"}...{if:else}....{/if}{/list_groups}
Total number of possible filters in filter group
{list_groups}{if total_filters > 0}...{/if}{/list_groups}
Total number of filters that have have been selected by the user.
{list_groups}Filtering by {active_filters} filters.{/list_groups}
Total number of filters that have at least one matching entry.
{list_groups}{if matching_filters > 0}...{if:else}No filters match{/if}{/list_groups}
The url to remove all active filters from the filter group.
{list_groups}<a href="{clear_url}">Clear</a>....{/list_groups}
This variable pair will contain your list of possible filter values for the filter group. The standard ExpressionEngine variables {count} and {total_results} are also available.
For categories this will be the category ID. For all other field types this is blank.
{list_groups}<ul>{filters}<li><a href="{url}">
{exp:channel:categories id="{filter_id}"}{category_image}{/exp:channel:categories}
</a></li>{/filters}</ul>{/list_groups}
This is the possible filter value, which is used in the URL. For categories this will be the category url title. For relationship fields this will be the url_title of the entry.
{list_groups}<ul>{filters}<li><a href="{url}">{filter_value}</a></li>{/filters}</ul>{/list_groups}
This is the possible filter title for displaying to the user.
{list_groups}<ul>{filters}<li><a href="{url}">**{filter_title}**</a></li>{/filters}</ul>{/list_groups}
The URL for that filter. No need to put {site_url} before it as it should do this itself.
{list_groups}<ul>{filters}<li><a href="**{url}**">{filter_title}</a></li>{/filters}</ul>{/list_groups}
The number of matching entries for that filter.
{list_groups}<ul>{filters}<li><a href="{url}">{filter_title} (**{filter_quantity}**)</a></li>{/filters}</ul>{/list_groups}
True if the filter is active (ie has been selected by user)
{list_groups}<ul>{filters}<li class="{if **filter_active**}active{if:else}inactive{/if}" >...</li>{/filters}</ul>{/list_groups}
If the filter is active this returns "active", if not "inactive". Useful for CSS class names.
{list_groups}<ul>{filters}<li class="{filter_active_class}" >...</li>{/filters}</ul>{/list_groups}
If the filter is active this returns "true", if not "false". Useful for specifying aria-selected for screen reader users.
{list_groups}<ul>{filters}<li aria-selected="{filter_active_boolean}">...</li>{/filters}</ul>{/list_groups}
This variable pair will contain all filter groups of the type "tree". It is used for showing categories with subcategories much like how ExpressionEngine shows them in the control panel. It contains all the same variables as the {list_groups} pair Each item in the {filters}...{/filters} pair represents a top most category. Additionally the {filters}...{/filters} variable pair also contains the variable pair {subfilters_1}...{/subfilters_1} which represents a subcategory which in turn has the variable pair {subfilters_2}...{/subfilters_2} which represents a sub-sub-category and so on. If you are using the shop theme then this will be taken care of for you. Here is an example taken from the "shop" theme:
This represents a main category and has all the same variables as {list_groups} > {filters}
This is true if this current filter has at least one subfilter selected.
{if has_active_subfilters}...{/if}
The same as {tree_groups} » {filters} » {has_active_subfilters} but it outputs "has-active-subfilters" if true, and "no-active-subfilters" if false. This can be used for styling, for example if you want to hide subfilters until the user has selected the parent filter.
<li class="{filter_active_class} {has_active_subfilters_class}">
This represents a sub-category. It has all the same variables as {tree_groups} » {filters} BUT each variable is appended with the subfilter number. So {url} is {url_1}, {filter_title} is {filter_title_1} and so on.
This represents a sub-sub-category. It has all the same variables as {tree_groups} » {filters} but each variable is appended with _2.
This represents a sub-sub-sub-category. It has all the same variables as {tree_groups} » {filters} but each variable is appended with _3 and so on, you get the idea :)
This variable pair will contain all filter groups of the type "list". The {number_range_groups} variable pair contains all the same variables as the {list_groups} pair. It contains only one filter which has the minimum and maximum values the user has specified and the minimum and maximum values of the filter for the current search. Here is an example from the "shop" theme:
{number_range_groups}
<h3 class="group_{group_name}">{label}</h3>
<form method="post" class="number_range" >
<input type="hidden" name="XID" value="{XID_HASH}" />
{filters}
<input type="text" name="{group_name}_min" id="{group_name}_min" placeholder="{filter_min}"
value="{filter_min_value}" aria-label="Minimum value"/>
— <input type="text" name="{group_name}_max" id="{group_name}_max" placeholder="{filter_max}"
value="{filter_max_value}" aria-label="Maximum value"/>
{/filters}
<input type="submit" name="submit" value="Go" />
</form>
{/number_range_groups}
The minimum possible value of the filter. Applies to filter groups of type number_range only.
{number_range_groups}{filters}<p>Min: {filter_min}</p>...{/filters}{/number_range_groups}
The maximum possible value of the filter. Applies to filter groups of type number_range only.
{number_range_groups}{filters}<p>Max: {filter_max}</p>...{/filters}{/number_range_groups}
The minimum value to filter by as specified by the user. Applies to filter groups of type number_range only.
{number_range_groups}{filters}...<input name="{group_name}_min" value="{filter_min_value}" />...{/filters}{/number_range_groups}
The maximum value to filter by as specified by the user. Applies to filter groups of type number_range only.
{number_range_groups}{filters}...<input name="{group_name}_max" value="{filter_max_value}" />...{/filters}{/number_range_groups}
This variable pair will contain all filter groups of the type "search". It has all the same variables as {list_groups}. It contains just the one filter which has the {filter_title} variable. Here is an example from the default theme:
{search_groups}
{filters}
<form method="post" class="{filter_active_class}">
<input type="hidden" name="XID" value="{XID_HASH}" />
<label for="{group_name}">{label}</label>
<input
type="text" id="{group_name}" name="{group_name}" placeholder="search"
value="{filter_title}" title="Search ({filter_quantity})" />
<input type="submit" name="submit" value="Go" />
</form>
{/filters}
{/search_groups}
This variable pair will contain all filter groups that have at least one active filter. This is useful for showing a list of selected criteria. It has all the same variables as {list_groups}. It will only output active filter groups and active filters. Here is an example from the default theme:
{if total_active_filters > 0}
<div class="reefine_active_filters">
<h3>Selected Criteria</h3>
<ul>
{active_groups}
<li><strong><a class="remove-filter" href="{clear_url}">{label}:</a></strong></li>
{filters}
<li class="{filter_active_class}" aria-selected="{filter_active_boolean}">
<a href="{url}">{filter_title}</a>
</li>
{/filters}
{/active_groups}
</ul>
<p class="total_entries">{total_entries} items found</p>
</div>
{/if}
This variable pair will output all filters regardless of type. The variables available depend on what type the group is.
Release 2022-11-23
- Fix Issue #10 Large numbers with commas cut off at first comma in number_range
- add parameter disable_multiple_selected_groups
- #6 Month list: fix date overlap issue
- fix PHP 7.4 warning, update demo url, remove old docs
- #3 fix has_active_subfilters problem
Release 2019-04-01
- Added {querystring} tag
- Big change to url encoding: Now uses --number-- encoding to fix disallowed character bug eg test@example becomes test--45--example
- Improved category filter Performance
- Bug fixes
Released 2019-01-07
- Bug fixes
- EE5 compatible
Release 3018-10-26
- EE4 compatible
Released 2018-01-16
- fixed bug with site id not in where clauses
- EE3: added fix for ajax loading template override error
Release 2017-04-06
- Bug fixes
- Added author_id, fixed_order parameters
- Added status as filter field
Release 2016-10-20
- Made EE3 compatible.
Release 2015-09-28
- Added new filter group type "tree" for showing categories and subcategories in a tree format.
- Added fix_pagination to {exp:reefine}
- Added show_separate_only, default, custom_values and custom_titles parameters to filter groups.
Release 2015-01-05
- Added url_output, category, filter:filter_group:sort, show_future_entries and show_expired parameters.
- status parameter can now be pipe seperated
- Added active_filters, matching_filters and filter_id tags
- Added rel="nofollow" to links in "shop" theme
- Fix for AJAX in "form" theme
- Fix for special characters in URL.
- Added custom ordering for filter:filter_group:orderby parameter.
Release 2013-12-11
- Added Grid, Matrix, Relationship & Playa compatibility
- Added methods "get", "post", and "ajax"
- Added "form" theme and made the "shop" theme compatible with get, post and ajax methods.
- Added disable_search parameter
- Added month_list filter group type.
Released 2013-09-25
- Added Store fieldtype compatibility
- Made seperate tags for each filter type and an active_groups tag
- Added filter:filter group:show_empty_filters parameter
- Modified themes to be more portable
- Made EE 2.7 compatible
- Fixed bug with {count} tag
- Modified default shop theme for better performance (by avoiding conditionals)
- seperate_filters parameter removed, reefine now automatically detects seperate filter tags.
- Improved accessability of default theme for screen readers.
Release 2013-09-05
Bug Fixes
Released 2013-08-09
Breaking Changes
- The {filter_value} parameter is now used as the value for url title for categories. Please change {filter_value} to {filter_title} in your code.
Other changes
- Added filter_title field
- Added fix for filter groups with multiple categories bug
- Fixed number_range problem with large numbers
- Fix paging problem when there is no filter
- Added category_url parameter
First version of Reefine.
Reefine can filter by categories, see filter:filter group:category_group
Reefine can filter by select dropdowns and multiselects. If you are using the filter:fields parameter it will automatically pick this up. If you using filter:field group:fields you will have to add delimiter="|" see delimiter parameter.
Reefine is compatible with Structure. However you will need to add the Freebie add-on so that the page will still display. You will need to add your page's segments to Freebie so Structure displays the correct page. Reefine will modify the page's URI string back to how it was before Freebie after processing to ensure EE's native paging still works.
Reefine is compatible with the Expresso Store fieldtype. You can access the details of a product by specify the field name in the same way as in the template eg if your field of fieldtype Store is called "product" and you wanted to get the price you would use filter:filter group:fields="product:price". Please note it can only retrive the values from the exp_store_products database table so it will not be able to add tax or shipping. To filter by what's on sale use filter:filter group:fields="product:on_sale".
Reefine is compatible with the Relationship fieldtype and Pixel and Tonic's Playa fieldtype. Both work in the same way. Just enter the field name and the filter will show the related entry's title and use the url_title for the url. For example:
channel="films"
filter:actors:fields="actors"
url="/films/{actors}"
You can also use a particular field within the related entry as the filter by appending a colon (:) and the field name of the related entry you want to filter. This example will show a filter for actor's nationality, so the user can see a list of all films that have French actors, for instance.
channel="films"
filter:actor_nationality:fields="actors:nationality"
url="/films/{actor_nationality}"
Reefine is compatible with the Grid fieldtype and Pixel and Tonic's Matrix fieldtype. Both will work in the same way. Just enter the field name of the Grid/Matrix field followed by a colon (:) and the field name within the grid/matrix. Please note that Reefine will only return the matching entries and will not be able to show filtered results of the grid rows. Here's an example of a clothes store that has clothes in the channel "clothes" and a Grid field "sizes" with columns "size" and "price". The price of an item of clothing is dependant on the size, the following example will allow the user to filter by both size and price:
channel="clothes"
filter:size:fields="sizes:size"
filter:price:fields="sizes:price"
filter:price:type="number_range"
url="/store/{size}/{price}"
The date fieldtype is supported with filter:filter group:type="month_list". You can also use the list and number_range filter group types, however it will be output as a number (unix time) which you'll have to convert to a date in the template .
Reefine may not be able to filter by custom fieldtypes not listed above. Although you can still display the content of custom fieldtypes in the search results as Reefine just relies on the exp:channel:entries tag.
If you have an issue then you will need to first use the process of elimination to pinpoint exactly what is causing the issue. First create a copy of your template and start removing everything but the filters or parts that are causing the issue. For example if you have 4 filters try removing all but the first filter then if the bug isn't appearing remove all but the second filter and so on until you find the filter or combination of filters that are causing the issue. Then check with the documentation that your syntax is correct.
Community support is available at the following places:
If you wish to hire me for ExpressionEngine work checkout my website:
Reefine allows you to make super SEO and user friendly URLs. However, you may want to limit the number of pages search engines index as you can be penalised for duplicate content. To do this you can add the rel="nofollow" parameter to all tags. If you're using a theme the nofollow tag is already there.
<a href="{url}" aria-selected="{filter_active_boolean}" rel="nofollow">{filter_title}</a>
This will prevent search engines from following the filter links, however the search pages may still be indexed if there are direct links going there. You may wish to use a canonical link in this case so hopefully the search engine will attribute the page rank to your main search page rather than spread out over different filters. You can do this by putting in a conditional in your head tag to make your search page the canonical link, for example:
{if segment_1=="my_search_page" && segment_2!=""}<link rel="canonical" href="{site_url}/my_search_page" />{/if}
Warning: I'm not an SEO expert so take care when using these.
Reefine can be resources heavy if searching large amounts of filters. Try to avoid using categories and any fields with multiple values (checkboxes, multiselects) to speed up search times. Ensure you're using a decent host. Try to keep the number of conditionals (especially advanced conditionals) in the filter tags to a minimum. You should also consider using a cacheing addon such as CE Cache or you can use ExpressionEngine's native cacheing as follows:
Add this to the {exp:reefine} tag:
cache="yes" refresh="120" cache_buster="{segment_1}/{segment_2}/{segment_3}/{segment_4}/{segment_5}/{segment_6}/{segment_7}/{segment_8}/"
Add this to the {exp:channel:entries} tag
cache="yes" refresh="120"
You can also get some good performance improvements by using indexes in MySQL.
If you would like to customise the default "shop" theme you can either remove the theme="shop" parameter and add your own filter tags as above or you can create your own theme. To create your own theme make a copy of the themes/third_party/reefine/shop folder eg themes/third_party/reefine/my_theme and change the theme="shop" to whatever you named the new folder eg theme="my_theme". You can then customise the css and html in that folder.
Rather than using {list_groups}, {number_range_groups} etc as above you can specify each filter group individually. Just use the filter group name. Check the code example below to get a better idea.
{colour}
<h3>Colour</h3>
<ul>
{filters}
<li class="{filter_active_class}" style="color:{filter_value};">
<a href="{url}">{filter_title} ({filter_quantity})</a>
</li>
{/filters}
</ul>
{/colour}
Sorting can be done using a filter group with hardcoded titles and values and then plugging the selected value into the exp:channel:entries orderby parameter. Here is an example with the relevant parts in bold. You can also use the same principle for other parameter in channel:entries such as limit and sort.
{exp:reefine channel="clothes" parse="inward" theme="shop"
filter:fields="price|colour"
filter:orderby:custom_titles="Product name|Price"
filter:orderby:custom_values="title|price"
filter:orderby:default="price"
filter:orderby:join="none"
url="/{segment_1}/{segment_2}/{price}/{colour}/{orderby}"}
{entries}
{exp:channel:entries entry_id="{entry_ids}"
disable="categories|category_fields|member_data" dynamic="no"
orderby="{orderby}{active_filter_values}{value}{/active_filter_values}{/orderby}"
sort="asc" status="not closed" limit="8" paginate="yes"}
....
{/exp:channel:entries}
{/entries}
{/exp:reefine}
This may occur if you are running ExpressionEngine version 2.5.2 or earlier. This is a bug in ExpressionEngine which was fixed in later releases. In the meantime you will need to specify all tags in all situations. This may mean you have to put the tags in comments as follows. The default theme has a few of these tags for compatibility which you may remove if you're using EE 2.5.5 and above.
<!--{url}{filter_value}{filter_title}{filter_quantity}{filter_min_value}{filter_max_value}{filter_min}{filter_max}-->
This example outputs each filter group in a seperate tag pair rather than using the {list_groups}, {number_groups} etc. This is useful for customising the order, position and formatting of different filters. Github Gist
This example uses the {number_range_groups} {list_groups} {search_groups} variable pairs and selects the correct html based on the group type. You can add extra fields to this example and they should show up automatically. Github Gist
This example uses a form to submit two dropdowns which can filter a list of events. When the user click the submit button it will redirect the url to include the filter parameters. Also notice it uses the month_list group type. Github Gist
Happy Filtering
The End