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

1

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\MVC\Factory\MVCFactory;
use Joomla\CMS\Plugin\CMSPlugin;
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') !== 'Joomla\\CMS\\Extension\\ComponentInterface')
        {
            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;
        }

        // Service key to override.
        $class = 'Joomla\\CMS\\MVC\\Factory\\MVCFactoryInterface';

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

        // Register the custom MVC factory. Here an anonymous class is used but you can use a concrete class.
        $container->set(
            $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 === 'Joomla\\Component\\Content\\Administrator\\Model\\ArticlesModel')
                    {
                        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');
        }
    }
}
1
  • Thank you, it's very interesting and useful to know.
    – Nintendomi
    Apr 22 at 10:31

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.