WordPress PHP 8 Upgrade Inventory
Point VS Code at a WordPress codebase and get back what in your own plugins
and themes stops working on a modern PHP, what still runs but raises a
deprecation notice, and what works today and is worth fixing while you are in
there — in the Problems panel, on the line it sits on.
Hosts are moving sites to PHP 8.2 and 8.3 whether or not the code is ready. The
hard part is rarely the fixing; it is finding out how much there is and where,
before anyone can plan. This reads the codebase and tells you.
How to use it
1. Open the WordPress codebase as a folder in VS Code (File → Open Folder).
Either the install root — the level with wp-content/ in it — or a single
plugin or theme folder on its own, which is the quickest way to try it.
2. Start a scan. Any one of these:
- It offers. If the folder holds a WordPress plugin or theme, a
notification appears: "WordPress code detected. Scan it for PHP 8 upgrade
work?" Click Scan. It never scans on its own, and Don't ask again for
this folder is remembered for that folder only.
- Command Palette. Ctrl+Shift+P
(Cmd+Shift+P on macOS), then type
WordPress and pick WordPress Upgrade: Scan workspace for PHP 8 upgrade
work.
- Right-click a folder in the Explorer → WordPress Upgrade: Scan this
folder. That scans just that folder, which is what you want when only one
plugin matters.
3. Read the results in two places.
- The Problems panel — Ctrl+Shift+M
(Cmd+Shift+M), or View → Problems. One entry
per occurrence, on the exact line and column. Click one to jump to the code.
Each entry names the version that removed or deprecated the thing it found,
and its code links to the decision it belongs to. Filter the panel by typing
wp-scan.
- The Output panel — View → Output, then choose WordPress PHP 8 Upgrade
Inventory in the dropdown. This is the full report: what is installed and
who owns it, totals per severity, and examples per finding. It opens by
itself when a scan finishes.
4. The other two commands, both in the Command Palette under WordPress
Upgrade:
- Open the inventory as Markdown — the same report as a document you can
paste into a ticket or a wiki. Scans first if you have not already.
- Clear the findings — empties the Problems panel and the report.
5. Two settings (File → Preferences → Settings, search wpScan):
wpScan.severity and wpScan.maxProblemsPerFinding, both described in
Settings below.
Nothing here needs an account, a network connection, or write access to your
code.
What it does
Three severities, because "deprecated" covers two very different problems
A PHP upgrade inventory that lumps everything together is not a work plan.
Findings are grouped by what actually happens when you upgrade:
- This stops working. The code no longer runs at all —
create_function(),
each(), the mysql_* extension, $string{0}, a PHP 4 style constructor, a
jQuery method removed in 3.0. These are reported one severity level higher
than everything else.
- This still runs, and warns. A deprecation notice today and a removal
later:
strftime(), utf8_encode(), an optional parameter before a required
one, $wpdb->escape(), wp_title() in a theme that declares title-tag
support.
- This works, and is a problem worth fixing now. Portability and security
issues that an upgrade is the cheapest moment to deal with: a variable
interpolated into SQL with no
prepare(), a hard-coded wp_ table prefix,
curl_init() instead of the HTTP API, session_start(), eval(), a
superglobal echoed without escaping, a plugin file with no ABSPATH guard.
Nine decisions, 53 rules, each citing the version that broke it
| Decision |
Rules |
| 1. Know what is installed and who owns it |
from file headers |
| 2. Remove PHP that no longer exists |
14 |
| 3. Fix what PHP deprecated but still runs |
9 |
| 4. Replace deprecated WordPress APIs |
9 |
| 5. Make database access prepared and portable |
3 |
| 6. Stop bypassing WordPress for HTTP, files, and paths |
9 |
| 7. Escape output and guard direct file access |
5 |
| 8. Decide the jQuery and front-end upgrade |
4 |
| 9. Set the target versions and rehearse the upgrade |
from file headers |
Every rule names the PHP or WordPress version that removed or deprecated the
thing it matches, so a finding can be checked against the upstream changelog
instead of taken on trust.
Decisions 1 and 9 carry no rules on purpose. They are answered from the plugin
and theme headers — the Requires PHP and Tested up to lines, or their
absence — so they appear in the panel on the header file itself rather than
being quietly dropped.
It skips what an update replaces anyway
Counting a create_function() inside somebody else's plugin buries the lines
that are actually yours, so it does not count it.
- WordPress core —
wp-admin/, wp-includes/, and the wp-*.php files at
the root.
- Distributed plugins and themes — anything carrying a WordPress.org
readme.txt with a Stable tag: line. They are listed separately with their
Requires PHP and Tested up to headers, because those are a decision.
wp-content/uploads, node_modules, vendor, and minified bundles.
wp-config.php is never opened. Nor is anything else that normally holds
credentials. The report says the file exists and moves on.
What it deliberately does not do
- It does not parse PHP. It is regex-and-line matching with
WordPress-shaped patterns. That buys speed, zero dependencies, and the
ability to scan a codebase that does not even run — and it costs precision.
Read it as "here is where to look", not "here is the complete list".
- A clean report is not a guarantee. Deprecations that depend on runtime
types are not text-detectable and are not reported: passing
null to a
non-nullable internal parameter (PHP 8.1), implicit float-to-int precision
loss (8.1), dynamic property creation (8.2).
- It is not a substitute for running the code. Rehearsing the upgrade on a
copy is still the test.
- It never writes, and never connects to the network. Not to WordPress.org,
not to telemetry, not to us. It has no dependencies.
Settings
| Setting |
Default |
What it does |
wpScan.severity |
Information |
How findings appear in Problems. They are decisions, not errors. Code that stops working on a modern PHP is always reported one level higher. |
wpScan.maxProblemsPerFinding |
200 |
Caps Problems entries per kind of finding so one repetitive pattern cannot bury the rest. The counts in the report are always the real totals. |
The same scanner without VS Code
The engine here is one dependency-free Node file, and it is a free download
that works as a CLI:
node wp-scan.mjs /path/to/wordpress
node wp-scan.mjs /path/to/wp-content/plugins/my-plugin
node wp-scan.mjs /path/to/wordpress --markdown > upgrade-inventory.md
node wp-scan.mjs --rules
https://practicalmodules.com/tools/wordpress-php-8-upgrade-scanner/
The nine decisions, in full
Every finding links to a section of the free WordPress PHP 8 upgrade
checklist — what to record for that decision, and a done when test for
telling whether it is actually settled. No signup, nothing to buy.
https://practicalmodules.com/guide/wordpress-php-8-upgrade-checklist/
If you are on Drupal instead
Drupal 7 Migration Inventory
is the same idea for a Drupal 7 codebase, from the same shop.
Licence
MIT. Original work; no code, data, or text is copied from any WordPress plugin,
theme, or tool.