Skip to content

Commit d82f567

Browse files
committed
[Blueprints v2] Add support for "enableMultisite" step
1 parent f4af6b0 commit d82f567

File tree

5 files changed

+309
-19
lines changed

5 files changed

+309
-19
lines changed

components/Blueprints/Runner.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
use WordPress\Blueprints\Steps\ActivateThemeStep;
2525
use WordPress\Blueprints\Steps\CpStep;
2626
use WordPress\Blueprints\Steps\DefineConstantsStep;
27+
use WordPress\Blueprints\Steps\EnableMultisiteStep;
2728
use WordPress\Blueprints\Steps\Exception;
2829
use WordPress\Blueprints\Steps\ImportContentStep;
2930
use WordPress\Blueprints\Steps\ImportMediaStep;
@@ -673,6 +674,8 @@ private function createStepObject( string $stepType, array $data ) {
673674
return new CpStep( $data['fromPath'], $data['toPath'] );
674675
case 'defineConstants':
675676
return new DefineConstantsStep( $data['constants'] );
677+
case 'enableMultisite':
678+
return new EnableMultisiteStep();
676679
case 'importContent':
677680
/**
678681
* Flatten the content declaration from
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
<?php
2+
3+
namespace WordPress\Blueprints\Steps;
4+
5+
use Symfony\Component\Process\Exception\ProcessFailedException;
6+
use WordPress\Blueprints\Exception\BlueprintExecutionException;
7+
use WordPress\Blueprints\Progress\Tracker;
8+
use WordPress\Blueprints\Runtime;
9+
10+
/**
11+
* Represents the 'enableMultisite' step.
12+
*/
13+
class EnableMultisiteStep implements StepInterface {
14+
public function run( Runtime $runtime, Tracker $tracker ) {
15+
$tracker->setCaption( 'Enabling multisite' );
16+
17+
$code =
18+
<<<'PHP'
19+
<?php
20+
/*
21+
* This code is mirroring the "wp core multisite-convert" command behavior.
22+
* See: https://github.com/wp-cli/core-command/blob/f157fb37dae1d13fe7318452f932917161e83e53/src/Core_Command.php#L505
23+
*/
24+
25+
require_once getenv( 'DOCROOT' ) . '/wp-load.php';
26+
require_once getenv( 'DOCROOT' ) . '/wp-admin/includes/upgrade.php';
27+
28+
// need to register the multisite tables manually for some reason
29+
foreach ( $wpdb->tables( 'ms_global' ) as $table => $prefixed_table ) {
30+
$wpdb->$table = $prefixed_table;
31+
}
32+
33+
install_network();
34+
35+
// Get multisite arguments
36+
$site_id = 1;
37+
$base = '/';
38+
$title = sprintf( '%s Sites', get_option( 'blogname' ) );
39+
$admin_email = get_option( 'admin_email' );
40+
$subdomains = false;
41+
42+
// Get the base domain
43+
$siteurl = get_option( 'siteurl' );
44+
$domain = (string) preg_replace( '|https?://|', '', $siteurl );
45+
$slash = strpos( $domain, '/' );
46+
if ( false !== $slash ) {
47+
$domain = substr( $domain, 0, $slash );
48+
}
49+
50+
// Eagerly check for custom ports
51+
if ( strpos( $domain, ':' ) !== false ) {
52+
throw new Exception(
53+
sprintf(
54+
'The current host is "%s", but WordPress multisites do not support custom ports.',
55+
$domain
56+
)
57+
);
58+
}
59+
60+
$result = populate_network(
61+
$site_id,
62+
$domain,
63+
$admin_email,
64+
$title,
65+
$base,
66+
$subdomains
67+
);
68+
69+
$site_id = $wpdb->get_var( "SELECT id FROM $wpdb->site" );
70+
$site_id = ( null === $site_id ) ? 1 : (int) $site_id;
71+
72+
if ( $result instanceof WP_Error ) {
73+
throw new Exception(
74+
sprintf(
75+
'Error: [%s] %s',
76+
$result->get_error_code(),
77+
$result->get_error_message()
78+
)
79+
);
80+
}
81+
82+
// delete_site_option() cleans the alloptions cache to prevent dupe option
83+
delete_site_option( 'upload_space_check_disabled' );
84+
update_site_option( 'upload_space_check_disabled', 1 );
85+
86+
$wp_config_constants = array(
87+
'WP_ALLOW_MULTISITE' => true,
88+
'MULTISITE' => true,
89+
'SUBDOMAIN_INSTALL' => $subdomains,
90+
'DOMAIN_CURRENT_SITE' => $domain,
91+
'PATH_CURRENT_SITE' => $base,
92+
'SITE_ID_CURRENT_SITE' => $site_id,
93+
'BLOG_ID_CURRENT_SITE' => 1,
94+
);
95+
96+
append_output( json_encode( $wp_config_constants ) );
97+
PHP;
98+
99+
try {
100+
$result = $runtime->evalPhpCodeInSubProcess( $code );
101+
} catch ( ProcessFailedException $e ) {
102+
throw new BlueprintExecutionException( $e->getMessage() );
103+
}
104+
105+
if ( '' === $result->outputFileContent ) {
106+
throw new BlueprintExecutionException( 'Failed to enable multisite' );
107+
}
108+
109+
// Reuse DefineConstantsStep to set the multisite constants.
110+
$wpConfigConstants = json_decode( $result->outputFileContent, true );
111+
$defineConstantsStep = new DefineConstantsStep( $wpConfigConstants );
112+
$defineConstantsStep->run( $runtime, $tracker );
113+
}
114+
}
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
<?php
2+
3+
namespace WordPress\Blueprints\Tests\Unit\Steps;
4+
5+
use Exception;
6+
use WordPress\Blueprints\Exception\BlueprintExecutionException;
7+
use WordPress\Blueprints\Progress\Tracker;
8+
use WordPress\Blueprints\Steps\EnableMultisiteStep;
9+
10+
class EnableMultisiteStepTest extends StepTestCase {
11+
public function setUp(): void {
12+
parent::setUp();
13+
14+
// Set site URL.
15+
$this->runtime->evalPhpCodeInSubProcess(
16+
<<<'PHP'
17+
<?php
18+
require_once getenv('DOCROOT') . '/wp-load.php';
19+
update_option( 'siteurl', 'http://localhost' );
20+
PHP
21+
);
22+
}
23+
24+
public function testEnableMultisite() {
25+
$step = new EnableMultisiteStep();
26+
$tracker = new Tracker();
27+
$step->run( $this->runtime, $tracker );
28+
29+
// Verify that multisite is set up and enabled.
30+
$result = $this->runtime->evalPhpCodeInSubProcess(
31+
<<<'PHP'
32+
<?php
33+
34+
// Load WordPress environment
35+
require_once getenv('DOCROOT') . '/wp-load.php';
36+
37+
// Verify multisite setup
38+
append_output(
39+
json_encode( [
40+
'is_multisite' => is_multisite(),
41+
'name' => get_bloginfo( 'name' ),
42+
'wpurl' => get_bloginfo( 'wpurl' ),
43+
'url' => get_bloginfo( 'url' ),
44+
'network' => get_network(),
45+
'constants' => [
46+
'WP_ALLOW_MULTISITE' => defined( 'WP_ALLOW_MULTISITE' ) ? WP_ALLOW_MULTISITE : null,
47+
'MULTISITE' => defined( 'MULTISITE' ) ? MULTISITE : null,
48+
'SUBDOMAIN_INSTALL' => defined( 'SUBDOMAIN_INSTALL' ) ? SUBDOMAIN_INSTALL : null,
49+
'DOMAIN_CURRENT_SITE' => defined( 'DOMAIN_CURRENT_SITE' ) ? DOMAIN_CURRENT_SITE : null,
50+
'PATH_CURRENT_SITE' => defined( 'PATH_CURRENT_SITE' ) ? PATH_CURRENT_SITE : null,
51+
'SITE_ID_CURRENT_SITE' => defined( 'SITE_ID_CURRENT_SITE' ) ? SITE_ID_CURRENT_SITE : null,
52+
'BLOG_ID_CURRENT_SITE' => defined( 'BLOG_ID_CURRENT_SITE' ) ? BLOG_ID_CURRENT_SITE : null,
53+
],
54+
] )
55+
);
56+
57+
PHP
58+
);
59+
60+
$output = json_decode( $result->outputFileContent, true );
61+
$this->assertSame( true, $output['is_multisite'] );
62+
$this->assertSame( 'WordPress Site', $output['name'] );
63+
$this->assertSame( 'http://localhost', $output['wpurl'] );
64+
$this->assertSame( 'http://127.0.0.1:80', $output['url'] );
65+
66+
$network = $output['network'];
67+
$this->assertSame( 'localhost', $network['domain'] );
68+
$this->assertSame( 'localhost', $network['cookie_domain'] );
69+
$this->assertSame( '/', $network['path'] );
70+
$this->assertSame( 'WordPress Site Sites', $network['site_name'] );
71+
72+
$constants = $output['constants'];
73+
$this->assertSame( true, $constants['WP_ALLOW_MULTISITE'] );
74+
$this->assertSame( true, $constants['MULTISITE'] );
75+
$this->assertSame( false, $constants['SUBDOMAIN_INSTALL'] );
76+
$this->assertSame( 'localhost', $constants['DOMAIN_CURRENT_SITE'] );
77+
$this->assertSame( '/', $constants['PATH_CURRENT_SITE'] );
78+
$this->assertSame( 1, $constants['SITE_ID_CURRENT_SITE'] );
79+
$this->assertSame( 1, $constants['BLOG_ID_CURRENT_SITE'] );
80+
}
81+
82+
83+
public function testEnableMultisiteRedirectsWhenSiteNotFound() {
84+
$step = new EnableMultisiteStep();
85+
$tracker = new Tracker();
86+
$step->run( $this->runtime, $tracker );
87+
88+
// Verify that multisite is set up and enabled.
89+
$result = $this->runtime->evalPhpCodeInSubProcess(
90+
<<<'PHP'
91+
<?php
92+
93+
register_shutdown_function( function() {
94+
if ( did_action( 'ms_site_not_found' ) ) {
95+
append_output( 'redirected' );
96+
}
97+
});
98+
99+
$_SERVER['HTTP_HOST'] = 'http://unknown';
100+
$_SERVER['REQUEST_URI'] = '/';
101+
102+
// Load WordPress environment
103+
require_once getenv('DOCROOT') . '/wp-load.php';
104+
append_output( 'not_redirected' );
105+
106+
PHP
107+
);
108+
109+
// In the CLI SAPI, the "header()" function is a no-op. We can only test
110+
// that "ms_site_not_found" was called and that the process exited early.
111+
$this->assertSame( 'redirected', $result->outputFileContent );
112+
}
113+
114+
public function testEnableMultisiteFailsOnNon80Port() {
115+
$this->runtime->evalPhpCodeInSubProcess(
116+
<<<'PHP'
117+
<?php
118+
require_once getenv('DOCROOT') . '/wp-load.php';
119+
update_option( 'siteurl', 'http://localhost:8080' );
120+
PHP
121+
);
122+
123+
$this->expectException( BlueprintExecutionException::class );
124+
$this->expectExceptionMessage( 'The current host is "localhost:8080", but WordPress multisites do not support custom ports.' );
125+
$step = new EnableMultisiteStep();
126+
$tracker = new Tracker();
127+
$step->run( $this->runtime, $tracker );
128+
}
129+
130+
public function testEnableMultisiteFailsWhenAlreadyEnabled() {
131+
$step = new EnableMultisiteStep();
132+
$tracker = new Tracker();
133+
$step->run( $this->runtime, $tracker );
134+
135+
$this->expectException( BlueprintExecutionException::class );
136+
$this->expectExceptionMessage( '[siteid_exists] The network already exists.' );
137+
$step->run( $this->runtime, $tracker );
138+
}
139+
140+
public function testEnableMultisiteFailsWhenConfigInvalid() {
141+
$this->runtime->evalPhpCodeInSubProcess(
142+
<<<'PHP'
143+
<?php
144+
require_once getenv('DOCROOT') . '/wp-load.php';
145+
delete_option( 'siteurl' );
146+
PHP
147+
);
148+
149+
$this->expectException( BlueprintExecutionException::class );
150+
$this->expectExceptionMessage( 'Failed to enable multisite' );
151+
$step = new EnableMultisiteStep();
152+
$tracker = new Tracker();
153+
$step->run( $this->runtime, $tracker );
154+
}
155+
}

0 commit comments

Comments
 (0)