🐛 fix: expose $this->plugin in Console commands#67
🐛 fix: expose $this->plugin in Console commands#67dansleboby wants to merge 11 commits intowpbones:masterfrom
Conversation
dansleboby
commented
Feb 23, 2026
- Add protected $plugin property and setPluginAttribute() setter to Command
- Fix loadWordPress() to use $currentDir (plugin root via $_SERVER['PWD']) instead of DIR for vendor/bootstrap paths, which was resolving to the wrong directory inside the vendor tree
- Capture the return value of bootstrap/plugin.php so $this->plugin is populated after calling loadWordPress()
- Add Kernel::setPlugin() to propagate the plugin instance to all registered command instances
- Store plugin in BonesCommandLine and pass it to the kernel before dispatching custom commands
- Add protected $plugin property and setPluginAttribute() setter to Command - Fix loadWordPress() to use $currentDir (plugin root via $_SERVER['PWD']) instead of __DIR__ for vendor/bootstrap paths, which was resolving to the wrong directory inside the vendor tree - Capture the return value of bootstrap/plugin.php so $this->plugin is populated after calling loadWordPress() - Add Kernel::setPlugin() to propagate the plugin instance to all registered command instances - Store plugin in BonesCommandLine and pass it to the kernel before dispatching custom commands
There was a problem hiding this comment.
Pull request overview
This PR aims to make the plugin instance available inside custom console commands (via $this->plugin) by capturing it from bootstrap/plugin.php and propagating it through the console kernel, while also fixing WordPress/bootstrap path resolution when running commands from a plugin root directory.
Changes:
- Add a
$pluginproperty + setter onConsole\Command, and populate it frombootstrap/plugin.phpduringloadWordPress(). - Add
Kernel::setPlugin()to inject the plugin instance into registered command instances. - Track the plugin instance in the
bonesCLI and pass it into the kernel before dispatching custom commands.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| src/Foundation/Console/Kernel.php | Adds setPlugin() to propagate the plugin instance to registered command objects. |
| src/Console/bin/bones | Stores plugin instance in the CLI runtime and attempts to pass it to the kernel before handling custom commands. |
| src/Console/Command.php | Introduces a protected $plugin property + setter and updates loadWordPress() to use the working directory for vendor/bootstrap paths and to capture the plugin instance. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
gfazioli
left a comment
There was a problem hiding this comment.
Thanks for this PR! I ran it on WPKirk-Boilerplate and the core feature works as advertised:
$this->pluginis correctly populated with aWPKirk\WPBones\Foundation\Plugininstance after$this->loadWordPress()in a custom command'shandle().- No regression on
--help, custom kernel commands (wp:sample,wpkirk:sample), code generators (make:controller), or the no-WordPress Docker-like deploy path (wpLoaded=false → graceful warning → deploy completes from an isolated/tmpdir). - It also fixes a pre-existing bug in
Command::loadWordPress()where__DIR__resolved inside the vendor tree forvendor/autoload.phpandbootstrap/plugin.php— those were never being included. 👍
Before we merge I'd like to raise three observations. None are strict blockers but they would make the change more robust.
1. require_once → require semantics change
Switching to require is needed to capture the return value, but it's not idempotent. The current WPKirk boilerplate's bootstrap/plugin.php creates a brand new Plugin instance and fires do_action('wp-kirk_loaded') every time the file executes. In the single-invocation CLI flow it's not reached twice today, but if a custom command (or any downstream code) ends up calling loadWordPress() twice, you'd get double plugin instantiation and double action firing.
Safer alternatives:
- Cache the instance inside
bootstrap/plugin.php(static cache + return the cached instance on subsequent requires). - Keep
require_onceand resolve the instance via a container accessor / global function (e.g.WPKirk()) instead of relying on the require return value.
2. \$this->plugin can silently become int(1)
If class_exists('\WPKirk\WPBones\Foundation\Plugin') returns false inside bootstrap/plugin.php (e.g. right after a rename, before composer dump-autoload), the file returns nothing and PHP's require returns 1. So \$this->plugin becomes the integer 1 with no warning. A user then doing \$this->plugin->options or get_class(\$this->plugin) hits a confusing error — I actually ran into exactly this during testing.
Possible mitigations:
- Type-guard in
setPluginAttribute(): only assign if the value is an object. - Ensure
bootstrap/plugin.phpalways returns either the instance ornull(never falls through without a return).
3. The setPlugin() call in bin/bones is unreachable in the declared use case
BonesCommandLine::\$this->plugin is populated only inside the CLI's own loadWordPress(), which boot() only invokes for tinker and deploy. For custom kernel commands, boot() falls through to handle() without calling loadWordPress(), so \$this->plugin in the CLI stays null and the guarded \$this->kernel->setPlugin(\$this->plugin) never fires. The mechanism that actually exposes \$this->plugin to custom commands is Command::loadWordPress() (the command sets \$this->plugin on its own instance).
Not harmful, but the kernel setPlugin() + the guard in bin/bones end up being dead code unless a future flow loads WordPress in the CLI before dispatching kernel commands. Worth either documenting the intent or removing if not needed.
Test setup for reference: WPKirk-Boilerplate with the patch applied manually to vendor/wpbones/wpbones/... + a custom wpkirk:plugin-access command. After a fresh composer dump-autoload, \$this->plugin resolves to the expected WPKirk\WPBones\Foundation\Plugin object. Also re-ran on /tmp/no-wp-deploy-test/ (isolated, no WP parent) to confirm php bones deploy /path --pkgm=npm --no-build still completes cleanly via the graceful wpLoaded=false branch.
Happy to merge once we align on 1 and 2 (3 is cosmetic). Thanks again!
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
…ignment Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com>
…pres Harden CLI plugin bootstrap loading against re-execution and invalid return types