1

I need to change the default ordering of the articles list in the administrator Articles page. To do this I probably would have to edit the populateState() method in administrator/components/com_content/src/Model/ArticlesModel.php but I'd really like to do this change by overriding...

Does anyone know a way to change the default sorting of the articles table using an override? I want the default sorting to be by 'modified date' and not by 'id' as it currently is.

Thank you!

UPDATE:

It was simpler than I thought. It was not necessary to override the model (although Starky's answer on how to do so remains very useful), but I solved the problem doing an override of the com_content in the administrator template. In the file administrator/templates/atum/html/com_content/articles/default.php I changed this code:

/* // Original code
elseif (strpos($listOrder, 'modified') !== false)
{
    $orderingColumn = 'modified';
}
else
{
    $orderingColumn = 'created';
}
*/

//My new code
elseif (strpos($listOrder, 'created') !== false)
{
    $orderingColumn = 'created';
}
else
{
    $orderingColumn = 'modified';
}

1 Answer 1

3

In J4 it is possible to override models and the rest of MVC classes. To do that, you need a system plugin to register a custom MVC factory during onAfterExtensionBoot or onBeforeExtensionBoot event.

use Joomla\CMS\Extension\ComponentInterface;
use Joomla\CMS\MVC\Factory\MVCFactory;
use Joomla\CMS\MVC\Factory\MVCFactoryInterface;
use Joomla\CMS\Plugin\CMSPlugin;
use Joomla\Component\Content\Administrator\Model\ArticlesModel;
use Joomla\DI\Container;
use Joomla\Event\EventInterface;

final class PlgSystemOverride extends CMSPlugin
{
    public function onAfterExtensionBoot(EventInterface $event)
    {
        // Test that a component is being booted.
        if ($event->getArgument('type') !== ComponentInterface::class)
        {
            return;
        }

        // Test that this is com_content component.
        if ($event->getArgument('extensionName') !== 'content')
        {
            return;
        }

        // Get the service container.
        $container = $event->getArgument('container');

        if (!($container instanceof Container))
        {
            return;
        }

        // Check that MVC factory is used and can be overridden.
        if (!$container->has(MVCFactoryInterface::class) || $container->isProtected(MVCFactoryInterface::class))
        {
            return;
        }

        // Register the custom MVC factory. Here an anonymous class is used but you can use a concrete class.
        $container->set(
            MVCFactoryInterface::class,
            static fn () => new class ('Joomla\\Component\\Content') extends MVCFactory
            {
                protected function getClassName(string $suffix, string $prefix)
                {
                    $class = parent::getClassName($suffix, $prefix);

                    // Override the backend article list model with a custom class.
                    if ($class === ArticlesModel::class)
                    {
                        return 'MyCustomArticlesModel';
                    }

                    return $class;
                }
            }
        );
    }
}

Then in your custom class extend the original class and add the overridden populateState() method. Additionally, depending on class name, you might need to declare $context and $filterFormName properties. This is because they're derived from class name when not set explicitly.

use Joomla\Component\Content\Administrator\Model\ArticlesModel;

class MyCustomArticlesModel extends ArticlesModel
{
    protected $context = 'com_content.articles';
    protected $filterFormName = 'filter_articles';

    protected function populateState($ordering = 'a.modified', $direction = 'DESC')
    {
        parent::populateState($ordering, $direction);
    }
}

Alternatively to all of this, you can also change the default ordering by setting the appropriate session key, also using a system plugin:

use Joomla\CMS\Plugin\CMSPlugin;

final class PlgSystemOverride extends CMSPlugin
{
    protected $app;

    public function onAfterRoute()
    {
        // Only run for logged in users in com_content backend.
        if (!$this->app->isClient('administrator') || $this->app->getInput()->get('option') !== 'com_content' || $this->app->getIdentity()->guest)
        {
            return;
        }

        // Session key to use.
        $key = 'com_content.articles.list.fullordering';

        // Set it only if it hasn't been set yet.
        if (!$this->app->getUserState($key))
        {
            $this->app->setUserState($key, 'a.modified DESC');
        }
    }
}
2
  • Thank you, it's very interesting and useful to know.
    – Nintendomi
    Commented Apr 22, 2022 at 10:31
  • @sharky - This is very helpful. We had created a github repo for this community, where we used to place various examples. Wondering if you could compile this as a full plugin draft and upload it there. github.com/Joomla-StackExchange. Let me know if you are interested to send you an invitation.
    – FFrewin
    Commented Jul 21, 2023 at 9:03

Your Answer

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

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