Have you ever inherited a WordPress site or installed multiple plugins and wondered, "Where on earth is this shortcode defined?"
Searching through thousands of files using "grep" or a code editor can be time-consuming. Fortunately, WordPress stores all registered shortcodes in a global variable called $shortcode_tags. By combining this with PHP’s Reflection API, we can find the file and line of the callback definition. That is not necessarily the line where the shortcode was registered.
The Ultimate Solution: "Shortcode Hunter" Script
This script goes beyond simple registration checks. It offers two powerful modes:
- Registry Reflection: Instantly finds active shortcodes using PHP's Reflection API.
- Deep Physical File Scan: If a shortcode is hidden (e.g., wrapped in
!is_admin()checks), it physically scans your/wp-content/plugins/and/themes/directories to find candidate files containing the shortcode name. A text match still needs inspection before it can be treated as registration evidence.
Installation (MU-Plugin Method)
The most reliable way to use this tool is as a "Must-Use Plugin" (MU-Plugin). MU-plugins load before ordinary plugins, while this script performs its inspection at shutdown. The registry it sees belongs to the request being processed.
- Create a file named
00-dicky-shortcode-hunter.phpin your/wp-content/mu-plugins/directory.- If the
mu-pluginsdirectory doesn't exist, create it inside/wp-content/.
- If the
- Paste the code below into that file.
<?php
/**
* Snippet Name: Ultimate Shortcode Hunter (Level 2)
* Description: Find shortcode sources via Registry reflection OR Deep Physical File Scan. Includes "Nuclear" all-listing.
* Version: 2.3.0
* Author: Dicky Ibrohim
* Author URI: https://www.dickyibrohim.com
*/
// We use 'shutdown' to ensure we capture shortcodes registered late in the load process.
add_action('shutdown', 'ibrohim_shortcode_hunter_execution');
/**
* Main Execution Function
*/
function ibrohim_shortcode_hunter_execution() {
// SECURITY: Only run if the user is an Admin AND the specific trigger is present.
if (!current_user_can('manage_options') || !isset($_GET['find_shortcode'])) {
return;
}
// POWER MOVE: Force disable caching for this specific request to ensure accurate results.
if (function_exists('apache_setenv')) @apache_setenv('no-gzip', 1);
@ini_set('zlib.output_compression', 0);
@ini_set('implicit_flush', 1);
if (!headers_sent()) {
nocache_headers();
}
$target_tag = sanitize_text_field($_GET['find_shortcode']);
global $shortcode_tags;
// UI: High Z-Index Floating Panel (v2.0 Fixed Style)
echo '<div id="ibrohim-shortcode-console" style="
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 450px;
z-index: 999999;
background: #1a1a1a;
border-bottom: 5px solid #00d084;
padding: 25px;
box-shadow: 0 10px 40px rgba(0,0,0,0.8);
font-family: Consolas, Monaco, monospace;
color: #f0f0f1;
overflow-y: scroll;
box-sizing: border-box;
">';
echo "<h2 style='margin: 0 0 10px 0; color: #00d084;'>🕵️ Shortcode Hunter: <span style='color:#fff'>[" . ($target_tag === 'all' ? 'NUCLEAR: ALL' : $target_tag) . "]</span></h2>";
echo "<p style='margin: 0 0 20px 0; color: #aaa; font-size:13px;'>Context: " . (is_admin() ? 'Admin Dashboard' : 'Front-End') . " | Total Registered: " . count($shortcode_tags) . "</p>";
if (empty($shortcode_tags)) {
echo "<h3 style='color: #ff6b6b;'>⚠️ No shortcodes registered in this context.</h3>";
ibrohim_shortcode_hunter_footer();
echo "</div>";
return;
}
$found_in_registry = false;
// 1. Registry Lookup Mode (Handles 'all' or specific tag)
if ($target_tag === 'all') {
echo "<h3 style='color:#00d084'>☢️ NUCLEAR OPTION: All Registered Shortcodes</h3>";
ksort($shortcode_tags);
}
foreach ($shortcode_tags as $tag => $callback) {
// Filter if specific tag requested
if ($target_tag !== 'all' && $tag !== $target_tag) {
continue;
}
$found_in_registry = true;
$info = ibrohim_reflect_shortcode($callback);
echo "<div style='background: #262626; padding: 15px; margin-bottom: 10px; border-left: 4px solid #00d084;'>";
echo "<strong style='font-size: 1.2em; color: #fff;'>[{$tag}]</strong><br>";
echo "<div style='margin-top: 5px; color: #ccc;'>";
echo "📂 File: <span style='color: #4db8ff; user-select: all;'>{$info['file']}</span><br>";
echo "📍 Line: <strong style='color: #ffab40;'>{$info['line']}</strong><br>";
echo "🔧 Type: <span style='color: #aaa;'>{$info['type']}</span>";
echo "</div>";
echo "</div>";
}
// 2. If Not Found in Registry, Fallback to Deep Physical File Scan
if (!$found_in_registry && $target_tag !== 'all') {
echo "<div style='padding: 20px; background: #3d1a1a; border: 1px solid #ff6b6b; margin-bottom:20px;'>";
echo "<h3 style='margin:0; color: #ff6b6b;'>❌ Not Found in Global Registry</h3>";
echo "<p>Starting Deep Physical File Scan... (Scanning /plugins/ and /themes/)</p>";
echo "</div>";
flush(); ob_flush();
$dirs = [WP_CONTENT_DIR . '/plugins', WP_CONTENT_DIR . '/themes'];
$match_count = 0;
foreach ($dirs as $dir) {
if (!is_dir($dir)) continue;
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS));
foreach ($iterator as $file) {
if ($file->getExtension() !== 'php') continue;
$handle = fopen($file->getRealPath(), "r");
if ($handle) {
$line_num = 0;
while (($line = fgets($handle)) !== false) {
$line_num++;
if (strpos($line, $target_tag) !== false) {
$match_count++;
echo "<div style='border-left:3px solid #ff6b6b; padding:10px; background:#222; margin-bottom:5px;'>";
echo "📂 <strong>" . str_replace(WP_CONTENT_DIR, '...', $file->getRealPath()) . "</strong><br>";
echo "📍 Line $line_num: <code>" . htmlspecialchars(trim(substr($line, 0, 150))) . "</code>";
echo "</div>";
flush(); ob_flush();
}
}
fclose($handle);
}
}
}
if ($match_count === 0) {
echo "<p style='color:#ff6b6b;'>No physical matches found for \"$target_tag\".</p>";
} else {
echo "<p style='color:#00d084;'>Scan complete. Found $match_count potential match(es).</p>";
}
}
ibrohim_shortcode_hunter_footer();
echo '</div>'; // End container
}
/**
* Helper: Reflector to extract file path and line number (v2.0 Logic)
*/
function ibrohim_reflect_shortcode($callback) {
try {
$ref = null;
$type = 'Unknown';
if (is_string($callback) && strpos($callback, '::') !== false) {
$callback = explode('::', $callback);
}
if (is_array($callback)) {
$type = 'Class Method';
$ref = new ReflectionMethod($callback[0], $callback[1]);
} elseif (is_string($callback) && function_exists($callback)) {
$type = 'Standard Function';
$ref = new ReflectionFunction($callback);
} elseif ($callback instanceof Closure) {
$type = 'Closure / Anonymous';
$ref = new ReflectionFunction($callback);
} elseif (is_object($callback) && method_exists($callback, '__invoke')) {
$type = 'Invokable Object';
$ref = new ReflectionMethod($callback, '__invoke');
}
if ($ref) {
return [
'file' => $ref->getFileName(),
'line' => $ref->getStartLine(),
'type' => $type
];
}
} catch (Throwable $e) {
return ['file' => 'Reflection Error: ' . $e->getMessage(), 'line' => '?', 'type' => 'Error'];
}
return ['file' => 'Native/Unknown', 'line' => '?', 'type' => 'Internal'];
}
/**
* Footer Attribution
*/
function ibrohim_shortcode_hunter_footer() {
echo "<div style='margin-top:20px; padding-top:15px; border-top:1px solid #333; font-size:11px; opacity:0.8; text-align:right;'>";
echo "Crafted with precision by <a href='https://www.dickyibrohim.com' style='color:#00d084; text-decoration:none;' target='_blank'>Dicky Ibrohim</a>";
echo "</div>";
}
Interpreting the Result
A shortcode is a short marker that lets a WordPress page call a function. An older page may depend on it; removing the supplying plugin can remove part of the page. Tracing the source helps an owner decide what needs maintenance, migration or replacement.
The WordPress shortcode API pairs a name with a callback, the function that handles it. PHP Reflection helps identify the function’s file. Several shortcodes may share that function, so repeated source locations can be legitimate.
The physical scan is a fallback when the target is absent from a non-empty registry. With an empty registry, this script returns early. File matching searches text in the plugin and theme directories it scans, not the entire database, MU-plugin folder or external services. A matching file is a candidate, not proof of registration.
Conditional registration can produce different results on the front end and dashboard. Use a request representative of the affected page. Absence from one request does not prove the shortcode is never available.
How to Use It
Once installed in your mu-plugins folder, you can trigger the hunter by simply adding parameters to your URL.
1. Front-End Check
Visit any page on your front-end and append ?find_shortcode=your_shortcode_name.
Example:
https://yoursite.com/?find_shortcode=my_test_shortcode
2. Admin Dashboard Check
If you are troubleshooting something specifically in the admin area:
Example:
https://yoursite.com/wp-admin/?find_shortcode=my_test_shortcode
☢️ The "Nuclear" Option (Find Everything)
If you still can't find it, or simply want to see every single shortcode currently active on your system, use the all keyword:
https://yoursite.com/?find_shortcode=all
This will generate a scrollable list of all registered shortcodes and their exact source files.
The list reflects the registry for that request. This mode does not scan every file for every possible shortcode.
Keep It a Temporary Diagnostic Tool
Use an account with the manage_options capability on a website you are authorized to maintain. Supply one ordinary shortcode name, not an array or malformed test input. The script does not add a nonce or a separate scan-cost limit.
Start on a test copy for a large site. File scans consume resources, so avoid repeated requests. A CDN or server cache can also answer before WordPress runs; the script’s anti-cache calls are not a guarantee across every cache layer.
Debug output reveals internal file paths. Keep it with the authorized team. If you own the business but do not usually install PHP files, ask your technical operator to run the check and explain what depends on the result. A clear diagnosis is more useful than removing plugins one by one on a trading store.
⚠️ IMPORTANT: Clean Up
Please verify and delete the 00-dicky-shortcode-hunter.php file from your mu-plugins directory once you are done debugging. While the script is secured to run only for administrators, it is best practice not to leave debug tools active in a production environment.