Fix child-theme/plugin path check when --path contains relative segments#385
Fix child-theme/plugin path check when --path contains relative segments#385armorbreak001 wants to merge 1 commit intowp-cli:mainfrom
Conversation
When --path includes .. or . segments (e.g. --path=../mysite/), WP_CONTENT_DIR retains the unnormalized path, but check_target_directory() canonicalizes the target_dir before comparing. This mismatch causes false rejection of valid theme/plugin directories. Apply canonicalize_path() to both sides of the comparison so paths with relative segments are resolved consistently.
|
Hello! 👋 Thanks for opening this pull request! Please check out our contributing guidelines. We appreciate you taking the initiative to contribute to this project. Contributing isn't limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. Here are some useful Composer commands to get you started:
To run a single Behat test, you can use the following command: # Run all tests in a single file
composer behat features/some-feature.feature
# Run only a specific scenario (where 123 is the line number of the "Scenario:" title)
composer behat features/some-feature.feature:123You can find a list of all available Behat steps in our handbook. |
There was a problem hiding this comment.
Code Review
This pull request updates the path comparison logic in src/Scaffold_Command.php by applying canonicalize_path to WordPress directory constants, ensuring consistency with the target directory's format. A review comment suggests refactoring this logic to reduce duplication and improve robustness against edge cases in path strings.
| if ( 'theme' === $type && self::canonicalize_path( str_replace( '\\', '/', WP_CONTENT_DIR . '/themes' ) ) !== $parent_dir ) { | ||
| return sprintf( 'The target directory \'%1$s\' is not in \'%2$s\'.', $target_dir, WP_CONTENT_DIR . '/themes' ); | ||
| } | ||
|
|
||
| if ( 'plugin' === $type && str_replace( '\\', '/', WP_PLUGIN_DIR ) !== $parent_dir ) { | ||
| if ( 'plugin' === $type && self::canonicalize_path( str_replace( '\\', '/', WP_PLUGIN_DIR ) ) !== $parent_dir ) { | ||
| return sprintf( 'The target directory \'%1$s\' is not in \'%2$s\'.', $target_dir, WP_PLUGIN_DIR ); | ||
| } |
There was a problem hiding this comment.
The path comparison logic is duplicated and potentially fragile if the WordPress constants contain trailing slashes or double slashes, as canonicalize_path() does not collapse them. Refactoring this to use a single normalized check improves maintainability and robustness. Using dirname() on the reference path (after appending /.) ensures it is normalized consistently with $parent_dir.
$check_dir = 'theme' === $type ? WP_CONTENT_DIR . '/themes' : WP_PLUGIN_DIR;
if ( in_array( $type, [ 'theme', 'plugin' ], true ) && dirname( self::canonicalize_path( str_replace( '\\', '/', $check_dir . '/.' ) ) ) !== $parent_dir ) {
return sprintf( 'The target directory \'%1$s\' is not in \'%2$s\'.', $target_dir, $check_dir );
}|
Looks like you opened this just after I assigned it to Copilot 😅 see #384 |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
Closing in favor of #384 which contains the exact same changes, but also tests. Thanks for your PR though! |
Problem
Using
wp scaffold child-themewith a--pathargument that contains relative path segments (e.g.--path=../mywpsite/) fails with:The same issue affects
scaffold pluginand other subcommands that usecheck_target_directory().Root Cause
In
check_target_directory(), the `` is canonicalized (resolving..and `.` segments) before comparison, but the reference paths (`WP_CONTENT_DIR . '/themes'` and `WP_PLUGIN_DIR`) are not canonicalized. When `--path` contains relative segments, `WP_CONTENT_DIR` retains them unnormalized, causing the string comparison to fail even though both paths refer to the same directory.Fix
Apply
canonicalize_path()to both sides of the comparison incheck_target_directory()so paths are resolved consistently. This is a 2-line change.Fixes #251