
The crude script will loop through each plugin and check load time. See here for an example output: https://app.warp.dev/block/P0mRiYKGhE2B6wQAD7q2x2.
function find_slow_plugin() {
_get_wp_execution_time() {
local output
local extracted_time
# Capture stderr (where --debug output goes) to stdout.
# 'command wp' ensures we call the actual wp binary, not an alias.
output=$(command wp "$@" --debug 2>&1)
# Perl script to extract the time like "0.123s". It handles debug formats
# like "(0.123s)" or "(0.123s|more_info)".
extracted_time=$(echo "$output" | perl -ne '/Debug \(bootstrap\): Running command: .+\(([^s]+s)/ && print $1')
if [[ -n "$extracted_time" ]]; then
echo "$extracted_time"
else
echo "" # Return empty on failure
fi
}
local base_time_s
local time_no_themes_s
local time_no_plugins_s
local time_with_skip_s
local active_plugins # Array to hold active plugin slugs
local plugin # Loop variable for plugin slug
local results=() # Array to store results for sorting
# Check 1: Is WP-CLI installed?
if ! command -v wp &>/dev/null; then
echo "â Error: WP-CLI (wp command) not found. Please install WP-CLI." >&2
echo "See: https://wp-cli.org/" >&2
return 1
fi
# Check 2: Are we in a WordPress directory?
if ! command wp core is-installed --quiet; then
echo "â Error: This does not appear to be a WordPress installation, or WP-CLI cannot connect." >&2
echo "Please run this script from the root directory of a WordPress site." >&2
return 1
fi
echo "đ WordPress Plugin Performance Test đ"
echo "This script measures the execution time of 'wp plugin list --debug' under various conditions."
echo ""
echo "đ Initial Baseline Measurements for 'wp plugin list --debug':"
printf " âŗ Measuring time with NO themes loaded (--skip-themes)... "
time_no_themes_s=$(_get_wp_execution_time plugin list --skip-themes)
if [[ -n "$time_no_themes_s" ]]; then
echo "Time: $time_no_themes_s"
else
echo "â ī¸ Could not measure (check 'wp plugin list --skip-themes --debug' manually)."
fi
printf " âŗ Measuring time with NO plugins loaded (--skip-plugins)... "
time_no_plugins_s=$(_get_wp_execution_time plugin list --skip-plugins)
if [[ -n "$time_no_plugins_s" ]]; then
echo "Time: $time_no_plugins_s"
else
echo "â ī¸ Could not measure (check 'wp plugin list --skip-plugins --debug' manually)."
fi
printf " âŗ Measuring base time (ALL plugins & theme active)... "
base_time_s=$(_get_wp_execution_time plugin list)
if [[ -z "$base_time_s" ]]; then
echo "â Error: Could not measure base execution time (all plugins & theme active)." >&2
echo "Please ensure WP-CLI is working correctly. Try 'wp plugin list --debug' manually." >&2
return 1
fi
echo "Base time: $base_time_s"
echo ""
# Get a list of active plugin slugs.
# 'mapfile' reads lines into an array, which is robust.
mapfile -t active_plugins < <(command wp plugin list --field=name --status=active)
if [[ ${#active_plugins[@]} -eq 0 ]]; then
echo "âšī¸ No active plugins found to test for individual impact."
echo "â
Test Complete (baselines reported above)."
return 0
fi
echo "đ Measuring impact of individual plugins (compared to '$base_time_s' base time):"
echo "A larger positive 'Impact' suggests the plugin contributes more to the load time of this specific WP-CLI command."
echo "---------------------------------------------------------------------------------"
printf "%-40s | %-15s | %-15s\n" "Plugin Skipped" "Time w/ Skip" "Impact (Base-Skip)"
echo "---------------------------------------------------------------------------------"
for plugin in "${active_plugins[@]}"; do
time_with_skip_s=$(_get_wp_execution_time plugin list --skip-plugins="$plugin")
if [[ -n "$time_with_skip_s" ]]; then
# Remove 's' suffix for calculations
local base_num=${base_time_s%s}
local skip_num=${time_with_skip_s%s}
# Use awk for floating-point arithmetic
local diff_s
diff_s=$(awk -v base="$base_num" -v skip="$skip_num" 'BEGIN { printf "%.3f", base - skip }')
local impact_sign=""
# Check if diff is positive using a robust numeric comparison
if [[ $(awk -v diff="$diff_s" 'BEGIN { print (diff > 0) }') -eq 1 ]]; then
impact_sign="+"
fi
# Store results for sorting later
results+=("$(printf "%.3f" "$diff_s")|$plugin|$time_with_skip_s|${impact_sign}${diff_s}s")
else
# Store error result if time couldn't be measured
results+=("0.000|$plugin|Error|Error measuring")
fi
done
# Sort results by the numeric impact value (first field) in descending order
mapfile -t sorted_results < <(for res in "${results[@]}"; do echo "$res"; done | sort -t'|' -k1,1nr)
# Display sorted results
for result_line in "${sorted_results[@]}"; do
local p_name=$(echo "$result_line" | cut -d'|' -f2)
local t_skip=$(echo "$result_line" | cut -d'|' -f3)
local i_str=$(echo "$result_line" | cut -d'|' -f4)
printf "%-40s | %-15s | %-15s\n" "$p_name" "$t_skip" "$i_str"
done
echo "---------------------------------------------------------------------------------"
echo ""
echo "â
Test Complete"
echo ""
echo "đĄ Note: This script measures impact on 'wp plugin list --debug' command execution time."
echo "Actual impact on front-end or admin page load times may vary. For comprehensive"
echo "profiling, consider tools like Query Monitor (plugin) or Xdebug."
echo ""
}
find_slow_plugin