I couldn’t think of a great title for this blog post so I stopped trying! The short of it is that a client has a batch of pages that have lots of custom fields (using Advanced Custom Fields) and their own special template to display everything. They want to move the content from one website to another, and we decided this would actually be a perfect time to convert the pages into a custom post type.
Why a custom post type vs a page with custom fields?
My main argument for using a custom post type is to improve the backend user experience in the WordPress dashboard.
Large sites with lots of pages can become very tedious to comb through when it is time to make edits. And adding new pages means being very meticulous about assigning the correct “parent” so that the page adopts the correct template and style sheet, or selecting the correct page template in the page options.
I like when users can just select a well-named post type in the admin Dashboard (like “Team Bios” or “Events” or “Locations”) and then quickly and logically enter the content.
What are the hiccups to look out for?
I don’t want to have to do any superfluous data entry so I’m going to pay close attention to the names of the custom fields as I duplicate them for the new website. If I want to easily export and import my data, everything has to match. If you are using Advanced Custom Fields, you can easily hop into their “tools” section and simply export your current custom fields group and then import them into the new site. Everything will match and you’ll just need to update the settings a bit.

On the old site, these custom fields displayed when the page template is “Country Page Template.” On the new site, these fields will display when the CPT is “Country.”
I’m anticipating that the featured images won’t pull over because that always seems to be an issue. But I can use that as an opportunity to clean up and optimize those images before pulling them in. I also want to take note of the names of any custom post types and taxonomies I’m creating, to make sure there aren’t any conflicts with current info on the new website.
Let’s get started
[I ASSUME YOU ARE GOING TO BE WORKING IN A STAGING ENVIRONMENT OR AT THE VERY LEAST HAVE A FRESH BACKUP OF YOUR WEBSITE BEFORE DOING ANYTHING FURTHER. Right? Right. Good.]
First, I’m going to create a new custom post type using CPT UI from WebDevStudios. Yes, you can do these things yourself in functions.php or a standalone plugin, but I’m looking out for the next developer who needs to maintain this stuff after me. Using a plugin with a nice GUI expands the number of people who can jump in to edit or extend what I’ve created.
I’m going to call the new CPT “country” and we don’t need a taxonomy. I’m going to import my custom field group and make sure to associate it with my new CPT. That is all that really needs to be done in terms of preparing the database aspects of the environment for the import. (We’ll tackle the template and display at the end).
Let’s import some stuff
Now that their home is ready, let’s pull over this content into the staging environment we’ve prepared. I think I’ll export and import over all of the pages from the old site first and then convert them into my new post type. If I’ve done my job properly with naming conventions, everything should line up perfectly. That will leave me with a clean set of data to import into the final site.
But, hold on. When I import these pages over, how will I be able to easily identify them when it is time to run the post type conversion? Let’s peek at the conversion plugin first before we make any final decisions.
Switch a post type
I’m going to use the Post Type Switcher from Triple J Software, Inc. to change these pages into my custom post type. If you have a clean environment to work in, you could import your pages into a new installation, convert ALL of the pages, and then export your new posts quite cleanly into another environment. That seems like the most sensible solution.
But what if that wasn’t an option? The Post Type Switcher plugin lets you change the post type right from the “quick edit” admin panel when you are viewing all of your posts in a type. In this case, I would be looking at a list of all the pages in my WordPress installation. What if, I create a new user and then during the import process, I assign that new author to all of my “country” pages? Then, in this “quick edit” menu, I could filter my view to just the pages that are made by that new author. Then I can do a “bulk edit” and change all of their post types at once. I like that plan.
But, wait…
Every time I go to start importing the pages, I think of another piece of the puzzle that I forgot to consider. When these pages first come in, they will STILL be pages. So I need to make sure that their custom field data has a proper place to land or else I risk losing that data entirely. So, to be sure my ACF are usable by both the new pages and the CPT they will later be transformed into, I’m going to add in another rule for when this ACF group should be used. I need it to be for BOTH pages with that template AND CPT that are named “country.”
I suppose that also means that the old template needs to exist with the identical file name… Okay, we’ll pull him in too. Let’s grab our old page-template-country.php file and add it to our child theme folder.

Okay, NOW we can import!
I’m using the standard WordPress importer instead of a premium plugin. It’s not much of a challenge or learning experience if you go premium to avoid every possible hiccup, right? We are importing the pages from our old site and we are going to assign them all to the new user we created, “country_author.”
After the import, I took a quick peek at one of the newly imported pages just to make sure all the custom field data is there. And it is! So now we can go about converting the pages into our new CPT. As I mentioned before, we are doing that from the quick edit screen. I’m filtering by “author” and then doing a “bulk edit” to change all these pages into my CPT of “Country.” This filtering was made possible with the Admin Columns Pro plugin that I installed for a completely different purpose!

Zip, bang, boom, pow, my 37 pages are now magically transformed into my new CPT of “country.”

So now I go into check to make sure that my new Custom Post Types have all of their custom fields intact… and they do not. Very peculiar. Even MORE peculiar is that the ACF plugin isn’t showing in the admin dashboard anymore!
This would have been a massive hiccup on a live production site because multiple features on this particular website use ACF.
I was able to make the plugin active again by going into the Avada theme’s “plugins/add-ons” and clicking “Activate” on the plugin there. Why it was bundle in there and not in the main plugins menu, I have no idea. Why it deactivated randomly like that, I also have no idea. But it’s fixed and none of the data was dropped from the database so we are still all okay!
It works. Time to make it pretty.
As expected, we can’t actually view any of our new posts on the front end. Because we lazily just pulled over the exact same template page from one website to the other, we see a mostly empty webpage when we try to view a post. It’s time to go in and rebuild that template so that it is compatible with the current website.
First, we need to rename the file. WordPress template naming convention says that if our CPT is “country”, this file should be called “single-country.php” so that it will automatically be used. Simply changing the name of the file now means we get that lovely “There has been a critical error on this website.” message when trying to view a CPT on the frontend. This makes perfect sense because the code in that template was built for an entirely different website. It is probably calling all kinds of variables and stuff that doesn’t exist over here.
We’ll keep the main body of the template, all the calls to the ACF variables that definitely exist, but swap out the wrapping elements to make sure they match other templates that exist on this site. I like to base my CPT templates on “single.php” because that template is used for single posts and other post-type that don’t have a specific template. Those changes are enough that now my CPT is displaying correctly and all the fields are populating. Of course, now we need to pull in our styles and we’ll be complete! But that’s just simple CSS stuff that we can cover in any old blog post.
The only thing left to do, after I’m happy with my styles, is to take this clean CPT and migrate it over to its final home on the live website. Creating the CPT and importing my ACF should be the only setup tasks necessary before exporting and importing the actual posts themselves.
Conclusion
Glad to see that this one worked out. As you can see, talking through all the steps and testing them in a safe environment is key for allowing yourself the space to make mistakes and having the peace and time to correct them.
Happy coding!