3

I know it's possible, using modifyEntrySortableAttributes, to sort the CP entries table by a custom field, when that field is a number, string, date/time, or bool. Would it be possible to sort a CP table by category? If not, is there another hook, or some other way I could implement this functionality?


Sorting by number, string, date/time, bool:
In Craft 2.5, how can you sort the entry index page by a custom field?

2

This is probably not the answer you are looking for but it works. You can change the Craft.BaseElementIndexand the updateElements function. All you have to do is to change the destination path to a custom controller

Craft.BaseElementIndex.prototype.updateElements = function()
{
    // Ignore if we're not fully initialized yet
    if (!this.initialized)
    {
        return;
    }

    this.setIndexBusy();

    var params = this.getViewParams();

    Craft.postActionRequest('yourPluginHandle/controllerName/getElements', params, $.proxy(function(response, textStatus)
    {
        this.setIndexAvailable();

        if (textStatus == 'success')
        {
            this._updateView(params, response);
        }
        else
        {
            Craft.cp.displayError(Craft.t('An unknown error occurred.'));
        }

    }, this));
},

Then you can create a custom controller that extends the ElementIndexController and can use it's function that calls the private function _getElementResponseData. All the elements that should be displayed are received in

$responseData['html'] = $this->_elementType->getIndexHtml(
    $this->_criteria,
    $disabledElementIds,
    $this->_viewState, <-- this is the important variable
    $this->_sourceKey,
    $this->_context,
    $includeContainer,
    $showCheckboxes
);

The sort order is defined here

if ($sortableAttributes)
{
    $order = (!empty($viewState['order']) && isset($sortableAttributes[$viewState['order']])) ? $viewState['order'] : ArrayHelper::getFirstKey($sortableAttributes);
    $sort  = (!empty($viewState['sort']) && in_array($viewState['sort'], array('asc', 'desc'))) ? $viewState['sort'] : 'asc';

    $criteria->order = preg_replace('/^(.*?)(?:\s+(?:asc|desc))?(,.*)?$/i', "$1 {$sort}$2", $order);
}

As you can easily see it checks if the $viewState['order'] is empty or not. This variable is defined in your controller so all you have to do is to check if your javascript returns a order variable, get the field by handle and check if the field handle is instance of BaseRelationField. If so, you'll unset the variable in the $viewState and change the $criteria by yourself.

Unfortunately the query is executed in BaseElementType.php so you have to implement a way to sort by eager loading elements (which I doubt is possible by default) or you can create a custom element type just for this case and overwrite the entire getIndexHtml() function.

It might sound like a lot of work and effort but honestly it can be done in 5-10 minutes... I've done the same once within no time. It's 99% copy paste. Maybe someone has a better answer but since there is no real event or hook I'm not sure if there is a real clean way to do this. Of course this is only for Craft 2. In Craft 3 it's much easier since there are more events and hooks and you can replace classes more easy.

Another approach would be to overwrite the entire BaseElementIndex class with Yii or this. But I never did that so I can't give much advice

  • Thank you so much! That's exactly the type of work around I'm needing. This all makes sense, but how exactly do you alter the criteria to order by category? Would I need to write custom SQL outside of the ElementAPI? – iRector Mar 4 '18 at 18:16
  • That's the question. I searched a little bit but the Elements getEagerLoadingMap includes the eager loading elements directly into the query. So I don't think you can include the sort order directly into the ElementCriteriaModel. Thus you'll need to create a custom element type in order to overwrite the entire getIndexHtml and reorder the entries before $criteria->find() is executed. I searched the last 30 minutes but every question of this type is unanswered at stack exchange. I think you have to create your own Query with $db = craft()->elements->buildElementsQuery($criteria); – Robin Schambach Mar 4 '18 at 18:56
  • yiiframework.com/doc/guide/1.1/en/database.query-builder, join Crafts relation table with the correct field Id on your entry id and order your entries by the title. I can provide a working example in about 12h if you are not able to make it. Edit: you can see how to join related entries here craftcms.stackexchange.com/questions/22833/… – Robin Schambach Mar 4 '18 at 19:01
  • Haven't actually tried this yet, but I know it would work. Accepting answer. – iRector Mar 6 '18 at 2:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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