Problem/Motivation

The original implementation of site overrides composed an "effective" entity at read time by merging individual overrideable fields from a site-specific override revision onto the canonical revision (SiteAwareEntityResolver::mergeFields()). This field-by-field merge approach made several things hard:

  • Sub-field-level overrides (e.g. individual values inside a compound field such as behaviors) were not possible without bespoke per-field merge logic.
  • Submodules that need a "real", loadable entity for the current site (Layout Builder sections, Content Moderation state, revision history) had to work around a synthetic, never-saved "effective" entity that didn't correspond to any stored revision.
  • Keeping overrides up to date when the canonical revision changes required ad-hoc logic instead of one well-defined re-sync step.

This issue also tracks the remaining work needed to publish a first stable 1.0.0 release of the module.

Proposed resolution

Move to a full-snapshot override model:

  • Each site override is now a complete revision of the entity (identified by site_id), not a virtual merge. loadEffective() simply returns the latest override revision for the current site, or the canonical revision otherwise — no more read-time field merging.
  • site_override_fields tracks which fields are "pinned" (intentionally diverged) on a given override revision.
  • SiteAwareEntityResolverInterface::buildSnapshot() builds a new override snapshot from the canonical revision plus the pinned fields from a source revision, and invokes the new hook_sites_content_overrides_snapshot_alter() so submodules can perform sub-field-level merging (used by sites_content_overrides_behaviors for the behaviors field).
  • SiteAwareEntityResolverInterface::resyncOverrides() re-snapshots all existing site overrides whenever the canonical revision is saved, so non-pinned fields stay in sync automatically (getOverriddenSiteIds() finds all sites with an override).
  • Adds sites_content_overrides.install with update hooks 10001/10002 to migrate existing sites from the old merge-based model to the new snapshot model.

API changes

  • SiteAwareEntityResolverInterface::loadEffective() no longer returns NULL (always returns the canonical or override revision).
  • New hook: hook_sites_content_overrides_snapshot_alter(ContentEntityInterface &$snapshot, array $context).
  • New methods on SiteAwareEntityResolverInterface: buildSnapshot(), getOverriddenSiteIds(), resyncOverrides().

Remaining tasks

  • Core: SiteAwareEntityResolver/SitesContentOverridesService snapshot-model refactor, update hooks, schema/service changes
  • Adapt sites_content_overrides_revisions_ui to the snapshot model
  • Adapt sites_content_overrides_content_moderation to the snapshot model
  • Adapt sites_content_overrides_layout_builder to the snapshot model; replace deprecated hook_module_implements_alter() usage with #[Hook('entity_presave')] + #[RemoveHook(...)]
  • Adapt sites_content_overrides_behaviors to the snapshot model via hook_sites_content_overrides_snapshot_alter()
  • Add/extend kernel test coverage for the update path and all submodules
  • Update README.md with a "How It Works" section documenting the snapshot model
  • Add CHANGELOG.md
  • Add .gitlab-ci.yml (enable phpstan) and phpstan.neon / baseline
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

hydra created an issue. See original summary.

hydra changed the visibility of the branch 3600769-refactor-site-overrides to hidden.

  • hydra committed f3d1a5b2 on 1.x
    feat: #3600769 Refactor site overrides to a full-snapshot model
    
hydra’s picture

Status: Needs review » Fixed

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • hydra committed 19f6da40 on 1.x
    Issue #3600769 follow-up: Fix phpcs, phpstan and cspell pipeline...

  • hydra committed ed55279d on 1.x
    Issue #3600769 follow-up: Remove PHPStan baseline and fix underlying...

  • hydra committed b4010f44 on 1.x
    Issue #3600769 follow-up: Fix "instanceof always true" PHPStan errors in...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.