From ad1c0cf34908a735f5fa9674ede8257ea92bae41 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sun, 21 Jun 2026 19:32:23 -0500 Subject: [PATCH] fix: scope #__fields_values dump and restore to com_content.article The fields_values table is shared across all Joomla extensions. Previously, dump captured ALL field values and restore deleted ALL field values, destroying data for contacts, users, and other extensions. Now scoped via subquery on field_id WHERE context = 'com_content.article'. --- .../src/Engine/SnapshotEngine.php | 26 +++++++++++++++++-- .../src/Engine/SnapshotRestoreEngine.php | 10 ++++++- 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/source/packages/com_mokosuitebackup/src/Engine/SnapshotEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SnapshotEngine.php index f47b045..b581e63 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SnapshotEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SnapshotEngine.php @@ -128,8 +128,8 @@ class SnapshotEngine $data['tables']['#__fields'] = $rows; $this->log(' #__fields: ' . count($rows) . ' rows'); - // Field values — dump all (small, article-scoped) - $rows = $this->dumpTable($db, str_replace('#__', $prefix, '#__fields_values'), '#__fields_values', 'articles'); + // Field values — only for com_content.article fields (table is shared across extensions) + $rows = $this->dumpFieldValues($db, $prefix); $data['tables']['#__fields_values'] = $rows; $this->log(' #__fields_values: ' . count($rows) . ' rows'); @@ -266,6 +266,28 @@ class SnapshotEngine * * Uses a subquery: field_id IN (SELECT id FROM #__fields WHERE context = 'com_content.article') */ + /** + * Dump field values only for com_content.article fields. + */ + private function dumpFieldValues(object $db, string $prefix): array + { + $fvTable = $prefix . 'fields_values'; + $fTable = $prefix . 'fields'; + + $subQuery = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName($fTable)) + ->where($db->quoteName('context') . ' = ' . $db->quote('com_content.article')); + + $query = $db->getQuery(true) + ->select('*') + ->from($db->quoteName($fvTable)) + ->where($db->quoteName('field_id') . ' IN (' . $subQuery . ')'); + $db->setQuery($query); + + return $db->loadAssocList() ?: []; + } + private function dumpFieldCategories(object $db, string $prefix): array { $fcTable = $prefix . 'fields_categories'; diff --git a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php index 665c301..917d276 100644 --- a/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php +++ b/source/packages/com_mokosuitebackup/src/Engine/SnapshotRestoreEngine.php @@ -304,7 +304,15 @@ class SnapshotRestoreEngine break; case '#__fields_values': - // Delete all field values — they are article-scoped + // Only delete field values for com_content.article fields + $prefix = $db->getPrefix(); + $fTable = $prefix . 'fields'; + + $subQuery = $db->getQuery(true) + ->select($db->quoteName('id')) + ->from($db->quoteName($fTable)) + ->where($db->quoteName('context') . ' = ' . $db->quote('com_content.article')); + $query->where($db->quoteName('field_id') . ' IN (' . $subQuery . ')'); break; case '#__fields_categories':