Pending

User tests: Successful: Unsuccessful:

avatar hikashop-nicolas
hikashop-nicolas
22 Apr 2026

Route::() retrieves the router for the current application and calls build() on it. The ApiRouter and the (unregistered) CLI router extend Joomla\Router\Router, which is parse-only and does not implement build(), so any Route::() call reached from an API endpoint or a console command crashes with "Call to undefined method Joomla\CMS\Router\ApiRouter::build()".

In practice this is hit whenever a component generates a frontend URL from code reached via webservice plugins or scheduled CLI tasks (emails with article links, notifications, etc.).

Detect those two clients in Route::_() and build the URL through the site router instead. Route::link('api', ...) / Route::link('cli', ...) is left untouched, so explicit calls continue to fail exactly as they do today and the fix stays scoped to the convenience dispatcher.

Pull Request resolves # .

  • I read the Generative AI policy and my contribution is either not created with the help of AI or is compatible with the policy and GNU/GPL 2 or later.

Summary of Changes

Route::_() builds a URL through the router of the currently-active application. The ApiApplication and the ConsoleApplication both use routers that extend Joomla\Router\Router (the framework router), which is parse-only and does not implement build(). As a result, any Route::_() call reached from an API endpoint or a CLI command crashes with:

Error: Call to undefined method Joomla\CMS\Router\ApiRouter::build()
  at libraries/src/Router/Route.php:150

In practice this breaks every extension that generates frontend URLs from code reachable via a webservice plugin or a scheduled console task. A common symptom is emails (order notifications, contact forms, etc.) that embed Route::_()-built links in their body.

The fix detects the api and cli clients inside Route::_() and routes through the site router instead. Route::link('api', ...) / Route::link('cli', ...) are left unchanged: an explicit call to a parse-only router still fails exactly as before, so the convenience dispatcher gets a sensible fallback while explicit requests keep their current semantics.

Testing Instructions

  1. Install a Joomla 5.x or 6.x site.
  2. From a CLI shell, run the repro script below against your installed site. It boots the API application the same way api/index.php does and then calls Route::_() on a standard com_content URL.
<?php
// reproduce.php — run with:  php reproduce.php
$joomlaBase = str_replace('/', DIRECTORY_SEPARATOR, '/path/to/your/joomla');

define('_JEXEC', 1);
define('JPATH_BASE', $joomlaBase . DIRECTORY_SEPARATOR . 'api');
define('JDEBUG', false);

require_once JPATH_BASE . '/includes/defines.php';
require_once JPATH_BASE . '/includes/framework.php';

$container = Joomla\CMS\Factory::getContainer();
$container->alias('session', 'session.cli')
    ->alias('JSession', 'session.cli')
    ->alias(Joomla\CMS\Session\Session::class, 'session.cli')
    ->alias(Joomla\Session\Session::class, 'session.cli')
    ->alias(Joomla\Session\SessionInterface::class, 'session.cli');

$app = $container->get(Joomla\CMS\Application\ApiApplication::class);
Joomla\CMS\Factory::$application = $app;
$app->bootComponent('com_content');

try {
    $url = Joomla\CMS\Router\Route::_('index.php?option=com_content&view=article&id=1');
    echo "OK: $url\n";
} catch (Throwable $e) {
    echo "FAIL: " . get_class($e) . ' - ' . $e->getMessage() . "\n";
}
  1. Run without the patch: observe the ApiRouter::build() crash.
  2. Apply the patch and rerun: observe that Route::_() returns a real site URL (e.g. /index.php/component/content/article/1).

Tested on Joomla 5.2.2 and 6.1.0.

Actual result BEFORE applying this Pull Request

 FAIL: Error - Call to undefined method Joomla\CMS\Router\ApiRouter::build()

Expected result AFTER applying this Pull Request

OK: /index.php/component/content/article/1

Link to documentations

Please select:

  • No documentation changes for guide.joomla.org needed
  • No documentation changes for manual.joomla.org needed
avatar hikashop-nicolas hikashop-nicolas - open - 22 Apr 2026
avatar hikashop-nicolas hikashop-nicolas - change - 22 Apr 2026
Status New Pending
avatar joomla-cms-bot joomla-cms-bot - change - 22 Apr 2026
Category Libraries
avatar hikashop-nicolas hikashop-nicolas - change - 22 Apr 2026
The description was changed
avatar hikashop-nicolas hikashop-nicolas - edited - 22 Apr 2026

Add a Comment

Login with GitHub to post a comment