Skip to content

Imported block values match what Umbraco publishes (#1097) - #1098

Merged
KevinJump merged 3 commits into
v17/mainfrom
fix/block-draft-matches-publish
Sep 30, 2026
Merged

KevinJump merged 3 commits into
v17/mainfrom
fix/block-draft-matches-publish

Conversation

@KevinJump

@KevinJump KevinJump commented Sep 30, 2026 •

Copy link
Copy Markdown
Owner

Fixes #1097

Problem

For a culture-variant document with an invariant block property that holds culture-variant elements, Umbraco doesn't copy the draft on publish. It merges each culture (MergePartialPropertyValueForCulture) and re-serializes the value with its own serializer. The pending-changes flag is then a plain string compare of the draft and published values (PropertyFactory.BuildDtos), so any textual difference flags the default culture as edited.

The block value uSync wrote on import differed from Umbraco's in three ways:

  1. editorAlias was null. It's computed from BlockPropertyValue.PropertyType, which is [JsonIgnore] and was never set after deserializing.
  2. Keys were in alphabetical order, from uSync's OrderedPropertiesJsonResolver. Umbraco writes them in declaration order.
  3. Values weren't sorted by culture. Umbraco has sorted them since 17.2 (Block editors: Fix false pending changes indicator for invariant block editor with culture-variant blocks (closes #21223) umbraco/Umbraco-CMS#21292).

Fix

SyncBlockMapperBase, import path only:

  • set each value's PropertyType from the element property type
  • sort each block item's values by culture (OrdinalIgnoreCase), as Umbraco does
  • serialize with options that keep Umbraco's property order (the flat options without the ordering resolver)

Export output is unchanged, so existing uSync files don't churn. Block List, Block Grid and Single Block all share the base class.

Side effects

  • Imported block values are now stored in the same format a backoffice save produces.
  • Before this change, block values saved from the backoffice never matched uSync's import output (IsUpdatedValue is a plain Equals), so they were rewritten whenever their item was imported. Now they're left alone.
  • Block values written by older uSync versions are in the old format. The first import after upgrading will rewrite them once.

Tests

uSync.Tests/Mappers/BlockListMapperPublishTests.cs runs the import through the mapper collection, then through Umbraco's own BlockListPropertyEditor per-culture publish merge. Umbraco's value editor is internal, so it's created by reflection.

  • the imported draft equals the published value
  • editorAlias is filled in
  • values stored out of culture order still match after import
  • an invariant block value in Umbraco's format comes back unchanged

All four fail without the fix. Full suite: 164/164 passing.

Also tested on an Umbraco 17.7.0 site pair with the steps from the issue. Released uSync reproduces the pending changes and this branch doesn't; results are in the comments.

🤖 Generated with Claude Code

KevinJump and others added 2 commits September 30, 2026 10:15
An invariant block editor holding culture variant elements is re-serialized
by Umbraco on publish (a per culture merge), and the pending changes flag is
a string compare of the draft and published values. The draft uSync wrote
differed in three ways: editorAlias was null (PropertyType was never set),
properties were in alphabetical order, and values were not sorted by culture.

On import we now set each value's PropertyType, sort values by culture, and
serialize with Umbraco's property order. Export output is unchanged.

Tests run the import through Umbraco's own BlockListPropertyEditor merge and
compare the draft to the published value.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nged

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KevinJump

Copy link
Copy Markdown
Owner Author

Tested on a site (Umbraco 17.7.0)

I set up a Source/Target pair on Umbraco 17.7.0 with two languages (en-US, fr-FR).

Source recreates the setup from #1097:

  • a culture-variant element type, with a culture-variant alt and an invariant url
  • a culture-variant page with an invariant Block List allowing that element

The page is saved through IContentEditingService (the same path as a backoffice save) and both cultures are published. Source itself shows no pending changes. uSync exported it, the export was copied to Target, and Target imported it into a clean database. I ran the import twice, once per uSync version, from the same files:

Target running edited Edited cultures Draft = published
uSync.Core 17.4.2 (released) true en-US no
This branch (local build) false none yes, byte for byte

With 17.4.2 the imported draft had "editorAlias":null and alphabetical key order, including in the layout items. Umbraco's published copy had neither. With this branch the draft matches the published value exactly.

I also restarted Target without wiping the database, so the startup import ran again over the existing content. The page wasn't changed. That import did report 3 unrelated changes (the Block List data type and two seed content types): Description going from (None) to (Blank). That happens already and isn't caused by this PR.

publish-nightly was limited to v17/main, so a prerelease run from a feature
branch built and packed but never reached the feed. The workflow is manual
only, so let any branch publish.

To keep branch builds distinguishable from main nightlies, non-main branches
are versioned "{version}-branch.{branch}.{date}.{run}" instead of
"{version}-prerelease.{date}.{run}". They sort below main nightlies, so a
floating prerelease range won't pick one up by accident.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Imported content shows "pending changes" when an invariant Block List contains culture-variant element values

1 participant