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

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.

Related

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.

How to preserve the order or terms in Orchard TaxonomyField

I have a Content Part in Orchard, to which I added a Taxonomy Field and set it to allow multiple terms. When I save a content item, it looks like the terms are re-ordered in alphabetical order. But I would like to preserve the order in which they were authored in the field.
E.g. here is what I author in my Taxonomy field:
Contributors: [Sebastien Ros] [Bertrand Le Roy]
And here is what it turns into after saving:
Contributors: [Bertrand Le Roy] [Sebastien Ros]
Is there a way to prevent terms re-ordering? If this is by design, does anyone familiar with implementation know if this can be patched easily? Would it make sense to create a pull-request and contribute a patch to Orchard? I mean, would it be useful for other users, so that the fix has a chance to be included in core. (Otherwise, I would have to maintain a modified version of Orchard and have problems upgrading to new versions, which is undesirable of course).
Thanks!
You should never count on the order in which the records are stored in the database. It is way too brittle, and has never been designed for this. If you need to have control over the order of terms, and have different orders depending on context, you need to use something else. The latest source code version of Vandelay.Industries has a projection filter that lets you drag and drop items in the order you want, for that specific projection.
If you go to the taxonomy section and look for the term itself, you will see a property call Weight which says..: 'If specified, it will be used to sort terms at the same level'.
That should do it.

Expression Engine - passing multiple categories as URL segments

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.

Is this the right way to filter channel entries using conditional variables?

Is this the most efficient way to filter a load of channel entries? I want to display entries that have no comments and that are not sticky. I'm using this code.
{exp:channel:entries channel="{segment_3}" status="open" orderby="date" disable="categories|category_fields|member_data|pagination"}
{if comment_total == "0" AND sticky == 'n'}
...
{/if}
{/exp:channel:entries}
Cheers
Lee
Using conditional variables, probably. But this will likely return lots more results than you need. Plus you won't be able to accurately use {count} (maybe not an issue for you, though).
Another approach which doesn't use conditional variables, but just goes straight after the results you want, and only the results you want, is to use the Query Module
{exp:query sql=
"SELECT title
FROM exp_channels
JOIN exp_channel_titles ON exp_channels.channel_id = exp_channel_titles.channel_id
WHERE exp_channels.channel_name = '{segment_3}'
AND exp_channel_titles.status = 'open'
AND exp_channel_titles.sticky = 'n'
AND exp_channel_titles.comment_total = 0"
}
<li>{title}</li>
{/exp:query}
This could get tedious if you needed to access a bunch of custom fields, but it is an efficient way to get the results you want.
Sticky is an available parameter on the entries loop, so you could filter at least that element in the entries loop itself by simply adding sticky="no", but comments, unfortunately, is not an available parameter, so Alex's suggestion may be the best option if your requirements are fairly simple. If you need access to a significant number of custom fields, however, it may be a bit tricky. So you'll have to decide what approach to take based on what you need within your loop.

Modify haystack query syntax?

Is it possible to modify or extend how haystack understands a query?
For example, I'm looking at integrating haystack with an OSQA-based site to get SO-style search -- a search where regular keywords search question/answer/comment text, but where syntax like "[tag]" is understood to be restricted to the question's tags field. At some point we might want to add other goodies like "user:eternicode" and "score:0", but for now keywords and tags are the must-haves.
Unfortunately, it's not as simple as regexing the tags out of the query string and using that to filter on the tags field, because we want all the complexity of AND, OR, NOT, and arbitrary grouping to apply.
Is this possible with haystack? Better yet, has anyone done it before?
It seems there is no way to customize how Haystack's auto_query works, so what we ended up doing was preparsing the search query to extract tag and other custom syntaxes, perform the auto_query with the leftovers, and then apply the custom syntaxes as extra filters on the auto_query results.
In order to do this, though, we had to simplify our requirements and drop the OR requirement, so all terms are only ANDed now -- that simplified a lot of things (for example, grouping is now unnecessary).

Resources