From de632e9c5c7c270f98322309c792ab79dda8631f Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Tue, 23 Jun 2026 11:52:52 -0500 Subject: [PATCH 1/2] feat: uppercase all placeholders + EXAMPLE prefix in resolution display MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All placeholders changed from lowercase to UPPERCASE: [host] → [HOST], [site_name] → [SITE_NAME], [date] → [DATE], [datetime] → [DATETIME], [profile_id] → [PROFILE_ID], etc. [HOME] and [DEFAULT_DIR] were already uppercase — now consistent. SQL migration 01.39.01 updates existing profile data in the database. Resolution display prefixed with "EXAMPLE:" to clarify these are example values resolved at backup time. 13 files updated across engines, fields, forms, templates, and SQL. --- .../com_mokosuitebackup/forms/profile.xml | 6 +- .../language/en-GB/com_mokosuitebackup.ini | 4 +- .../com_mokosuitebackup/sql/install.mysql.sql | 2 +- .../sql/updates/mysql/01.01.02.sql | 2 +- .../sql/updates/mysql/01.39.01.sql | 34 ++++++++++ .../src/Controller/AjaxController.php | 2 +- .../src/Engine/BackupEngine.php | 2 +- .../src/Engine/PlaceholderResolver.php | 66 +++++++++---------- .../src/Engine/SteppedBackupEngine.php | 2 +- .../src/Field/FolderPickerField.php | 54 +++++++-------- .../src/Field/PlaceholderTextField.php | 4 +- .../src/View/Profile/HtmlView.php | 2 +- .../tmpl/profiles/default.php | 2 +- .../tmpl/snapshots/default.php | 2 +- 14 files changed, 109 insertions(+), 75 deletions(-) create mode 100644 source/packages/com_mokosuitebackup/sql/updates/mysql/01.39.01.sql diff --git a/source/packages/com_mokosuitebackup/forms/profile.xml b/source/packages/com_mokosuitebackup/forms/profile.xml index cf02521..3551ee0 100644 --- a/source/packages/com_mokosuitebackup/forms/profile.xml +++ b/source/packages/com_mokosuitebackup/forms/profile.xml @@ -75,10 +75,10 @@ type="PlaceholderText" label="COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT" description="COM_MOKOJOOMBACKUP_FIELD_ARCHIVE_NAME_FORMAT_DESC" - default="[host]_[datetime]_profile[profile_id]" + default="[HOST]_[DATETIME]_profile[PROFILE_ID]" maxlength="512" - hint="[host]_[datetime]_profile[profile_id]" - placeholders="[host],[datetime],[date],[time],[year],[month],[day],[hour],[minute],[second],[profile_id],[profile_name],[site_name],[type],[random]" + hint="[HOST]_[DATETIME]_profile[PROFILE_ID]" + placeholders="[HOST],[DATETIME],[DATE],[TIME],[YEAR],[MONTH],[DAY],[HOUR],[MINUTE],[SECOND],[PROFILE_ID],[PROFILE_NAME],[SITE_NAME],[TYPE],[RANDOM]" addfieldprefix="Joomla\Component\MokoSuiteBackup\Administrator\Field" /> input->getInt('profile_id', 0); if ($profileId > 0) { diff --git a/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php b/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php index 0d96c17..778982b 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/BackupEngine.php @@ -88,7 +88,7 @@ class BackupEngine $archiveName = ''; $archiver = $this->createArchiver($archiveFormat); $archiveExt = $archiver->getExtension(); - $nameFormat = $profile->archive_name_format ?? '[host]_[datetime]_profile[profile_id]'; + $nameFormat = $profile->archive_name_format ?? '[HOST]_[DATETIME]_profile[PROFILE_ID]'; $archiveName = $resolver->resolve($nameFormat) . '.' . $archiveExt; if (empty($description)) { diff --git a/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php b/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php index b2eb727..36fa19d 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php +++ b/source/packages/com_mokosuitebackup/src/Engine/PlaceholderResolver.php @@ -7,7 +7,7 @@ * @copyright Copyright (C) 2026 Moko Consulting. All rights reserved. * @license GNU General Public License version 3 or later; see LICENSE * - * Resolves placeholders like [host], [date], [profile_name] in backup + * Resolves placeholders like [HOST], [DATE], [PROFILE_NAME] in backup * directory paths and archive filename formats. */ @@ -24,21 +24,21 @@ class PlaceholderResolver * Supported placeholders and their descriptions (for documentation). */ public const PLACEHOLDERS = [ - '[host]' => 'Server hostname', - '[date]' => 'Date as Ymd (e.g. 20260604)', - '[time]' => 'Time as His (e.g. 143025)', - '[datetime]' => 'Date and time as Ymd_His', - '[year]' => 'Four-digit year', - '[month]' => 'Two-digit month', - '[day]' => 'Two-digit day', - '[hour]' => 'Two-digit hour (24h)', - '[minute]' => 'Two-digit minute', - '[second]' => 'Two-digit second', - '[profile_id]' => 'Backup profile ID', - '[profile_name]' => 'Profile title (sanitized)', - '[site_name]' => 'Joomla site name (sanitized)', - '[type]' => 'Backup type (full, database, files, differential)', - '[random]' => 'Random 6-character hex string', + '[HOST]' => 'Server hostname', + '[DATE]' => 'Date as Ymd (e.g. 20260604)', + '[TIME]' => 'Time as His (e.g. 143025)', + '[DATETIME]' => 'Date and time as Ymd_His', + '[YEAR]' => 'Four-digit year', + '[MONTH]' => 'Two-digit month', + '[DAY]' => 'Two-digit day', + '[HOUR]' => 'Two-digit hour (24h)', + '[MINUTE]' => 'Two-digit minute', + '[SECOND]' => 'Two-digit second', + '[PROFILE_ID]' => 'Backup profile ID', + '[PROFILE_NAME]' => 'Profile title (sanitized)', + '[SITE_NAME]' => 'Joomla site name (sanitized)', + '[TYPE]' => 'Backup type (full, database, files, differential)', + '[RANDOM]' => 'Random 6-character hex string', '[DEFAULT_DIR]' => 'Default backup directory', '[HOME]' => 'Home directory of the PHP process owner', ]; @@ -62,21 +62,21 @@ class PlaceholderResolver } $this->replacements = [ - '[host]' => $hostname, - '[date]' => $now->format('Ymd'), - '[time]' => $now->format('His'), - '[datetime]' => $now->format('Ymd_His'), - '[year]' => $now->format('Y'), - '[month]' => $now->format('m'), - '[day]' => $now->format('d'), - '[hour]' => $now->format('H'), - '[minute]' => $now->format('i'), - '[second]' => $now->format('s'), - '[profile_id]' => (string) ($profile->id ?? '0'), - '[profile_name]' => $this->sanitize($profile->title ?? 'default'), - '[site_name]' => $this->sanitize($siteName ?: 'joomla'), - '[type]' => $profile->backup_type ?? 'full', - '[random]' => bin2hex(random_bytes(3)), + '[HOST]' => $hostname, + '[DATE]' => $now->format('Ymd'), + '[TIME]' => $now->format('His'), + '[DATETIME]' => $now->format('Ymd_His'), + '[YEAR]' => $now->format('Y'), + '[MONTH]' => $now->format('m'), + '[DAY]' => $now->format('d'), + '[HOUR]' => $now->format('H'), + '[MINUTE]' => $now->format('i'), + '[SECOND]' => $now->format('s'), + '[PROFILE_ID]' => (string) ($profile->id ?? '0'), + '[PROFILE_NAME]' => $this->sanitize($profile->title ?? 'default'), + '[SITE_NAME]' => $this->sanitize($siteName ?: 'joomla'), + '[TYPE]' => $profile->backup_type ?? 'full', + '[RANDOM]' => bin2hex(random_bytes(3)), '[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(), '[HOME]' => BackupDirectory::getHomeDirectory(), ]; @@ -103,7 +103,7 @@ class PlaceholderResolver */ public function getHostname(): string { - return $this->replacements['[host]']; + return $this->replacements['[HOST]']; } /** @@ -111,7 +111,7 @@ class PlaceholderResolver */ public function getTag(): string { - return $this->replacements['[datetime]']; + return $this->replacements['[DATETIME]']; } /** diff --git a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php index d268ac4..0c89b8f 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SteppedBackupEngine.php @@ -83,7 +83,7 @@ class SteppedBackupEngine $now = date('Y-m-d H:i:s'); $tag = $resolver->getTag(); - $nameFormat = $profile->archive_name_format ?? '[host]_[datetime]_profile[profile_id]'; + $nameFormat = $profile->archive_name_format ?? '[HOST]_[DATETIME]_profile[PROFILE_ID]'; $archiveName = $resolver->resolve($nameFormat) . '.zip'; $session->archivePath = $backupDir . '/' . $archiveName; diff --git a/source/packages/com_mokosuitebackup/src/Field/FolderPickerField.php b/source/packages/com_mokosuitebackup/src/Field/FolderPickerField.php index 4177a56..6244bc8 100644 --- a/source/packages/com_mokosuitebackup/src/Field/FolderPickerField.php +++ b/source/packages/com_mokosuitebackup/src/Field/FolderPickerField.php @@ -52,15 +52,15 @@ class FolderPickerField extends FormField $placeholders = [ '[DEFAULT_DIR]' => BackupDirectory::getDefaultAbsolute(), '[HOME]' => BackupDirectory::getHomeDirectory(), - '[host]' => $hostname, - '[site_name]' => $sanitizedSiteName ?: 'joomla', - '[profile_id]' => '1', - '[profile_name]' => 'default', - '[type]' => 'full', - '[year]' => date('Y'), - '[month]' => date('m'), - '[day]' => date('d'), - '[date]' => date('Ymd'), + '[HOST]' => $hostname, + '[SITE_NAME]' => $sanitizedSiteName ?: 'joomla', + '[PROFILE_ID]' => '1', + '[PROFILE_NAME]' => 'default', + '[TYPE]' => 'full', + '[YEAR]' => date('Y'), + '[MONTH]' => date('m'), + '[DAY]' => date('d'), + '[DATE]' => date('Ymd'), ]; $placeholdersJson = json_encode($placeholders); @@ -104,12 +104,12 @@ class FolderPickerField extends FormField Insert: - - - - - - + + + + + +
@@ -137,21 +137,21 @@ class FolderPickerField extends FormField [HOME]Home directory of the server user{$placeholders['[HOME]']} [DEFAULT_DIR]Default backup directory (inside web root){$placeholders['[DEFAULT_DIR]']} - [host]Server hostname{$placeholders['[host]']} - [site_name]Joomla site name{$placeholders['[site_name]']} - [date]Date (Ymd){$placeholders['[date]']} - [year]Four-digit year{$placeholders['[year]']} - [month]Two-digit month{$placeholders['[month]']} - [day]Two-digit day{$placeholders['[day]']} - [profile_id]Backup profile ID1 - [profile_name]Profile titledefault - [type]Backup typefull + [HOST]Server hostname{$placeholders['[HOST]']} + [SITE_NAME]Joomla site name{$placeholders['[SITE_NAME]']} + [DATE]Date (Ymd){$placeholders['[DATE]']} + [YEAR]Four-digit year{$placeholders['[YEAR]']} + [MONTH]Two-digit month{$placeholders['[MONTH]']} + [DAY]Two-digit day{$placeholders['[DAY]']} + [PROFILE_ID]Backup profile ID1 + [PROFILE_NAME]Profile titledefault + [TYPE]Backup typefull
Recommended Paths
  • [HOME]/backups — Outside web root (recommended)
  • -
  • [HOME]/backups/[host] — Per-site subdirectory
  • +
  • [HOME]/backups/[HOST] — Per-site subdirectory
  • [DEFAULT_DIR] — Inside web root (protected by .htaccess)
@@ -195,7 +195,7 @@ class FolderPickerField extends FormField var input = document.getElementById(fieldId); var placeholders = {$placeholdersJson}; - // Resolve placeholders in a path (forward: [site_name] -> actual value) + // Resolve placeholders in a path (forward: [SITE_NAME] -> actual value) function resolve(path) { for (var key in placeholders) { path = path.split(key).join(placeholders[key]); @@ -322,7 +322,7 @@ class FolderPickerField extends FormField fullResolved.className = 'mt-1'; var arrow = document.createElement('span'); arrow.className = 'text-muted'; - arrow.textContent = 'Resolves to: '; + arrow.textContent = 'EXAMPLE: '; fullResolved.appendChild(arrow); var code = document.createElement('code'); code.textContent = resolve(val); diff --git a/source/packages/com_mokosuitebackup/src/Field/PlaceholderTextField.php b/source/packages/com_mokosuitebackup/src/Field/PlaceholderTextField.php index 228418e..722dc7b 100644 --- a/source/packages/com_mokosuitebackup/src/Field/PlaceholderTextField.php +++ b/source/packages/com_mokosuitebackup/src/Field/PlaceholderTextField.php @@ -33,8 +33,8 @@ class PlaceholderTextField extends FormField $placeholders = array_filter(array_map('trim', explode(',', $placeholderAttr))); if (empty($placeholders)) { - $placeholders = ['[host]', '[date]', '[datetime]', '[time]', '[year]', '[month]', '[day]', - '[hour]', '[minute]', '[second]', '[profile_id]', '[profile_name]', '[site_name]', '[type]', '[random]']; + $placeholders = ['[HOST]', '[DATE]', '[DATETIME]', '[TIME]', '[YEAR]', '[MONTH]', '[DAY]', + '[HOUR]', '[MINUTE]', '[SECOND]', '[PROFILE_ID]', '[PROFILE_NAME]', '[SITE_NAME]', '[TYPE]', '[RANDOM]']; } $html = 'linkButton('view-backups', 'COM_MOKOJOOMBACKUP_VIEW_BACKUPS') ->url($backupsUrl) ->icon('icon-database') diff --git a/source/packages/com_mokosuitebackup/tmpl/profiles/default.php b/source/packages/com_mokosuitebackup/tmpl/profiles/default.php index dc5c0b0..e743a5c 100644 --- a/source/packages/com_mokosuitebackup/tmpl/profiles/default.php +++ b/source/packages/com_mokosuitebackup/tmpl/profiles/default.php @@ -78,7 +78,7 @@ $listDirn = $this->escape($this->state->get('list.direction')); escape($item->backup_type); ?> - + backup_count; ?> diff --git a/source/packages/com_mokosuitebackup/tmpl/snapshots/default.php b/source/packages/com_mokosuitebackup/tmpl/snapshots/default.php index 560464d..11b73d7 100644 --- a/source/packages/com_mokosuitebackup/tmpl/snapshots/default.php +++ b/source/packages/com_mokosuitebackup/tmpl/snapshots/default.php @@ -403,7 +403,7 @@ $listDirn = $this->escape($this->state->get('list.direction')); var label = document.createElement('label'); label.className = 'form-check-label'; label.setAttribute('for', 'mb-rtype-' + type); - label.textContent = typeLabels[type] || type; + label.textContent = typeLabels[TYPE] || type; div.appendChild(input); div.appendChild(label); -- 2.52.0 From fb99afbeba38fcc33ca05387e40fe57df00ead98 Mon Sep 17 00:00:00 2001 From: "gitea-actions[bot]" Date: Tue, 23 Jun 2026 16:53:16 +0000 Subject: [PATCH 2/2] chore(version): pre-release bump to 01.38.04-dev [skip ci] --- .mokogitea/workflows/issue-branch.yml | 2 +- README.md | 2 +- source/packages/com_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml | 2 +- .../packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml | 2 +- source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml | 2 +- .../plg_webservices_mokosuitebackup/mokosuitebackup.xml | 2 +- source/pkg_mokosuitebackup.xml | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.mokogitea/workflows/issue-branch.yml b/.mokogitea/workflows/issue-branch.yml index da2a1d6..e3d4244 100644 --- a/.mokogitea/workflows/issue-branch.yml +++ b/.mokogitea/workflows/issue-branch.yml @@ -5,7 +5,7 @@ # FILE INFORMATION # DEFGROUP: Gitea.Workflow # INGROUP: mokocli.Automation -# VERSION: 01.38.03 +# VERSION: 01.38.04 # BRIEF: Auto-create feature branch when an issue is opened name: "Universal: Issue Branch" diff --git a/README.md b/README.md index 87b65e4..317b346 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MokoSuiteBackup - + Full-site backup and restore for Joomla — database, files, and configuration. diff --git a/source/packages/com_mokosuitebackup/mokosuitebackup.xml b/source/packages/com_mokosuitebackup/mokosuitebackup.xml index 357f20b..79d8b84 100644 --- a/source/packages/com_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/com_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml index 2a3862d..8ff8e7c 100644 --- a/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_actionlog_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Action Log - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml index 69c7137..f93680b 100644 --- a/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_console_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Console - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml index 49863ae..1f9cd0e 100644 --- a/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_content_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Content - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-04 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml index 643228f..6bf5f1b 100644 --- a/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_quickicon_mokosuitebackup/mokosuitebackup.xml @@ -1,7 +1,7 @@ Quick Icon - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml index 2f573c3..81ef864 100644 --- a/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_system_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> System - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml index 7e06fb4..7829726 100644 --- a/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_task_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Task - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml index de28263..5096e8b 100644 --- a/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml +++ b/source/packages/plg_webservices_mokosuitebackup/mokosuitebackup.xml @@ -7,7 +7,7 @@ --> Web Services - MokoSuiteBackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech diff --git a/source/pkg_mokosuitebackup.xml b/source/pkg_mokosuitebackup.xml index c330d28..3ce9a1e 100644 --- a/source/pkg_mokosuitebackup.xml +++ b/source/pkg_mokosuitebackup.xml @@ -8,7 +8,7 @@ Package - MokoSuiteBackup mokosuitebackup - 01.38.03 + 01.38.04 2026-06-02 Moko Consulting hello@mokoconsulting.tech -- 2.52.0