diff --git a/administrator/components/com_admin/script.php b/administrator/components/com_admin/script.php
index 768a04aa6df02..3f5cf6cb4d666 100644
--- a/administrator/components/com_admin/script.php
+++ b/administrator/components/com_admin/script.php
@@ -2346,6 +2346,10 @@ public function postflight($action, $installer)
return false;
}
+ if (!$this->migrateDeleteActionlogsConfiguration()) {
+ return false;
+ }
+
if (!$this->migratePrivacyconsentConfiguration()) {
return false;
}
@@ -2355,6 +2359,75 @@ public function postflight($action, $installer)
return true;
}
+ /**
+ * Migrate Deleteactionlogs plugin configuration
+ *
+ * @return boolean True on success
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ private function migrateDeleteActionlogsConfiguration(): bool
+ {
+ $db = Factory::getDbo();
+
+ try {
+ // Get the ActionLogs system plugin's parameters
+ $row = $db->setQuery(
+ $db->getQuery(true)
+ ->select([$db->quotename('enabled'), $db->quoteName('params')])
+ ->from($db->quoteName('#__extensions'))
+ ->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
+ ->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
+ ->where($db->quoteName('element') . ' = ' . $db->quote('actionlogs'))
+ )->loadObject();
+ } catch (Exception $e) {
+ echo Text::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()) . '
';
+
+ return false;
+ }
+
+ // If not existing or disabled there is nothing to migrate
+ if (!$row || !$row->enabled) {
+ return true;
+ }
+
+ $params = new Registry($row->params);
+
+ // If deletion of outdated logs was disabled there is nothing to migrate
+ if (!$params->get('logDeletePeriod', 0)) {
+ return true;
+ }
+
+ /** @var SchedulerComponent $component */
+ $component = Factory::getApplication()->bootComponent('com_scheduler');
+
+ /** @var TaskModel $model */
+ $model = $component->getMVCFactory()->createModel('Task', 'Administrator', ['ignore_request' => true]);
+ $task = [
+ 'title' => 'DeleteActionLogs',
+ 'type' => 'delete.actionlogs',
+ 'execution_rules' => [
+ 'rule-type' => 'interval-hours',
+ 'interval-hours' => 24,
+ 'exec-time' => gmdate('H:i', $params->get('lastrun', time())),
+ 'exec-day' => gmdate('d'),
+ ],
+ 'state' => 1,
+ 'params' => [
+ 'logDeletePeriod' => $params->get('logDeletePeriod', 0),
+ ],
+ ];
+
+ try {
+ $model->save($task);
+ } catch (Exception $e) {
+ echo Text::sprintf('JLIB_DATABASE_ERROR_FUNCTION_FAILED', $e->getCode(), $e->getMessage()) . '
';
+
+ return false;
+ }
+
+ return true;
+ }
/**
* Migrate privacyconsents system plugin configuration
*
@@ -2370,7 +2443,7 @@ private function migratePrivacyconsentConfiguration(): bool
// Get the PrivacyConsent system plugin's parameters
$row = $db->setQuery(
$db->getQuery(true)
- ->select($db->quotename('enabled'), $db->quoteName('params'))
+ ->select([$db->quotename('enabled'), $db->quoteName('params')])
->from($db->quoteName('#__extensions'))
->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
@@ -2382,14 +2455,14 @@ private function migratePrivacyconsentConfiguration(): bool
return false;
}
- // If not existing or disbled there is nothing to migrate
+ // If not existing or disabled there is nothing to migrate
if (!$row || !$row->enabled) {
return true;
}
$params = new Registry($row->params);
- // If consent expiration was disbled there is nothing to migrate
+ // If consent expiration was disabled there is nothing to migrate
if (!$params->get('enabled', 0)) {
return true;
}
diff --git a/administrator/components/com_admin/sql/updates/mysql/5.0.0-2023-09-02.sql b/administrator/components/com_admin/sql/updates/mysql/5.0.0-2023-09-02.sql
index 27c020cd2fb52..4e74349940933 100644
--- a/administrator/components/com_admin/sql/updates/mysql/5.0.0-2023-09-02.sql
+++ b/administrator/components/com_admin/sql/updates/mysql/5.0.0-2023-09-02.sql
@@ -1,4 +1,5 @@
INSERT INTO `#__extensions` (`name`, `type`, `element`, `folder`, `client_id`, `enabled`, `access`, `protected`, `locked`, `manifest_cache`, `params`, `custom_data`, `checked_out`, `checked_out_time`, `ordering`, `state`) VALUES
+('plg_task_deleteactionlogs', 'plugin', 'deleteactionlogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0);
diff --git a/administrator/components/com_admin/sql/updates/postgresql/5.0.0-2023-09-02.sql b/administrator/components/com_admin/sql/updates/postgresql/5.0.0-2023-09-02.sql
index 931f4acb15b6e..08e8541039d17 100644
--- a/administrator/components/com_admin/sql/updates/postgresql/5.0.0-2023-09-02.sql
+++ b/administrator/components/com_admin/sql/updates/postgresql/5.0.0-2023-09-02.sql
@@ -1,4 +1,5 @@
INSERT INTO "#__extensions" ("name", "type", "element", "folder", "client_id", "enabled", "access", "protected", "locked", "manifest_cache", "params", "custom_data", "checked_out", "checked_out_time", "ordering", "state") VALUES
+('plg_task_deleteactionlogs', 'plugin', 'deleteactionlogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0),
('plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', NULL, NULL, 0, 0);
diff --git a/administrator/language/en-GB/plg_system_actionlogs.ini b/administrator/language/en-GB/plg_system_actionlogs.ini
index 1b63c7b5a6acb..1f0ec95576f52 100644
--- a/administrator/language/en-GB/plg_system_actionlogs.ini
+++ b/administrator/language/en-GB/plg_system_actionlogs.ini
@@ -9,8 +9,6 @@ PLG_SYSTEM_ACTIONLOGS_INFO_DESC="The Action Log - Joomla plugin is disabled"
PLG_SYSTEM_ACTIONLOGS_INFO_LABEL="Information"
PLG_SYSTEM_ACTIONLOGS_JOOMLA_ACTIONLOG_DISABLED="Action Log - Joomla"
PLG_SYSTEM_ACTIONLOGS_JOOMLA_ACTIONLOG_DISABLED_REDIRECT="The %s plugin is disabled."
-PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD="Days to delete logs after"
-PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD_DESC="Enter 0 if you don't want to delete the logs."
PLG_SYSTEM_ACTIONLOGS_NOTIFICATIONS="Email Notifications"
PLG_SYSTEM_ACTIONLOGS_OPTIONS="User Actions Log Options"
PLG_SYSTEM_ACTIONLOGS_XML_DESCRIPTION="Records the actions of users on the site so they can be reviewed if required."
@@ -22,3 +20,7 @@ PLG_SYSTEM_ACTIONLOGS_CONTENT_PUBLISHED="User {usernam
PLG_SYSTEM_ACTIONLOGS_CONTENT_TRASHED="User {username} trashed the {type} {title}"
PLG_SYSTEM_ACTIONLOGS_CONTENT_UNPUBLISHED="User {username} unpublished the {type} {title}"
PLG_SYSTEM_ACTIONLOGS_CONTENT_UPDATED="User {username} updated the {type} {title}"
+
+; All the following strings are deprecated and will be removed with 6.0
+PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD="Days to delete logs after"
+PLG_SYSTEM_ACTIONLOGS_LOG_DELETE_PERIOD_DESC="Enter 0 if you don't want to delete the logs."
diff --git a/administrator/language/en-GB/plg_task_deleteactionlogs.ini b/administrator/language/en-GB/plg_task_deleteactionlogs.ini
new file mode 100644
index 0000000000000..30a9ede1a6fb2
--- /dev/null
+++ b/administrator/language/en-GB/plg_task_deleteactionlogs.ini
@@ -0,0 +1,10 @@
+; Joomla! Project
+; (C) 2023 Open Source Matters, Inc.
+; License GNU General Public License version 2 or later; see LICENSE.txt
+; Note : All ini files need to be saved as UTF-8
+
+PLG_TASK_DELETEACTIONLOGS="Task - Delete Action Logs"
+PLG_TASK_DELETEACTIONLOGS_DELETE_DESC="Delete Action logs after days"
+PLG_TASK_DELETEACTIONLOGS_DELETE_TITLE="Delete ActionLogs - Task"
+PLG_TASK_DELETEACTIONLOGS_LOG_DELETE_PERIOD="Days to delete action logs after"
+PLG_TASK_DELETEACTIONLOGS_XML_DESCRIPTION="This plugin for schedule Action Logs delete Tasks."
diff --git a/administrator/language/en-GB/plg_task_deleteactionlogs.sys.ini b/administrator/language/en-GB/plg_task_deleteactionlogs.sys.ini
new file mode 100644
index 0000000000000..fed421579b57f
--- /dev/null
+++ b/administrator/language/en-GB/plg_task_deleteactionlogs.sys.ini
@@ -0,0 +1,7 @@
+; Joomla! Project
+; (C) 2023 Open Source Matters, Inc.
+; License GNU General Public License version 2 or later; see LICENSE.txt
+; Note : All ini files need to be saved as UTF-8
+
+PLG_TASK_DELETEACTIONLOGS="Task - Delete Action Logs"
+PLG_TASK_DELETEACTIONLOGS_XML_DESCRIPTION="This plugin for schedule Action Logs delete Tasks."
diff --git a/installation/sql/mysql/base.sql b/installation/sql/mysql/base.sql
index 0c0b6a33700aa..b978a5c41fc33 100644
--- a/installation/sql/mysql/base.sql
+++ b/installation/sql/mysql/base.sql
@@ -364,12 +364,13 @@ INSERT INTO `#__extensions` (`package_id`, `name`, `type`, `element`, `folder`,
(0, 'plg_system_tasknotification', 'plugin', 'tasknotification', 'system', 0, 1, 1, 0, 1, '', '', '', 24, 0),
(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', '', 26, 0),
(0, 'plg_task_checkfiles', 'plugin', 'checkfiles', 'task', 0, 1, 1, 0, 1, '', '{}', '', 1, 0),
-(0, 'plg_task_globalcheckin', 'plugin', 'globalcheckin', 'task', 0, 1, 1, 0, 0, '', '{}', '', 2, 0),
-(0, 'plg_task_requests', 'plugin', 'requests', 'task', 0, 1, 1, 0, 1, '', '{}', '', 3, 0),
-(0, 'plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', 4, 0),
-(0, 'plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 5, 0),
-(0, 'plg_task_sitestatus', 'plugin', 'sitestatus', 'task', 0, 1, 1, 0, 1, '', '{}', '', 6, 0),
-(0, 'plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', 7, 0),
+(0, 'plg_task_deleteactionlogs', 'plugin', 'deleteactionlogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 2, 0),
+(0, 'plg_task_globalcheckin', 'plugin', 'globalcheckin', 'task', 0, 1, 1, 0, 0, '', '{}', '', 3, 0),
+(0, 'plg_task_requests', 'plugin', 'requests', 'task', 0, 1, 1, 0, 1, '', '{}', '', 4, 0),
+(0, 'plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', 5, 0),
+(0, 'plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 6, 0),
+(0, 'plg_task_sitestatus', 'plugin', 'sitestatus', 'task', 0, 1, 1, 0, 1, '', '{}', '', 7, 0),
+(0, 'plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', 8, 0),
(0, 'plg_multifactorauth_totp', 'plugin', 'totp', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 1, 0),
(0, 'plg_multifactorauth_yubikey', 'plugin', 'yubikey', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 2, 0),
(0, 'plg_multifactorauth_webauthn', 'plugin', 'webauthn', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 3, 0),
diff --git a/installation/sql/postgresql/base.sql b/installation/sql/postgresql/base.sql
index 883ad28bf8ff5..d4f3a214375fc 100644
--- a/installation/sql/postgresql/base.sql
+++ b/installation/sql/postgresql/base.sql
@@ -370,12 +370,13 @@ INSERT INTO "#__extensions" ("package_id", "name", "type", "element", "folder",
(0, 'plg_system_tasknotification', 'plugin', 'tasknotification', 'system', 0, 1, 1, 0, 1, '', '', '', 24, 0),
(0, 'plg_system_webauthn', 'plugin', 'webauthn', 'system', 0, 1, 1, 0, 1, '', '{}', '', 26, 0),
(0, 'plg_task_checkfiles', 'plugin', 'checkfiles', 'task', 0, 1, 1, 0, 1, '', '{}', '', 1, 0),
-(0, 'plg_task_globalcheckin', 'plugin', 'globalcheckin', 'task', 0, 1, 1, 0, 0, '', '{}', '', 2, 0),
-(0, 'plg_task_requests', 'plugin', 'requests', 'task', 0, 1, 1, 0, 1, '', '{}', '', 3, 0),
-(0, 'plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', 4, 0),
-(0, 'plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 5, 0),
-(0, 'plg_task_sitestatus', 'plugin', 'sitestatus', 'task', 0, 1, 1, 0, 1, '', '{}', '', 6, 0),
-(0, 'plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', 7, 0),
+(0, 'plg_task_deleteactionlogs', 'plugin', 'deleteactionlogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 2, 0),
+(0, 'plg_task_globalcheckin', 'plugin', 'globalcheckin', 'task', 0, 1, 1, 0, 0, '', '{}', '', 3, 0),
+(0, 'plg_task_requests', 'plugin', 'requests', 'task', 0, 1, 1, 0, 1, '', '{}', '', 4, 0),
+(0, 'plg_task_privacyconsent', 'plugin', 'privacyconsent', 'task', 0, 1, 1, 0, 1, '', '{}', '', 5, 0),
+(0, 'plg_task_rotatelogs', 'plugin', 'rotatelogs', 'task', 0, 1, 1, 0, 1, '', '{}', '', 6, 0),
+(0, 'plg_task_sitestatus', 'plugin', 'sitestatus', 'task', 0, 1, 1, 0, 1, '', '{}', '', 7, 0),
+(0, 'plg_task_updatenotification', 'plugin', 'updatenotification', 'task', 0, 1, 1, 0, 1, '', '{}', '', 8, 0),
(0, 'plg_multifactorauth_totp', 'plugin', 'totp', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 1, 0),
(0, 'plg_multifactorauth_yubikey', 'plugin', 'yubikey', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 2, 0),
(0, 'plg_multifactorauth_webauthn', 'plugin', 'webauthn', 'multifactorauth', 0, 1, 1, 0, 1, '', '', '', 3, 0),
diff --git a/libraries/src/Extension/ExtensionHelper.php b/libraries/src/Extension/ExtensionHelper.php
index bde784432c9d1..1e2929863263c 100644
--- a/libraries/src/Extension/ExtensionHelper.php
+++ b/libraries/src/Extension/ExtensionHelper.php
@@ -318,6 +318,7 @@ class ExtensionHelper
// Core plugin extensions - task scheduler
['plugin', 'checkfiles', 'task', 0],
+ ['plugin', 'deleteactionlogs', 'task', 0],
['plugin', 'globalcheckin', 'task', 0],
['plugin', 'privacyconsent', 'task', 0],
['plugin', 'requests', 'task', 0],
diff --git a/plugins/system/actionlogs/actionlogs.xml b/plugins/system/actionlogs/actionlogs.xml
index fdb319a0dc7a8..6bb24222ccce7 100644
--- a/plugins/system/actionlogs/actionlogs.xml
+++ b/plugins/system/actionlogs/actionlogs.xml
@@ -19,26 +19,4 @@
language/en-GB/plg_system_actionlogs.ini
language/en-GB/plg_system_actionlogs.sys.ini
-
-
-
-
-
diff --git a/plugins/system/actionlogs/src/Extension/ActionLogs.php b/plugins/system/actionlogs/src/Extension/ActionLogs.php
index 4d8f3d75b6f5d..22e0a8c1d14f2 100644
--- a/plugins/system/actionlogs/src/Extension/ActionLogs.php
+++ b/plugins/system/actionlogs/src/Extension/ActionLogs.php
@@ -10,8 +10,6 @@
namespace Joomla\Plugin\System\ActionLogs\Extension;
-use Joomla\CMS\Cache\Cache;
-use Joomla\CMS\Factory;
use Joomla\CMS\Form\Form;
use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
@@ -192,129 +190,6 @@ public function onContentPrepareData($context, $data)
return true;
}
- /**
- * Runs after the HTTP response has been sent to the client and delete log records older than certain days
- *
- * @return void
- *
- * @since 3.9.0
- */
- public function onAfterRespond()
- {
- $daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
-
- if ($daysToDeleteAfter <= 0) {
- return;
- }
-
- // The delete frequency will be once per day
- $deleteFrequency = 3600 * 24;
-
- // Do we need to run? Compare the last run timestamp stored in the plugin's options with the current
- // timestamp. If the difference is greater than the cache timeout we shall not execute again.
- $now = time();
- $last = (int) $this->params->get('lastrun', 0);
-
- if (abs($now - $last) < $deleteFrequency) {
- return;
- }
-
- // Update last run status
- $this->params->set('lastrun', $now);
-
- $db = $this->getDatabase();
- $params = $this->params->toString('JSON');
- $query = $db->getQuery(true)
- ->update($db->quoteName('#__extensions'))
- ->set($db->quoteName('params') . ' = :params')
- ->where($db->quoteName('type') . ' = ' . $db->quote('plugin'))
- ->where($db->quoteName('folder') . ' = ' . $db->quote('system'))
- ->where($db->quoteName('element') . ' = ' . $db->quote('actionlogs'))
- ->bind(':params', $params);
-
- try {
- // Lock the tables to prevent multiple plugin executions causing a race condition
- $db->lockTable('#__extensions');
- } catch (\Exception $e) {
- // If we can't lock the tables it's too risky to continue execution
- return;
- }
-
- try {
- // Update the plugin parameters
- $result = $db->setQuery($query)->execute();
-
- $this->clearCacheGroups(['com_plugins'], [0, 1]);
- } catch (\Exception $exc) {
- // If we failed to execute
- $db->unlockTables();
- $result = false;
- }
-
- try {
- // Unlock the tables after writing
- $db->unlockTables();
- } catch (\Exception $e) {
- // If we can't lock the tables assume we have somehow failed
- $result = false;
- }
-
- // Stop on failure
- if (!$result) {
- return;
- }
-
- $daysToDeleteAfter = (int) $this->params->get('logDeletePeriod', 0);
- $now = Factory::getDate()->toSql();
-
- if ($daysToDeleteAfter > 0) {
- $days = -1 * $daysToDeleteAfter;
-
- $query->clear()
- ->delete($db->quoteName('#__action_logs'))
- ->where($db->quoteName('log_date') . ' < ' . $query->dateAdd($db->quote($now), $days, 'DAY'));
-
- $db->setQuery($query);
-
- try {
- $db->execute();
- } catch (\RuntimeException $e) {
- // Ignore it
- return;
- }
- }
- }
-
- /**
- * Clears cache groups. We use it to clear the plugins cache after we update the last run timestamp.
- *
- * @param array $clearGroups The cache groups to clean
- * @param array $cacheClients The cache clients (site, admin) to clean
- *
- * @return void
- *
- * @since 3.9.0
- */
- private function clearCacheGroups(array $clearGroups, array $cacheClients = [0, 1])
- {
- foreach ($clearGroups as $group) {
- foreach ($cacheClients as $clientId) {
- try {
- $options = [
- 'defaultgroup' => $group,
- 'cachebase' => $clientId ? JPATH_ADMINISTRATOR . '/cache' :
- $this->getApplication()->get('cache_path', JPATH_SITE . '/cache'),
- ];
-
- $cache = Cache::getInstance('callback', $options);
- $cache->clean();
- } catch (\Exception $e) {
- // Ignore it
- }
- }
- }
- }
-
/**
* Utility method to act on a user after it has been saved.
*
diff --git a/plugins/task/deleteactionlogs/deleteactionlogs.xml b/plugins/task/deleteactionlogs/deleteactionlogs.xml
new file mode 100644
index 0000000000000..97ea8df143f13
--- /dev/null
+++ b/plugins/task/deleteactionlogs/deleteactionlogs.xml
@@ -0,0 +1,22 @@
+
+
+ plg_task_deleteactionlogs
+ Joomla! Project
+ 2023-07
+ (C) 2023 Open Source Matters, Inc.
+ GNU General Public License version 2 or later; see LICENSE.txt
+ admin@joomla.org
+ www.joomla.org
+ 5.0.0
+ PLG_TASK_DELETEACTIONLOGS_XML_DESCRIPTION
+ Joomla\Plugin\Task\DeleteActionLogs
+
+ forms
+ services
+ src
+
+
+ language/en-GB/plg_task_deleteactionlogs.ini
+ language/en-GB/plg_task_deleteactionlogs.sys.ini
+
+
diff --git a/plugins/task/deleteactionlogs/forms/deleteForm.xml b/plugins/task/deleteactionlogs/forms/deleteForm.xml
new file mode 100644
index 0000000000000..df2935362b77c
--- /dev/null
+++ b/plugins/task/deleteactionlogs/forms/deleteForm.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/plugins/task/deleteactionlogs/services/provider.php b/plugins/task/deleteactionlogs/services/provider.php
new file mode 100644
index 0000000000000..be8a108e29ace
--- /dev/null
+++ b/plugins/task/deleteactionlogs/services/provider.php
@@ -0,0 +1,48 @@
+
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+defined('_JEXEC') or die;
+
+use Joomla\CMS\Extension\PluginInterface;
+use Joomla\CMS\Factory;
+use Joomla\CMS\Plugin\PluginHelper;
+use Joomla\Database\DatabaseInterface;
+use Joomla\DI\Container;
+use Joomla\DI\ServiceProviderInterface;
+use Joomla\Event\DispatcherInterface;
+use Joomla\Plugin\Task\DeleteActionLogs\Extension\DeleteActionLogs;
+
+return new class () implements ServiceProviderInterface {
+ /**
+ * Registers the service provider with a DI container.
+ *
+ * @param Container $container The DI container.
+ *
+ * @return void
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public function register(Container $container)
+ {
+ $container->set(
+ PluginInterface::class,
+ function (Container $container) {
+ $plugin = new DeleteActionLogs(
+ $container->get(DispatcherInterface::class),
+ (array) PluginHelper::getPlugin('task', 'deleteactionlogs')
+ );
+ $plugin->setApplication(Factory::getApplication());
+ $plugin->setDatabase($container->get(DatabaseInterface::class));
+
+ return $plugin;
+ }
+ );
+ }
+};
diff --git a/plugins/task/deleteactionlogs/src/Extension/DeleteActionLogs.php b/plugins/task/deleteactionlogs/src/Extension/DeleteActionLogs.php
new file mode 100644
index 0000000000000..e9535dbcf0384
--- /dev/null
+++ b/plugins/task/deleteactionlogs/src/Extension/DeleteActionLogs.php
@@ -0,0 +1,108 @@
+
+ * @license GNU General Public License version 2 or later; see LICENSE.txt
+ */
+
+namespace Joomla\Plugin\Task\DeleteActionLogs\Extension;
+
+use Joomla\CMS\Factory;
+use Joomla\CMS\Plugin\CMSPlugin;
+use Joomla\Component\Scheduler\Administrator\Event\ExecuteTaskEvent;
+use Joomla\Component\Scheduler\Administrator\Task\Status;
+use Joomla\Component\Scheduler\Administrator\Task\Task;
+use Joomla\Component\Scheduler\Administrator\Traits\TaskPluginTrait;
+use Joomla\Database\DatabaseAwareTrait;
+use Joomla\Event\SubscriberInterface;
+
+// phpcs:disable PSR1.Files.SideEffects
+\defined('_JEXEC') or die;
+// phpcs:enable PSR1.Files.SideEffects
+
+/**
+ * A task plugin. For Delete Action Logs after x days
+ * {@see ExecuteTaskEvent}.
+ *
+ * @since __DEPLOY_VERSION__
+ */
+final class DeleteActionLogs extends CMSPlugin implements SubscriberInterface
+{
+ use DatabaseAwareTrait;
+ use TaskPluginTrait;
+
+ /**
+ * @var string[]
+ * @since __DEPLOY_VERSION__
+ */
+ private const TASKS_MAP = [
+ 'delete.actionlogs' => [
+ 'langConstPrefix' => 'PLG_TASK_DELETEACTIONLOGS_DELETE',
+ 'method' => 'deleteLogs',
+ 'form' => 'deleteForm',
+ ],
+ ];
+
+ /**
+ * @var boolean
+ * @since __DEPLOY_VERSION__
+ */
+ protected $autoloadLanguage = true;
+
+ /**
+ * @inheritDoc
+ *
+ * @return string[]
+ *
+ * @since __DEPLOY_VERSION__
+ */
+ public static function getSubscribedEvents(): array
+ {
+ return [
+ 'onTaskOptionsList' => 'advertiseRoutines',
+ 'onExecuteTask' => 'standardRoutineHandler',
+ 'onContentPrepareForm' => 'enhanceTaskItemForm',
+ ];
+ }
+
+ /**
+ * @param ExecuteTaskEvent $event The `onExecuteTask` event.
+ *
+ * @return integer The routine exit code.
+ *
+ * @since __DEPLOY_VERSION__
+ * @throws \Exception
+ */
+ private function deleteLogs(ExecuteTaskEvent $event): int
+ {
+ $daysToDeleteAfter = (int) $event->getArgument('params')->logDeletePeriod ?? 0;
+ $this->logTask(sprintf('Delete Logs after %d days', $daysToDeleteAfter));
+ $now = Factory::getDate()->toSql();
+ $db = $this->getDatabase();
+ $query = $db->getQuery(true);
+
+ if ($daysToDeleteAfter > 0) {
+ $days = -1 * $daysToDeleteAfter;
+
+ $query->clear()
+ ->delete($db->quoteName('#__action_logs'))
+ ->where($db->quoteName('log_date') . ' < ' . $query->dateAdd($db->quote($now), $days, 'DAY'));
+
+ $db->setQuery($query);
+
+ try {
+ $db->execute();
+ } catch (\RuntimeException $e) {
+ // Ignore it
+ return Status::KNOCKOUT;
+ }
+ }
+
+ $this->logTask('Delete Logs end');
+
+ return Status::OK;
+ }
+}