Skip to content

fix: Preload GutenbergKit and invalidate cache for non-Jetpack sites#25226

Open
dcalhoun wants to merge 6 commits intotrunkfrom
fix/preload-gutenberg-kit-without-jetpack
Open

fix: Preload GutenbergKit and invalidate cache for non-Jetpack sites#25226
dcalhoun wants to merge 6 commits intotrunkfrom
fix/preload-gutenberg-kit-without-jetpack

Conversation

@dcalhoun
Copy link
Member

@dcalhoun dcalhoun commented Feb 5, 2026

Description

This PR fixes editor preloading and cache invalidation for non-Jetpack self-hosted sites. Previously, these features only worked for Jetpack-connected sites because the logic was in BlogDashboardViewModel, which is only used when displaying the dashboard. Non-Jetpack sites show BlogDetailsViewController (Site Menu) instead.

Changes

  1. Add LockingValue<T> utility - Thread-safe wrapper for single values, fixing Swift 6 Sendable warning on _lastPluginsFlagValue

  2. Consolidate editor warmup in EditorDependencyManager - Add warmUpEditor(for:) method that combines WebKit warmup with data prefetch

  3. Move editor preloading to MySiteViewController - Call warmUpEditor from MySiteViewController.configure(for:) so all site types get editor preloading

  4. Move cache invalidation to MySiteViewController - Call EditorDependencyManager.invalidate(for:) in pulledToRefresh() so all site types get cache invalidation on pull-to-refresh

  5. Remove duplicate code from BlogDashboardViewModel - Remove warmUpEditorIfNeeded() and clearEditorCache() methods since this logic is now in MySiteViewController

Root cause

Both issues stem from the same architectural problem: non-Jetpack self-hosted sites display BlogDetailsViewController (Site Menu) instead of BlogDashboardViewController (Dashboard). The editor warmup and cache invalidation logic was in BlogDashboardViewModel, which is never instantiated for non-Jetpack sites.

Fix CMM-1214.

Testing instructions

1. Editor Preloading (Non-Jetpack)

  1. Add a self-hosted site without Jetpack
  2. Navigate to the Site Menu
  3. Open the editor
  4. Verify the loading bar is NOT shown (editor should load instantly due to preloading)

2. Cache Invalidation (Non-Jetpack)

  1. Add a self-hosted site without Jetpack
  2. Pull-to-refresh on the Site Menu
  3. Open the editor
  4. Verify the loading bar IS shown (cache was invalidated, so editor reloads fresh)

3. Jetpack Sites (Regression Test)

  1. Verify editor preloading still works on Jetpack sites (no loading bar on first open)
  2. Verify cache invalidation on pull-to-refresh still works on Jetpack sites (loading bar shown after refresh)

Add a thread-safe value wrapper for single values and use it to fix
the Swift 6 warning on `_lastPluginsFlagValue` in EditorDependencyManager.
Add warmUpEditor(for:) method that combines WebKit warmup with data
prefetch, consolidating the warmup logic in a single location.
Call warmUpEditor from MySiteViewController so all site types get
editor preloading, including self-hosted sites without Jetpack that
display BlogDetailsViewController instead of the dashboard.
Remove warmUpEditorIfNeeded() since warmup is now handled by
MySiteViewController through EditorDependencyManager.warmUpEditor().
Move editor cache invalidation from BlogDashboardViewController to
MySiteViewController so all site types get cache invalidation on
pull-to-refresh.

Previously, cache invalidation only happened in
BlogDashboardViewController.pulledToRefresh(), which calls
viewModel.clearEditorCache(). Non-Jetpack self-hosted sites show
BlogDetailsViewController (Site Menu) instead of the dashboard, so
the cache invalidation never occurred for these users.

Now MySiteViewController.pulledToRefresh() handles cache invalidation
for both dashboard and site menu sections, ensuring consistent behavior
across all site types.
@dangermattic
Copy link
Collaborator

1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

Add comprehensive tests for LockingValue including:
- Initialization with various types (primitives, optionals, complex types)
- Basic value access (get/set)
- withLock operations (read, modify, return results, conditional updates)
- Thread safety (concurrent reads, writes, increments, compare-and-swap)
@sonarqubecloud
Copy link

sonarqubecloud bot commented Feb 5, 2026

@wpmobilebot
Copy link
Contributor

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

@dcalhoun dcalhoun added [Type] Bug Posting/Editing Gutenberg Editing and display of Gutenberg blocks. labels Feb 5, 2026
@dcalhoun dcalhoun added this to the 26.7 milestone Feb 5, 2026
/// Tracks the `newGutenbergPlugins` flag value at the time the cache was last populated.
/// Used to detect when the flag changes and invalidate all stale entries.
private let pluginsFlagLock = NSLock()
private var _lastPluginsFlagValue: Bool?
Copy link
Member Author

@dcalhoun dcalhoun Feb 5, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced with a new LockingValue to address the following warning and mirror LockingHashMap.

Stored property '_lastPluginsFlagValue' of 'Sendable'-conforming class 'EditorDependencyManager' is mutable; this is an error in the Swift 6 language mode

@dcalhoun
Copy link
Member Author

dcalhoun commented Feb 5, 2026

The CI failures are seemingly unrelated to these changes and should be addressed by #25224.

@dcalhoun dcalhoun marked this pull request as ready for review February 5, 2026 21:55
@dcalhoun dcalhoun requested a review from jkmassel February 5, 2026 21:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Gutenberg Editing and display of Gutenberg blocks. Posting/Editing [Type] Bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants