Summary
keepSqliteIntegrationUpdated() unconditionally overwrites wp-content/db.php with the stock SQLite drop-in on every site start, site stop, import, export, push, and pull operation. This makes it impossible to use a custom database drop-in that extends the SQLite integration.
Impact
The markdown-database-integration plugin provides a custom db.php that extends WP_SQLite_DB and WP_SQLite_Driver to use markdown files as the source of truth with in-memory SQLite as the runtime query engine. It depends on the SQLite mu-plugin's driver classes but replaces db.php with its own drop-in.
Every time Studio touches the site, it overwrites the custom db.php, causing:
- The site boots with the stock SQLite driver instead of the custom one
- The custom storage layer is bypassed, causing data loss (posts stored as markdown files become invisible)
- The user has to manually reinstall
db.php after every restart
Root Cause
In tools/common/lib/sqlite-integration.ts:
async needsSqliteSetup(sitePath: string): Promise<boolean> {
const hasDbPhp = fs.existsSync(path.join(sitePath, 'wp-content', 'db.php'));
const hasWpConfig = fs.existsSync(path.join(sitePath, 'wp-config.php'));
return hasDbPhp || !hasWpConfig;
}
This returns true when db.php exists, which triggers installSqliteIntegration() which unconditionally overwrites db.php from db.copy. There is no check for whether the existing db.php is a custom drop-in.
Proposed Fix
Before overwriting db.php, check if the existing file is a custom drop-in. A custom drop-in defines SQLITE_DB_DROPIN_VERSION (so the SQLite plugin recognizes it) but does NOT contain the stock auto-generated header comment. The fix:
- Add
hasCustomDbDropin() method that reads db.php and checks for the stock header
- Skip overwriting
db.php in installSqliteIntegration() if a custom drop-in is detected
- Still update the SQLite mu-plugin (custom drop-ins depend on those driver classes)
I have a working implementation with tests at tools/common/lib/sqlite-integration.ts — happy to open a PR.
How to Reproduce
- Create a site in Studio
- Replace
wp-content/db.php with a custom version that defines SQLITE_DB_DROPIN_VERSION
- Run
studio site start or restart via the desktop app
- Observe that
db.php has been reverted to the stock version
Summary
keepSqliteIntegrationUpdated()unconditionally overwriteswp-content/db.phpwith the stock SQLite drop-in on everysite start,site stop,import,export,push, andpulloperation. This makes it impossible to use a custom database drop-in that extends the SQLite integration.Impact
The markdown-database-integration plugin provides a custom
db.phpthat extendsWP_SQLite_DBandWP_SQLite_Driverto use markdown files as the source of truth with in-memory SQLite as the runtime query engine. It depends on the SQLite mu-plugin's driver classes but replacesdb.phpwith its own drop-in.Every time Studio touches the site, it overwrites the custom
db.php, causing:db.phpafter every restartRoot Cause
In
tools/common/lib/sqlite-integration.ts:This returns
truewhendb.phpexists, which triggersinstallSqliteIntegration()which unconditionally overwritesdb.phpfromdb.copy. There is no check for whether the existingdb.phpis a custom drop-in.Proposed Fix
Before overwriting
db.php, check if the existing file is a custom drop-in. A custom drop-in definesSQLITE_DB_DROPIN_VERSION(so the SQLite plugin recognizes it) but does NOT contain the stock auto-generated header comment. The fix:hasCustomDbDropin()method that readsdb.phpand checks for the stock headerdb.phpininstallSqliteIntegration()if a custom drop-in is detectedI have a working implementation with tests at
tools/common/lib/sqlite-integration.ts— happy to open a PR.How to Reproduce
wp-content/db.phpwith a custom version that definesSQLITE_DB_DROPIN_VERSIONstudio site startor restart via the desktop appdb.phphas been reverted to the stock version