-
Notifications
You must be signed in to change notification settings - Fork 1k
Description
Bug Report
- Yes, I reviewed the contribution guidelines.
- Yes, more specifically, I reviewed the guidelines on how to write clear bug reports.
Describe the current, buggy behavior
When running wp post delete <image-id> --force on Windows I noticed that the alternative image sizes files (image-150x150.jpg etc.) weren't being deleted. I eventually traced this back to path_join() mangling the file paths, which in turn was down to path_is_absolute() returning false for paths that are absolute, which in turn was due to ABSPATH starting with C:/ instead of C:\.
On Windows, when running WordPress through the browser ABSPATH is C:\wp\public/, but in WP-CLI it is C:/wp/public/.
Since path_is_absolute() checks for preg_match( '#^[a-zA-Z]:\\\\#', $path ), then any path starting with ABSPATH returns true when run from the browser (the expected value), but false in WP-CLI.
In WP-CLI this then causes path_join() to mangle the returned paths, which means wp_delete_attachment_files() does not delete alternatives sizes from the uploads directory, and since wp post delete <image-id> --false eventually calls that it fails too.
For info, it seems the only place path_is_absolute() is used is in path_join(), but path_join() is used in a few places.
Describe how other contributors can replicate this bug
You can check the ABSPATH value with wp eval "echo ABSPATH;".
Assuming WordPress is installed in C:\wp\public, when running WordPress through the browser ABSPATH will be C:\wp\public/, but the above will returnC:/wp/public/.
To show how this effects wp post delete:
-
Import a new image that will generate alternative sizes with
wp media import image.jpg -
Check that it has generated alternative sizes with
dir wp-content\uploads\2025\09\image* /b, for exampleimage-150x150.jpg image.jpg -
Delete the image with
wp post delete <image-id> --force -
Check the alternative sizes again
dir wp-content\uploads\2025\09\image* /b, in the above example this would beimage-150x150.jpg
Describe what you expect as the correct outcome
After the image is deleted dir wp-content\uploads\2025\09\image* /b should return File Not Found.
wp eval "echo ABSPATH;" should probably return C:\wp\public/ (depending on the solution chosen).
Provide a possible solution
I don't know enough about the code to know whether the best solution is to change path_is_absolute in WordPress core wp-includes\functions.php to handle C:/ and C:\, or the way I fixed it by commenting out the first line in normalize_path() in utils.php as below (though I have no idea what side effects that will have), or probably some other way.
function normalize_path( $path ) {
// $path = str_replace( '\\', '/', $path );
...
}For info, I first extracted wp-cli.phar to directory wp-cli in my wordpress root, and then I could run it with php wp-cli\vendor\wp-cli\wp-cli\php\boot-fs.php, so then I could change the code.
Workaround
wp post delete <image-id> --force --exec="define('ABSPATH', 'C:\wp\public/');" 2> nul
This sets the value of ABSPATH to the same as when running via a browser, so the delete works OK.
This workaround actually exposed another bug. You will see that I ran it with 2> nul as otherwise it came back with:
The --path parameter cannot be used when ABSPATH is already defined elsewhere
ABSPATH is defined as: "C:\wp\public/"
Success: Deleted post 1929.
As you can see, no --path was given. This bug is in WP_CLI\Runner.php:
private static function set_wp_root( $path ) {
if ( ! defined( 'ABSPATH' ) ) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Declaring a WP native constant.
define( 'ABSPATH', Utils\normalize_path( Utils\trailingslashit( $path ) ) );
} elseif ( ! is_null( $path ) ) {
WP_CLI::error_multi_line(
[
'The --path parameter cannot be used when ABSPATH is already defined elsewhere',
'ABSPATH is defined as: "' . ABSPATH . '"',
]
);
}It seems $path is always set as the result of find_wp_root() is passed into this function, so I believe the appropriate fix would be to change the code to:
private function set_wp_root( $path ) {
if ( ! defined( 'ABSPATH' ) ) {
// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedConstantFound -- Declaring a WP native constant.
define( 'ABSPATH', Utils\normalize_path( Utils\trailingslashit( $path ) ) );
} elseif ( isset( $this->config['path'] ) ) {
WP_CLI::error_multi_line(
[
'The --path parameter cannot be used when ABSPATH is already defined elsewhere',
'ABSPATH is defined as: "' . ABSPATH . '"',
]
);
}and change the call to
// Handle --path parameter
$this::set_wp_root( $this->find_wp_root() );Let us know what environment you are running this on
OS: Windows NT 10.0 build 19045 (Windows 10) AMD64
Shell: C:\WINDOWS\system32\cmd.exe
PHP binary: C:\Users\[user]\AppData\Roaming\Local\lightning-services\php-8.4.12+0>\bin\win64\php.exe
PHP version: 8.4.12
php.ini used: C:\Users\[user]\AppData\Roaming\Local\run\duUC4zCgt\conf\php\php.ini
MySQL binary:
MySQL version:
SQL modes:
WP-CLI root dir: phar://wp-cli.phar/vendor/wp-cli/wp-cli
WP-CLI vendor dir: phar://wp-cli.phar/vendor
WP_CLI phar path: phar://C:/Program Files (x86)/Local/resources/extraResources/bin/wp-cli/wp-cli.phar
WP-CLI packages dir: C:\Users\[user]/.wp-cli/packages/
WP-CLI cache dir: C:\Users\[user]/.wp-cli/cache
WP-CLI global config:
WP-CLI project config:
WP-CLI version: 2.12.0
Thanks in advance for your help