Recently, I was working on refreshing a client site (new theme, layout, etc), which also included maintaining some custom post functionality that I’d built for them in the past. It was basically a type of post that they could use to advertise their product sales; I’ll refer to them as “Deals” in this post. So in doing the refresh, I built their new WP site from the existing WP site⦠but their Deals custom post type was not present. What happened?!? My initial guess (and vague recollection) is that custom post types need to be “registered” somewhere like functions.php, or maybe there was some other configuration file that was replaced by the new theme. Time to investigate!
So here was my rough game plan:
- Step 1 – verify that the database contains the ‘missing’ Deal data.
- Step 2 – review old git commits in bitbucket for a refresher on how I did it the first time.
- Step 3 – re-execute the ‘custom post registration’ steps on new site, if that’s even a real thing.
- Step ??? – Some combination of google-fu, StackOverflow, and WordPress Codex.
- Step 5 – Create new template file to show custom post type. And maybe profit.
- Bonus Step! – Figure out how to set up a sweet custom icon, which we never did on the old site.
And here’s what actually happened:
Step 1 – Check database for expected/missing data
select post_type, count(*) from wp_posts
group by post_type;
-- Looking good! I see 118 records for post_type = 'REDACTED_deal'
select * from wp_posts where post_type = 'REDACTED_deal';
-- Yep, beautiful, this has plenty of (outdated) data for setting the custom post back up and testing functionality.
Step 2 – Search through old commits
Luckily bitbucket has a solid search feature, and my coworkers and I do a decent job of writing meaningful(ish) commit messages. Searched commits for ‘deals’, and went to the oldest commits. Jan 2018?! Wow I’ve been here a long time. Well anyway, here was the magic code which indeed was placed in the functions.php file of our previous theme (which explains its absence in our new theme):
// original
function create_post_type() {
register_post_type( 'REDACTED_deal',
array(
'labels' => array(
'name' => ( 'Deals' ),
'singular_name' => ( 'Deal' )
),
'public' => true,
'has_archive' => false,
'supports' => array(
'title',
'editor',
'excerpt',
'thumbnail',
'custom-fields',
'revisions'
),
'rewrite' => array('slug' => 'deals')
)
);
}
add_action( 'init', 'create_post_type' );
Tempting to just throw this bad boy of a snippet into our new child theme‘s (you are using a child theme, right?) functions.php file and see what we get. Could probably do that with minimal consequences, but I’ll go ahead and take a peek at the latest version of the old site’s functions.php file to see how/if that bit of code has been updated in the last 2+ years. Here it is:
// latest
function create_post_type() {
register_post_type( 'REDACTED_deal',
array(
'labels' => array(
'name' => ( 'Deals' ),
'singular_name' => ( 'Deal' )
),
'public' => true,
'has_archive' => false,
'supports' => array(
'title',
'editor',
'custom-fields',
'revisions'
),
'rewrite' => array('slug' => 'REDACTED')
)
);
}
add_action( 'init', 'create_post_type' );
So, for the record, I’m pretty handy with the terminal and my IDE, meaning I’ve got a couple different options for diff-ing two chunks of code, but for two quick chunks of code like this I really just like using mergely. Fast and easy, customizable, and sharable diff:

Okay it looks like we dropped a couple of unnecessary fields(?) in later versions, and updated the URL slug generator to include the company name. Neat!
Step 3 – Register new post type
Time to toss this snippet into my child theme’s functions.php and see what happens. Generally this is located in the following directory
<root web directory>/wp-content/themes/<child-theme-name>/functions.php
So I load that snippet into my local environment, and hit refresh…
*closes eyes*
Well the site still works, so that’s a good sign! Now I’ll actually go into the WP Admin dashboard to see if anything is there š

Yesss! Okay well that was pretty painless and not very exciting. And Step 5 isn’t going to be much more exciting, so I’m going to jump to Step 6 for fun.
Step 6 – Sweet Custom Icon!

Doing a quick browser inspect on that existing thumbtack image gives me some good info for googling: ‘wp-menu-image’ and ‘dashicons’ seem like good places to start.

The first 3 search results look pretty promising⦠and after reading through them it looks like my options are to:
- Create a new custom font using SVG, register it via functions.php, and add it to the menu interface⦠somewhere. This is the most complicated option, but offers the most customization.
- Use a little .png image and some css to ‘hack’ it. Quick and easy, but as the blog author admits, it might not be future-proof.
- It looks like WordPress has quite a few other icon available in the Dashicon font set, and I could simply pick one and add a new line to my functions.php. This is super easy, but with limited options for icons. I’m going with this for now!
I know, I know, taking the easy path is kind of a cop-out. But hey, I have deadlines too!
After choosing the ‘tickets-alt’ dashicon, my snippet becomes:
function create_post_type() { register_post_type( 'REDACTED_deal', array( 'labels' => array( 'name' => ( 'Deals' ), 'singular_name' => ( 'Deal' ) ), 'public' => true, 'has_archive' => false, 'supports' => array( 'title', 'editor', 'custom-fields', 'revisions' ),
// NEW CODE HERE
'menu_icon' => 'dashicons-tickets-alt',
'rewrite' => array('slug' => 'REDACTED') ) ); } add_action( 'init', 'create_post_type' );
And victory!
