This is probably not the answer you are looking for but it works. You can change the Craft.BaseElementIndex
and 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