4

First some context. I'm using Smart Map for Craft to display some location based events in a listing. My structure is as follows:

  • Events channel
  • Locations channel

Each event can occur multiple times, so I created a matrix field for this, where they can add blocks with a time and select a location.

The problem occurs when I want to filter the list of results based on the city of the location. Smartmaps doesn't support filtering by cities and I do want to use pagination, so I went with the custom plugin solution mentioned in that question. Unfortunately I can't comment yet on that answer, so therefore I created my new question.

The problem is that Craft {% paginate %} doesn't work with the Array result of EntryModel::populateModels. I'm getting the following error in my search results page:

Argument 1 passed to Craft\TemplateHelper::paginateCriteria() must be an instance of Craft\ElementCriteriaModel, array given

So my question is, how can I modify the ElementCriteriaModel to join content from different tables (in this case Smartmaps') and still return an ElementCriteriaModel to be used by the Craft pagination?

I also have read some more explanation about ElementCriteriaModel and some similar issues like this one and this one, but without any luck. Maybe there is a much simpler solution, but I'm out of options for now.

1 Answer 1

5

You can only modify a craft.entries criteria model with a field (→ Add custom element criteria attribute without a field type?). So what you have to do is to create a new custom field type with your plugin, and add such a field to the entry types you want to filter.

{% set entries = craft.entries.section('mySection').country('germany') %}

With that criteria model you would pass the value "germany" to your custom field type field "country". The field type would then use this parameter to modify criteria model's query.

Here's some code that should help you putting this together:

public function getInputHtml($name, $value)
{
    return;
}

public function modifyElementsQuery(DbCommand $query, $params)
{
    if ($params !== null)
    {
        craft()->businessLogic->addCountryCriteria($query, $params);
    }
}

You don't want the field to show up as an input field in the edit entry view, so we let getInputHtml() return null.

In our modifyElementsQuery method we just check if there's a parameter submitted (the country), before passing the criteria model's query to the service.

public function addCountryCriteria(DbCommand $query, $country)
{
    // Add conditons to the query 
    $query->andWhere($conditions, $params);
}

Your addCountryCriteria service can basically stay untouched, except that you can remove buildElementsQuery(), queryAll() and populateModels(). As you only want to modify the query.

2
  • Thanks for your quick and perfect answer! This is my first time handling with custom fieldtypes, but your clear explanation makes it very easy to understand. I'm going to dive into plugin development for Craft, it looks promising to me this way. For now I've got it up and running thanks to you.
    – ctigelaar
    Oct 30, 2015 at 13:31
  • wow that is a very cool way to go about it. i'm sure that will come in handy for me in the future. Nov 28, 2015 at 15:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.