Skip to content

Introduce wp profile queries command#207

Merged
swissspidy merged 31 commits intomainfrom
copilot/add-wp-profile-queries
Apr 14, 2026
Merged

Introduce wp profile queries command#207
swissspidy merged 31 commits intomainfrom
copilot/add-wp-profile-queries

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Nov 8, 2025

  • Understand the codebase structure and how profiling works
  • Design the wp profile queries command structure
  • Implement the core queries() method in Command.php
  • Add support for viewing all queries with execution time
  • Add --hook=<hook> parameter to filter queries for a specific hook
  • Add --callback=<callback> parameter to filter queries for a specific callback
  • Add formatting support (table, json, yaml, csv)
  • Add ordering support (--order, --orderby)
  • Add tests for the new command including hook/callback filtering
  • Enhance Logger to track query indices
  • Update documentation in README.md
  • Run code review and security checks
  • Improve first test to add custom plugin with database queries
  • Fix PHP warnings for non-numeric values in Formatter
  • Address code review feedback (callback filtering, query_indices reset, handle both params)
  • Fix test failures (add hook property to callback loggers, improve Formatter validation)
  • Change query map to use last-logger-wins approach for better specificity in nested hooks
  • Document performance characteristics and complexity of query mapping
  • Fix root cause of hook/callback filtering returning 0 results
  • Implementation complete

Summary

Fixed the root cause of hook and callback filtering always returning 0 results. The Logger::stop() method was populating query_indices during the for-loop, but then immediately clearing it ($this->query_indices = array()). This meant the array was always empty when read by the queries() command after profiling. Removed the reset from stop() to match the behavior of other accumulated properties like query_time and query_count which also accumulate across runs without being reset in stop().

Original prompt

This section details on the original issue you should resolve

<issue_title>Introduce wp profile queries</issue_title>
<issue_description>It would be helpful to be able to see all queries and how much time they're taking.

Also make it possible to show actual queries for (a) a specific callback or (b) all queries within a specific hook</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI self-assigned this Nov 8, 2025
Copilot AI and others added 3 commits November 8, 2025 10:36
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Copilot AI changed the title [WIP] Introduce wp profile queries to monitor query performance Introduce wp profile queries command Nov 8, 2025
Copilot AI requested a review from swissspidy November 8, 2025 10:42
@swissspidy swissspidy requested a review from Copilot November 8, 2025 14:23

This comment was marked as resolved.

swissspidy and others added 3 commits November 8, 2025 15:27
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
@swissspidy

This comment was marked as resolved.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>

This comment was marked as resolved.

@swissspidy

This comment was marked as resolved.

…e normalization

Co-authored-by: swissspidy <841956+swissspidy@users.noreply.github.com>
Agent-Logs-Url: https://github.com/wp-cli/profile-command/sessions/03bb039a-1130-42cb-b79e-f3182e25c4e5

This comment was marked as resolved.

@codecov
Copy link
Copy Markdown

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 93.18182% with 6 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
src/Command.php 91.78% 6 Missing ⚠️

📢 Thoughts on this report? Let us know!

@swissspidy swissspidy marked this pull request as ready for review March 21, 2026 06:23
@swissspidy swissspidy requested a review from a team as a code owner March 21, 2026 06:23
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +618 to +619
$order = Utils\get_flag_value( $assoc_args, 'order', 'ASC' );
$orderby = Utils\get_flag_value( $assoc_args, 'orderby', null );
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In queries(), $order and $orderby are taken directly from Utils\get_flag_value() without the string/null normalization used elsewhere in this file (e.g. stage() around Command.php:142-145). If a non-string slips through, sorting/formatting can behave unexpectedly. Suggest normalizing $order to a string (defaulting to 'ASC') and $orderby to string|null the same way as the other subcommands for consistency and robustness.

Suggested change
$order = Utils\get_flag_value( $assoc_args, 'order', 'ASC' );
$orderby = Utils\get_flag_value( $assoc_args, 'orderby', null );
$order_val = Utils\get_flag_value( $assoc_args, 'order', 'ASC' );
$order = is_string( $order_val ) ? $order_val : 'ASC';
$orderby_val = Utils\get_flag_value( $assoc_args, 'orderby', null );
$orderby = is_string( $orderby_val ) ? $orderby_val : null;

Copilot uses AI. Check for mistakes.
Comment on lines +693 to +696
$query_time = $query_data[1];
if ( null !== $time_threshold && $query_time < (float) $time_threshold ) {
continue;
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--time_threshold is cast to (float) without validating that the provided value is numeric. For inputs like --time_threshold=abc, this becomes 0.0 and silently changes filtering behavior. Consider validating with is_numeric() and erroring with a clear message when the value is not a number.

Copilot uses AI. Check for mistakes.
Comment on lines +317 to 324
'function' => function () use ( $func, $i, $current_filter ) {
if ( ! isset( $this->loggers[ $i ] ) ) {
$this->loggers[ $i ] = new Logger(
array(
'hook' => $current_filter,
'callback' => $func,
)
);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap_current_filter_callbacks() keys callback-level loggers only by $i (the callback unique ID). That ID can collide across different hooks when the same callback is attached to multiple hooks, so the same Logger instance can be reused for different $current_filter values and the stored hook/callback metadata (and collected query_indices) can become incorrect. Consider namespacing the logger key by hook+callback (e.g., $current_filter . ':' . $i) so each hook/callback pair has its own logger and query attribution is accurate when profiling all hooks (e.g. --callback mode).

Copilot uses AI. Check for mistakes.
@swissspidy
Copy link
Copy Markdown
Member

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the wp profile queries command, enabling users to profile database queries, execution times, and callers. Key implementation details include the new QueryLogger class, logic to map queries to hooks and callbacks, and updates to the Formatter to handle non-numeric fields. Review feedback suggests enhancing maintainability by replacing hardcoded method markers and field lists with more dynamic or constant-based solutions.


$location_index = array_search( 'location', $fields, true );
$location_index = array_search( 'location', $fields, true );
$non_numeric_fields = array( 'query', 'caller', 'hook', 'callback' );
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The non_numeric_fields array is a hardcoded list of fields to exclude from numeric calculations. This approach is fragile as it requires manual updates whenever new non-numeric fields are added to the output. Consider using a more dynamic approach, such as checking the type of the field values or defining metadata on the logger classes to indicate which fields should be summed.

@swissspidy swissspidy merged commit 7c72b49 into main Apr 14, 2026
62 checks passed
@swissspidy swissspidy deleted the copilot/add-wp-profile-queries branch April 14, 2026 18:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce wp profile queries

3 participants