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 [email protected] --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 [email protected] --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 [email protected] --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';
}
Comment on lines +478 to +495

Choose a reason for hiding this comment

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

medium

The logic for setting $_SERVER variables based on the provided URL is duplicated across install(), multisite_install(), and do_install(). While the layered approach is understandable for defense in depth, extracting this common logic into a private helper method (e.g., setServerUrlVars($url)) would improve maintainability by reducing redundancy and ensuring consistency if this logic ever needs to be updated. This would make the code cleaner and easier to manage.

            $this->setServerUrlVars( $assoc_args['url'] );

}

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