My hunt for hidden plugin junk in the WordPress database — And back (to manual) again

Previously on the CogitActive Saga:
That realization brings me here, asking myself: Is there a safer way to do this? This time, I’m turning to the very thing I usually avoid—another plugin. But not just any plugin. I need a cleanup tool that’s precise, trustworthy, and (dare I say) smarter than me when it comes to distinguishing junk from gold. Can a plugin help clean up after plugins?

It took me two posts—Chasing plugin promises and From illusion to disillusion—to figure this out, but the short answer is NO! Some tools do claim to identify orphaned tables, trace options back to their source, or clean up abandoned cron jobs. But those are the very features locked behind paywalls. And even then, they offer educated guesses at best: hints at orphaned tables and, maybe even, leftover options. Maybe. Which, to be fair, is as far as any plugin can go. Because here’s the inconvenient truth: no plugin can definitively know what’s junk in your database. No algorithm can predict whether a cryptically named database entry is critical or disposable without real context—your context. Theme customizations, multisite quirks, obscure plugin remnants… It’s just too specific. So, why would I/you pay for something that doesn’t actually exist?

The problem is that there’s literally no way to know for sure, detect with 100% accuracy, whether a given piece of data in the database is really a “leftover” from some plugin or not and whether it’s used by anything or not.Adam Czajczyk

After all the detours, the only path that remains is the one I started on. So, let me take a deep breath, roll up my sleeves, and summon the courage to dive back into the cryptic depths of phpMyAdmin. There’s indeed only one reliable solution: go back to manual—and this time, finish the job. No shortcuts. No safety nets (other than my backups). Just me. The database. And the resolve to see it through.

The plan — revisited

Previously, I had a plan. A good plan. A plugin-assisted reconnaissance mission to identify and eliminate leftover junk in my WordPress database. But as you may recall from Part 3 of this miniseries, Step 2 (i.e., Reconnaissance with Database Cleaner, or another plugin for that matter) failed spectacularly. The bonus step? Also a bust. So, here I am—back to square one. Or rather, back to phpMyAdmin. The blueprint hasn’t changed. It’s the same job I set out on in Part 1: identify and remove leftover plugin junk from my WordPress database. But now, I know better than to outsource it.

Now, this isn’t my first time spelunking through phpMyAdmin. But this time, I’m not just poking around—I’m finishing what I started. Here’s how I plan to tackle the final sweep.

Backup (again!)

Before I even think about touching a single row or table, I’ll back up everything. Because if I mess up, I want to be able to roll back.

And I’ll say it louder for the people in the back: Backup! Again! Not just once. Not just casually. Back up everything. Do it thoroughly. Do it systematically. Treat your backup like the parachute it is. There’s a reason seasoned developers and sysadmins chant this like a mantra. Backups aren’t a luxury. They’re your emergency escape hatch.

Because here’s the harsh truth: phpMyAdmin doesn’t come with an “Undo” button. Once you click Delete, there’s no going back unless you’ve made arrangements beforehand. So before you roll up your sleeves and dive into digital surgery, make sure your recovery plan is solid. And test your backup, too—an unusable backup is just a false sense of security dressed as a ZIP file.

After you make your backup, go ahead and restore it so you can see what it’s like before you get in an emergency situation. Remember, if you have an untested backup system, you don’t have disaster recovery, you have hopes and wishes.Cal Evans

I’ll be following the method outlined by Brian Jackson 1 — first, search the database and take care of the rows where the remnants of deleted plugins will be found. Second, I’ll move on to identifying orphaned tables. Last, I’ll tackle leftover cron jobs.

When I first skimmed Brian Jackson’s article—and also while cleaning up after Totalrating—I didn’t give much thought to the sequence: rows first, tables second. But is that really the best order? To find out, I asked Gemini. It confidently told me that the safest and most effective method was to clean up orphan rows in the wp_options table first, then move on to orphan tables. Something about better performance 2, fewer errors, and easier identification. The next day, I asked Gemini again. This time, it told me the exact opposite: start with tables, then rows. Same tone, completely reversed logic. So, I turned to Copilot (twice). Guess what? Déjà vu. Opposite answers again. Naturally, I tried searching for a definitive answer on my own, but to no avail. So, does the order matter? I don’t know. What made me settle on that order in the end? One compelling reason sealed the deal:

Deleting a table prematurely could break your site if it’s still referenced by active options.Copilot

Rows

One of the most challenging aspects of cleaning up is figuring out how deleted plugins are represented in the database. What search terms should I even use? I don’t recall every plugin I’ve ever installed and removed—plus, many don’t leave behind their display names. Instead, they often lurk as cryptic identifiers. To make sense of it, I checked the uninstall_plugins row in the wp_options table. Sadly, it only gave me part of the picture:

classic-editor – vicomi-feelbacks – userfeedback – totalrating – wp-optimize

And not an accurate one, for that matter: totalrating was deleted, but installed again! In fact, this was the only one listed in active_plugin. Odd!

Tables

Tables can be bulky—loaded with data that’s either outdated or completely irrelevant to your site’s current functionality. Clearing them out can trim a significant chunk of unnecessary information in one go, reducing overall database size and complexity.

Thankfully, these tables are usually easier to identify—especially if you’re familiar with plugin naming conventions (and, of course, the default WordPress tables). Still, caution is key. I’ll do a triple-check with Google—though I won’t bother quizzing Copilot or Gemini—before I press Drop.

Cron jobs

Plugins don’t just leave behind rows and tables—they often schedule recurring tasks, known as cron jobs, that quietly run in the background. These can range from checking for updates to purging temporary files or triggering custom hooks.

The problem? When the plugin that created them disappears, the scheduled tasks often don’t. They linger, unexecuted but still present, cluttering the database and subtly dragging down performance.

WordPress stores these cron jobs in the wp_options table (typically under the option_name of cron), serialized and jam-packed with data. Dissecting them takes patience—and sometimes a strong stomach. I’ll comb through these entries carefully, looking for hooks or callbacks that reference long-gone plugins. Anything that smells suspicious gets flagged for deeper scrutiny.

And just like with rows and tables, I’ll cross-check everything before deletion. Because when it comes to cron jobs, it’s not always clear what each one does or whether it’s still needed. Better safe than rebuilding a crashed schedule from scratch.


So, that’s the plan. No plugins. No shortcuts. Just me, phpMyAdmin, and a healthy dose of paranoia. I’ll revisit my database with fresh eyes, informed by the lessons of the last three posts, and cross-reference everything against my own experience. Tables, options, cron jobs… every line of data gets a second look. If I don’t recognize it or can’t trace its origin, it stays. If I know it’s junk, it goes. No guessing. No gambling. Still, I’ll be praying to the gods of SQL and WordPress that I don’t crash my site in the process. If you hear a distant scream, it’s probably me deleting the wrong row.

The hunt

What follows isn’t theory—it’s real, hands-on exploration. I’m armed with caution, a half-decent memory of past plugins, and a checklist forged from trial and error. Each plugin has left a unique fingerprint, and I’m determined to find them. One entry at a time. One ghost at a time.

“What’s the worst that could happen?”

Katorymnd Reaction Process Plugin

This is the plugin that pulled the first thread—and what a tangled web followed. My cleanup obsession started here, when traces of Katorymnd refused to disappear, haunting the database like code ghosts.

Back in Part 1, I ran a full search for traces of “katorymnd”—but didn’t touch a thing. Not a single row deleted. Not one table dropped. Just observation. Because when you’re staring down cryptic entries in phpMyAdmin, hesitation isn’t weakness—it’s survival.

Out of the 19 matches (7 in wp-options, 5 in wp-usermeta, 6 in wp-posts, and 1 in wp-totalrating_widgets), I now deleted the following rows:

  • katorymnd_wlse_version (wp-option)
  • katorymnd_rating_type (wp-option)
  • katorymnd_header_bg_color (wp-option)
  • katorymnd_filter_settings (wp-option)
  • katorymnd_emoji_theme (wp-option)
  • katorymnd_reaction_user_name (wp-usermeta)
  • katorymnd_reaction_user_email (wp-usermeta)
  • katorymnd_reaction_full_names (wp-usermeta)
  • katorymnd_reaction_profile_picture (wp-usermeta)
  • katorymnd_reaction_user_id (wp-usermeta)

Then, I dropped the following 7 tables:

  • wp_katorymnd_kr_abuse_reports
  • wp_katorymnd_kr_comments
  • wp_katorymnd_kr_custom_user_sessions
  • wp_katorymnd_kr_intialid_commentid_page
  • wp_katorymnd_kr_reactions
  • wp_katorymnd_kr_user_details
  • wp_katorymnd_kr_user_ratings

Nothing crashed!

“So far, so good.”

Reactions By Vicomi

This plugin was a user reaction plugin that promised customizable emotional feedback through text or emoji-based buttons. Attracted by its claim to offer flexibility between emoji icons and text labels, I explored it as part of my search for a replacement for React & Share. However, the plugin appeared abandoned, and attempts to access its settings—particularly the switch from emoji to text—were unsuccessful, ultimately leading to its removal.

With “vicomi” as a search term, I obtained 8 matches (7 in wp-options and 1 in wp-posts). I do indeed mention the above info in a post. As for the 7 matches in wp-options, you should already know that one was in uninstall_plugins. I deleted the 6 others:

  • vicomi_feelbacks_uuid
  • vicomi_feelbacks_api_key
  • vicomi_feelbacks_replace
  • vicomi_feelbacks_active
  • vicomi_checkboxes
  • vicomi_exclude_pages_id

There was no cron job and no table!

“So far, so good.”

UserFeedback

Recommended by Copilot, although not a true reaction tool, this plugin turned dead end. The features I needed were locked behind a paywall, and its core functionality didn’t align with my goals. Time to retrace the remnants of this error: 16 matches to be precise (13 in wp-options and 3 in wp-posts). The wp-option entries were fairly recognizable (and quickly deleted):

  • userfeedback_usage_tracking_config
  • userfeedback_over_time
  • userfeedback_db_version
  • userfeedback_current_version
  • userfeedback_settings
  • userfeedback_notifications
  • userfeedback_onboarding_complete
  • userfeedback_notifications_run
  • userfeedback_parsed_addons
  • userfeedback_version_upgraded_from

But one entry was in cron: “userfeedback_usage_tracking_cron.” How to remove it? I could use the WP Crontrol plugin (or maybe try again the Database cleaner one), but decided to leave this one entry for now. Honestly, my mental bandwidth had already maxed out, and chasing this one leftover felt like tipping the scale from productive to punishing.

Instead, I dropped the following four tables:

  • wp_userfeedback_heatmaps
  • wp_userfeedback_heatmap_recordings
  • wp_userfeedback_surveys
  • wp_userfeedback_survey_responses

“So far, so good.”

WP-optimize

Ah yes, the poetic irony: cleaning up after a cleanup plugin. If a plugin built to optimize ends up needing to be optimized out… what hope is there for the rest? And with 27 matches for “wpo” (I knew from Part 3 that this plugin uses this convention), this one left quite a mess; even if I do not count the 6 in wp-posts.

The usual suspects were in wp-options (5 and 7 for my two sites; remember this plugin was multisite compatible); I deleted only those:

  • wpo_update_version
  • wpo_update_version
  • updraft_lock_wpo_page_cache_preloader_creating_tasks
  • updraft_lock_wpo_minify_preloader_creating_tasks

Again, I didn’t mess up with cron. Nor did I bother with the transients.

“So far, so good.”

Da Reaction

My uninstalled_plugin list was done—my job not! Remember (in Part 3), Database Cleaner digs this one name, Da Reaction, like a lost sock behind the dryer. No frills, no drama—just proof that even after the big cleanup, surprises still linger. Looks like the final pass wasn’t so final after all: 18 matches (4 + 1 in wp-options, 1 in wp-posts, and 6 + 6 in tables that I cannot name). The deletion was quick:

  • widget_da-reactions-most-voted-widget
  • da-reactions_general
  • widget_da-reactions-most-voted-widget (yep twice, in two tables)
  • da-reactions_buttons
  • da-reactions_graphic

“So far, so good.”

Vuukle Comments, Reactions, Share Bar, Revenue

This plugin wasn’t flagged in the uninstall_plugins list either. To track it down, I had to rely on something far less technical: memory. Or more precisely, a deep scroll through my own blog posts about reaction plugins. It wasn’t much, but it was enough to warrant a fresh search. Because if it touched the site, even briefly, it might’ve left something behind. Not much, though: only 4 matches (1 + 1 in wp-options and 2 in wp-posts). Easy to delete then:

  • Vuukle_App_Id
  • Activated_Vuukle_Plugin_Date

“So far, so good.”

Post Reaction – Add reaction buttons in any posts

Using the same strategy that helped uncover Vuukle—alongside confirming activity through the recently_activated list—I identified another potential plugin: Post Reaction by bPlugins. It stood out not just by name but also by a lingering breadcrumb from a previous search: two custom tables named wp-bppr-post-reactions. The connection seemed more than coincidental. Given the table prefix, it’s reasonable to assume that bppr was the next keyword to explore.

With only two matches (1 + 1 in wp-option; bppr_post_reactions_database_version twice), it was not that bad. I deleted them, followed by the two tables (which were empty anyway).

“So far, so good.”

React & Share

This was the first plugin I truly installed—not just tested and tossed aside. React & Share marked the beginning of my journey into user reaction tools. Naturally, I remembered it. Yet, when I searched the database for traces, nothing came up. Not a single match. It was as if the plugin had vanished without a trace. That is, until I combed through the wp-options table manually—row by row, content included—and spotted a cryptic entry: gs-user-email. The value? An email alias I had created specifically for React & Share. That was the breadcrumb I needed. Armed with a new search term (gs-), I dove back in: 157 matches! I did the usual cleaning, but I will not share the details here, other than to say that I only deleted all the 15 rows in wp-options (all with Autoload = “yes”, by the way).

“So far, so good.”

Reaction-buttons by Jakob Lenfers

Out of ideas and running low on leads, I searched for the term “reaction”—a fitting full-circle moment, given that this entire mess began with my quest for a reaction plugin. To my surprise, Da Reaction resurfaced in wp_options, this time under the prefix da_reaction (not da-reaction), with a lingering entry: da_reactions_db_version. I deleted it.

But the real twist came next. I stumbled upon another entry. Multiple entries, actually. At first, the prefix reaction-buttons gave me pause—it could’ve belonged to ShareThis Reaction Buttons. But then I saw them: my four old reactions—“Like, Agree, Disagree, Thank you”—still sitting in reaction_buttons_button_names. That was all the confirmation I needed. This was my old, unfortunately abandoned, friend. I launched a fresh search for reaction_buttons and found 94 matches.

This plugin has been closed as of February 16, 2025 and is not available for download. Reason: Security Issue.

Given the lingering pain from having to delete all the votes—a difficult decision I shared in A necessary reset—my apologies!—I couldn’t bring myself to let this one go. After some reflection, I knew what needed to be done. No matter how sentimental those reactions had become—keeping abandoned plugin data in the database was no longer an option. The security risk was real, and nostalgia wasn’t worth the vulnerability. So I did what I had to.

Revisiting Database Cleaner

After blazing through waves of plugin cleanup and systematic purges, it’s time for a pause—not to second-guess, but to double-check. There’s a lingering suspicion that I didn’t extract all plugin debris. I’m fully aware some junk probably slipped through. For this reason, one plugin deserves a revisit: Database Cleaner by Meow Apps. This isn’t an attempt to redeem what was already disappointing. It’s a deliberate reassessment. Besides, this plugin was never network activated. I intend to flip that switch to see whether the outcome improves—and whether multisite recognition evolves beyond those 70 “unknown” tables.

Cron Jobs left hanging: One task I never truly tackled was the cron tab review—hidden behind the plugin’s “Expert Mode.” I dismissed it too hastily last time. This time, I plan to comb through it deliberately. If the plugin lets me clean those from within its interface, all the better.

“Why this plugin and not others?”
“Because it didn’t lie. Unlike the other tested plugin peddling hallucinated revisions, Database Cleaner kept its delusions in check.”

So, I gave it another shot. I reinstalled Database Cleaner—well, not exactly fresh, as the telltale dbclnr remnants in the database reminded me it never truly left. Still, I went ahead with a network activation, curious to see if broader multisite access might yield different results.

First stop: the Tables tab on the blog. No improvement. The dreaded “70 unknown” count stared back at me unchanged. But when I shifted to the main site, something curious happened—tables from one plugin were now recognized. Not all. Just one. Still, a sliver of progress. The wp_ tables belonging to the blog itself? Still categorized as unknown, of course. So, one mysterious table remains… mysterious.

Next up, the Options tab. The same story: far too many entries still marked as “unknown.” But at least the plugin properly identified WordPress core entries (and itself), which was more than I could say last time. That gave me confidence in what not to touch. I didn’t spot anything worth deleting, so I hopped back to the blog’s Options tab. A few entries looked suspicious—some even had autoload set to “yes”—but erring on the side of caution, I kept my hands off. No point playing roulette with the registry.

Then came the cron jobs, where things finally clicked. On the blog, 23 scheduled tasks popped up. I immediately recognized a few:

  • wpo_smush_clear_backup_images
  • wpo_weekly_cron_tasks
  • userfeedback_usage_tracking_cron

Three clicks on the cross, three clean deletes. Gone. No crash. Easy. Satisfying. Moving on to the main site: 25 counts. All looked legitimate—no ghosts from long-deleted plugins lurking about. Cleanup complete.

I closed the chapter with a Network Deactivate followed by Delete. The system, ever so polite, asked: “Are you sure you want to delete Database Cleaner and its data?” Nice try. I already knew better. Some traces would linger—the dbclnr leftovers being the quiet proof. Because in WordPress, “complete uninstall” is often just marketing lingo. Still, for what it’s worth, this plugin got its second chance. It wasn’t perfect. But it was honest.

The end

What began as a simple plugin reinstall spiraled into a full-blown excavation. From the first unsettling discovery in phpMyAdmin to the final click of “Delete” on Database Cleaner, this quadrilogy has been less about cleaning and more about learning—about WordPress, about plugins, and about the messy truth behind “uninstall.”

Uninstalling a plugin isn’t the end—it’s the beginning of a cleanup I didn’t know I signed up for.

Uninstalling a plugin isn’t the end—it’s the beginning. No tool can replace context. Only you know what’s junk and what’s legacy. Manual cleanup is tedious, but it’s the only way to be sure. Backups aren’t optional—they’re your parachute. And above all, keep a log. Your future self will thank you.

Did I remove every single leftover? Honestly… I don’t think so. There’s always a chance some rogue setting or orphaned meta entry is still lurking in the digital shadows. What I did accomplish, however, was my main mission: getting rid of the troublesome Katorymnd Reaction Process Plugin and a whole trail of others that had quietly piled up over time. While the database may never be spotless, it’s now leaner, safer, and better understood. That’s a win. And one thing’s for sure—I didn’t break anything. The site is still standing, and that alone feels like a triumph.

Was I stressed? Big time. This wasn’t just a spring cleaning—it was a psychological gauntlet. It took four full posts and even an “Intermission” to psych myself up. But I got through it, with fingers crossed and a kind of stubborn relief. Whether this whole purging spree will speed up my blog or not, I can’t say yet (and it wasn’t my goal anyway). But I did clear out a lot of junk that should’ve never overstayed their welcome. It’s wild that plugins can dump all that into your database but rarely clean up after themselves.

This clearly won’t be my last deep dive into the database—I’m bracing for many other rounds. But next time, I won’t be caught off guard. Now I know to document plugin activity more meticulously and track their impact before cleaning up thoroughly. That proactive mindset is already paying off. And most importantly, this whole saga has only solidified my long-held hesitation about plugins: the fewer I depend on, the better. If I needed proof, this mess delivered it.


1 Brian Jackson (2023) How to Uninstall a WordPress Plugin (the Proper Way) (external link). Kinsta. ^
2 One of the key reasons to start with rows is their direct impact on performance—especially autoloaded options, which are loaded on every single page request. This happens even if the plugin responsible for those entries has long been deleted. For this reason, people advise prioritizing reviewing autoloaded entries. This is not why I chose this order… ^