Skip to content

Commit c5e273a

Browse files
[5.4] Allow opt-out from automated updates during installation (joomla#45697)
* Allow Automated Updates optout --------- Co-authored-by: Brian Teeman <[email protected]>
1 parent 547cdc2 commit c5e273a

File tree

6 files changed

+327
-147
lines changed

6 files changed

+327
-147
lines changed

installation/language/en-GB/joomla.ini

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ INSTL_LANGUAGES_WARNING_NO_INTERNET="Joomla was unable to connect to the languag
144144
INSTL_LANGUAGES_WARNING_NO_INTERNET2="Note: You will be able to install languages later using the Joomla Administrator."
145145
INSTL_LANGUAGES_WARNING_BACK_BUTTON="Return to last installation step"
146146

147+
; Automated Updates Opt Out
148+
INSTL_AUTOMATED_UPDATES="Automated Updates"
149+
INSTL_AUTOMATED_UPDATES_DESC="Joomla automatically updates itself for minor and patch releases.<br><br><strong>Please note:</strong> Automated Updates will register your site at the respective service provided by the Joomla! project. The registration allows the Joomla project to access information about your site and server environment, specifically Site Url, PHP version, Database type and version, CMS version and Server OS type and version. This information is only used to improve the service.<br><br>Alternatively you can disable automated updates using the button below."
150+
INSTL_AUTOMATED_UPDATES_DISABLE="Disable Automated Updates"
151+
INSTL_DISABLE_AUTOUPDATE="Are you sure you want to disable automated updates?"
152+
INSTL_COMPLETE_ERROR_AUTOMATED_UPDATES_DISABLE="Could not disable automated updates."
153+
147154
; Default language view
148155
INSTL_DEFAULTLANGUAGE_ADMINISTRATOR="Default Administrator language"
149156
INSTL_DEFAULTLANGUAGE_ADMIN_COULDNT_SET_DEFAULT="Joomla was unable to set the language as default. English will be used as the default language for the Backend Administrator."

installation/src/Controller/InstallationController.php

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,4 +299,42 @@ public function delete()
299299
// We can't send a response with sendJsonResponse because our installation classes now do not exist
300300
echo json_encode(['error' => false]);
301301
}
302+
303+
/**
304+
* Opt out from automated updates
305+
*
306+
* @return void
307+
*
308+
* @since __DEPLOY_VERSION__
309+
*/
310+
public function disableAutomatedUpdates()
311+
{
312+
$this->checkValidToken();
313+
314+
/** @var \Joomla\CMS\Installation\Model\AutomatedUpdatesModel $model */
315+
$model = $this->getModel('AutomatedUpdates');
316+
317+
if (!$model->disable()) {
318+
// We can't send a response with sendJsonResponse because our installation classes might not exist yet
319+
$error = [
320+
'token' => Session::getFormToken(true),
321+
'error' => true,
322+
'data' => [
323+
'view' => 'remove',
324+
],
325+
'messages' => [
326+
'warning' => [
327+
Text::sprintf('INSTL_COMPLETE_ERROR_AUTOMATED_UPDATES_DISABLE'),
328+
],
329+
],
330+
];
331+
332+
echo json_encode($error);
333+
334+
return;
335+
}
336+
337+
// We can't send a response with sendJsonResponse because our installation classes do not exist yet
338+
echo json_encode(['error' => false]);
339+
}
302340
}
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
<?php
2+
3+
/**
4+
* @package Joomla.Installation
5+
* @subpackage Model
6+
*
7+
* @copyright (C) 2025 Open Source Matters, Inc. <https://www.joomla.org>
8+
* @license GNU General Public License version 2 or later; see LICENSE.txt
9+
*/
10+
11+
namespace Joomla\CMS\Installation\Model;
12+
13+
use Joomla\CMS\Factory;
14+
use Joomla\Database\DatabaseAwareInterface;
15+
use Joomla\Database\DatabaseAwareTrait;
16+
use Joomla\Registry\Registry;
17+
18+
// phpcs:disable PSR1.Files.SideEffects
19+
\defined('_JEXEC') or die;
20+
// phpcs:enable PSR1.Files.SideEffects
21+
22+
/**
23+
* Automated Updates model for the Joomla Core Installer.
24+
*
25+
* @since __DEPLOY_VERSION__
26+
*/
27+
class AutomatedUpdatesModel extends BaseInstallationModel implements DatabaseAwareInterface
28+
{
29+
use DatabaseAwareTrait;
30+
31+
/**
32+
* @since __DEPLOY_VERSION__
33+
*/
34+
public function __construct()
35+
{
36+
// Overrides application config and set the configuration.php file so tokens and database works.
37+
if (file_exists(JPATH_BASE . '/configuration.php')) {
38+
/** @phpstan-ignore class.notFound */
39+
Factory::getApplication()->setConfiguration(new Registry(new \JConfig()));
40+
}
41+
42+
parent::__construct();
43+
}
44+
45+
/**
46+
* Opt out from automated Updates
47+
*
48+
* @since __DEPLOY_VERSION__
49+
*/
50+
public function disable()
51+
{
52+
// Get the params of com_joomlaupdate
53+
$db = $this->getDatabase();
54+
$query = $db->getQuery(true);
55+
56+
$query->select('params')
57+
->from($db->quoteName('#__extensions'))
58+
->where($db->quoteName('element') . ' = ' . $db->quote('com_joomlaupdate'));
59+
60+
$params = new Registry($db->setQuery($query)->loadResult());
61+
$params->set('autoupdate', 0);
62+
$params->set('autoupdate_status', 0);
63+
64+
// Update the language settings in the language manager.
65+
$query->clear()
66+
->update($db->quoteName('#__extensions'))
67+
->set($db->quoteName('params') . ' = ' . $db->quote($params->toString()))
68+
->where($db->quoteName('element') . ' = ' . $db->quote('com_joomlaupdate'));
69+
$db->setQuery($query)->execute();
70+
71+
return true;
72+
}
73+
}

installation/template/index.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,11 @@
5555
Text::script('INSTL');
5656
Text::script('INSTL_FINISHED');
5757
Text::script('INSTL_IN_PROGRESS');
58-
59-
// Load the JavaScript translated messages
6058
Text::script('INSTL_PROCESS_BUSY');
6159

6260
// Load strings for translated messages (directory removal)
6361
Text::script('INSTL_REMOVE_INST_FOLDER');
62+
Text::script('INSTL_DISABLE_AUTOUPDATE');
6463
Text::script('INSTL_COMPLETE_REMOVE_FOLDER');
6564
?>
6665
<!DOCTYPE html>

installation/template/js/remove.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ if (document.getElementById('removeInstallationFolder')) {
4141
});
4242
}
4343

44+
if (document.getElementById('automatedUpdatesDisableButton')) {
45+
document.getElementById('automatedUpdatesDisableButton')
46+
.addEventListener('click', function (e) {
47+
e.preventDefault();
48+
let confirm = window.confirm(Joomla.Text._('INSTL_DISABLE_AUTOUPDATE'));
49+
if (confirm) {
50+
Joomla.disableAutomatedUpdates();
51+
}
52+
});
53+
}
54+
4455
const completeInstallationOptions = document.querySelectorAll('.complete-installation');
4556

4657
completeInstallationOptions.forEach(function(item) {
@@ -59,6 +70,35 @@ completeInstallationOptions.forEach(function(item) {
5970
});
6071
});
6172

73+
74+
Joomla.disableAutomatedUpdates = function () {
75+
Joomla.request({
76+
method: "POST",
77+
url: Joomla.installationBaseUrl + '?task=installation.disableAutomatedUpdates&format=json',
78+
perform: true,
79+
token: true,
80+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
81+
onSuccess: function (response) {
82+
const successresponse = JSON.parse(response);
83+
if (successresponse.error === true) {
84+
if (successresponse.messages) {
85+
Joomla.renderMessages(successresponse.messages);
86+
Joomla.loadOptions({'csrf.token': successresponse.token});
87+
} else {
88+
// Stuff went wrong. No error messages. Just panic bail!
89+
Joomla.renderMessages({error:['Unknown error disabling the automated updates.']});
90+
}
91+
} else {
92+
const automatedUpdates = document.getElementById('automatedUpdates');
93+
automatedUpdates.parentNode.removeChild(automatedUpdates);
94+
}
95+
},
96+
onError: function (xhr) {
97+
Joomla.renderMessages(Joomla.ajaxErrorsMessages(xhr));
98+
}
99+
});
100+
}
101+
62102
Joomla.deleteJoomlaInstallationDirectory = function (redirectUrl) {
63103
Joomla.request({
64104
method: "POST",
@@ -77,6 +117,9 @@ Joomla.deleteJoomlaInstallationDirectory = function (redirectUrl) {
77117
if (document.getElementById('installAddFeatures')) {
78118
document.getElementById('installAddFeatures').disabled = true;
79119
}
120+
if (document.getElementById('automatedUpdatesDisableButton')) {
121+
document.getElementById('automatedUpdatesDisableButton').disabled = true;
122+
}
80123
if (document.getElementById('removeInstallationFolder')) {
81124
document.getElementById('removeInstallationFolder').disabled = true;
82125
}
@@ -92,6 +135,14 @@ Joomla.deleteJoomlaInstallationDirectory = function (redirectUrl) {
92135
} else {
93136
const customInstallation = document.getElementById('customInstallation');
94137
customInstallation.parentNode.removeChild(customInstallation);
138+
139+
const automatedUpdates = document.getElementById('automatedUpdates');
140+
141+
// This will only exist if it has not been removed with a previous step
142+
if (automatedUpdates) {
143+
automatedUpdates.parentNode.removeChild(automatedUpdates);
144+
}
145+
95146
const removeInstallationTab = document.getElementById('removeInstallationTab');
96147

97148
// This will only exist in debug mode

0 commit comments

Comments
 (0)