How to leave a site better than you found it, and with fewer tables.
The short version
Nothing here needed a new plugin. The fix was a small change to a query and a better idea of when to run it. That is usually the case: the expensive part of a site is rarely the code you can see, and adding a layer on top only moves the cost somewhere harder to find. Delete first, then decide what is still missing.
Escaping belongs at the point of output, where a reviewer can see it. When a value has been cleaned three functions earlier, nobody can tell by reading the template whether it is safe, and the next person to touch that line will not know either. We moved every escape next to its echo and the file got shorter and easier to trust.
wp cron event list --fields=hook,next_run_relative
wp transient delete --expired
wp cache flush
What we found first
The review took longer than the fix, and that is the right way round. Most of the time went on working out what the code was meant to do and who depended on it. Once that was written down, the change itself was four lines, a test and a note in the changelog that future maintainers will actually thank us for.
A throwaway site is the cheapest tool in the kit. We can build one in a minute, break it completely and delete it without a single awkward conversation. Everything risky in this post happened there first, including the mistakes we are not going to mention, and nothing touched production until it had survived a full run from a clean start.
Why it matters
Releases go badly when they are exciting. Our best ones are dull: a checklist, a backup someone has actually restored, a rollback plan and a time of day when the people who can fix things are awake. If your release needs courage, something earlier in the process needs more attention, and a calmer Tuesday afternoon will show you what it is.
Keyboard testing costs nothing and finds real bugs. Put the mouse in a drawer and try to use the page with the tab key alone. You will find focus styles that vanish, menus you cannot leave and buttons that are really links. None of these need a specialist to spot, and most of them take minutes to put right.
The part that surprised us
We kept the change small on purpose. It is tempting to tidy everything nearby while the file is open, but every extra line makes the review slower and the rollback riskier. A short diff that does one thing gets merged this week. A long diff that does six things gets argued about until someone quietly closes it.
Scheduled tasks deserve more suspicion than they get. WordPress runs them on the back of ordinary page views, so a slow job can land on a visitor who did nothing to deserve it. List what is registered, work out what each job does and how long it takes, and move the heavy ones to a real system cron.
What we changed
Names matter more than cleverness. When a function says exactly what it returns, the template that calls it reads like a sentence and the bug has nowhere to hide. We renamed more than we rewrote on this project, and the reviewers noticed. Six months from now that will be worth more than any micro-optimisation we could have shipped.
Migrations fail in the details: serialized data, hard-coded URLs and that one plugin nobody remembers installing. We make an inventory before we move anything, then we move it twice, once for practice. The rehearsal always finds something. Finding it on a Wednesday at a desk is much better than finding it on launch night with the client watching.
How we tested it
Good defaults are a kindness to the next person. If a feature only works after someone reads a long page of setup notes, then for most sites it does not work at all. We would rather ship something modest that behaves well on a fresh install than something impressive that needs a careful afternoon before it shows anything.
The numbers moved less than we hoped, and that is worth saying plainly. Posts like this tend to end with a dramatic chart, but real work mostly produces a steady, unglamorous improvement. The page got a little faster, the logs got a lot quieter and the support inbox stopped filling up on Monday mornings. We will take that.
What we would do differently
Logs are the cheapest witness you have. Before anyone proposes a theory, we turn on debug logging on a copy of the site, repeat the problem once and read what it left behind. Half the time the answer is sitting there in plain words, and the other half we at least know which theories to stop discussing.
Permissions tend to drift. A role that made sense at launch picks up one extra capability each year until nobody can say who is allowed to do what. We list the roles, list the people and compare them with what the job actually needs. It is a dull hour, and it has found more real problems than most scanners.
The boring fix
Every feature has a running cost, even when nobody touches it. It needs testing on each upgrade, explaining to each new editor and checking in each review. When a client asks for something small, we ask who will look after it in two years. Sometimes the honest answer is that it should stay a good idea.
Hannah Weiss May 30, 2024
Good write-up. I would add a note about checking the logs before you clear anything.
Noah Bennett Mar 29, 2026
This saved me an afternoon. The bit about testing the cold path first is going on the team wiki.
Noah Bennett Aug 12, 2024
Tried this on a client site this morning. The query count dropped straight away.
Grace Tanaka Jan 07, 2025
Thanks for showing the failed attempts as well. That is the useful part.
Ravi Menon Oct 25, 2024
I disagree slightly on the rollback plan, but the rest matches what we do.
Grace Tanaka Aug 18, 2025
The point about small diffs is the one I keep having to repeat at work.
Ravi Menon Mar 23, 2025
Could you share the checklist as a plain text file? I would like to adapt it.
Hannah Weiss Jun 05, 2025
We do something similar with WP-CLI in our deploy step and it has been solid.
Felix Moreau Oct 31, 2025
Sending this to a colleague who is about to start a migration next week.
Lena Fischer Jan 14, 2026
Nice. One small correction: that hook fires earlier than the post suggests.
Hannah Weiss Jun 11, 2026
We hit the same thing last spring and blamed the host for a month. Wish I had read this then.
Felix Moreau Aug 24, 2026
Does this still hold on a site with a persistent object cache, or does the picture change?