From 7d0688814b06c4922f1dd5dd8366194b3de6df22 Mon Sep 17 00:00:00 2001 From: Gilbert Paquin Date: Mon, 23 Feb 2026 15:04:57 -0500 Subject: [PATCH 01/10] =?UTF-8?q?=F0=9F=90=9B=20fix:=20expose=20$this->plu?= =?UTF-8?q?gin=20in=20Console=20commands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- src/Console/Command.php | 29 ++++++++++++++++++++++++----- src/Console/bin/bones | 8 +++++++- src/Foundation/Console/Kernel.php | 14 ++++++++++++++ 3 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index fb9141af..4fcdcb31 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -66,6 +66,13 @@ abstract class Command */ protected $argv = []; + /** + * The plugin instance, available after calling loadWordPress(). + * + * @var mixed + */ + protected $plugin = null; + /** * */ @@ -274,6 +281,16 @@ public function setArgvAttribute($value): void $this->argv = $value; } + /** + * Set the plugin instance (injected by the Kernel or loadWordPress). + * + * @param mixed $value + */ + public function setPluginAttribute($value): void + { + $this->plugin = $value; + } + /** * Load WordPress environment. * @@ -281,9 +298,11 @@ public function setArgvAttribute($value): void */ protected function loadWordPress() { + // Plugin root is the working directory when running `php bones` + $currentDir = $_SERVER['PWD'] ?? getcwd(); + try { // We have to load the WordPress environment. - $currentDir = $_SERVER['PWD'] ?? __DIR__; $wpLoadPath = dirname(dirname(dirname($currentDir))) . '/wp-load.php'; if (!file_exists($wpLoadPath)) { @@ -306,8 +325,8 @@ protected function loadWordPress() * need to use it! Requiring it here means we don't have to load classes * manually. Feels great to relax. */ - if (file_exists(__DIR__ . '/vendor/autoload.php')) { - require __DIR__ . '/vendor/autoload.php'; + if (file_exists($currentDir . '/vendor/autoload.php')) { + require $currentDir . '/vendor/autoload.php'; } } catch (\Exception $e) { $this->error("Error! Can't load Composer autoload (" . $e->getMessage() . ')'); @@ -320,8 +339,8 @@ protected function loadWordPress() * Load this plugin env * -------------------------------------------------------------------------- */ - if (file_exists(__DIR__ . '/bootstrap/plugin.php')) { - require_once __DIR__ . '/bootstrap/plugin.php'; + if (file_exists($currentDir . '/bootstrap/plugin.php')) { + $this->plugin = require $currentDir . '/bootstrap/plugin.php'; } } catch (\Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); diff --git a/src/Console/bin/bones b/src/Console/bin/bones index e44212ad..51fd58de 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -615,6 +615,9 @@ namespace Bones\Traits { // WordPress loaded flag protected $wpLoaded = false; + // Plugin instance loaded from bootstrap/plugin.php + protected $plugin = null; + /* Protected version of the do_action function */ protected function do_action(...$args) { @@ -687,7 +690,7 @@ namespace Bones\Traits { * -------------------------------------------------------------------------- */ if (file_exists(__DIR__ . '/bootstrap/plugin.php')) { - require_once __DIR__ . '/bootstrap/plugin.php'; + $this->plugin = require __DIR__ . '/bootstrap/plugin.php'; } } catch (Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); @@ -1425,6 +1428,9 @@ namespace Bones { $extended = false; if ($this->kernel) { + if (!is_null($this->plugin)) { + $this->kernel->setPlugin($this->plugin); + } $extended = $this->kernel->handle($this->arguments()); } diff --git a/src/Foundation/Console/Kernel.php b/src/Foundation/Console/Kernel.php index b6f3182a..aa040817 100644 --- a/src/Foundation/Console/Kernel.php +++ b/src/Foundation/Console/Kernel.php @@ -21,6 +21,20 @@ public function hasCommands(): bool return !empty($this->instances); } + /** + * Inject the plugin instance into all registered command instances. + * + * @param mixed $plugin + */ + public function setPlugin($plugin): void + { + foreach ($this->instances as $commands) { + foreach ($commands as $command) { + $command->plugin = $plugin; + } + } + } + public function handle($argv) { // wpkirk:sample From 2f53ab9a7ad3cf12c92f9993fb9e7e128f4f7e78 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:02:42 +0000 Subject: [PATCH 02/10] Harden plugin loading against duplicate require and invalid returns Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 16 +++++++++++++--- src/Console/bin/bones | 9 +++++++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index 4fcdcb31..5296b9e9 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -73,6 +73,13 @@ abstract class Command */ protected $plugin = null; + /** + * Whether bootstrap/plugin.php has already been executed. + * + * @var bool + */ + protected bool $pluginBootstrapLoaded = false; + /** * */ @@ -288,7 +295,9 @@ public function setArgvAttribute($value): void */ public function setPluginAttribute($value): void { - $this->plugin = $value; + if (is_object($value) || is_null($value)) { + $this->plugin = $value; + } } /** @@ -339,8 +348,9 @@ protected function loadWordPress() * Load this plugin env * -------------------------------------------------------------------------- */ - if (file_exists($currentDir . '/bootstrap/plugin.php')) { - $this->plugin = require $currentDir . '/bootstrap/plugin.php'; + if (!$this->pluginBootstrapLoaded && file_exists($currentDir . '/bootstrap/plugin.php')) { + $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); + $this->pluginBootstrapLoaded = true; } } catch (\Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); diff --git a/src/Console/bin/bones b/src/Console/bin/bones index 51fd58de..27e9759f 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -618,6 +618,9 @@ namespace Bones\Traits { // Plugin instance loaded from bootstrap/plugin.php protected $plugin = null; + // Whether bootstrap/plugin.php has already been executed. + protected bool $pluginBootstrapLoaded = false; + /* Protected version of the do_action function */ protected function do_action(...$args) { @@ -689,8 +692,10 @@ namespace Bones\Traits { * Load this plugin env * -------------------------------------------------------------------------- */ - if (file_exists(__DIR__ . '/bootstrap/plugin.php')) { - $this->plugin = require __DIR__ . '/bootstrap/plugin.php'; + if (!$this->pluginBootstrapLoaded && file_exists(__DIR__ . '/bootstrap/plugin.php')) { + $plugin = require __DIR__ . '/bootstrap/plugin.php'; + $this->plugin = is_object($plugin) ? $plugin : null; + $this->pluginBootstrapLoaded = true; } } catch (Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); From fc48e4f8f717152087c917d450decb2cc85c9748 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:03:29 +0000 Subject: [PATCH 03/10] Warn on invalid plugin return and gate bootstrap caching on valid assignment Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 11 ++++++++--- src/Console/bin/bones | 9 ++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index 5296b9e9..ae395cec 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -293,11 +293,17 @@ public function setArgvAttribute($value): void * * @param mixed $value */ - public function setPluginAttribute($value): void + public function setPluginAttribute($value): bool { if (is_object($value) || is_null($value)) { $this->plugin = $value; + + return true; } + + $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); + + return false; } /** @@ -349,8 +355,7 @@ protected function loadWordPress() * -------------------------------------------------------------------------- */ if (!$this->pluginBootstrapLoaded && file_exists($currentDir . '/bootstrap/plugin.php')) { - $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); - $this->pluginBootstrapLoaded = true; + $this->pluginBootstrapLoaded = $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); } } catch (\Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); diff --git a/src/Console/bin/bones b/src/Console/bin/bones index 27e9759f..81e953da 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -694,8 +694,12 @@ namespace Bones\Traits { */ if (!$this->pluginBootstrapLoaded && file_exists(__DIR__ . '/bootstrap/plugin.php')) { $plugin = require __DIR__ . '/bootstrap/plugin.php'; - $this->plugin = is_object($plugin) ? $plugin : null; - $this->pluginBootstrapLoaded = true; + if (is_object($plugin) || is_null($plugin)) { + $this->plugin = $plugin; + $this->pluginBootstrapLoaded = true; + } else { + $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); + } } } catch (Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); @@ -3179,4 +3183,3 @@ namespace Bones { BonesCommandLine::run(); } - From 88009f156f693ac4a88714a2272893327c87db1a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:04:03 +0000 Subject: [PATCH 04/10] Keep bootstrap require idempotent and avoid setter API break Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 10 ++++------ src/Console/bin/bones | 2 +- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index ae395cec..c7dfb871 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -293,17 +293,14 @@ public function setArgvAttribute($value): void * * @param mixed $value */ - public function setPluginAttribute($value): bool + public function setPluginAttribute($value): void { if (is_object($value) || is_null($value)) { $this->plugin = $value; - - return true; + return; } $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); - - return false; } /** @@ -355,7 +352,8 @@ protected function loadWordPress() * -------------------------------------------------------------------------- */ if (!$this->pluginBootstrapLoaded && file_exists($currentDir . '/bootstrap/plugin.php')) { - $this->pluginBootstrapLoaded = $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); + $this->pluginBootstrapLoaded = true; + $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); } } catch (\Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); diff --git a/src/Console/bin/bones b/src/Console/bin/bones index 81e953da..e51e4863 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -693,10 +693,10 @@ namespace Bones\Traits { * -------------------------------------------------------------------------- */ if (!$this->pluginBootstrapLoaded && file_exists(__DIR__ . '/bootstrap/plugin.php')) { + $this->pluginBootstrapLoaded = true; $plugin = require __DIR__ . '/bootstrap/plugin.php'; if (is_object($plugin) || is_null($plugin)) { $this->plugin = $plugin; - $this->pluginBootstrapLoaded = true; } else { $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); } From ea2547bd1ee898a2ddce78ee06cdcfc6770463ad Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:04:36 +0000 Subject: [PATCH 05/10] Clarify invalid plugin warning expectations Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 2 +- src/Console/bin/bones | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index c7dfb871..33a9609f 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -300,7 +300,7 @@ public function setPluginAttribute($value): void return; } - $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); + $this->warning('Invalid plugin instance returned from bootstrap/plugin.php; expected object or null'); } /** diff --git a/src/Console/bin/bones b/src/Console/bin/bones index e51e4863..ec816330 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -698,7 +698,7 @@ namespace Bones\Traits { if (is_object($plugin) || is_null($plugin)) { $this->plugin = $plugin; } else { - $this->warning('Invalid plugin instance returned from bootstrap/plugin.php'); + $this->warning('Invalid plugin instance returned from bootstrap/plugin.php; expected object or null'); } } } catch (Exception $e) { From 785bbf496eb54a11f9c894ab676e8f1a91dcfb1f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:05:12 +0000 Subject: [PATCH 06/10] Rename bootstrap guard to executed flag for clarity Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 6 +++--- src/Console/bin/bones | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index 33a9609f..cb7f2036 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -78,7 +78,7 @@ abstract class Command * * @var bool */ - protected bool $pluginBootstrapLoaded = false; + protected bool $pluginBootstrapExecuted = false; /** * @@ -351,8 +351,8 @@ protected function loadWordPress() * Load this plugin env * -------------------------------------------------------------------------- */ - if (!$this->pluginBootstrapLoaded && file_exists($currentDir . '/bootstrap/plugin.php')) { - $this->pluginBootstrapLoaded = true; + if (!$this->pluginBootstrapExecuted && file_exists($currentDir . '/bootstrap/plugin.php')) { + $this->pluginBootstrapExecuted = true; $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); } } catch (\Exception $e) { diff --git a/src/Console/bin/bones b/src/Console/bin/bones index ec816330..09bf94ab 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -619,7 +619,7 @@ namespace Bones\Traits { protected $plugin = null; // Whether bootstrap/plugin.php has already been executed. - protected bool $pluginBootstrapLoaded = false; + protected bool $pluginBootstrapExecuted = false; /* Protected version of the do_action function */ protected function do_action(...$args) @@ -692,8 +692,8 @@ namespace Bones\Traits { * Load this plugin env * -------------------------------------------------------------------------- */ - if (!$this->pluginBootstrapLoaded && file_exists(__DIR__ . '/bootstrap/plugin.php')) { - $this->pluginBootstrapLoaded = true; + if (!$this->pluginBootstrapExecuted && file_exists(__DIR__ . '/bootstrap/plugin.php')) { + $this->pluginBootstrapExecuted = true; $plugin = require __DIR__ . '/bootstrap/plugin.php'; if (is_object($plugin) || is_null($plugin)) { $this->plugin = $plugin; From 917f9450a16b1103d73ebc6f41a0d67194cf760f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:05:44 +0000 Subject: [PATCH 07/10] Set bootstrap executed flag after successful require Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 3 ++- src/Console/bin/bones | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index cb7f2036..ef5166f4 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -352,8 +352,9 @@ protected function loadWordPress() * -------------------------------------------------------------------------- */ if (!$this->pluginBootstrapExecuted && file_exists($currentDir . '/bootstrap/plugin.php')) { + $plugin = require $currentDir . '/bootstrap/plugin.php'; $this->pluginBootstrapExecuted = true; - $this->setPluginAttribute(require $currentDir . '/bootstrap/plugin.php'); + $this->setPluginAttribute($plugin); } } catch (\Exception $e) { $this->error("Error! Can't load the plugin env (" . $e->getMessage() . ')'); diff --git a/src/Console/bin/bones b/src/Console/bin/bones index 09bf94ab..f379097e 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -693,8 +693,8 @@ namespace Bones\Traits { * -------------------------------------------------------------------------- */ if (!$this->pluginBootstrapExecuted && file_exists(__DIR__ . '/bootstrap/plugin.php')) { - $this->pluginBootstrapExecuted = true; $plugin = require __DIR__ . '/bootstrap/plugin.php'; + $this->pluginBootstrapExecuted = true; if (is_object($plugin) || is_null($plugin)) { $this->plugin = $plugin; } else { From 287ab77c59955a000b720301946b2911d56f235d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:06:15 +0000 Subject: [PATCH 08/10] Include actual type in invalid plugin warnings Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 4 +++- src/Console/bin/bones | 5 ++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index ef5166f4..24dcff63 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -300,7 +300,9 @@ public function setPluginAttribute($value): void return; } - $this->warning('Invalid plugin instance returned from bootstrap/plugin.php; expected object or null'); + $this->warning( + 'Invalid plugin instance returned from bootstrap/plugin.php; expected object or null, got ' . get_debug_type($value) + ); } /** diff --git a/src/Console/bin/bones b/src/Console/bin/bones index f379097e..b87dc5bb 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -698,7 +698,10 @@ namespace Bones\Traits { if (is_object($plugin) || is_null($plugin)) { $this->plugin = $plugin; } else { - $this->warning('Invalid plugin instance returned from bootstrap/plugin.php; expected object or null'); + $this->warning( + 'Invalid plugin instance returned from bootstrap/plugin.php; expected object or null, got ' . + get_debug_type($plugin) + ); } } } catch (Exception $e) { From bcef940230c3b0b71d65e0a4fc056dedf922cca2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:06:50 +0000 Subject: [PATCH 09/10] Set plugin to null when bootstrap returns invalid type Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 1 + src/Console/bin/bones | 1 + 2 files changed, 2 insertions(+) diff --git a/src/Console/Command.php b/src/Console/Command.php index 24dcff63..617982f5 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -303,6 +303,7 @@ public function setPluginAttribute($value): void $this->warning( 'Invalid plugin instance returned from bootstrap/plugin.php; expected object or null, got ' . get_debug_type($value) ); + $this->plugin = null; } /** diff --git a/src/Console/bin/bones b/src/Console/bin/bones index b87dc5bb..4d368b28 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -702,6 +702,7 @@ namespace Bones\Traits { 'Invalid plugin instance returned from bootstrap/plugin.php; expected object or null, got ' . get_debug_type($plugin) ); + $this->plugin = null; } } } catch (Exception $e) { From c4158a464f3992449ae71aab4384422b26ed4b4f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 18 Apr 2026 14:07:23 +0000 Subject: [PATCH 10/10] Use generic warning text in plugin setter Agent-Logs-Url: https://github.com/dansleboby/WPBones/sessions/dca69aca-0215-425d-9f0e-49a1d7998433 Co-authored-by: dansleboby <4716382+dansleboby@users.noreply.github.com> --- src/Console/Command.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Console/Command.php b/src/Console/Command.php index 617982f5..853b2ebc 100644 --- a/src/Console/Command.php +++ b/src/Console/Command.php @@ -301,7 +301,7 @@ public function setPluginAttribute($value): void } $this->warning( - 'Invalid plugin instance returned from bootstrap/plugin.php; expected object or null, got ' . get_debug_type($value) + 'Invalid plugin instance; expected object or null, got ' . get_debug_type($value) ); $this->plugin = null; }