Skip to content

Fix studio push for native reprint-pulled sites#3994

Open
epeicher wants to merge 4 commits into
trunkfrom
stu-1950-verify-that-studio-push-functionality-works-the-same-with
Open

Fix studio push for native reprint-pulled sites#3994
epeicher wants to merge 4 commits into
trunkfrom
stu-1950-verify-that-studio-push-functionality-works-the-same-with

Conversation

@epeicher

@epeicher epeicher commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Related issues

How AI was used in this PR

Claude Code was used throughout: to reproduce and diagnose the failure, to discover that there were two distinct blockers (a DB-connection error and a separate "could not locate the SQLite integration plugin" error), to validate the fix design with controlled experiments against a real reprint-pulled site, to implement the changes, and to verify the full push end-to-end. All generated code was reviewed.

Proposed Changes

Makes studio push work for sites created by studio pull-reprint on the native-php runtime. The export step previously failed — first with "Error establishing a database connection", then "Database export failed". The same WP-CLI path backs the desktop "get theme details" / "get site icon" features, which failed identically for these sites and are fixed too.

Why it failed: a reprint pull wires SQLite only through a generated runtime.php, which the web server applies as a PHP auto_prepend_file; these sites have no wp-content/db.php drop-in. The server reaches the database, but standalone WP-CLI — which push uses for wp plugin list, wp theme list, and wp sqlite export — never loads runtime.php. That produced two separate failures:

  1. wp plugin list / theme list fell back to MySQL → "Error establishing a database connection".
  2. wp sqlite export additionally needs the SQLite integration plugin discoverable in wp-content, which reprint sites don't have → "Could not locate the SQLite integration plugin".

WASM/Playground imported sites were never affected because their pull installs a real db.php drop-in; native imported sites never did.

The fix is two coordinated changes:

  • The native WP-CLI runner loads the site's runtime.php as auto_prepend_file for imported sites, restoring the database connection for general WP-CLI.
  • The sqlite-command (wp sqlite export/tables) is the exception: it loads its own integration copy and reads the database file directly, so it runs without the prepend, and push installs the SQLite integration into the imported site's wp-content so the command can find it.

Safe on both ends: runtime.php takes precedence over the drop-in on the running server (require_wp_db() returns early when $wpdb is set, so the drop-in is inert), and the exporter already excludes db.php and sqlite-database-integration from the upload, so neither reaches the MySQL remote.

Testing Instructions

  1. Apply the changes on this branch and run npm run cli:build
  2. Create a Studio site or use an existing Studio site
  3. Run STUDIO_ENABLE_PULL_REPRINT=true node apps/cli/dist/cli/main.mjs pull-reprint --path <path-to-Studio-site> to pull a remote site using Reprint, e.g. STUDIO_ENABLE_PULL_REPRINT=true node apps/cli/dist/cli/main.mjs pull-reprint --path ~/Studio/my-shiny-website. Select the remote site to pull and wait for completion
  4. Open Studio and connect to the remote site selected in previous step, or use the following CLI command on the Studio folder cd <path-to-Studio-site> && node ~/github/studio/apps/cli/dist/cli/main.mjs push, e.g. cd ~/Studio/my-shiny-website && node ~/github/studio/apps/cli/dist/cli/main.mjs push
  5. Verify that the Push complete successfully

Sites created by `studio pull-reprint` on the native-php runtime wire SQLite
only through a generated runtime.php (applied by the server as
auto_prepend_file) and ship no wp-content/db.php drop-in. Standalone WP-CLI
never loaded runtime.php, so `studio push` failed two ways: `wp plugin list`
and `wp theme list` (meta.json) hit "Error establishing a database
connection", and `wp sqlite export` (the DB dump) reported "Could not locate
the SQLite integration plugin".

The native WP-CLI runner now loads the site's runtime.php as auto_prepend_file
for imported sites, restoring the database connection for general WP-CLI. This
also fixes the desktop get-theme-details / get-site-icon errors.

The sqlite-command (wp sqlite export/tables) is the exception: it loads its own
SQLite integration copy and reads the database file directly, so prepending
runtime.php loads a second integration copy and fatals. It runs without the
prepend, and push installs the SQLite integration into the imported site's
wp-content so the command can find it. This is safe: runtime.php takes
precedence over the drop-in on the running server (require_wp_db returns early
when $wpdb is set), and the exporter already excludes db.php and the
integration from the upload, so neither the local server nor the MySQL remote
is affected.

Claude-Session: https://claude.ai/code/session_015EADJrWvjTQrmdgpFZre6j
Comment thread apps/cli/commands/push.ts
Comment on lines 59 to +71
await keepSqliteIntegrationUpdated( siteFolder );
// Reprint-pulled (imported) sites wire SQLite through runtime.php and ship no db.php
// drop-in, so the step above skips them. The database export below uses `wp sqlite
// export`, which requires the SQLite integration to be discoverable in wp-content.
// Install it for imported sites; the exporter excludes db.php and the integration from
// the upload, so it never reaches the remote.
if ( site.runtimeBlueprintPath && ! ( await isSqliteIntegrationInstalled( siteFolder ) ) ) {
await installSqliteIntegration( siteFolder );
}

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.

Could we if/else here?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done as part of 1ce73b2

epeicher added 2 commits July 1, 2026 12:01
Addresses review feedback on #3994: move keepSqliteIntegrationUpdated into
the else branch so the imported-site install and the normal-site update are
mutually exclusive, instead of always calling keepSqliteIntegrationUpdated
and then conditionally installing. Behavior-preserving.

Claude-Session: https://claude.ai/code/session_015EADJrWvjTQrmdgpFZre6j
…rify-that-studio-push-functionality-works-the-same-with
@epeicher epeicher marked this pull request as ready for review July 1, 2026 11:01
@epeicher epeicher requested a review from a team July 1, 2026 11:03
@wpmobilebot

wpmobilebot commented Jul 1, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing 3b6e83b vs trunk

app-size

Metric trunk 3b6e83b Diff Change
App Size (Mac) 1316.83 MB 1316.83 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk 3b6e83b Diff Change
load 1114 ms 1114 ms 0 ms ⚪ 0.0%

site-startup

Metric trunk 3b6e83b Diff Change
siteCreation 6500 ms 6503 ms +3 ms ⚪ 0.0%
siteStartup 1865 ms 1860 ms 5 ms ⚪ 0.0%

Results are median values from multiple test runs.

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

@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.

Nice and targeted fix 👍 Looks good overall, although it'd be nice to address the SQLite integration issue in the export command here, too. Let me know your thoughts there, @epeicher

const autoPrependFile = options.requireSqliteCliCommand
? undefined
: getImportedSiteAutoPrependFile( site );
const prependArgs = autoPrependFile ? [ '-d', `auto_prepend_file=${ autoPrependFile }` ] : [];

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.

Can we move this into getDefaultPhpArgs() and edit spawnPhpProcess() in apps/cli/lib/native-php/php-process.ts accordingly?

Comment on lines +207 to +209
export function getImportedSiteAutoPrependFile( site: {
runtimeBlueprintPath?: string;
} ): string | undefined {

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.

Suggested change
export function getImportedSiteAutoPrependFile( site: {
runtimeBlueprintPath?: string;
} ): string | undefined {
export function getImportedSiteAutoPrependFile( site: SiteData ): string | undefined {

We might as well use the canonical type here, unless we have good reason to take a partial type

Comment on lines +194 to +206
/**
* Locates the reprint `runtime.php` to load as a native WP-CLI `auto_prepend_file`.
*
* Reprint-pulled sites wire SQLite only through `runtime.php`, which the web server
* applies as a PHP `auto_prepend_file`. A standalone native WP-CLI process never loads
* it, so WordPress falls back to MySQL and fails with "Error establishing a database
* connection". Loading the same file the server uses gives WP-CLI matching SQLite wiring.
*
* Only reprint/imported sites have `runtimeBlueprintPath`; `runtime.php` is its sibling
* (the same directory the native server-start path resolves it from above). Returns
* undefined — never throws — for normal `studio create` sites or when the file is absent,
* so those are unaffected.
*/

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 think this can be shortened quite a bit. It's just unnecessarily verbose

Comment thread apps/cli/commands/push.ts
Comment on lines +63 to +72
// Reprint-pulled (imported) sites wire SQLite through runtime.php and ship no db.php
// drop-in, so keepSqliteIntegrationUpdated skips them. The database export below uses
// `wp sqlite export`, which requires the SQLite integration to be discoverable in
// wp-content. Install it for imported sites; the exporter excludes db.php and the
// integration from the upload, so it never reaches the remote.
if ( site.runtimeBlueprintPath && ! ( await isSqliteIntegrationInstalled( siteFolder ) ) ) {
await installSqliteIntegration( siteFolder );
} else {
await keepSqliteIntegrationUpdated( siteFolder );
}

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 noticed the export CLI command failing for a Reprint-pulled site on the database step, and I assume that's because of a missing "regular" SQLite integration. That's arguably a separate issue, but it seems small enough that we might fix it here. Either by moving this SQLite integration updating/installation into the exporter, or by copying this logic to the export command.

We should also consider preview site creation.

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.

3 participants