Expression Engine - passing multiple categories as URL segments - expressionengine

I'm trying to create a product filter with deep-linking capability. Essentially, I want the user to be able to filter my product list on multiple categories and have the URL reflect the filtering they've done.
So it would start as:
www.site.com/products/
My first level of category filtering already works. So I can use EE's regular handling of URL segments to get to my first level of filtering. For instance:
www.site.com/products/leatherthongs
Returns a filtered subset showing only a spectacular collection of leather thongs. But now I want the user to be able to filter on another category - color for instance. This is where stuff stops working.
EE's way of handling multiple categories inside templates (with ampersands or pipes) doesn't work in the URL:
www.site.com/products/leatherthongs&red
Nor does any variation that I've tried.
My next move is to create a simple raw PHP method that can capture regular querystring parameters and then inject them into the {entries} tag before rendering. Not very difficult, but quite ugly. I would love to know if there is a way to handle multiple categories in the URL natively.
Thanks for your time.

Have you considered using Low's Seg2Cat add-on? I'm not sure how complex you want to make this but it seems that you could specify something in your channel:entries loop like categories='{segment_2){if segment_3}|{segment_3_category_id}{/if}'
This exact syntax is untested but I have had success in the past with a similar solution.

Related

Tabulator - exclusive header filters - how?

I wrote and support a little web app for our local animal shelter to help volunteers locate dogs. I chose Tabulator because it had great features and was easy to use and have been very happy with my choice. For the first version of the app I used external input fields to search and manually did all the wiring to support live search.
Now I am working on v2 and am trying to use header filters. My problem is that the filters need to be exclusive, that is, using filter1 clears/disables filters 2 and 3, using filter2 clears/disables 1 and 3, and so on. With the external search fields I used focus() events to do this. When I try using jQuery on(focus) delegates to do the same with header filters and for example table.setHeaderFilterValue("field1", "") it does not work; the event triggers but the input box never gets the focus so I cannot type in it. I've tried different events like click; but nothing I've tried works properly.
I've studied the docs and struggled with this for several hours. I've considered hooking dataFiltering() and eliminating the filters I don't want, but I'm not sure how to identify the filter that I want to keep, and there is still the matter of the text in the fields to be dealt with. I'm sure it doesn't help that front-end work is not my area of expertise, though so far I've managed well enough. Is there a simple or normal way to do this that I'm just not seeing?
For the record, I found a way to do exclusive filtering with header filters with a single event callback:
\$(document).on("focus", ".tabulator-col input[type=search]", function() {
var hfNames = ["name", "anum", "kennel"];
var fieldName = \$(this).closest(".tabulator-col")[0].getAttribute("tabulator-field");
hfNames.map(function(hfN) { if (hfN != fieldName) table.setHeaderFilterValue(hfN, "") });
});
The three hfNames are the field names of the columns with filtering on. Yes, I could have derived them dynamically, but it didn't seem worth it for a small app like this.
As I suspected, the key was simply a better knowledge of JQuery.

Lookup for large list on xPage

I have a list of approx 10K entries (and growing) I need to be able to reference in an xPages app. I have had lookup limitations using #DbLookup, so have looked at other options. Unfortunately I continue to run into these limitations.
I am currently loading the lookup list into a session scope variable on page load (which has performance impacts), and the reference the scoped variable for the combo box.
I am using the following simple process to load the list for the combo box. This, however, is also running into limitations.
var lookupView:NotesView = database.getView("LookupView");
sessionScope.lookupList = lookupView.getColumnValues(0) + "|" + lookupView.getColumnValues(4);
I would like a method to perform a lookup that can handle the larger list (main priority) with performance being number 2. The page is used by a limited number of users with the function being most important.
Take a look at this code snippet "Pure Java version of DbLookup & DbColumn, with cache, sort and unique" and either use it directly or use it as inspiration.
You should consider storing the list in application scope since it seems that the list is the same for all users. This means that you need to change the code in the code snippet to use applicationScope instead of sessionScope.
I doubt your users want or need to pick some value from combo with 10k+ lines.
Rethink your approach, you can use autocomplete feature with dynamic filter/search in live view (no scoped variable needed), as pointed by Mark. Another approach is to divide that values into some groups and split that combo to two or three with cascading choose/lookup function. First one picks one group, second one looks up only options from first group. That way you probably won't hit that #DbLookup limitations.

How to make filters in queries optional

How to make a query filter bound to a request parameter inactive if the parameter is not present?
For example: I have a query MyQuery that can be accessed through the projection MyProjection. I add a filter to that query where I say that MyDate field should be equal to {Request.QueryString:MyDate}. I want URLs like ~/MyProjection?MyDate=2016-03-08 to filter content items by the given value, but the url ~/MyProjection to just not filter by that field. But this is not what happens: a condition gets added to the query anyway and it's of the form '[minimum DateTime value] < MyDate < [maximum DateTime value]'. This is not good because it will filter out fields with NULL values. If I try to do the same with a numeric field, it's even worse because it throws exceptions when the parameter is not present.
I know I can create a new query and projection to get different options, but that seems like an overkill - also, what if I wanted to create an advanced search form, it would have to target a single projection.
Is there an "official" way to do this? Or a workaround? Or is this simply not supported in Orchard?
I'm not aware of a way to do this out of the box. However, you could pretty easily create your own filter with the behavior you want by implementing IFilterProvider.
Take a look at the Orchard.Projections module. That's where you'll find many of the default query filters (including the date field filter you referenced). Your's will likely be even simpler if you only need to handle a specific case.
For a very simple example, checkout the Orchard.Tags module (look in the projections folder). The contents of this folder will give you pretty much all the boilerplate you'll need to get started creating your own. Just plug in your own logic.

Expression Engine - Is it possible for exp:channel:entries tag to have complex filters?

Coming from Codeigniter and new to Expression Engine, I am at a loss on how to do complex filters on the exp:channel:entries tag.
I am interested in this filters
status
start_on
stop_before
How do you do you implement filters for a complex condition like this?
(status=X|Y|Z AND start_on=A AND stop_before=B) OR (status=X AND start_on=C AND stop_before=D)
Is this even possible?
You can only use the search= parameter to search on “Text Input”, “Textarea”, and “Drop-down Lists” fields unfortunately. So you'd need to use the query module for this.
If you're just querying on those parameters you should be able to get the entry id's you need from the exp_channel_titles table, then use something like the Stash plugin to feed the entry_id's of the results into a regular channel entries tag. Yes it's nominally one more query that way but as EE abstracts the db schema fairly heavily the alternative is to get lost in a mess of JOINs.
So something like (pseudocode, won't work as is):
Get the entries, statuses are just a string in exp_channel_titles, entry_date is the date column you want - which is stored as a unix timestamp, so you'll need to select it with something like DATE( FROM_UNIXTIME(entry_date)) depending on the format of your filter data.
{exp:stash:set name="filtered_ids"}{exp:query sql="SELECT entry_id
FROM exp_channel_titles
WHERE status LIKE ...<your filter here>"
backspace="1"
}{entry_id}|{/exp:query}{/exp:stash:set}
Later in template:
{exp:channel:entries
entry_id="{exp:stash:get name="filtered_ids"}"
}
{!--loop --}
{/exp:channel:entries}
Yes it's a mess compared to what you're probably used to in pure CI, but the trade off is all the stuff you get for free from EE (CP, templating, member management etc).
Stash is awesome by the way - can be used to massively mitigate most EE performance issues/get around parse order issues
You can get a lot of this functionality using the search= parameter in your {exp:channel:entries...} loop.
It's not immediately clear to me how you'll get the complexity you seek, so you might end up resorting to the query module though.
If you're working with dates you might find the DT plugin useful.

Extending Orchard Search and Indexing

We need to provide search options for users to find content based on specific field values.
We're developing a Training Course module for a client but the standard search looks for the text in any indexed field. We want to allow users to find courses based on searches against specific fields (i.e. Course Type, Location, Price, Date).
We've extended the search to check against specific fields but can't work out how to get the URL parameters passed by the Search form as a GET.
Where does Orchard put URL parameters?
Also, are we missing something, is there a way that Orchard already supports this that we haven't realized?
I would suggest you to copy part of the Search module, more specifically the Controller and the View and then modify it to suit your specific needs. I see you are actually modifying the original module, but this might be a problem on the long term, for instance if we start updating the module you might either lose you changes or have to reapply them to the code base. In the end you will target a MySiteName.Search module. And you can also add custom routes, custom settings.
On a side note the Search API is really powerful and you can even use it to do faceted search, or search on inherited taxonomy terms, tags, full text, ranges, ... Having your own controller code will let you use all of these features easily.

Resources