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
18 changes: 18 additions & 0 deletions features/flags.feature
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,24 @@ Feature: Global flags
Error: Site 'invalid.example.com' not found. Verify `--url=<url>` matches an existing site.
"""

Scenario: Malformed URL with typo in protocol
Given a WP installation

When I try `wp eval 'echo "test";' --url=http:/example.com`
Then STDERR should contain:
"""
Warning: The URL 'http:/example.com' does not appear to be valid.
"""

Scenario: URL with typo in scheme
Given a WP installation

When I try `wp eval 'echo "test";' --url=htp://example.com`
Then STDERR should contain:
"""
Warning: The URL 'htp://example.com' has an unrecognized scheme 'htp'.
"""

Scenario: Quiet run
Given a WP installation

Expand Down
54 changes: 54 additions & 0 deletions php/WP_CLI/Runner.php
Original file line number Diff line number Diff line change
Expand Up @@ -1403,6 +1403,9 @@ static function () {

WP_CLI::debug( 'Loaded WordPress', 'bootstrap' );
WP_CLI::do_hook( 'after_wp_load' );

// Validate multisite URL if applicable
$this->validate_multisite_url();
}

private static function fake_current_site_blog( $url_parts ): void {
Expand Down Expand Up @@ -1868,6 +1871,57 @@ private function is_multisite(): bool {
return false;
}

/**
* Validate that the URL matches an existing site in a multisite installation.
*
* For use after WordPress is fully loaded.
* Checks if the provided --url parameter corresponds to an existing site
* in a multisite installation.
*/
private function validate_multisite_url(): void {
// Only validate if this is a multisite and a URL was explicitly provided
if ( ! is_multisite() || empty( $this->config['url'] ) ) {
return;
}

// Parse the URL to get domain and path
$url_parts = Utils\parse_url( $this->config['url'] );
if ( empty( $url_parts['host'] ) ) {
// URL is malformed - already warned about in WP_CLI::set_url()
return;
}

$domain = $url_parts['host'];
$path = isset( $url_parts['path'] ) ? $url_parts['path'] : '/';

// Ensure path ends with a slash for multisite lookup
if ( '/' !== substr( $path, -1 ) ) {
$path .= '/';
}

// Use WP_Site_Query to check if site exists
$sites = get_sites(
[
'domain' => $domain,
'path' => $path,
'number' => 1,
]
);

if ( empty( $sites ) ) {
// Format URL the same way as ms_site_not_found hook
$url = $domain . $path;
// Remove trailing slash if path is just '/'
if ( '/' === $path ) {
$url = $domain;
}
WP_CLI::error(
"Site '{$url}' not found. " .
'Verify `--url=<url>` matches an existing site.'
);
}
}

/**
* Error handler for `wp_die()` when the command is help to try to trap errors (db connection failure in particular) during WordPress load.
*/
Expand Down
14 changes: 14 additions & 0 deletions php/class-wp-cli.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ function () use ( $cache ) {
public static function set_url( $url ) {
self::debug( 'Set URL: ' . $url, 'bootstrap' );
$url_parts = Utils\parse_url( $url );

// Validate that the URL has a host component and the scheme looks valid
if ( ! isset( $url_parts['host'] ) || empty( $url_parts['host'] ) ) {
self::warning(
"The URL '{$url}' does not appear to be valid. " .
'Please check for typos (e.g., missing slashes in the protocol like "http://").'
);
} elseif ( isset( $url_parts['scheme'] ) && ! in_array( strtolower( $url_parts['scheme'] ), [ 'http', 'https' ], true ) ) {
self::warning(
"The URL '{$url}' has an unrecognized scheme '{$url_parts['scheme']}'. " .
'Expected "http" or "https".'
);
}

self::set_url_params( $url_parts );
}

Expand Down
Loading