Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions features/core-install.feature
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,78 @@ Feature: Install WordPress core
"""
And the return code should be 0

Scenario: Verify correct siteurl and home when URL has no path
Given an empty directory
And WP files
And wp-config.php
And a database

When I run `wp core install --url=example.com --title=Test --admin_user=wpcli --admin_email=wpcli@example.org --admin_password=password --skip-email`
Then STDOUT should contain:
"""
Success: WordPress installed successfully.
"""

When I run `wp option get home`
Then STDOUT should be:
"""
http://example.com
"""

When I run `wp option get siteurl`
Then STDOUT should be:
"""
http://example.com
"""

Scenario: Verify correct siteurl and home when URL has a path
Given an empty directory
And WP files
And wp-config.php
And a database

When I run `wp core install --url=example.com/subdir --title=Test --admin_user=wpcli --admin_email=wpcli@example.org --admin_password=password --skip-email`
Then STDOUT should contain:
"""
Success: WordPress installed successfully.
"""

When I run `wp option get home`
Then STDOUT should be:
"""
http://example.com/subdir
"""

When I run `wp option get siteurl`
Then STDOUT should be:
"""
http://example.com/subdir
"""

Scenario: Install ensures correct siteurl and home regardless of PHP_SELF
Given an empty directory
And WP files
And wp-config.php
And a database

When I run `wp core install --url=https://example.com --title=Test --admin_user=wpcli --admin_email=wpcli@example.org --admin_password=password --skip-email`
Then STDOUT should contain:
"""
Success: WordPress installed successfully.
"""

When I run `wp option get home`
Then STDOUT should be:
"""
https://example.com
"""

When I run `wp option get siteurl`
Then STDOUT should be:
"""
https://example.com
"""

@less-than-php-7
Scenario: Install WordPress with locale set to de_DE on WP < 4.0
Given an empty directory
Expand Down
92 changes: 86 additions & 6 deletions src/Core_Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,32 @@ public function is_installed( $args, $assoc_args ) {
* @param array{url: string, title: string, admin_user: string, admin_password?: string, admin_email: string, locale?: string, 'skip-email'?: bool} $assoc_args Associative arguments.
*/
public function install( $args, $assoc_args ) {
// Fix $_SERVER['PHP_SELF'] and $_SERVER['SCRIPT_NAME'] early to prevent incorrect
// URL detection by WordPress. When WP-CLI is executed from the root of the
// filesystem (e.g., /wp), these variables contain the WP-CLI executable path
// rather than the WordPress installation path, which causes wp_guess_url() to
// construct incorrect URLs. This must be done as early as possible.
if ( isset( $assoc_args['url'] ) ) {
$url_parts = Utils\parse_url( $assoc_args['url'] );
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '/';

// Ensure path represents a PHP script for proper WordPress URL detection.
$path = rtrim( $path, '/' );
if ( empty( $path ) ) {
$path = '/index.php';
} elseif ( '' === pathinfo( $path, PATHINFO_EXTENSION ) ) {
$path .= '/index.php';
}

$_SERVER['PHP_SELF'] = $path;
$_SERVER['SCRIPT_NAME'] = $path;

// Set SCRIPT_FILENAME to the actual WordPress index.php if available.
if ( file_exists( Utils\trailingslashit( ABSPATH ) . 'index.php' ) ) {
$_SERVER['SCRIPT_FILENAME'] = Utils\trailingslashit( ABSPATH ) . 'index.php';
}
}

if ( $this->do_install( $assoc_args ) ) {
WP_CLI::success( 'WordPress installed successfully.' );
} else {
Expand Down Expand Up @@ -600,6 +626,32 @@ public function multisite_convert( $args, $assoc_args ) {
* @param array{url?: string, base: string, subdomains?: bool, title: string, admin_user: string, admin_password?: string, admin_email: string, 'skip-email'?: bool, 'skip-config'?: bool} $assoc_args Associative arguments.
*/
public function multisite_install( $args, $assoc_args ) {
// Fix $_SERVER['PHP_SELF'] and $_SERVER['SCRIPT_NAME'] early to prevent incorrect
// URL detection by WordPress. When WP-CLI is executed from the root of the
// filesystem (e.g., /wp), these variables contain the WP-CLI executable path
// rather than the WordPress installation path, which causes wp_guess_url() to
// construct incorrect URLs. This must be done as early as possible.
if ( isset( $assoc_args['url'] ) ) {
$url_parts = Utils\parse_url( $assoc_args['url'] );
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '/';

// Ensure path represents a PHP script for proper WordPress URL detection.
$path = rtrim( $path, '/' );
if ( empty( $path ) ) {
$path = '/index.php';
} elseif ( '' === pathinfo( $path, PATHINFO_EXTENSION ) ) {
$path .= '/index.php';
}

$_SERVER['PHP_SELF'] = $path;
$_SERVER['SCRIPT_NAME'] = $path;

// Set SCRIPT_FILENAME to the actual WordPress index.php if available.
if ( file_exists( Utils\trailingslashit( ABSPATH ) . 'index.php' ) ) {
$_SERVER['SCRIPT_FILENAME'] = Utils\trailingslashit( ABSPATH ) . 'index.php';
}
}

if ( $this->do_install( $assoc_args ) ) {
WP_CLI::log( 'Created single site database tables.' );
} else {
Expand Down Expand Up @@ -663,6 +715,40 @@ private function do_install( $assoc_args ) {
return false;
}

// Fix $_SERVER['PHP_SELF'] and $_SERVER['SCRIPT_NAME'] early to prevent incorrect
// URL detection by WordPress during installation. When WP-CLI is executed from
// the root of the filesystem (e.g., /wp), these variables contain the WP-CLI
// executable path rather than the WordPress installation path, which causes
// wp_guess_url() to construct incorrect URLs. This must be done before loading
// any WordPress files that might use these values.
if ( isset( $assoc_args['url'] ) ) {
WP_CLI::set_url( $assoc_args['url'] );

$url_parts = Utils\parse_url( $assoc_args['url'] );
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '/';

// Ensure path represents a PHP script for proper WordPress URL detection.
// If the path doesn't already end with a file (no extension in basename),
// append '/index.php' to represent the WordPress entry point.
$path = rtrim( $path, '/' );
if ( empty( $path ) ) {
$path = '/index.php';
} elseif ( '' === pathinfo( $path, PATHINFO_EXTENSION ) ) {
// Path doesn't end with a file, append /index.php
$path .= '/index.php';
}

$_SERVER['PHP_SELF'] = $path;
$_SERVER['SCRIPT_NAME'] = $path;

// Set SCRIPT_FILENAME to the actual WordPress index.php if available.
// This is optional and only set when ABSPATH is defined and index.php exists.
// If not set, WordPress can still function using PHP_SELF and SCRIPT_NAME.
if ( file_exists( Utils\trailingslashit( ABSPATH ) . 'index.php' ) ) {
$_SERVER['SCRIPT_FILENAME'] = Utils\trailingslashit( ABSPATH ) . 'index.php';
}
}

if ( true === Utils\get_flag_value( $assoc_args, 'skip-email' ) ) {
if ( ! function_exists( 'wp_new_blog_notification' ) ) {
// @phpstan-ignore function.inner
Expand All @@ -687,12 +773,6 @@ function wp_new_blog_notification() {

$args = wp_parse_args( $assoc_args, $defaults );

// Support prompting for the `--url=<url>`,
// which is normally a runtime argument
if ( isset( $assoc_args['url'] ) ) {
WP_CLI::set_url( $assoc_args['url'] );
}

$public = true;
$password = $args['admin_password'];

Expand Down