diff --git a/components/Blueprints/Runner.php b/components/Blueprints/Runner.php index 08e3d55f..004a9668 100644 --- a/components/Blueprints/Runner.php +++ b/components/Blueprints/Runner.php @@ -24,6 +24,7 @@ use WordPress\Blueprints\Steps\ActivateThemeStep; use WordPress\Blueprints\Steps\CpStep; use WordPress\Blueprints\Steps\DefineConstantsStep; +use WordPress\Blueprints\Steps\EnableMultisiteStep; use WordPress\Blueprints\Steps\Exception; use WordPress\Blueprints\Steps\ImportContentStep; use WordPress\Blueprints\Steps\ImportMediaStep; @@ -673,6 +674,8 @@ private function createStepObject( string $stepType, array $data ) { return new CpStep( $data['fromPath'], $data['toPath'] ); case 'defineConstants': return new DefineConstantsStep( $data['constants'] ); + case 'enableMultisite': + return new EnableMultisiteStep( $data['wpCliPath'] ?? null ); case 'importContent': /** * Flatten the content declaration from diff --git a/components/Blueprints/Steps/EnableMultisiteStep.php b/components/Blueprints/Steps/EnableMultisiteStep.php new file mode 100644 index 00000000..26a94778 --- /dev/null +++ b/components/Blueprints/Steps/EnableMultisiteStep.php @@ -0,0 +1,45 @@ +wpCliPath = $wpCliPath; + } + + public function run( Runtime $runtime, Tracker $tracker ) { + $tracker->setCaption( 'Enabling WordPress multisite' ); + + $wp_cli_path = $this->wpCliPath ?? $runtime->getWpCliPath(); + $site_url = $runtime->getConfiguration()->getTargetSiteUrl(); + + // Convert existing WordPress installation to multisite + $process = $runtime->startShellCommand( [ + 'php', + $wp_cli_path, + 'core', + 'multisite-convert', + // For Docker compatibility. If we got this far, Blueprint runner was already + // allowed to run as root. + '--allow-root', + '--url=' . $site_url, + '--title=Multisite Network', + ] ); + $process->mustRun(); + } +} \ No newline at end of file diff --git a/components/Blueprints/Tests/Unit/Steps/EnableMultisiteStepTest.php b/components/Blueprints/Tests/Unit/Steps/EnableMultisiteStepTest.php new file mode 100644 index 00000000..35a75106 --- /dev/null +++ b/components/Blueprints/Tests/Unit/Steps/EnableMultisiteStepTest.php @@ -0,0 +1,67 @@ +run( $this->runtime, $tracker ); + + // Verify multisite is enabled by checking for multisite constants in wp-config.php + $this->assertMultisiteEnabled(); + } + + /** + * Test enabling multisite with custom WP-CLI path + */ + public function testEnableMultisiteWithCustomWpCliPath() { + $customWpCliPath = $this->runtime->getWpCliPath(); // Use the same path for testing + $step = new EnableMultisiteStep( $customWpCliPath ); + $tracker = new Tracker(); + $step->run( $this->runtime, $tracker ); + + // Verify multisite is enabled + $this->assertMultisiteEnabled(); + } + + /** + * Helper to verify multisite is enabled + */ + private function assertMultisiteEnabled() { + $result = $this->runtime->evalPhpCodeInSubProcess( + <<<'PHP' + $is_multisite, + 'subdomain_install' => $is_subdomain, + 'multisite_function' => function_exists('is_multisite') && is_multisite() +]) ); +PHP + )->outputFileContent; + + $multisite_status = json_decode( $result, true ); + + $this->assertTrue( + $multisite_status['multisite'], + 'WordPress multisite should be enabled (MULTISITE constant should be true)' + ); + + $this->assertTrue( + $multisite_status['multisite_function'], + 'WordPress is_multisite() function should return true' + ); + } +} \ No newline at end of file diff --git a/components/Blueprints/Tests/Unit/Versions/Version1/V1ToV2TranspilerTest.php b/components/Blueprints/Tests/Unit/Versions/Version1/V1ToV2TranspilerTest.php new file mode 100644 index 00000000..193d668f --- /dev/null +++ b/components/Blueprints/Tests/Unit/Versions/Version1/V1ToV2TranspilerTest.php @@ -0,0 +1,80 @@ +transpiler = new V1ToV2Transpiler( new NullLogger() ); + } + + /** + * Test converting enableMultisite step from v1 to v2 + */ + public function testConvertEnableMultisiteStep() { + $v1Blueprint = [ + 'steps' => [ + [ + 'step' => 'enableMultisite' + ] + ] + ]; + + $v2Blueprint = $this->transpiler->upgrade( $v1Blueprint ); + + $this->assertArrayHasKey( 'additionalStepsAfterExecution', $v2Blueprint ); + $this->assertCount( 1, $v2Blueprint['additionalStepsAfterExecution'] ); + + $step = $v2Blueprint['additionalStepsAfterExecution'][0]; + $this->assertEquals( 'enableMultisite', $step['step'] ); + $this->assertArrayNotHasKey( 'wpCliPath', $step ); + } + + /** + * Test converting enableMultisite step with custom wpCliPath from v1 to v2 + */ + public function testConvertEnableMultisiteStepWithCustomWpCliPath() { + $v1Blueprint = [ + 'steps' => [ + [ + 'step' => 'enableMultisite', + 'wpCliPath' => '/custom/path/to/wp-cli.phar' + ] + ] + ]; + + $v2Blueprint = $this->transpiler->upgrade( $v1Blueprint ); + + $this->assertArrayHasKey( 'additionalStepsAfterExecution', $v2Blueprint ); + $this->assertCount( 1, $v2Blueprint['additionalStepsAfterExecution'] ); + + $step = $v2Blueprint['additionalStepsAfterExecution'][0]; + $this->assertEquals( 'enableMultisite', $step['step'] ); + $this->assertEquals( '/custom/path/to/wp-cli.phar', $step['wpCliPath'] ); + } + + /** + * Test that v2 blueprint doesn't warn about enableMultisite anymore + */ + public function testNoWarningForEnableMultisite() { + $v1Blueprint = [ + 'steps' => [ + [ + 'step' => 'enableMultisite' + ] + ] + ]; + + // This should not throw any warnings or exceptions + $v2Blueprint = $this->transpiler->upgrade( $v1Blueprint ); + + // Verify the step was actually converted and not ignored + $this->assertNotEmpty( $v2Blueprint['additionalStepsAfterExecution'] ); + $this->assertEquals( 'enableMultisite', $v2Blueprint['additionalStepsAfterExecution'][0]['step'] ); + } +} \ No newline at end of file diff --git a/components/Blueprints/Versions/Version1/V1ToV2Transpiler.php b/components/Blueprints/Versions/Version1/V1ToV2Transpiler.php index ba2bd9f6..0552d21b 100644 --- a/components/Blueprints/Versions/Version1/V1ToV2Transpiler.php +++ b/components/Blueprints/Versions/Version1/V1ToV2Transpiler.php @@ -210,9 +210,13 @@ public function upgrade( array $validated_v1_blueprint ): array { $this->logger->warning( 'The `defineSiteUrl` step is not supported by the Blueprint v2 schema. Use the runner configuration to set the site URL instead.' ); break; case 'enableMultisite': - // @TODO: Support this step in v3. Multisites will require a separate schema - // that defines what's related to which site. - $this->logger->warning( 'The `enableMultisite` step is not supported by the Blueprint v2 schema and will be ignored.' ); + $v2step = [ + 'step' => 'enableMultisite', + ]; + if ( isset( $v1step['wpCliPath'] ) ) { + $v2step['wpCliPath'] = $v1step['wpCliPath']; + } + $v2steps[] = $v2step; break; case 'importWordPressFiles': if ( isset( $v1step['progress'] ) ) { diff --git a/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/appendix-A-blueprint-v2-schema.ts b/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/appendix-A-blueprint-v2-schema.ts index 0136a9d9..f337b7cf 100644 --- a/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/appendix-A-blueprint-v2-schema.ts +++ b/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/appendix-A-blueprint-v2-schema.ts @@ -1449,6 +1449,14 @@ type DefineConstantsStep = { constants: WordPressConstants; }; +type EnableMultisiteStep = { + step: 'enableMultisite'; + /** + * Optional path to the WP-CLI executable. + */ + wpCliPath?: string; +}; + type ImportContentStep = { step: 'importContent'; content: ContentDefinition[]; @@ -1572,6 +1580,7 @@ type Step = | ActivateThemeStep | CpStep | DefineConstantsStep + | EnableMultisiteStep | ImportContentStep | ImportMediaStep | ImportThemeStarterContentStep diff --git a/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/proposal.md b/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/proposal.md index 4a781a17..4740a811 100644 --- a/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/proposal.md +++ b/components/Blueprints/Versions/Version2/json-schema/wsp/wsp-1-blueprint-v2-schema/proposal.md @@ -861,6 +861,4 @@ described below. On a successful merge, the runner **MUST** execute the merged B ## Areas intentionally not covered by this proposal -- Multisite configuration – it may require a separate schema and is left for a future iteration of the Blueprint - standard. - Content import format – it is a separate, nuanced topic that warrants a dedicated proposal. diff --git a/components/DataLiberation/Tests/fixtures/epub-entity-reader/childrens-literature.epub b/components/DataLiberation/Tests/fixtures/epub-entity-reader/childrens-literature.epub index ba84a643..338bf418 100644 Binary files a/components/DataLiberation/Tests/fixtures/epub-entity-reader/childrens-literature.epub and b/components/DataLiberation/Tests/fixtures/epub-entity-reader/childrens-literature.epub differ diff --git a/components/Git/Tests/fixtures/woocommerce-response.bin b/components/Git/Tests/fixtures/woocommerce-response.bin index 13d9f748..bd3c88b4 100644 --- a/components/Git/Tests/fixtures/woocommerce-response.bin +++ b/components/Git/Tests/fixtures/woocommerce-response.bin @@ -602,7 +602,7 @@ x mOWJ(57$U73/)B7/$3-39#IgcT~Mz)TgqFfAAf^nAbQI^j>m /='fʓP@mE@:RORsNٮt nɦ x31 |L^2c