Skip to content

Commit 2a709ee

Browse files
committed
Merge branch 'main' into copilot/introduce-wp-profile-requests
2 parents 6275bc2 + 8590872 commit 2a709ee

10 files changed

Lines changed: 175 additions & 70 deletions

File tree

.gitattributes

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/.actrc export-ignore
2+
/.distignore export-ignore
3+
/.editorconfig export-ignore
4+
/.github export-ignore
5+
/.gitignore export-ignore
6+
/.typos.toml export-ignore
7+
/AGENTS.md export-ignore
8+
/behat.yml export-ignore
9+
/features export-ignore
10+
/phpcs.xml.dist export-ignore
11+
/phpstan.neon.dist export-ignore
12+
/phpunit.xml.dist export-ignore
13+
/tests export-ignore
14+
/wp-cli.yml export-ignore

.github/workflows/copilot-setup-steps.yml

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,11 @@ jobs:
2121

2222
- name: Check existence of composer.json file
2323
id: check_composer_file
24-
uses: andstor/file-existence-action@076e0072799f4942c8bc574a82233e1e4d13e9d6 # v3
25-
with:
26-
files: "composer.json"
24+
run: echo "files_exists=$(test -f composer.json && echo true || echo false)" >> "$GITHUB_OUTPUT"
2725

2826
- name: Set up PHP environment
2927
if: steps.check_composer_file.outputs.files_exists == 'true'
30-
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2
28+
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # v2
3129
with:
3230
php-version: 'latest'
3331
ini-values: zend.assertions=1, error_reporting=-1, display_errors=On
@@ -38,7 +36,7 @@ jobs:
3836

3937
- name: Install Composer dependencies & cache dependencies
4038
if: steps.check_composer_file.outputs.files_exists == 'true'
41-
uses: ramsey/composer-install@3cf229dc2919194e9e36783941438d17239e8520 # v3
39+
uses: ramsey/composer-install@65e4f84970763564f46a70b8a54b90d033b3bdda # v3
4240
env:
4341
COMPOSER_ROOT_VERSION: dev-${{ github.event.repository.default_branch }}
4442
with:

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ render based on the main query, and renders it.
115115
Profile key metrics for WordPress hooks (actions and filters).
116116

117117
~~~
118-
wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
118+
wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>] [--search=<pattern>]
119119
~~~
120120

121121
In order to profile callbacks on a specific hook, the action or filter
@@ -161,6 +161,9 @@ will need to execute during the course of the request.
161161
[--orderby=<fields>]
162162
Set orderby which field.
163163

164+
[--search=<pattern>]
165+
Filter callbacks to those matching the given search pattern (case-insensitive).
166+
164167
**EXAMPLES**
165168

166169
# Profile a hook.
@@ -297,7 +300,7 @@ current theme.
297300

298301
## Installing
299302

300-
Installing this package requires WP-CLI v2.12 or greater. Update to the latest stable release with `wp cli update`.
303+
Installing this package requires WP-CLI v2.13 or greater. Update to the latest stable release with `wp cli update`.
301304

302305
Once you've done so, you can install the latest stable version of this package with:
303306

@@ -333,5 +336,9 @@ Want to contribute a new feature? Please first [open a new issue](https://github
333336

334337
Once you've decided to commit the time to seeing your pull request through, [please follow our guidelines for creating a pull request](https://make.wordpress.org/cli/handbook/pull-requests/) to make sure it's a pleasant experience. See "[Setting up](https://make.wordpress.org/cli/handbook/pull-requests/#setting-up)" for details specific to working on this package locally.
335338

339+
### License
340+
341+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
342+
336343

337344
*This README.md is generated dynamically from the project's codebase using `wp scaffold package-readme` ([doc](https://github.com/wp-cli/scaffold-package-command#wp-scaffold-package-readme)). To suggest changes, please submit a pull request against the corresponding part of the codebase.*

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"authors": [],
88
"require": {
99
"php": ">=7.2.24",
10-
"wp-cli/wp-cli": "^2.12"
10+
"wp-cli/wp-cli": "^2.13"
1111
},
1212
"require-dev": {
1313
"wp-cli/wp-cli-tests": "^5"

features/profile-hook.feature

Lines changed: 42 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
Feature: Profile a specific hook
22

3-
@require-wp-4.0
43
Scenario: Profile all hooks when a specific hook isn't specified
54
Given a WP install
65

@@ -12,7 +11,6 @@ Feature: Profile a specific hook
1211
| template_redirect |
1312
And STDERR should be empty
1413

15-
@require-wp-4.4
1614
Scenario: Profile all callbacks when --all flag is used
1715
Given a WP install
1816

@@ -21,21 +19,6 @@ Feature: Profile a specific hook
2119
| callback | cache_hits | cache_misses |
2220
| sanitize_comment_cookies() | 0 | 0 |
2321

24-
@less-than-php-7 @require-wp-4.0
25-
Scenario: Profile an intermediate stage hook
26-
Given a WP install
27-
28-
When I run `wp profile hook wp_head:before --fields=callback,cache_hits,cache_misses`
29-
Then STDOUT should be a table containing rows:
30-
| callback | cache_hits | cache_misses |
31-
| parse_blocks() | 0 | 0 |
32-
| _get_wptexturize_split_regex() | 0 | 0 |
33-
And STDOUT should not contain:
34-
"""
35-
WP_CLI\Profile\Profiler->wp_tick_profile_begin()
36-
"""
37-
38-
@require-wp-4.0
3922
Scenario: Profile a hook before the template is loaded
4023
Given a WP install
4124

@@ -44,7 +27,6 @@ Feature: Profile a specific hook
4427
| callback |
4528
And STDERR should be empty
4629

47-
@require-wp-4.0
4830
Scenario: Profile a hook without any callbacks
4931
Given a WP install
5032

@@ -66,7 +48,7 @@ Feature: Profile a specific hook
6648
<meta name="generator"
6749
"""
6850

69-
@require-wp-4.0 @less-than-wp-6.9
51+
@less-than-wp-6.9
7052
Scenario: Profile the shutdown hook
7153
Given a WP install
7254
And a wp-content/mu-plugins/shutdown.php file:
@@ -108,7 +90,6 @@ Feature: Profile a specific hook
10890
| total (3) | 0 | 1 |
10991
And STDERR should be empty
11092

111-
@require-wp-4.0
11293
Scenario: Indicate where a callback is defined with profiling a hook
11394
Given a WP install
11495
And a wp-content/mu-plugins/custom-action.php file:
@@ -128,64 +109,67 @@ Feature: Profile a specific hook
128109
| total (1) | | 0 | 1 |
129110
And STDERR should be empty
130111

131-
@require-wp-4.4
132-
Scenario: Hooks should only be called once
112+
Scenario: Search for callbacks by name pattern on a specific hook
133113
Given a WP install
134-
And a wp-content/mu-plugins/action-test.php file:
114+
And a wp-content/mu-plugins/search-test.php file:
135115
"""
136116
<?php
137-
add_action( 'init', function(){
138-
static $i;
139-
if ( ! isset( $i ) ) {
140-
$i = 0;
141-
}
142-
$i++;
143-
WP_CLI::warning( 'Called ' . $i );
144-
});
117+
function wp_cli_search_hook_one() {}
118+
function wp_cli_search_hook_two() {}
119+
function unrelated_callback() {}
120+
add_action( 'init', 'wp_cli_search_hook_one' );
121+
add_action( 'init', 'wp_cli_search_hook_two' );
122+
add_action( 'init', 'unrelated_callback' );
145123
"""
146124

147-
When I try `wp profile hook init`
148-
Then STDERR should be:
125+
When I run `wp profile hook init --fields=callback --search=wp_cli_search_hook`
126+
Then STDOUT should contain:
149127
"""
150-
Warning: Called 1
128+
wp_cli_search_hook_one()
151129
"""
152-
153-
@less-than-php-7 @require-wp-4.0
154-
Scenario: Profile the mu_plugins:before hook
155-
Given a WP install
156-
And a wp-content/mu-plugins/awesome-file.php file:
130+
And STDOUT should contain:
157131
"""
158-
<?php
159-
function awesome_func() {
160-
// does nothing
161-
}
162-
awesome_func();
132+
wp_cli_search_hook_two()
163133
"""
164-
165-
When I run `wp profile hook muplugins_loaded:before --fields=callback`
166-
Then STDOUT should contain:
134+
And STDOUT should not contain:
167135
"""
168-
wp-content/mu-plugins/awesome-file.php
136+
unrelated_callback()
169137
"""
138+
And STDERR should be empty
170139

171-
@less-than-php-7 @require-wp-4.0
172-
Scenario: Profile the :after hooks
140+
Scenario: Search for callbacks by name pattern across all hooks
173141
Given a WP install
142+
And a wp-content/mu-plugins/search-all-test.php file:
143+
"""
144+
<?php
145+
function wp_cli_search_all_hook() {}
146+
add_action( 'init', 'wp_cli_search_all_hook' );
147+
"""
174148

175-
When I run `wp profile hook wp_loaded:after`
149+
When I run `wp profile hook --all --fields=callback --search=wp_cli_search_all_hook`
176150
Then STDOUT should contain:
177151
"""
178-
do_action()
152+
wp_cli_search_all_hook()
179153
"""
154+
And STDERR should be empty
180155

181-
When I run `wp profile hook wp:after`
182-
Then STDOUT should contain:
156+
Scenario: Hooks should only be called once
157+
Given a WP install
158+
And a wp-content/mu-plugins/action-test.php file:
183159
"""
184-
do_action_ref_array()
160+
<?php
161+
add_action( 'init', function(){
162+
static $i;
163+
if ( ! isset( $i ) ) {
164+
$i = 0;
165+
}
166+
$i++;
167+
WP_CLI::warning( 'Called ' . $i );
168+
});
185169
"""
186170

187-
When I run `wp profile hook wp_footer:after`
188-
Then STDOUT should contain:
171+
When I try `wp profile hook init`
172+
Then STDERR should be:
189173
"""
190-
do_action()
174+
Warning: Called 1
191175
"""

features/profile-stage.feature

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,17 @@ Feature: Profile the template render stage
134134
Error: Invalid stage. Must be one of bootstrap, main_query, template, or use --all.
135135
"""
136136

137+
@require-wp-4.0
138+
Scenario: Invalid field name supplied to --fields
139+
Given a WP install
140+
141+
When I try `wp profile stage template --fields=test`
142+
Then STDERR should contain:
143+
"""
144+
Invalid field(s): test
145+
"""
146+
And the return code should be 1
147+
137148
@require-wp-4.0
138149
Scenario: Identify callback_count for each hook
139150
Given a WP install
@@ -160,3 +171,32 @@ Feature: Profile the template render stage
160171
| hook |
161172
| init |
162173
| wp_loaded:after |
174+
175+
@require-wp-4.0
176+
Scenario: Admin URL runs as a backend request and skips frontend stages
177+
Given a WP install
178+
179+
When I run `wp profile stage --url=example.com/wp-admin/ --context=admin --fields=stage`
180+
Then STDOUT should be a table containing rows:
181+
| stage |
182+
| bootstrap |
183+
And STDOUT should not contain:
184+
"""
185+
main_query
186+
"""
187+
And STDOUT should not contain:
188+
"""
189+
template
190+
"""
191+
And STDERR should be empty
192+
193+
@require-wp-4.0
194+
Scenario: Admin URL without --context=admin emits an error
195+
Given a WP install
196+
197+
When I try `wp profile stage --url=example.com/wp-admin/ --fields=stage`
198+
Then STDERR should contain:
199+
"""
200+
Profiling an admin URL requires --context=admin.
201+
"""
202+
And the return code should be 1

features/profile.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Feature: Basic profile usage
88
"""
99
usage: wp profile eval <php-code> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
1010
or: wp profile eval-file <file> [--hook[=<hook>]] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
11-
or: wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
11+
or: wp profile hook [<hook>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>] [--search=<pattern>]
1212
or: wp profile requests [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
1313
or: wp profile stage [<stage>] [--all] [--spotlight] [--url=<url>] [--fields=<fields>] [--format=<format>] [--order=<order>] [--orderby=<fields>]
1414

src/Command.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ class Command {
127127
* | total (7) | 1.0335s | 77.42% |
128128
* +--------------------------+---------+-------------+
129129
*
130+
* @skipglobalargcheck
130131
* @when before_wp_load
131132
*/
132133
public function stage( $args, $assoc_args ) {
@@ -233,6 +234,9 @@ public function stage( $args, $assoc_args ) {
233234
* [--orderby=<fields>]
234235
* : Set orderby which field.
235236
*
237+
* [--search=<pattern>]
238+
* : Filter callbacks to those matching the given search pattern (case-insensitive).
239+
*
236240
* ## EXAMPLES
237241
*
238242
* # Profile a hook.
@@ -251,6 +255,7 @@ public function stage( $args, $assoc_args ) {
251255
* | total (7) | 8 | 0 |
252256
* +--------------------------------+------------+--------------+
253257
*
258+
* @skipglobalargcheck
254259
* @when before_wp_load
255260
*/
256261
public function hook( $args, $assoc_args ) {
@@ -291,6 +296,13 @@ public function hook( $args, $assoc_args ) {
291296
if ( Utils\get_flag_value( $assoc_args, 'spotlight' ) ) {
292297
$loggers = self::shine_spotlight( $loggers, $metrics );
293298
}
299+
$search = Utils\get_flag_value( $assoc_args, 'search', false );
300+
if ( false !== $search && '' !== $search ) {
301+
if ( ! $focus ) {
302+
WP_CLI::error( '--search requires --all or a specific hook.' );
303+
}
304+
$loggers = self::filter_by_callback( $loggers, $search );
305+
}
294306
$formatter->display_items( $loggers, true, $order, $orderby );
295307
}
296308

@@ -606,4 +618,20 @@ private static function shine_spotlight( $loggers, $metrics ) {
606618

607619
return $loggers;
608620
}
621+
622+
/**
623+
* Filter loggers to only those whose callback name matches a pattern.
624+
*
625+
* @param array $loggers
626+
* @param string $pattern
627+
* @return array
628+
*/
629+
private static function filter_by_callback( $loggers, $pattern ) {
630+
return array_filter(
631+
$loggers,
632+
function ( $logger ) use ( $pattern ) {
633+
return isset( $logger->callback ) && false !== stripos( $logger->callback, $pattern );
634+
}
635+
);
636+
}
609637
}

0 commit comments

Comments
 (0)