WordPress ships with two ways to store things: posts and pages. That is fine until you want to publish something that is neither. Recipes, staff profiles, properties, case studies, events. You can force them into posts and hope, or you can tell WordPress that recipes are their own kind of thing.
Telling it takes about forty lines of PHP, and roughly thirty of those lines are just naming things. Fill in the boxes and the tool writes all of it.
After adding this, go to Settings then Permalinks and press Save once. Without that, every single post of the new type returns 404 and the code looks broken when it is not.
What you actually get
Once this code is in place, a new item appears in your WordPress sidebar, under Posts and Pages, with its own icon. Click it and you get a list screen, an Add New button, and an editor. Everything works the way the post editor works, because underneath it is the same editor.
The difference is separation. Recipes stay out of your blog feed. They do not appear on the blog page, they do not turn up in category archives, and your RSS feed stays about blogging. They get their own web addresses, their own listing page, and they can have their own categories that have nothing to do with your post categories.
None of this needs a plugin at runtime. It is a feature built into WordPress. The code below is not a workaround, it is the official way.
Going through the boxes
Say you are building the recipe site. Here is what each box is asking for, and why it matters.
The two name boxes
You type Recipe and Recipes. That is it. Those two words get combined into twenty seven separate label strings, which is the part that makes people give up halfway through writing this by hand.
Labels are the words WordPress shows you in the admin. The button says Add New Recipe. The empty list says “No recipes found.” The media popup says “Insert into recipe.” The trash screen says “No recipes found in Trash.” There is a label for every single one of those, and if you leave them out, WordPress guesses. It guesses using the word “post”, so you end up with a recipe screen that says “No posts found” and a media popup that says “Insert into post”. It looks unfinished, and it is the fastest way to spot a custom post type that somebody rushed.
Watch the code as you type. Every one of those strings updates.
The internal name
This one fills itself in, and most of the time you can leave it. It is the name WordPress uses in the database and in code. Not the pretty name, the machine name.
Three rules apply, and WordPress enforces none of them helpfully. It has to be twenty characters or fewer. It can only contain lowercase letters, numbers, underscores and dashes. And it must not be a name WordPress has already taken.
That last rule is the dangerous one. Try to register a post type called post or page and nothing explodes. WordPress just quietly does something other than what you wanted. Some names are worse than that: author, order, date, type and name are not post types at all, they are query variables WordPress uses to work out which page you are looking at. Take one of those over and you break author pages, or sorting, or date archives, and nothing in the error log will point you at the cause. The tool checks the full list and tells you before you paste anything.
It also checks against names popular plugins have claimed. If you call yours product and somebody installs WooCommerce two years from now, whichever loads last wins and the other one vanishes from the admin. A short prefix, like wth_product, costs you nothing and removes the problem permanently.
What can it have
These tick boxes decide what appears on the edit screen. Untick the content editor and you get a title and nothing else, which is genuinely what you want for something like a list of team members where all the real information lives in custom fields.
Two are worth explaining. Revisions keeps the history of every save, which is useful but does add rows to your database over time. Manual ordering adds an Order number box so you can arrange items yourself instead of by date, which is what you want for staff profiles or a portfolio where newest first makes no sense.
Featured image has a catch that is not the tool’s fault. It only shows up if your theme has switched featured images on. Nearly every theme built in the last decade has, but if the box is ticked and no featured image panel appears, that is why.
The behaviour boxes
Visitors can see these on the site. On for anything you are publishing. Off for anything you are only collecting. Contact form entries, order records, internal notes, imported data waiting to be processed. With it off, the items exist in the admin but have no web address at all, so nobody can stumble onto one.
Has a listing page. This gives you /recipes/ showing all of them, the same way /blog/ shows all your posts. Leave it off if every recipe will only ever be reached from a page you built by hand.
Use the block editor. Almost always on. This one does more than it sounds like: it also decides whether your recipes are visible to the WordPress REST API, which is what the mobile app, the site editor, and most modern integrations talk to. Turn it off and you get the old classic editor and a post type that is invisible to all of that.
Can have parents. Off, recipes behave like posts: a flat list. On, they behave like pages, so one can sit inside another and the address becomes /recipes/desserts/tiramisu/. Useful for documentation and chapters. Confusing for most other things.
The taxonomy box
A taxonomy is a way of grouping. Categories and tags are the two WordPress gives you for posts, and this makes a third one that belongs only to your recipes.
You want this more often than you would think. Reusing post categories for recipes means your blog category list slowly fills up with Desserts and Mains, and your recipe category list fills up with News and Announcements. Give recipes their own Course taxonomy and the two never touch. You also get /course/desserts/ as a real page listing everything in it, for free.
The generated taxonomy is the category kind, meaning you pick from a list of existing ones with tick boxes and they can nest. Same rules on naming apply, so do not call it category or tag.
Where the code goes
Three options, in the order I would actually pick them.
A code snippet plugin. WPCode and Code Snippets are the common ones and both are free. You paste the code into a box in your admin, give it a name, and switch it on. The advantage over everything else is the safety net: if the code has a mistake, these plugins catch it and switch the snippet back off instead of taking your site down. For anyone not comfortable editing files over FTP, this is the right answer.
Your own small plugin. Make a folder in wp-content/plugins/ called my-post-types, put one PHP file in it, and start the file like this:
<?php
/**
* Plugin Name: My Post Types
*/
// paste the generated code below this line
Activate it from the Plugins screen like any other plugin. This is what I would do on a site I owned. It takes two minutes and your post types survive every theme change and every theme update, forever.
Your theme’s functions.php. It works, and it is what most tutorials tell you, and it is the one I would avoid. Two reasons. If you ever switch theme, every recipe on the site becomes invisible in one click. And if you are editing the theme directly rather than a child theme, the next theme update deletes your code without asking.
Then save your permalinks. Really.
This is the step that generates more confused forum posts than the rest of the subject combined, so it gets its own section.
After you add the code, go to Settings, then Permalinks, and click Save Changes. You do not need to change anything on that screen. Just click Save.
WordPress keeps a stored list of every URL pattern it knows how to handle, and it does not rebuild that list on its own. Your new post type is not in it yet. Skip this and the admin side looks perfect, you can create recipes and edit them and everything seems fine, but clicking View on one gives you a 404. The code is correct. The list is stale. Saving the permalinks page rebuilds it.
You only do this once, after adding the code, and again if you ever change the address slug.
When something looks wrong
Nothing appeared in the sidebar
Either the code is not running, or it errored. Check the snippet is actually switched on, or the plugin actually activated. If you used functions.php, make sure you pasted it inside the file and not after a closing ?> tag, because anything after that is ignored.
The single item 404s but the admin is fine
The permalinks step above. It is this one about nine times out of ten.
The listing page 404s too
Same fix first. If that does not do it, check you have not got a normal WordPress page using the same slug. A page called Recipes at /recipes/ and a post type archive at /recipes/ are fighting, and the page usually wins. Rename one of them.
Everything vanished after a theme change
The code was in the old theme’s functions.php. The recipes themselves are still safe in your database, nothing is lost. Move the code into a snippet plugin or a small plugin of your own and they all reappear exactly as they were.
They show up but look like a blog post
That is expected. WordPress has no template for your new type, so it falls back to the single post template. Registering the post type and designing how it looks are two separate jobs, and this tool only does the first one.
What this does not cover
Worth being straight about the edges, because a generator that pretends to do everything wastes your afternoon.
Custom fields. Cooking time, difficulty, ingredients. Registering a post type gives you a title and an editor, not extra boxes. For those you want Advanced Custom Fields, Meta Box, or Pods, and they all attach cleanly to whatever you make here.
How it looks on the site. That is a template file, named single-recipe.php and archive-recipe.php in your theme folder, or a template in the site editor if you are on a block theme.
Who can edit what. The generated code uses the same permissions as normal posts, so anyone who can write a post can write a recipe. Splitting those apart is a separate and much larger job involving custom capabilities, and most sites never need it.
Moving existing posts across. If you already have forty recipes sitting in your blog, this does not move them. The Post Type Switcher plugin adds a dropdown to the edit screen that does, and it handles bulk edits too.