As much as I love Joomla!, there is a shortcoming compared to the other two major Open Source PHP CMS, WordPress and Drupal: it doesn't come with a command-line interface like wp-cli or drush. This is a bit of a problem when you're in need of mass-provisioning sites with extensions or updates in an unattended manner. Using a CLI tool is the only way to provide a scriptable, efficient and unattended method of doing so. In this post we'll see a practical way to overcome this limitation.

Tip: If you're not interested in the technical information please skip to "TL;DR: that's how you do it".

How extension installation works

Everything that's not included in the Joomla! core is a Joomla! extension. This includes components, plugins, modules, templates, libraries, file packages and the "package" extension type which includes one or more extensions of any type. On top of that, Joomla! doesn't really discriminate between a new install and an update. It's always an installation. If the database indicates that the extension we're about to install is already installed Joomla! assumes it's an update. Therefore, no matter if we're updating an existing extension or installing a new one we just need to install the extension package file.

Extensions usually come in ZIP, tar or tar.gz/tgz archives which you install through the Extensions Manager. Actually, Joomla! cannot directly install a compressed extension package. It first needs to extract it to a temporary directory in your site's temp-folder, as defined in your Global Configuration. Thankfully there's an API for that, namely JInstallerHelper::unpack(). Therefore, we need to extract the extension package before installation and remove the temporary directory afterwards.

The PHP code to carry out these operations is quite simple:

$packageFile = '/path/to/extension.zip';

// Extract the package file into a temporary folder
$package = JInstallerHelper::unpack($packageFile);

if (!$package)
{
die('An error occurred while unpacking the file');
}

// Install the package
$installer = new JInstaller;
$installed = $installer->install($package['extractdir']);

// Remove the temporary folder where the package was extracted to
if (JFolder::exists($package['extractdir']))
{
JFolder::delete($package['extractdir']);
}

// Remove the extension package
if (JFile::exists($package['packagefile']))
{
JFile::delete($package['packagefile']);
}

if ($installed)
{
echo "Extension successfully installed";
}
else
{
echo "Extension installation failed";
}

The next reasonable question is exactly how do you run this PHP code from the CLI. It's obvious that it needs to run inside the context of a Joomla! application, otherwise none of the JSomething classes will be available or working properly. You can't just put the code in a .php file and have it work. Since Joomla! 1.6 this problem is solved thanks to Joomla! having added support for CLI scripts. We just need to create a JApplicationCli class in our .php file, put the PHP code in the execute() method, instantiate the object and execute it.

Of course there are a few issues with such a simplistic approach. JApplicationCli is not really designed to work with PHP CGI which is all you've got on some servers. It can't work on servers which don't have a default timezone in their php.ini files. The error detection and reporting in the sample PHP code is rather naive. Plus another few minor issues, like JInstaller being written to only work with the back-end web application of Joomla! and dying due to missing methods in JApplicationCli.

TL;DR: that's how you do it

All of these issues have been properly debugged in the install-joomla-extension.php script I wrote.

First, create a new plain text file and paste that code in it. Save it as install-joomla-extension.php in your Joomla! site's cli directory. The name is not important, the location (cli directory) is.

Now you can call it like this:

cd /path/to/site/cli php ./install-joomla-extension.php --package=/where/is/your/extension.zip

The script returns one of the following exit statuses:

  • 0. The extension was installed successfully.
  • 1. The package file was not found.
  • 3. The package file could not be extracted.
  • 250. The extension could not be installed.

You can copy this file to your site's cli directory and install extensions and extension updates any time you want.