Part 1 – Initial idea, design, and first-pass implementation
Part 2 – Building the product box that gets displayed in posts
Part 3 – Refactoring the codebase into classes, views, and separate files
Part 4 – Adding image uploading, shared plugin options, and uninstallation
Day 8: Refactoring the plugin’s management page with WP_List_Table
I did some soul-searching and realized that while I was happy with what I’d built so far in Part 1 and Part 2, it wasn’t very ‘standardized’. In other words, I had finally learned enough to want to scrap it all and start over.
I’m glad I did – and while it took some effort, it was worth it in the end.

Using WP List Table for a standard-looking admin table
I noticed many plugins (such as Contact Form 7 and TablePress ) seemed to be using a standardized table design that looks like WP’s own default for managing posts, with Edit and Delete links on hover, a checkbox for each row, and bulk actions.
I dug around a bit and found the WP_List_Table class. It’s not an official developer API, but it’s stable and widely used for the creation of admin tables in plugins.
Reading about WP List Table led me to a few example codebases (this one is my favorite), a detailed guide, and even a generator.
(I recommend reading all of the aforementioned links before attempting to work with WP List Table, even if through a generator or boilerplate code.)
I used the tareq.co generators to get started. (Definitely watch the video to see how all the parts fit together and how to name the files, using the generators alone is not enough to piece it together).
The generator did not include delete so I implemented that myself.
Implementing Delete (both single and bulk delete) in the WP List Table
I got stuck on implementing “Delete” (both the singular variety and the bulk kind) for a little while, mostly because I was trying to refresh the page myself after calling my delete method. Naively, I tried solutions like wp_redirect() right after calling my delete function, but that didn’t work – the page would reload but the stale, already-deleted row(s) were still in the table until the page was refreshed a second time or I would get a “headers already sent” error.
Ultimately, the solution was not to call any kind of redirect or refresh action but to simply call process_bulk_actions() before getting $items (in my code, that’s apb_get_all_product_boxes()) in the prepare_items() method in list-table.php.
The prepare_items() method (starting at about line 190) is called any time the list page is rendered, and the list page is automatically reloaded and rendered when clicking the Delete link or submitting the bulk action on the form. With that in mind, I didn’t need to reload the page manually – I just needed to make sure the deleted items were processed and removed from the db before retrieving the latest list of items.
For more on how I implemented Delete after using Tareq’s generated files as a starting point, see my comment on the generator’s repo here.
Here’s the merged pull request for this refactor.
And here’s how it all looks now:

Final thoughts on this refactor
It took a few days and it felt like backwards progress for a while, but I’m glad I did it – now my plugin looks more like “professional” plugins, both in-page and in the codebase, and I learned a lot in the process. I’d rather do it right than hold onto prototype-grade code.
Building it myself from scratch was still an important learning step for me. At this point, I feel like I might actually finish this thing because all that’s left is… implementing the image box! (And uninstalling, and finding and fixing bugs, and trying it out on a live site…)