Skip to content

Instantly share code, notes, and snippets.

@morosmo
Forked from mikeschinkel/instrument-hooks.php
Last active May 1, 2025 12:36
Show Gist options
  • Save morosmo/e955aa41a59754e7905cc4b42c551253 to your computer and use it in GitHub Desktop.
Save morosmo/e955aa41a59754e7905cc4b42c551253 to your computer and use it in GitHub Desktop.
<?php
/*
Plugin Name: Hook Scanner Pro
Description: Scans plugin folders for WordPress PHP and JS hook usage and displays file, line, arguments, and example usage.
Version: 0.3
Author: ChatGPT
*/
if (isset($_GET['instrument']) && $_GET['instrument'] === 'scan') {
add_action('init', 'scan_plugin_for_hooks');
function scan_plugin_for_hooks()
{
$base_dir = WP_PLUGIN_DIR;
$folder = sanitize_text_field($_GET['folder'] ?? '');
$hook_type = sanitize_text_field($_GET['hook'] ?? '');
$filetype = sanitize_text_field($_GET['filetype'] ?? 'all'); // js, php, or all
if (empty($folder) || empty($hook_type)) {
wp_die('Missing required parameters: folder and hook');
}
$target_path = trailingslashit($base_dir . '/' . $folder);
if (!is_dir($target_path)) {
wp_die("Folder not found: $target_path");
}
$results = [];
if (str_starts_with($hook_type, 'wp.hooks')) {
// Match any wp.hooks.* call
$regex = '/wp\.hooks\.(\w+)\s*\(\s*[\'"]([^\'"]+)[\'"]\s*(?:,\s*([^\),]+))?/i';
$expected_ext = 'js';
$hook_lang = 'JS';
} else {
$regex = '/' . preg_quote($hook_type) . '\s*\(\s*[\'"]([^\'"]+)[\'"]\s*(?:,\s*([^\),]+))?/i';
$expected_ext = 'php';
$hook_lang = 'PHP';
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($target_path)
);
foreach ($iterator as $file) {
if (!$file->isFile()) continue;
$ext = pathinfo($file->getFilename(), PATHINFO_EXTENSION);
if ($filetype !== 'all' && $ext !== $filetype) continue;
if (!in_array($ext, ['php', 'js'])) continue;
$lines = file($file->getRealPath());
foreach ($lines as $line_number => $line_content) {
if (preg_match($regex, $line_content, $matches)) {
if (str_starts_with($hook_type, 'wp.hooks')) {
$js_method = $matches[1];
$hook_name = $matches[2];
$arg_info = isset($matches[3]) ? trim($matches[3]) : '';
} else {
$hook_name = $matches[1];
$arg_info = isset($matches[2]) ? trim($matches[2]) : '';
}
$arg_count = preg_match_all('/\$/', $arg_info, $_);
$results[] = [
'file' => str_replace(ABSPATH, '', $file->getRealPath()),
'line' => $line_number + 1,
'hook' => $hook_name,
'args' => $arg_count,
'code' => trim($line_content),
'type' => strtoupper($ext),
'method' => $js_method ?? $hook_type
];
}
}
}
// Output
echo "<style>table {border-collapse: collapse;} td,th {border: 1px solid #aaa; padding: 5px;} code{background:#f4f4f4; padding:2px 4px;} pre{margin:0;}</style>";
echo "<h2>Scan Results for <code>{$hook_type}</code> in <code>{$folder}</code></h2>";
echo "<table><tr><th>#</th><th>Hook</th><th>File</th><th>Line</th><th>Args</th><th>Type</th><th>Example</th><th>Code</th></tr>";
foreach ($results as $i => $row) {
$example = '';
if ($row['type'] === 'PHP' && in_array($row['method'], ['add_action', 'add_filter'])) {
$args = implode(', ', array_map(fn($i) => '$arg' . $i, range(1, $row['args'])));
$example = htmlspecialchars("{$row['method']}('{$row['hook']}', function({$args}) {\n // your code\n});");
} elseif ($row['type'] === 'PHP' && in_array($row['method'], ['do_action', 'apply_filters'])) {
$args = implode(', ', array_map(fn($i) => "'val{$i}'", range(1, $row['args'])));
$example = htmlspecialchars("{$row['method']}('{$row['hook']}', {$args});");
} elseif ($row['type'] === 'JS') {
$args = implode(', ', array_map(fn($i) => 'val' . $i, range(1, $row['args'])));
$example = htmlspecialchars("wp.hooks.{$row['method']}('{$row['hook']}', function({$args}) {\n // your code\n});");
}
printf(
'<tr><td>%d</td><td><code>%s</code></td><td>%s</td><td>%d</td><td>%d</td><td>%s</td><td><pre>%s</pre></td><td><code>%s</code></td></tr>',
$i + 1,
esc_html($row['hook']),
esc_html($row['file']),
$row['line'],
$row['args'],
esc_html($row['type']),
$example,
esc_html($row['code'])
);
}
echo '</table>';
exit;
}
}
@morosmo
Copy link
Author

morosmo commented May 1, 2025

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment