In our previous post on custom post types, we created a custom post type called Cat Memes. We went through the three methods to create a custom post-type: using a plugin, coding it ourselves, or using a generator to copy and paste the code from. In this tutorial, you will have to work with code.

Now we are going to change things up a little. We’ve expanded from solely cat memes to memes of all types of animals.

dog image

Now that we are creating memes for all types of animals, we will need to use a taxonomy to differentiate between each of them. We are also going to output these memes on the front-end.

Update our Custom Post Type

As we’ve evolved our custom post type from only cats to all animals, we have to update our custom post type code.


// Animal Memes post type
function animalmeme_posttype() {

	register_post_type( 'animal_memes',
	//CPT Options
			'labels' => array(
				'name' => __('Animal Memes'),
				'singular_name' => __('Animal Meme'),
				'add_new_item' => __('Add New Animal Meme'),
				'edit_item' => __('Edit Animal Meme'),
				'all_items' => __('All Animal Memes'),
			'public' => true,
			'has_archive' => true,
			'rewrite' => array('slug' => 'animal-memes'),
			'supports' => array( 'title', 'thumbnail' ),
			'taxonomies' => array( 'species' ),
// Call at the init hook
add_action('init', 'animalmeme_posttype');

We’ve made quite a few changes to our custom post type.

We’ve substituted the word ‘cat’ for ‘animal’.
We’ve added a couple of extra labels to make things a bit clearer in the back-end.

Also, note that for each of these labels we’ve wrapped the label in parentheses and preceded them with a double underscore.

__('Animal Meme')

This is to make these labels easily translatable. We won’t actually be doing any translation in this tutorial, this is merely good practice.

We’ve also added support for a featured image with the command

'supports' => array( 'thumbnail' ),

We’ve also retained the title tag within the same command. We have however lost the post editor. That’s ok, as we’re going to be using Advanced Custom Fields to create the content for our memes.

Finally, we’ve included the category as a taxonomy.

'taxonomies' => array( 'species' ),

That’s a custom taxonomy. We could have used one of WordPress’ default taxonomies such as category or tags, however, we want to keep this taxonomy separate from the taxonomies used for regular posts.

A custom taxonomy has to be created. You can include it in the functions.php file or the plugin you used to register your custom post type; or a totally separate plugin if you wish.

// Register Species Taxonomy
function species_taxonomy() {

	$labels = array(
		'name'                       => _x( 'Species', 'Species', 'text_domain' ),
		'singular_name'              => _x( 'Species', 'Species', 'text_domain' ),
		'menu_name'                  => __( 'Species', 'text_domain' ),
		'all_items'                  => __( 'All Species', 'text_domain' ),
		'parent_item'                => __( 'Parent Species', 'text_domain' ),
		'parent_item_colon'          => __( 'Parent Species:', 'text_domain' ),
		'new_item_name'              => __( 'New Species Name', 'text_domain' ),
		'add_new_item'               => __( 'Add Species Item', 'text_domain' ),
		'edit_item'                  => __( 'Edit Species', 'text_domain' ),
		'update_item'                => __( 'Update Species', 'text_domain' ),
		'view_item'                  => __( 'View Species', 'text_domain' ),
		'separate_items_with_commas' => __( 'Separate Species with commas', 'text_domain' ),
		'add_or_remove_items'        => __( 'Add or remove Species', 'text_domain' ),
		'choose_from_most_used'      => __( 'Choose from the most used', 'text_domain' ),
		'popular_items'              => __( 'Popular Species', 'text_domain' ),
		'search_items'               => __( 'Search Species', 'text_domain' ),
		'not_found'                  => __( 'Not Found', 'text_domain' ),
		'no_terms'                   => __( 'No Species', 'text_domain' ),
		'items_list'                 => __( 'Species list', 'text_domain' ),
		'items_list_navigation'      => __( 'Species list navigation', 'text_domain' ),
	$args = array(
		'labels'                     => $labels,
		'hierarchical'               => true,
		'public'                     => true,
		'show_ui'                    => true,
		'show_admin_column'          => true,
		'show_in_nav_menus'          => true,
		'show_tagcloud'              => true,
	register_taxonomy( 'species', array( 'animal_memes' ), $args );

add_action( 'init', 'species_taxonomy', 0 );

For your custom taxonomy to function like the default WordPress categories, you have to set hierarchical to true. Leaving it false would make it function like tags.

Eventually, we will use this taxonomy to allow the user to filter the memes themselves on the front-end.

Custom Fields

Currently, our edit screen looks like this. We can give our new meme a title, an image and group it within a species taxonomy.

wordpress dashboard

We want to have a couple more additional elements. We want to know the animal’s name. We also want to know what species of animal is featured.

Advanced Custom Fields

The easiest way to add custom fields into our editor is by using a plugin called Advanced Custom Fields. After installing and activating the plugin, select the Custom Fields option in the left-hand sidebar on your dashboard. Click add new. Add a title to your field group. We’re calling ours Animal Memes, but you can call yours whatever you want. Before adding fields, set a rule in the location section. Only show the field group if the post type is equal to Animal Meme. This way, our custom fields will only show in our Animal Meme custom post type and not on regular posts or pages.

Adding new field group

Now we will add some fields. The animal’s name is simple enough. Click Add Field and enter ‘Animal Name’ for Field Label. This will automatically generate ‘animal_name’ as the field name. You can choose a different label and name if you wish. Leave the field type as text. There’s no need to change anything else for this field.

adding new field

For our second field, we’re going to add a link to the place we originally found the meme. The field type for this will be URL, which is the same as text other than it requires you to enter a valid URL. You could instead use text or the link fields if you prefer. Links are basically a more powerful version of URLs, allowing you to return an array of data. We’ve confusingly called our URL field ‘Link’ so that you remember this.

animal memes second field

The Animal Memes editor now looks like this:

animal meme editor

Note we’ve added in some species in the right-hand sidebar. Go ahead and create your Animal Meme post, and don’t forget to choose a featured image.

If you try to view your Animal meme, you will most likely encounter a problem. WordPress won’t be able to find your custom post type. Whenever you create a new custom post type in WordPress, you’ll have to go into Settings > Permalinks and click Save Changes.

WordPress Settings

You don’t even have to make changes. However, the act of refreshing the permalinks will force WordPress to check the database and realize your new custom post type exists. It can then assign a link to it. The next time you attempt to load your animal meme, it should load. Here’s how it looks on the Twenty Nineteen theme.

animal meme on WordPress theme

This output is controlled by the single.php template file – the same file used by regular posts. If you wanted to create a custom template for this file, you could create a file called single-animal_memes.php and enter your own custom layout for this post type.

In this tutorial, we’re going to focus on creating a page to display all of our Animal memes on one page. This is controlled by an archive page. To see what your custom post type archive looks like when output by the default archive file, just add /animal-memes/ to the end of your site’s URL in the address bar.

To take control of the archive template for this custom post type, we’ll create a new file: archive-animal_memes.php. We created a child theme of the Twenty Nineteen theme and saved this file in that theme’s folder.

Let’s create a new layout with a grid three posts wide.


$animalMemes = new WP_Query(array(
	'posts_per_page' => 9,
	'post_type' => 'animal_memes',



	set_post_thumbnail_size( 300, 450, true ); 

	while ($animalMemes->have_posts()) {
			$animalMemes->the_post(); ?>
					<h1><?php the_title(); ?></h1>
					<div class="sub-data">
						<p><?php the_field('animal_name'); ?></p>
						<p><?php echo get_the_term_list($post->id, 'species'); ?></p>
<a href="<?php the_field('link'); ?>"><button>Meme Source</button></a>
					<?php the_post_thumbnail(); ?>


In our code, we’ve created a new custom query using WP_Query. We’ve saved this to a variable $animalMemes. We’ve chosen 9 posts per page, to have a 3 x 3 grid of posts on each page. Crucially, we’ve referred to our custom post type with ‘post_type’ => ‘animal_memes’.

To start outputting our custom posts onto the page, we open up a while loop

while ($animalMemes->have_posts()) {

This has to be followed by $animalMemes->the_post(); as this is what pulls in the post data for the custom post being output in the loop.

Then we output what we want to see on the front-end.
the_title(); is what outputs the title of the post.
the_post_thumbnail(); outputs the featured image.

the_field(‘animal_name’); is the way to output fields from advanced custom fields. Simply use the name of your custom field inside the parentheses after the field, and the text entered on the back-end will be output on the front-end. The link is similarly easy to output on the front-end, just use the_field(‘link’); We used it in an HTML link and wrapped it around a button with the name ‘Meme Source’ to give the user something to press to take them to the original source of our meme.

We also want to include our species taxonomy.You can output the taxonomy using echo get_the_term_list($post->id, ‘species’);

The set_post_thumbnail_size( 300, 450, true ); controls the size of the featured image. You can read more about that on the WordPress codex.

Finally, we added the absolute minimum amount of style needed to make it somewhat presentable and added a couple of extra memes.


	ul {
		display: flex;
		flex-wrap: wrap;
		justify-content: space-between;
	li {
		width: 30%;
		list-style: none;
	h1 {
		font-size: 1.4em;
	.sub-data {
		width: 80%;
		margin: 20px auto; 
		display: flex;
		justify-content: space-between;
	p:nth-of-type(2) {
		margin-left: 25px;


The finished archive page looks like this.

finished archive page with animal memes

In our next post in the series, we’ll be making these post types filterable from the front-end, by using the animal categories. We’ll also be making our custom query more resource-efficient by using the transients API.

Subscribe To Our Newsletter

Subscribe To Our Newsletter

Join our mailing list to receive the latest news and updates from our team.

You have Successfully Subscribed!