From a265316f80d60a45f6cfe3a5e556a75849cfd78c Mon Sep 17 00:00:00 2001 From: ashfame Date: Mon, 13 Apr 2026 23:00:34 +0545 Subject: [PATCH 1/5] Inject PLAYGROUND_AUTO_LOGIN_AS_USER in mergeDefinedConstants when --login is set When the CLI's --login flag is true, inject the PLAYGROUND_AUTO_LOGIN_AS_USER constant into the merged constants so it flows through the boot-time path alongside other --define constants. This ensures the auto-login constant is set before the server starts accepting requests, rather than relying on the blueprint login step which runs on a single pool-proxied worker. An explicit --define PLAYGROUND_AUTO_LOGIN_AS_USER override is respected. Made-with: Cursor --- packages/playground/cli/src/defines.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/playground/cli/src/defines.ts b/packages/playground/cli/src/defines.ts index 790b6daa2dd..7ec41880774 100644 --- a/packages/playground/cli/src/defines.ts +++ b/packages/playground/cli/src/defines.ts @@ -172,6 +172,10 @@ function mergeConstants( /** * Merge all constants from CLI arguments. * + * When `login` is true, `PLAYGROUND_AUTO_LOGIN_AS_USER` is injected so that + * every PHP worker defines the constant at boot time — not just the single + * worker that would run the blueprint `login` step via the pool proxy. + * * @param args - CLI arguments * @returns Merged constants */ @@ -179,10 +183,17 @@ export function mergeDefinedConstants(args: { define?: Record; 'define-bool'?: Record; 'define-number'?: Record; + login?: boolean; }): Record { - return mergeConstants( + const merged = mergeConstants( args['define'], args['define-bool'], args['define-number'] ); + + if (args.login && !Object.hasOwn(merged, 'PLAYGROUND_AUTO_LOGIN_AS_USER')) { + merged['PLAYGROUND_AUTO_LOGIN_AS_USER'] = 'admin'; + } + + return merged; } From 53baaed5c1306fbb2bee9bb13a835f3f5a03acc3 Mon Sep 17 00:00:00 2001 From: ashfame Date: Mon, 13 Apr 2026 23:01:16 +0545 Subject: [PATCH 2/5] Pass CLI-defined constants to each V1 worker via bootRequestHandler Previously, mergeDefinedConstants was only passed to bootWordPress which runs on a single pool-proxied worker. While the shared nativeInternalDirPath means consts.json is visible across workers, feeding constants through bootRequestHandler ensures they are applied at PHP instance creation time and survive runtime rotation without relying on file-level sharing. This also fixes --define/--define-bool/--define-number for V1 workers that were not the one selected by the pool proxy for bootWordPress. Made-with: Cursor --- .../playground/cli/src/blueprints-v1/blueprints-v1-handler.ts | 1 + packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts | 2 ++ 2 files changed, 3 insertions(+) diff --git a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts index b03fb70ef06..9407bc93a7d 100644 --- a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts +++ b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts @@ -195,6 +195,7 @@ export class BlueprintsV1Handler { withXdebug: !!this.args.xdebug, nativeInternalDirPath, pathAliases: this.args.pathAliases, + constants: mergeDefinedConstants(this.args), }); await playground.isReady(); return playground; diff --git a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts index c28cd4a159e..e1ceb238a26 100644 --- a/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts +++ b/packages/playground/cli/src/blueprints-v1/worker-thread-v1.ts @@ -52,6 +52,7 @@ interface WorkerBootRequestHandlerOptions { withMemcached?: boolean; withXdebug?: boolean; pathAliases?: PathAlias[]; + constants?: Record; } /** @@ -162,6 +163,7 @@ export class PlaygroundCliBlueprintV1Worker extends PHPWorker { const requestHandler = await bootRequestHandler({ siteUrl: options.siteUrl, maxPhpInstances: 1, + constants: options.constants, createPhpRuntime: createPhpRuntimeFactory( options, this.fileLockManager! From ffc75c575c4ca649a2c7312e4b2f4e396baaaa1e Mon Sep 17 00:00:00 2001 From: ashfame Date: Mon, 13 Apr 2026 23:03:10 +0545 Subject: [PATCH 3/5] Add tests for mergeDefinedConstants login constant injection Covers: login=true injects the constant, login=false/undefined does not, explicit --define override is preserved, and coexistence with other constants. Made-with: Cursor --- .../cli/tests/merge-defined-constants.spec.ts | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 packages/playground/cli/tests/merge-defined-constants.spec.ts diff --git a/packages/playground/cli/tests/merge-defined-constants.spec.ts b/packages/playground/cli/tests/merge-defined-constants.spec.ts new file mode 100644 index 00000000000..2f91963f6d1 --- /dev/null +++ b/packages/playground/cli/tests/merge-defined-constants.spec.ts @@ -0,0 +1,61 @@ +import { mergeDefinedConstants } from '../src/defines'; + +describe('mergeDefinedConstants', () => { + it('should merge string, boolean, and number constants', () => { + const result = mergeDefinedConstants({ + define: { API_KEY: 'secret' }, + 'define-bool': { WP_DEBUG: true }, + 'define-number': { LIMIT: 100 }, + }); + expect(result).toEqual({ + API_KEY: 'secret', + WP_DEBUG: true, + LIMIT: 100, + }); + }); + + it('should return empty object when no constants are provided', () => { + const result = mergeDefinedConstants({}); + expect(result).toEqual({}); + }); + + it('should inject PLAYGROUND_AUTO_LOGIN_AS_USER when login is true', () => { + const result = mergeDefinedConstants({ login: true }); + expect(result).toEqual({ + PLAYGROUND_AUTO_LOGIN_AS_USER: 'admin', + }); + }); + + it('should not inject login constant when login is false', () => { + const result = mergeDefinedConstants({ login: false }); + expect(result).toEqual({}); + }); + + it('should not inject login constant when login is undefined', () => { + const result = mergeDefinedConstants({}); + expect(result).toEqual({}); + }); + + it('should not override explicit PLAYGROUND_AUTO_LOGIN_AS_USER from --define', () => { + const result = mergeDefinedConstants({ + define: { PLAYGROUND_AUTO_LOGIN_AS_USER: 'editor' }, + login: true, + }); + expect(result).toEqual({ + PLAYGROUND_AUTO_LOGIN_AS_USER: 'editor', + }); + }); + + it('should preserve other constants alongside the injected login constant', () => { + const result = mergeDefinedConstants({ + define: { API_KEY: 'secret' }, + 'define-bool': { WP_DEBUG: true }, + login: true, + }); + expect(result).toEqual({ + API_KEY: 'secret', + WP_DEBUG: true, + PLAYGROUND_AUTO_LOGIN_AS_USER: 'admin', + }); + }); +}); From c999884d8d895dab6f6a5cbd5463b7be7e7d4d90 Mon Sep 17 00:00:00 2001 From: ashfame Date: Tue, 14 Apr 2026 00:11:56 +0545 Subject: [PATCH 4/5] Remove resolved TODO and fix mu-plugin filename in login step docstring The TODO to make defineConstant apply to all workers is addressed by injecting the constant at boot time via mergeDefinedConstants. Also corrects the mu-plugin filename from 0-auto-login.php to 1-auto-login.php. Made-with: Cursor --- packages/playground/blueprints/src/lib/steps/login.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/playground/blueprints/src/lib/steps/login.ts b/packages/playground/blueprints/src/lib/steps/login.ts index 2e6bd1632a8..7a1cdf20530 100644 --- a/packages/playground/blueprints/src/lib/steps/login.ts +++ b/packages/playground/blueprints/src/lib/steps/login.ts @@ -28,9 +28,12 @@ export type LoginStep = { /** * Logs in to Playground. * Under the hood, this function sets the `PLAYGROUND_AUTO_LOGIN_AS_USER` constant. - * The `0-auto-login.php` mu-plugin uses that constant to log in the user on the first load. + * The `1-auto-login.php` mu-plugin uses that constant to log in the user on the first load. * This step depends on the `@wp-playground/wordpress` package because * the plugin is located in and loaded automatically by the `@wp-playground/wordpress` package. + * + * In the CLI, the `--login` flag injects this constant at boot time via + * `mergeDefinedConstants` so every worker has it before the server starts. */ export const login: StepHandler = async ( playground, @@ -39,6 +42,5 @@ export const login: StepHandler = async ( ) => { progress?.tracker.setCaption(progress?.initialCaption || 'Logging in'); - // TODO: Make defineConstant apply to all workers playground.defineConstant('PLAYGROUND_AUTO_LOGIN_AS_USER', username); }; From 28275240b50abee30fa388eacae1a1833d1e2f50 Mon Sep 17 00:00:00 2001 From: ashfame Date: Tue, 14 Apr 2026 00:53:10 +0545 Subject: [PATCH 5/5] Skip blueprint login step when PLAYGROUND_AUTO_LOGIN_AS_USER is set via --define When the user provides a custom auto-login username via --define, the boot-time constant from mergeDefinedConstants already handles auto-login. The blueprint login step compiles login:true to username:'admin' and calls defineConstant which would overwrite the custom value in consts.json. Skip the step entirely so the user's --define value is respected. Made-with: Cursor --- .../src/blueprints-v1/blueprints-v1-handler.ts | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts index 9407bc93a7d..d81a0a267fe 100644 --- a/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts +++ b/packages/playground/cli/src/blueprints-v1/blueprints-v1-handler.ts @@ -238,7 +238,7 @@ export class BlueprintsV1Handler { return isBlueprintBundle(resolvedBlueprint) ? resolvedBlueprint : { - login: this.args.login, + login: this.getEffectiveLogin(), ...(resolvedBlueprint || {}), preferredVersions: { php: @@ -253,4 +253,20 @@ export class BlueprintsV1Handler { }, }; } + + /** + * When the user explicitly sets PLAYGROUND_AUTO_LOGIN_AS_USER via + * --define, skip the blueprint login step — the boot-time constant + * from mergeDefinedConstants already handles auto-login and the + * blueprint step would overwrite the custom username with 'admin'. + */ + private getEffectiveLogin(): boolean { + if (!this.args.login) { + return false; + } + if (this.args.define?.['PLAYGROUND_AUTO_LOGIN_AS_USER']) { + return false; + } + return true; + } }