Organizing Your Stuff Is[n't] Easy
But stuff rarely is, is it? This week we did a thing on a website. It required us to create or update something, depending on whether or not that thing exists. Simple enough, if you’re copy and pasting, but still time consuming when you’re writing DRY code.
By the way, DRY means Don’t Repeat Yourself.
DRY code is one of those useful code quotes that was probably coined by Uncle Bob or Ada Lovelace or Abraham Lincoln (it’s actually attributed to Andy Hunt and Dave Thomas, if you care), which is incredibly overworked by the fancy developers you’ll see waxing eloquent on complex new frameworks, or talking quickly and passionately about things that don’t matter.
But it’s time consuming. If you are a precognitive savant, you can use your innate talents to divine the whole structure of what you’re doing the first time. For the rest of us, we review our code many times as things progress, and keep refining it.
So I’m thinking about this code that I wrote once, which is a perfectly useful example. I’m trying to process some existing Custom Post Types and import them into existing, more specific ones.
I’m not thinking about speed, here. Even if there are hundreds and hundreds of these things, it’s not going to overwhelm my server’s processor. It’s not a web view, so I’m not making users wait around. It’s just a one-time transaction.
Prepare to skip to the end if you don’t want to scroll through the muck and comments!
The First Pass
After the First Pass
That was fine, and you should feel fine. But it was also super long. Way too long to store in one function. Kurt Vonnegut famously said, “separate your concerns”.
That would work if we made a bunch of individual functions for updating or creating, for checking if Kittens
exist. Sure. But that’s necessarily going to make this even bigger. I want to DRY it out first, or we’re going to be all.over.the.place.
Why Did You Do That?
I’m gonna visually separate this giant code block into things that we did:
- Query the
Cats
that areKittens
- Iterate the
Kittens
to process:- Query the data we need from each of the matching
Cats
- Query existing
Kittens
to check for a match - If there’s a
Kitten
, Post an update - Else, Post a new post
- Query the data we need from each of the matching
There’s a pretty hard mental stop between database queries and local processing. I can’t gain any meaningful ground by trying to combine the foreach
into a query, or even combining my Cats
query with my Kittens
query. They feel separate because they are!
But that last bit about posting changes felt pretty long. Even when I wrote the bullets I felt like it should be shorter. If
conditions are notorious for making big, unnecessary code.
What Did You Want to Do?
We’ve got two fellow commands inside of that conditional, and they both do similar things: wp_update_post()
and wp_insert_post()
. Wait, no, on a computer level they’re really doing the same thing: pushing identical data to the database. The only difference seems to be that one creates a unique ID and the other doesn’t.
So click on them and read around! You’ll find something interesting. If you already work with WordPress a lot, you probably already had an inkling about it.
wp_insert_post()
can also update posts!
Oh cool. So if we have the right parameters we can make that add or update posts exactly like we want it to.
Side rant: How bloody confusing! Most of the time WP update_ functions are the ones that create-or-update. Welcome to PHP, a Wild West of naming conventions where array_push($home_array, $other_stuff) but implode($separators, $home_array). I even had to look it up again for this article to make sure I was right. But yeah, in this case you're going to use wp_insert_post().
So wp_insert_post()
can take an existing ID and update that. Cool. But we don’t want to leave that field blank: that would be a great way to get errors, or overwrite an existing post elsewhere in the database. Or even worse, if the ID isn’t found… it breaks.
Luckily, I contributed something to the docs about that.
Compare
We can copy everything else into both functions. Cleaning these args should just require us to insert the ID. So let’s do that separately!
Woah. That’s it! That’s the conditional. It’s one whole line long. Now we can separate any concerns we want, because I’m satisfied that an inevitable change in the post_meta
keys won’t make me update five of the same things – it’ll only make me update four.
Conclusions
There’s a ton of other stuff we could do to make this look even better, but this took me three hours to write. Go have a drink! You know this code is rock solid. I mean, you did make sure all the post_titles
were unique, right? …right? …Bueller?
About the Author:
Benji is a professional web dude. He is a freelance web developer, making cool things for money (and sometimes beer).