From a3841ec18a71ecd508b7265e993b9ae1a285d362 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:45:10 +0000 Subject: [PATCH 1/7] Initial plan From 44a91713700ef47467b9f8c85589ef26e33d4c69 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 12:53:36 +0000 Subject: [PATCH 2/7] Permit running requests as frontend vs. backend Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/profile-stage.feature | 18 ++++++++++++++++++ src/Profiler.php | 13 +++++++++++++ 2 files changed, 31 insertions(+) diff --git a/features/profile-stage.feature b/features/profile-stage.feature index 0a1152b7..4ff39ccc 100644 --- a/features/profile-stage.feature +++ b/features/profile-stage.feature @@ -171,3 +171,21 @@ Feature: Profile the template render stage | hook | | init | | wp_loaded:after | + + @require-wp-4.0 + Scenario: Admin URL runs as a backend request and skips frontend stages + Given a WP install + + When I run `wp profile stage --url=example.com/wp-admin/ --fields=stage` + Then STDOUT should be a table containing rows: + | stage | + | bootstrap | + And STDOUT should not contain: + """ + main_query + """ + And STDOUT should not contain: + """ + template + """ + And STDERR should be empty diff --git a/src/Profiler.php b/src/Profiler.php index 7d376575..8a775ff9 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -48,6 +48,8 @@ class Profiler { private $tick_cache_hit_offset = null; private $tick_cache_miss_offset = null; + private $is_admin_request = false; + public function __construct( $type, $focus ) { $this->type = $type; $this->focus = $focus; @@ -77,6 +79,9 @@ public function get_loggers() { * Run the profiler against WordPress */ public function run() { + $url = WP_CLI::get_runner()->config['url']; + $this->is_admin_request = ! empty( $url ) && (bool) preg_match( '#/wp-admin(/|$)#i', $url ); + WP_CLI::add_wp_hook( 'muplugins_loaded', function () { @@ -97,6 +102,9 @@ function () { if ( ! defined( 'SAVEQUERIES' ) ) { define( 'SAVEQUERIES', true ); } + if ( $this->is_admin_request && ! defined( 'WP_ADMIN' ) ) { + define( 'WP_ADMIN', true ); + } } ); if ( @@ -437,6 +445,11 @@ private function load_wordpress_with_template() { $this->loggers[] = $logger; } + // Skip main_query and template stages for admin requests. + if ( $this->is_admin_request ) { + return; + } + // Set up main_query main WordPress query. if ( 'stage' === $this->type ) { if ( 'main_query' === $this->focus ) { From 51c34f6d40aa95d4a2050a0019c35ee556b0cf32 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:01:47 +0000 Subject: [PATCH 3/7] Remove redundant WP_ADMIN define, handled by --context=admin Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- src/Profiler.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/Profiler.php b/src/Profiler.php index 8a775ff9..81e269cc 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -102,9 +102,6 @@ function () { if ( ! defined( 'SAVEQUERIES' ) ) { define( 'SAVEQUERIES', true ); } - if ( $this->is_admin_request && ! defined( 'WP_ADMIN' ) ) { - define( 'WP_ADMIN', true ); - } } ); if ( From b3253383ee3e935c655f6d7df8cdd0f1d7cd4abf Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Mar 2026 13:10:40 +0000 Subject: [PATCH 4/7] Require --context=admin for admin URL profiling, add error and test Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com> --- features/profile-stage.feature | 13 ++++++++++++- src/Profiler.php | 4 ++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/features/profile-stage.feature b/features/profile-stage.feature index 4ff39ccc..ee993ca1 100644 --- a/features/profile-stage.feature +++ b/features/profile-stage.feature @@ -176,7 +176,7 @@ Feature: Profile the template render stage Scenario: Admin URL runs as a backend request and skips frontend stages Given a WP install - When I run `wp profile stage --url=example.com/wp-admin/ --fields=stage` + When I run `wp profile stage --url=example.com/wp-admin/ --context=admin --fields=stage` Then STDOUT should be a table containing rows: | stage | | bootstrap | @@ -189,3 +189,14 @@ Feature: Profile the template render stage template """ And STDERR should be empty + + @require-wp-4.0 + Scenario: Admin URL without --context=admin emits an error + Given a WP install + + When I try `wp profile stage --url=example.com/wp-admin/ --fields=stage` + Then STDERR should contain: + """ + Profiling an admin URL requires --context=admin. + """ + And the return code should be 1 diff --git a/src/Profiler.php b/src/Profiler.php index 81e269cc..f300bb8c 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -82,6 +82,10 @@ public function run() { $url = WP_CLI::get_runner()->config['url']; $this->is_admin_request = ! empty( $url ) && (bool) preg_match( '#/wp-admin(/|$)#i', $url ); + if ( $this->is_admin_request && 'admin' !== WP_CLI::get_runner()->config['context'] ) { + WP_CLI::error( 'Profiling an admin URL requires --context=admin.' ); + } + WP_CLI::add_wp_hook( 'muplugins_loaded', function () { From 9ba40cc4f3d0baae7a6963f15b7318a8b2542fa8 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 20 Mar 2026 11:01:21 +0100 Subject: [PATCH 5/7] Update src/Profiler.php Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/Profiler.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Profiler.php b/src/Profiler.php index f300bb8c..7d0b076d 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -79,8 +79,18 @@ public function get_loggers() { * Run the profiler against WordPress */ public function run() { - $url = WP_CLI::get_runner()->config['url']; - $this->is_admin_request = ! empty( $url ) && (bool) preg_match( '#/wp-admin(/|$)#i', $url ); + $url = WP_CLI::get_runner()->config['url']; + $path = ''; + if ( ! empty( $url ) ) { + $parsed_url = @parse_url( $url ); + if ( false !== $parsed_url && isset( $parsed_url['path'] ) ) { + $path = $parsed_url['path']; + } else { + // Fallback for cases where $url is just a path. + $path = $url; + } + } + $this->is_admin_request = ! empty( $path ) && (bool) preg_match( '#/wp-admin(/|$|\?)#i', $path ); if ( $this->is_admin_request && 'admin' !== WP_CLI::get_runner()->config['context'] ) { WP_CLI::error( 'Profiling an admin URL requires --context=admin.' ); From 0a29f25baa1c67edb49bbe365f851a0567440447 Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 20 Mar 2026 12:26:51 +0100 Subject: [PATCH 6/7] Lint fix --- src/Profiler.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Profiler.php b/src/Profiler.php index 7d0b076d..280cac8a 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -79,10 +79,10 @@ public function get_loggers() { * Run the profiler against WordPress */ public function run() { - $url = WP_CLI::get_runner()->config['url']; - $path = ''; + $url = WP_CLI::get_runner()->config['url']; + $path = ''; if ( ! empty( $url ) ) { - $parsed_url = @parse_url( $url ); + $parsed_url = wp_parse_url( $url ); if ( false !== $parsed_url && isset( $parsed_url['path'] ) ) { $path = $parsed_url['path']; } else { From 7ff1edea7fd849e65a0b34940a3d2ea8dc2e4a5c Mon Sep 17 00:00:00 2001 From: Pascal Birchler Date: Fri, 20 Mar 2026 12:37:42 +0100 Subject: [PATCH 7/7] Use utils --- src/Profiler.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Profiler.php b/src/Profiler.php index 280cac8a..2658441f 100644 --- a/src/Profiler.php +++ b/src/Profiler.php @@ -82,7 +82,7 @@ public function run() { $url = WP_CLI::get_runner()->config['url']; $path = ''; if ( ! empty( $url ) ) { - $parsed_url = wp_parse_url( $url ); + $parsed_url = WP_CLI\Utils\parse_url( $url ); if ( false !== $parsed_url && isset( $parsed_url['path'] ) ) { $path = $parsed_url['path']; } else {