@@ -126,6 +126,8 @@ public class MultiTreeAPIImpl implements MultiTreeAPI {
126126 private static final String SELECT_CHILD_BY_PARENT_RELATION_PERSONALIZATION_VARIANT_LANGUAGE =
127127 SELECT_CHILD_BY_PARENT_RELATION_PERSONALIZATION_VARIANT + " AND child IN (SELECT DISTINCT identifier FROM contentlet, multi_tree " +
128128 "WHERE multi_tree.child = contentlet.identifier AND multi_tree.parent1 = ? AND language_id = ?)" ;
129+ private static final String SELECT_NOT_EMPTY_CONTENTLET_STYLES_BY_PARENTS_AND_RELATIONS =
130+ SELECT_ALL + "WHERE parent1 = ? AND style_properties IS NOT NULL" ;
129131
130132 @ WrapInTransaction
131133 @ Override
@@ -661,7 +663,7 @@ public void overridesMultitreesByPersonalization(final String pageId,
661663 * @param multiTrees {@link List} of {@link MultiTree} to safe
662664 * @param languageIdOpt {@link Optional} {@link Long} optional language, if present will deletes only the contentlets that have a version on this language.
663665 * Since it is by identifier, when deleting for instance in spanish, will remove the english and any other lang version too.
664- * @throws DotDataException
666+ * @throws DotDataException If there is an issue retrieving data from the DB.
665667 */
666668 @ Override
667669 @ WrapInTransaction
@@ -683,6 +685,13 @@ public void overridesMultitreesByPersonalization(final String pageId,
683685 Logger .debug (MultiTreeAPIImpl .class , ()->String .format ("Saving page's content: %s" , multiTrees ));
684686 Set <String > originalContentletIds = new HashSet <>();
685687 final DotConnect db = new DotConnect ();
688+
689+ // preserve style properties if feature flag is disabled and there are style properties to preserve
690+ final boolean isStyleEditorEnabled = Config .getBooleanProperty ("FEATURE_FLAG_UVE_STYLE_EDITOR" , false );
691+ if (!isStyleEditorEnabled ) {
692+ preserveStylesBeforeSaving (pageId , multiTrees );
693+ }
694+
686695 if (languageIdOpt .isPresent ()) {
687696 if (DbConnectionFactory .isMySql ()) {
688697 deleteMultiTreeToMySQL (pageId , personalization , languageIdOpt , variantId );
@@ -1570,6 +1579,55 @@ private Set<String> getOriginalContentlets(final String sqlQuery, final List<Obj
15701579 return contentletData .stream ().map (dataMap -> dataMap .get ("child" ).toString ()).collect (Collectors .toSet ());
15711580 }
15721581
1582+ /**
1583+ * Restores the style properties for a list of MultiTree objects by looking up
1584+ * their existing values in the database.
1585+ * * This prevents style data loss when overwriting existing records. It matches
1586+ * records based on the composite key of Container + Contentlet.
1587+ *
1588+ * @param pageId The identifier of the page being processed.
1589+ * @param multiTrees The list of MultiTree objects to be saved.
1590+ * NOTE: This list is modified in-place.
1591+ * The same list of multiTrees will be enriched with their original styles.
1592+ * @throws DotDataException If there is an issue retrieving data from the DB.
1593+ */
1594+ private void preserveStylesBeforeSaving (final String pageId , List <MultiTree > multiTrees ) throws DotDataException {
1595+ // Gets existing multiTrees by Page from DB
1596+ final List <MultiTree > multiTreesFromDB = fetchStylesFromDB (pageId );
1597+
1598+ if (multiTreesFromDB .isEmpty ()) {
1599+ return ;
1600+ }
1601+
1602+ // Create a "Lookup Map" from the DB multiTrees.
1603+ // Key: Unique combination of Container + Contentlet
1604+ // Value: Contentlet styleProperties of the Contentlet
1605+ final Map <String , Map <String , Object >> dbStyleMap = multiTreesFromDB .stream ()
1606+ .collect (Collectors .toMap (
1607+ mt -> mt .getContainer () + "_" + mt .getContentlet (),
1608+ MultiTree ::getStyleProperties ,
1609+ // In case of duplicates, keep last entrance value (shouldn't happen)
1610+ (existing , replacement ) -> replacement
1611+ ));
1612+
1613+ // Update the multiTrees list to preserve existing styleProperties
1614+ for (MultiTree multiTree : multiTrees ) {
1615+ String key = multiTree .getContainer () + "_" + multiTree .getContentlet ();
1616+
1617+ // If this relationship already existed in DB, preserves the old styles
1618+ if (dbStyleMap .containsKey (key )) {
1619+ multiTree .setStyleProperties (dbStyleMap .get (key ));
1620+ }
1621+ }
1622+ }
1623+
1624+ protected List <MultiTree > fetchStylesFromDB (String pageId ) throws DotDataException {
1625+ final DotConnect db = new DotConnect ()
1626+ .setSQL (SELECT_NOT_EMPTY_CONTENTLET_STYLES_BY_PARENTS_AND_RELATIONS )
1627+ .addParam (pageId );
1628+ return TransformerLocator .createMultiTreeTransformer (db .loadObjectResults ()).asList ();
1629+ }
1630+
15731631 /**
15741632 * Takes the list of Contentlet IDs present in an HTML Page before any change is made, and the list of
15751633 * {@link MultiTree} objects representing the updated Contentlets. Then, compares both lists and determines what
0 commit comments