Skip to content

Recreate missing db.php drop-ins and preserve custom SQLite drop-ins - #3993

Merged
gcsecsey merged 11 commits into
trunkfrom
gcsecsey/stu-1821-fix-clone-fatals
Jul 2, 2026
Merged

Recreate missing db.php drop-ins and preserve custom SQLite drop-ins#3993
gcsecsey merged 11 commits into
trunkfrom
gcsecsey/stu-1821-fix-clone-fatals

Conversation

@gcsecsey

@gcsecsey gcsecsey commented Jun 29, 2026

Copy link
Copy Markdown
Member

Related issues

  • Related to STU-1821 (fixes Problem 1: database suddenly disconnected after cloning)
  • Fixes STU-1571

How AI was used in this PR

I used Claude to investigate both issues, trace the shared root cause in the SQLite drop-in management policy, implement the fix, and write the unit and end-to-end tests. I reviewed the diagnosis and verified every branch of the new policy against real db.php files from local sites.

Proposed Changes

The way Studio managed the wp-content/db.php SQLite drop-in was wrong in two ways. A configured site whose db.php went missing was never restored, leaving the site stuck on "Error establishing a database connection" (STU-1821 Problem 1). At the same time, a present db.php was reinstalled on every operation, breaking custom SQLite drop-ins like markdown-database-integration (STU-1571).

  • Studio now ensures the SQLite drop-in on every site operation and recreates db.php whenever it is missing, so a cloned or repaired site can connect to its database again.
  • The drop-in is now classified by its contents instead of merely by presence: our stock file is refreshed, a missing or foreign (non-SQLite) db.php is replaced so the site can boot, and a custom SQLite-compatible drop-in (or one marked @studio-keep) is preserved.
  • After a pull, the drop-in is reinstalled even when the site server was stopped, because WordPress.com backups never bundle it.

Testing Instructions

Core fix (STU-1821 Problem 1):

  • Open a working site and confirm the front end and wp-admin both load.
  • Stop the site, delete wp-content/db.php, then start the site again.
  • Expect the site to boot with no Error establishing a database connection error, and to recreate db.php.

db.php policy (STU-1571):

For each case below, drop the file into ~/Studio/<site>/wp-content/db.php, then stop and start the site. A unique comment that survives means the file was kept, if it is gone, the file was replaced.

  • Missing, gets recreated: delete the file entirely.
  • Foreign, gets replaced:
<?php
// Query Monitor drop-in, not a SQLite drop-in
require_once 'qm-db.php';
  • Custom SQLite drop-in, gets kept:
<?php
// My custom SQLite drop-in
define( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );
require_once __DIR__ . '/mu-plugins/sqlite-database-integration/wp-includes/sqlite/db.php';
  • Marked with @studio-keep, gets kept:
<?php
// @studio-keep
define( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );
require_once __DIR__ . '/mu-plugins/sqlite-database-integration/wp-includes/sqlite/db.php';
  • Stock drop-in (edited), gets replaced:
<?php
/**
 * Plugin Name: SQLite integration (Drop-in)
 *
 * This file is auto-generated and copied from the sqlite plugin.
 */
define( 'SQLITE_DB_DROPIN_VERSION', '1.8.0' );
// EDIT ME, gone after next start

Pull path:

  • With a connected site, stop the local site, then pull it from WP.com.
  • Expect db.php to be present after the pull.

Pre-merge Checklist

  • Have you checked for TypeScript, React or other console errors?
@gcsecsey
gcsecsey marked this pull request as ready for review June 29, 2026 17:45
@gcsecsey
gcsecsey requested review from a team and chubes4 June 29, 2026 17:45

@chubes4 chubes4 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I tested the old MDI failure mode against this branch: a configured site with MDI's custom wp-content/db.php, with @studio-keep removed, running the Studio SQLite setup path via keepSqliteIntegrationUpdated() -> installSqliteIntegration(). The markerless MDI drop-in was preserved, stayed identifiable via MARKDOWN_DB_DROPIN, did not become the stock drop-in, and the SQLite mu-plugin was still refreshed.

Given that, this fixes the issue I cared about. One cleanup suggestion: if SQLITE_DB_DROPIN_VERSION is now the preservation contract for SQLite-compatible custom drop-ins, I think we can remove the @studio-keep escape hatch to avoid carrying two contracts. MDI can align to the new contract without the marker. Not blocking from me.

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The needsSqliteSetup logic is meant to allow users to use MySQL instead of SQLite if they want, which I would think is a more common use case than bringing custom db.php drop-ins (although we can support both). See documentation about MySQL support for more context

@wojtekn

wojtekn commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

The needsSqliteSetup logic is meant to allow users to use MySQL instead of SQLite if they want, which I would think is a more common use case than bringing custom db.php drop-ins (although we can support both). See documentation about MySQL support for more context

Agreed, this is a use case that allows users to use Studio with a MySQL server of their choice. Let's ensure that all the test cases from the spreadsheet are still supported.

@wpmobilebot

wpmobilebot commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing 4421166 vs trunk

app-size

Metric trunk 4421166 Diff Change
App Size (Mac) 1316.93 MB 1316.83 MB 0.10 MB ⚪ 0.0%

site-editor

Metric trunk 4421166 Diff Change
load 1049 ms 1099 ms +50 ms 🔴 4.8%

site-startup

Metric trunk 4421166 Diff Change
siteCreation 6532 ms 6506 ms 26 ms ⚪ 0.0%
siteStartup 1870 ms 1856 ms 14 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

@gcsecsey

Copy link
Copy Markdown
Member Author

The needsSqliteSetup logic is meant to allow users to use MySQL instead of SQLite if they want, which I would think is a more common use case than bringing custom db.php drop-ins (although we can support both). See documentation about MySQL support for more context

Agreed, this is a use case that allows users to use Studio with a MySQL server of their choice. Let's ensure that all the test cases from the spreadsheet are still supported.

@fredrikekelund @wojtekn Thanks for the catch, and for the MySQL docs link. I restored needsSqliteSetup with checks according to the docs, and updated the tests. @wojtekn could you share the spreadsheet you mentioned?

@gcsecsey

Copy link
Copy Markdown
Member Author

I tested the old MDI failure mode against this branch: a configured site with MDI's custom wp-content/db.php, with @studio-keep removed, running the Studio SQLite setup path via keepSqliteIntegrationUpdated() -> installSqliteIntegration(). The markerless MDI drop-in was preserved, stayed identifiable via MARKDOWN_DB_DROPIN, did not become the stock drop-in, and the SQLite mu-plugin was still refreshed.

Given that, this fixes the issue I cared about. One cleanup suggestion: if SQLITE_DB_DROPIN_VERSION is now the preservation contract for SQLite-compatible custom drop-ins, I think we can remove the @studio-keep escape hatch to avoid carrying two contracts. MDI can align to the new contract without the marker. Not blocking from me.

Good call, thanks @chubes4! I checked that we don't have any public-facing docs about it, then removed @studio-keep. A custom db.php is now preserved if it defines SQLITE_DB_DROPIN_VERSION (and isn’t our stock drop-in, which we still refresh). Thanks for testing the markerless drop-in against the branch!

@gcsecsey
gcsecsey requested review from a team, fredrikekelund and wojtekn July 1, 2026 14:40

@fredrikekelund fredrikekelund left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM 👍 This works as expected.

I left a comment about changing the logic of shouldKeepExistingDbDropin() from negative to affirmative that'd be nice to address, but I'll let you decide about that, @gcsecsey.

Comment thread packages/common/lib/sqlite-integration.ts Outdated
Comment thread packages/common/lib/sqlite-integration.ts Outdated
Comment thread apps/cli/commands/pull.ts Outdated
@gcsecsey
gcsecsey merged commit 37a740e into trunk Jul 2, 2026
11 checks passed
@gcsecsey
gcsecsey deleted the gcsecsey/stu-1821-fix-clone-fatals branch July 2, 2026 15:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

5 participants