{"id":155640,"date":"2016-06-28T14:00:57","date_gmt":"2016-06-28T14:00:57","guid":{"rendered":"https:\/\/premium.wpmudev.org\/blog\/?p=155640"},"modified":"2016-10-05T05:44:10","modified_gmt":"2016-10-05T05:44:10","slug":"wordpress-development-for-intermediate-users-custom-post-types-and-taxonomies","status":"publish","type":"post","link":"https:\/\/wpmudev.com\/blog\/wordpress-development-for-intermediate-users-custom-post-types-and-taxonomies\/","title":{"rendered":"WordPress Development for Intermediate Users: Custom Post Types and Taxonomies"},"content":{"rendered":"<p>Custom post types and taxonomies are what make WordPress a Content Management System (CMS), and not just a blogging platform.<\/p>\n<p>With them, you can add your own post types, which you can then display using targeted template files. You can also create custom taxonomies that let you use more than just categories and tags to classify your content.<\/p>\n<p>This is the fourth post in our WordPress Development for Intermediate Users series. This series follows on from our popular <a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-beginners-getting-started\/\" target=\"_blank\">WordPress Development for Beginners tutorials<\/a>, which introduced you to the fundamentals of developing websites with WordPress, how to get started coding with PHP, and building themes and plugins.<\/p>\n<p>So far in this series, you&#8217;ve created your own theme and plugin and now you&#8217;ll move on to adding custom post types and taxonomies to your site. In this tutorial you&#8217;re going to learn:<\/p>\n<ul>\n<li>What custom post types and taxonomies are, how they differ from the ones you get with vanilla WordPress, and how they can help you.<\/li>\n<li>How to register\u00a0custom post types and taxonomies in a plugin.<\/li>\n<li>How to add a taxonomy to (or remove one from)\u00a0a post type.<\/li>\n<li>How to display custom post types and taxonomies, including via template files.<\/li>\n<li>Which functions you can use to fetch posts using your custom post types and taxonomies.<\/li>\n<\/ul>\n<p>Let&#8217;s start with an overview.<\/p>\n<p><strong>Missed a tutorial in our WordPress Development for Intermediate Users series? You can catch up on all seven posts here:<\/strong><\/p>\n<ul>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-theme-development-in-detail\/\" target=\"_blank\">WordPress Development for Intermediate Users: Theme Development in Detail<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-for-intermediate-users-making-your-themes-customizer-ready\/\" target=\"_blank\">WordPress Development for Intermediate Users: Making Your Themes Customizer-Ready<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-building-plugins\/\" target=\"_blank\">WordPress Development for Intermediate Users: Building Plugins<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-for-intermediate-users-custom-post-types-and-taxonomies\/\" target=\"_blank\">WordPress Development for Intermediate Users: Custom Post Types and Taxonomies<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-users-queries-loops\/\" target=\"_blank\">WordPress Development for Intermediate Users: Queries and Loops<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-users-custom-fields-metadata\/\" target=\"_blank\">WordPress Development for Intermediate Users: Custom Fields and Metadata<\/a><\/li>\n<li><a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-users-internationalization\/\" target=\"_blank\">WordPress Development for Intermediate Users: Internationalization<\/a><\/li>\n<\/ul>\n<a class=\"general_big_button\" href=\"https:\/\/wpmudev.com\/academy\/\"><span class=\"text\">That&#8217;s right, tons of WordPress knowledge, peer review, instructor feedback and certification, for free for WPMU DEV members<\/span><span class=\"button-a-b\">Start Learning<\/span><\/a>\n<h3>Post Types and Taxonomies in WordPress<\/h3>\n<p>WordPress comes with a number of <a href=\"https:\/\/codex.wordpress.org\/Post_Types\" target=\"_blank\">post types<\/a> and <a href=\"https:\/\/codex.wordpress.org\/Taxonomies\" target=\"_blank\">taxonomies<\/a> already included. The post types are:<\/p>\n<ul>\n<li><strong>Post<\/strong> &#8211; the posts you use for your blog.<\/li>\n<li><strong>Page<\/strong> &#8211; static pages.<\/li>\n<li><strong>Attachment<\/strong> &#8211; media files.<\/li>\n<li><strong>Revision<\/strong> &#8211; each revision for each post is stored as a post of the &#8216;revision&#8217; post type.<\/li>\n<li><strong>Navigation menu item<\/strong> &#8211; every item in your navigation menus is stored against this post type.<\/li>\n<\/ul>\n<p>The word &#8220;post&#8221; can be a bit confusing when it comes to WordPress. Let&#8217;s take a look at some of the terminology, and try to get it straight:<\/p>\n<ul>\n<li><strong>post<\/strong> (with a lower case &#8220;p&#8221;) &#8211; in the database, WordPress stores every item\u00a0of every post type as a <em>post<\/em>. So if you create a post type called <em>product<\/em> and then create products for your site, they go in the <em>wp_posts<\/em> table of the database in the same way a standard post would. The difference is that the post type stored against that post as a value in the database would be <em>product<\/em> instead of <em>post<\/em>.<\/li>\n<li><strong>Post<\/strong> &#8211; this is a post type, in the same way that any custom post type you create is a post type. A <em>Post<\/em> is the post type that comes with WordPress for blog posts, updates, news items etc.<\/li>\n<li><strong>post type<\/strong> &#8211; this refers to any post type (with a little &#8220;p&#8221;) including Pages, Posts etc. Don&#8217;t confuse it with post formats &#8211; post format is a taxonomy that&#8217;s used to classify Posts, as you&#8217;ll see shortly.<\/li>\n<\/ul>\n<p>In this part of the series, I&#8217;m going to use a capital P to refer to <em>Posts<\/em> in the context of blog posts, and a lower case p to refer to <em>posts<\/em> in the more general sense, including posts of any post type. I&#8217;m not doing that in the rest of the series though as it&#8217;s not the usual way to write, so please don&#8217;t get confused!<\/p>\n<p>Phew! So that&#8217;s post types. What about taxonomies? Well, WordPress also comes with some of these out of the box:<\/p>\n<ul>\n<li><strong>Category<\/strong> &#8211; a hierarchical taxonomy (meaning you can nest categories inside each other) used for Posts.<\/li>\n<li><strong>Tag<\/strong> &#8211; a non-hierarchical taxonomy used for Posts.<\/li>\n<li><strong>Link Category<\/strong> &#8211; used to classify links, if you&#8217;re using the old &#8220;blogroll&#8221; function. This is disabled by default so I wouldn&#8217;t worry about it if I were you.<\/li>\n<li><strong>Post Format<\/strong> &#8211; another taxonomy for classifying Posts, which isn&#8217;t hierarchical. You can use this to display\u00a0different post formats differently, using the relevant template file.<\/li>\n<\/ul>\n<p>By default, three of these taxonomies apply to Posts and one to Links, but there&#8217;s no reason why you can&#8217;t make them also apply to another post type, or remove them from the default post type. Later on, I&#8217;ll show you how to make tags and categories apply to a new post type that you register, add them to Pages, or remove them from Posts if you don&#8217;t want to use them.<\/p>\n<p>Each taxonomy has terms, which are the values you use to classify your content. So each category you add to your Posts is a term in the category taxonomy. Once you&#8217;ve registered a taxonomy, you can add terms to it via the admin screens &#8211; either by a dedicated screen for adding terms or when editing your posts.<\/p>\n<p>Now you know what post types and taxonomies are, let&#8217;s see how you create a post type for your site.<\/p>\n<h3>Registering a Post Type<\/h3>\n<p>The best way to register a post type is by writing a plugin to do so. This is because if you add the post type to your theme and then switch themes at a later date, you&#8217;ll lose your post types.<\/p>\n<p>Let&#8217;s create a plugin to register our post types and taxonomies for this part of the series. In your development site&#8217;s <em>wp-content\/plugins folder<\/em>, create a file\u00a0for your plugin and add the opening text to it as you would for any other plugin. I&#8217;m not going to show you how to do this as it should be second nature by now, but if you need to check, take a look at the <a href=\"https:\/\/github.com\/rachelmccollin\/wpmudev-intermediate-WordPress-development\" target=\"_blank\">source files<\/a> for this series.<\/p>\n<p>Next, create a function to register your post type. This needs to do three things:<\/p>\n<ul>\n<li>Define the labels for the post type that your users will see when working with them in the admin screens.<\/li>\n<li>Define the other arguments for the post type, such as whether it&#8217;s hierarchical (like a Page) or not (like a Post).<\/li>\n<li>Register the post type using the <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\/register_post_type\" target=\"_blank\"><code>register_post_type()<\/code><\/a> function.<\/li>\n<\/ul>\n<p>Your function containing all this is then hooked to the <code>init<\/code> action hook.<\/p>\n<p>Here&#8217;s my function registering a project post type:<\/p>\n<div class=\"gist\" data-gist=\"5239c772555495197f8eadbf8d8540ba\" data-gist-file=\"register-posttype.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/5239c772555495197f8eadbf8d8540ba.js?file=register-posttype.php\">Loading gist 5239c772555495197f8eadbf8d8540ba<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>So let&#8217;s take a look at what I&#8217;ve done in my function:<\/p>\n<ul>\n<li>I&#8217;ve defined a bunch of labels based around the &#8220;Project&#8221; title for my post type.<\/li>\n<li>I&#8217;ve used that <code>$labels<\/code> variable in the array of variables for <code>$args<\/code> to define <code>$labels<\/code> as one of those arguments.<\/li>\n<li>I&#8217;ve used<code>'has_archive'<\/code> to ensure that there is an archive page for this post type on the site&#8217;s front end &#8211; if your post type will be embedded in other posts or pages and won&#8217;t be shown in an archive, set this to\u00a0<code>false<\/code>.<\/li>\n<li>I&#8217;ve set <code>'public'<\/code> to <code>true<\/code> so people can see my post type, and <code>'hierarchical'<\/code> to <code>false<\/code> as I want it to behave like a Post, not a Page.<\/li>\n<li>I&#8217;ve defined a slug for the post type archive of projects &#8211; if I didn&#8217;t do this, the slug would be <em>project<\/em>.<\/li>\n<li>I&#8217;ve defined the features it will support such as a title, featured image, excerpt etc.<\/li>\n<li>I&#8217;ve specified the taxonomies it will have as <em>category<\/em> and <em>tag<\/em>. I&#8217;ll add an extra custom taxonomy to it later. If your post type will just have a custom taxonomy applied to it, that you haven&#8217;t registered yet, leave this line out.<\/li>\n<li>Finally, I&#8217;ve used the <code>register_post_type()<\/code> function with two parameters: the id for the post type (project) and the arguments, using my <code>$args<\/code> variable.<\/li>\n<\/ul>\n<p>Now if I take a look at my site, I can see my post type in the admin screens:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/project-cpt-admin.png\" alt=\"Project custom post type in the admin screens\" width=\"735\" height=\"401\" \/><\/p>\n<h4>Adding Featured Image Support to the Post Type<\/h4>\n<p>In my function to register the post type I included support for featured images but at the moment I still can&#8217;t add them to my Projects. This is because my theme doesn&#8217;t support featured images for that post type. You may remember that back in part one of this series we added theme support for post thumbnails (or featured images) to posts and pages.<\/p>\n<p>Let&#8217;s fix this.<\/p>\n<ol>\n<li>In your theme, open your <em>functions.php<\/em> file and find this line:<br \/>\n<div class=\"gist\" data-gist=\"0009d72dac802bb510aab09ca1c0525b\" data-gist-file=\"posttype_thumbnail_theme_support_before.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/0009d72dac802bb510aab09ca1c0525b.js?file=posttype_thumbnail_theme_support_before.php\">Loading gist 0009d72dac802bb510aab09ca1c0525b<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Edit it so it reads as follows:<br \/>\n<div class=\"gist\" data-gist=\"416f51e2d0367ce97b6479923b65227a\" data-gist-file=\"posttype_thumbnail_theme_support_after.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/416f51e2d0367ce97b6479923b65227a.js?file=posttype_thumbnail_theme_support_after.php\">Loading gist 416f51e2d0367ce97b6479923b65227a<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save the file.<\/li>\n<\/ol>\n<p>Now when you add a project you can upload a featured image. So now I can add post types to my site and assign categories and tags to them, with featured images and other features supported.<\/p>\n<h3>Registering a Taxonomy<\/h3>\n<p>But what if categories and tags don&#8217;t give me the level of control I need for classifying my Projects? That&#8217;s where custom taxonomies come in. You can register a custom taxonomy to apply to any post type, including Posts, Pages, Attachments or your own custom post types. Or you can register a taxonomy that applies to multiple taxonomies. Let&#8217;s register one for our new post type.<\/p>\n<p>In your plugin file, add a function to register the custom taxonomy. This will include three similar elements to the posts type&#8217;s function:<\/p>\n<ul>\n<li>Defining the labels<\/li>\n<li>Defining the arguments, including labels.<\/li>\n<li>Registering the taxonomy using <code>register_taxonomy()<\/code>.<\/li>\n<\/ul>\n<p>And again, the function needs to be hooked to the init action hook.<\/p>\n<p>Here&#8217;s my &#8220;service&#8221; taxonomy, for a site that includes a portfolio of projects categorized by services offered:<\/p>\n<div class=\"gist\" data-gist=\"8ecbb30aabd596b3d7743c3ce65df856\" data-gist-file=\"register-taxonomy.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/8ecbb30aabd596b3d7743c3ce65df856.js?file=register-taxonomy.php\">Loading gist 8ecbb30aabd596b3d7743c3ce65df856<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div>\n<p>As with the post type, I&#8217;ve defined the labels, some arguments and then used the <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\/register_taxonomy\" target=\"_blank\"><code>register_taxonomy()<\/code><\/a> function to register\u00a0the taxonomy. This has three parameters: the id of the taxonomy, the post type or types it applies to, and the arguments. In this case, there are multiple post types so I&#8217;ve used an array; if you just wanted to apply your taxonomy to one post type, you&#8217;d add it on its own.<\/p>\n<p>Now in my admin screens I have a taxonomy I can add values to:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/service-taxonomy-admin.png\" alt=\"The service taxonomy in the admin screens\" width=\"735\" height=\"494\" \/><\/p>\n<p>So that&#8217;s how you register a new post type and taxonomy.<\/p>\n<h3>Adding an Existing Taxonomy to an Existing Post Type<\/h3>\n<p>Applying your custom taxonomy to your chosen post type or types is easy &#8211; you do this when registering the post type. It&#8217;s also easy to apply existing taxonomies to your custom post types, as you do this when registering the post type.<\/p>\n<p>But what if you want to take a taxonomy that comes with WordPress, and apply it to a default post type or to a post type that&#8217;s been added via a third party plugin?<\/p>\n<p>To do this you don&#8217;t need to re-register the taxonomy or edit the code in the third party plugin. All you need to do is use the <a href=\"http:\/\/codex.wordpress.org\/Function_Reference\/register_taxonomy_for_object_type\" target=\"_blank\"><code>register_taxonomy_for_object_type()<\/code><\/a> function (not the nicest name, huh?).<\/p>\n<p>Let&#8217;s do this with categories and pages, in our existing plugin file.<\/p>\n<ol>\n<li>Open your plugin.<\/li>\n<li>Add this function:<br \/>\n<div class=\"gist\" data-gist=\"3648f158ce0b8d5f2e971ecc64393793\" data-gist-file=\"register_categories_to_pages.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/3648f158ce0b8d5f2e971ecc64393793.js?file=register_categories_to_pages.php\">Loading gist 3648f158ce0b8d5f2e971ecc64393793<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save your plugin file.<\/li>\n<\/ol>\n<p>Now when you edit a Page, you&#8217;ll see that you can assign categories to it:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/06\/page-edit-categories.png\" alt=\"Editing categories when adding a page\" width=\"735\" height=\"427\" \/><\/p>\n<p>You aren&#8217;t limited to doing this for the &#8220;page&#8221; post type \u2013 you could add categories or tags to attachments, for example. I&#8217;ve used this technique to create a kind of <a href=\"http:\/\/code.tutsplus.com\/articles\/advanced-use-of-attachments-in-wordpress-creating-a-featured-image-for-a-category--wp-35203\" target=\"_blank\">featured image for each category<\/a>, by uploading one image for each category and adding a custom loop to my category\u00a0archives to output that image.<\/p>\n<p>By default, your Pages won&#8217;t show up in your category archive pages. We&#8217;ll fix that in the next part of the series, which is about the WordPress loop.<\/p>\n<h3>Viewing Post Types and Taxonomies in the Site<\/h3>\n<p>Once you&#8217;ve registered your posts types and\/or taxonomies, you need to visit <strong>Settings &gt;\u00a0Permalinks<\/strong>\u00a0to refresh rewrite rules and make the slugs for your posts types and taxonomies work. All you need to do is visit it; you don&#8217;t need to enter anything or save changes. Although if you haven&#8217;t yet, you might take the opportunity to set up <a href=\"https:\/\/wpmudev.com\/blog\/wordpress-permalinks\/\" target=\"_blank\">pretty permalinks<\/a>.<\/p>\n<h4>Adding Your Post Type to the Navigation Menu<\/h4>\n<p>If you want to add your post type archive to the navigation menu, you&#8217;ll need to set up a custom link.<\/p>\n<ol>\n<li>Go to <strong>Appearance &gt; Menus<\/strong> in the admin and\u00a0click on the\u00a0<strong>Links<\/strong>\u00a0box to the left.<\/li>\n<li>In the\u00a0<strong>URL<\/strong>\u00a0field, type\u00a0<em>http:\/\/mysite.com\/projects\/<\/em>, replacing\u00a0<em>mysite.com<\/em>\u00a0with your own\u00a0domain and <strong>projects<\/strong> with the slug for your post type. Note that if you didn&#8217;t user the <code>rewrite<\/code> argument when registering the post type, the slug will\u00a0be in the singular.<\/li>\n<li>In the <strong>Link<\/strong> text field, type\u00a0<strong>Products<\/strong>.<\/li>\n<li>Click the\u00a0<strong>Add to Menu<\/strong>\u00a0button.<\/li>\n<li>Once the link has been added to the menu, move it to the right place and save the menu.<\/li>\n<li>Save your changes by clicking\u00a0<strong>Save Menu<\/strong>.\u00a0<strong>Don&#8217;t miss this step!<\/strong><\/li>\n<\/ol>\n<p>Now if you visit your site&#8217;s front end and click on that menu link, you&#8217;ll be taken to your projects\u00a0archive page. Here&#8217;s mine, with some high-profile projects added:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/project-archive.png\" alt=\"The projects archive\" width=\"735\" height=\"481\" \/><\/p>\n<p>Next, add the taxonomy terms you&#8217;ve created as sub-items for that projects menu item. You can do this using the <strong>Menus<\/strong> admin screen or the Customizer. Once you&#8217;ve done that you&#8217;ll be able to access those in the site too. Here&#8217;s one of mine:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/service-archive.png\" alt=\"Service taxonomy archive page\" width=\"735\" height=\"452\" \/><\/p>\n<h4>Displaying Post Types and Taxonomies via Template Files<\/h4>\n<p>WordPress will use the first template file for displaying\u00a0your custom post types and taxonomies that it comes across in the <a href=\"https:\/\/wphierarchy.com\" target=\"_blank\">theme template hierarchy<\/a>, which we studied in detail in part one of this series.<\/p>\n<p>At the moment\u00a0using our theme, it will use the <em>archive.php<\/em> file, which in turn uses the <em>loop.php<\/em> file to output the loop.<\/p>\n<p>Let&#8217;s create a new template file for our post type archive. If you remember from what you learned in part one, we&#8217;ll need to call it <em>archive-project.php<\/em>. So go ahead and create a file with that name in your theme, and copy the contents of <em>archive.php<\/em> into it.<\/p>\n<p>First, let&#8217;s change the title.<\/p>\n<ol>\n<li>In your <em>archive-project.php<\/em> file, find these\u00a0lines:<br \/>\n<div class=\"gist\" data-gist=\"5288e84104157cf832c5e0ed371084d9\" data-gist-file=\"project-archive-title-to-edit.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/5288e84104157cf832c5e0ed371084d9.js?file=project-archive-title-to-edit.php\">Loading gist 5288e84104157cf832c5e0ed371084d9<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Delete the first of those two lines and edit the second so it reads as follows:<br \/>\n<div class=\"gist\" data-gist=\"ed8dce5f514d622de888259d5a432c98\" data-gist-file=\"project-archive-title-edited.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/ed8dce5f514d622de888259d5a432c98.js?file=project-archive-title-edited.php\">Loading gist ed8dce5f514d622de888259d5a432c98<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save the file.<\/li>\n<\/ol>\n<p>Note that I&#8217;ve included the text inside a filter called\u00a0<code>project_archive_title<\/code>. This means that I or anyone else using my theme can write a function attached to that hook at any time to change that text. If you&#8217;re ever adding static text to a template file it&#8217;s good practice to put it inside a filter.<\/p>\n<p><em>Note: If you need a recap on filters, go back to <a href=\"https:\/\/wpmudev.com\/blog\/wordpress-development-intermediate-building-plugins\/\" target=\"_blank\">part three of this series<\/a>.<\/em><\/p>\n<p>Next, let&#8217;s add the featured image to our archive page. We do this by creating a new template part for\u00a0the loop.<\/p>\n<ol>\n<li>Make a copy of <em>loop.php<\/em> and call it <em>loop-project.php<\/em>.<\/li>\n<li>In your <em>archive-project.php<\/em> file, find this line:<br \/>\n<div class=\"gist\" data-gist=\"a9fa6b2518fd8c2f1cf8d2c263e14fb8\" data-gist-file=\"archive_project_old_loop_include.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/a9fa6b2518fd8c2f1cf8d2c263e14fb8.js?file=archive_project_old_loop_include.php\">Loading gist a9fa6b2518fd8c2f1cf8d2c263e14fb8<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Edit it so it reads:<br \/>\n<div class=\"gist\" data-gist=\"d2c7d28a435af5c1364654b5e0d64d33\" data-gist-file=\"archive_project_new_loop_include.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/d2c7d28a435af5c1364654b5e0d64d33.js?file=archive_project_new_loop_include.php\">Loading gist d2c7d28a435af5c1364654b5e0d64d33<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save the template file.<\/li>\n<li>Open your new loop file and find this line:<br \/>\n<div class=\"gist\" data-gist=\"0df6ef43d625b9972b2fdab51b7c3b0d\" data-gist-file=\"loop_project_code_to_find.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/0df6ef43d625b9972b2fdab51b7c3b0d.js?file=loop_project_code_to_find.php\">Loading gist 0df6ef43d625b9972b2fdab51b7c3b0d<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Below that, add this:<br \/>\n<div class=\"gist\" data-gist=\"b231fc5fc85619dc6c113aea0c8fc696\" data-gist-file=\"project_loop_featured_image.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/b231fc5fc85619dc6c113aea0c8fc696.js?file=project_loop_featured_image.php\">Loading gist b231fc5fc85619dc6c113aea0c8fc696<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<\/ol>\n<p>Now let&#8217;s take a look at the archive page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/projects-archive-with-image.png\" alt=\"Projects archive with featured image added\" width=\"735\" height=\"651\" \/><\/p>\n<p>Now add that featured image to your <em>loop-single.php<\/em> file, so any Post or Project with a featured image will display that on its single page. I&#8217;m not going to tell you to do this as I&#8217;d like you to use the skills you&#8217;ve learned so far instead. But if you get stuck, you can take a look at the <a href=\"https:\/\/github.com\/rachelmccollin\/wpmudev-intermediate-WordPress-development\" target=\"_blank\">source files<\/a> for this series \u2013 you&#8217;ll need the part four version of the theme.<\/p>\n<p>The layout with the featured images isn&#8217;t perfect right now so I&#8217;m going to make some tweaks to the styling for the <code>h2<\/code> element &#8211; you can see this in the source files.<\/p>\n<p>If you prefer to display an excerpt on your projects archive instead of the content, you can edit your <em>loop-project.php<\/em> file to use <a href=\"https:\/\/developer.wordpress.org\/reference\/functions\/the_excerpt\/\" target=\"_blank\"><code>the_excerpt()<\/code><\/a> where you&#8217;ve used\u00a0<code>the_content()<\/code>. I&#8217;m sticking with the full content as I&#8217;m going to keep the content brief.<\/p>\n<p>Next, let&#8217;s take a look at taxonomy term archives for our custom taxonomy. Here&#8217;s how this looks right now:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/tax-term-archive-before.png\" alt=\"The taxonomy term archive without a featured image\" width=\"735\" height=\"476\" \/><\/p>\n<p>To change the way the taxonomy term archive works, you need to create a new template file for your taxonomy\u00a0called <em>taxonomy-service.php<\/em>. I&#8217;d like you to create and edit that\u00a0file but I&#8217;m not going to give you detailed guidance as I&#8217;d like you to work it out for yourself using what you&#8217;ve learned so far.<\/p>\n<p>Here&#8217;s what you need to do:<\/p>\n<ol>\n<li>Create the new file, and copy the relevant code from the existing files in your theme.<\/li>\n<li>Make sure the heading in the h1 tags fetches the currently queried object and echoes that (see <em>archive.php<\/em> for this code).<\/li>\n<li>Make sure\u00a0the <code>get_template_part()<\/code> function to calls the <em>loop-project.php<\/em> file.<\/li>\n<\/ol>\n<p>If you get stuck, you can check out the source files. Here&#8217;s the new version of the taxonomy term archive page:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/tax-term-archive-new.png\" alt=\"The taxonomy term archive with featured images\" width=\"735\" height=\"596\" \/><\/p>\n<p>Now let&#8217;s add the description to the taxonomy term archive.<\/p>\n<p>Start by creating some descriptions for your services via the admin screens. Here are mine:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/services-descriptions-admin.png\" alt=\"Descriptions for the services terms in the admin screens\" width=\"735\" height=\"542\" \/><\/p>\n<p>Now let&#8217;s edit the <em>taxonomy-service.php<\/em> file to output those descriptions. To do this, we use the <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\/term_description\" target=\"_blank\"><code>term_description()<\/code><\/a> function.<\/p>\n<ol>\n<li>Open the <em>taxonomy-service.php<\/em> file and find the line with the <code>h1<\/code> element.<\/li>\n<li>Below it, add this code:<br \/>\n<div class=\"gist\" data-gist=\"f5e0fe3721f1488dfc3dc4aaca524d10\" data-gist-file=\"term_description.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/f5e0fe3721f1488dfc3dc4aaca524d10.js?file=term_description.php\">Loading gist f5e0fe3721f1488dfc3dc4aaca524d10<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save the file.<\/li>\n<\/ol>\n<p>Now if you revisit\u00a0your site and open a taxonomy term archive you&#8217;ll see the description:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/tax-term-description-frontend.png\" alt=\"Taxonomy term archives with the description added\" width=\"735\" height=\"526\" \/><\/p>\n<p>So now you have some template files in place for your project archives, including taxonomy term archives.<\/p>\n<h3>Outputting Links to Post Type and Taxonomy Term Archives<\/h3>\n<p>WordPress has a number of functions you can use to fetch and output the terms and post types that apply to a specific post or any post type.<\/p>\n<p>These have a number of uses:<\/p>\n<ul>\n<li>Identifying the taxonomy terms for a given post and providing a link to their archive pages.<\/li>\n<li>Fetching a list of taxonomy terms for use in a custom loop (which you&#8217;ll learn about in the next part of this series).<\/li>\n<li>Identifying the current post type so you can display other posts of the same post type after the main content (which we&#8217;ll look at in the next part of the series, as it involves writing a custom query).<\/li>\n<\/ul>\n<p>Let&#8217;s work with the first\u00a0of those applications, and add a list of taxonomy terms for each of our posts to the loop. You need to do this in your <em>loop-project.php<\/em> file and your <em>loop-single.php<\/em> file.<\/p>\n<ol>\n<li>Open <em>loop-project.php<\/em>.<\/li>\n<li>After the closing <code>&lt;\/div&gt;<\/code> tag for your content section, add this:<br \/>\n<div class=\"gist\" data-gist=\"1155bfca382659ad71a8aed0b972647c\" data-gist-file=\"term_list.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/1155bfca382659ad71a8aed0b972647c.js?file=term_list.php\">Loading gist 1155bfca382659ad71a8aed0b972647c<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Open <em>loop-single.php<\/em>.<\/li>\n<li>Again, after the content div, add this:<br \/>\n<div class=\"gist\" data-gist=\"98ebba9db181f89d127eeb1d070b98de\" data-gist-file=\"term_list_singular.php\"><a class=\"loading\" href=\"https:\/\/gist.github.com\/98ebba9db181f89d127eeb1d070b98de.js?file=term_list_singular.php\">Loading gist 98ebba9db181f89d127eeb1d070b98de<\/a><div class=\"gist-consent-notice\" style=\"display:none\"><p>Please <a href=\"javascript:Cookiebot.renew()\">update your cookie preferences<\/a> to enable preference cookies to view this gist.<\/p><\/div><\/div><\/li>\n<li>Save both files.<\/li>\n<\/ol>\n<p>This uses two functions:<\/p>\n<ul>\n<li>In both files, you used <a href=\"https:\/\/codex.wordpress.org\/Function_Reference\/the_terms\" target=\"_blank\"><code>the_terms()<\/code><\/a> to output a list of the terms the current post belongs to, with three parameters: the post ID, the preceding text, and the text between each item in the list.<\/li>\n<li>In the <em>loop-single.php<\/em> file, you used the <a href=\"https:\/\/codex.wordpress.org\/Conditional_Tags#A_Single_Page.2C_a_Single_Post.2C_an_Attachment_or_Any_Other_Custom_Post_Type\" target=\"_blank\"><code>is_singular( 'project' )<\/code><\/a> function to check we&#8217;re in a single post of the\u00a0project post type, rather than any other kind of single post.<\/li>\n<\/ul>\n<p>Now take a look at your single projects or an archive page for them, and you&#8217;ll see a list of\u00a0services for each project, with clickable links:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/services-list.png\" alt=\"project with a list of applicable services\" width=\"735\" height=\"464\" \/><\/p>\n<p>There isn&#8217;t much spacing between that list and the footer in the screenshot above, or between it and subsequent posts on archive pages, so you might want to add a margin to that <code>.entry-meta<\/code> class. If you&#8217;d like, you can also put it in a box to make it stand out more. I&#8217;ve added some extra styling to the source files for the series and here&#8217;s my post now:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"attachment-735x735 size-735x735 aligncenter\" src=\"https:\/\/wpmudev.com\/blog\/wp-content\/uploads\/2016\/05\/services-list-styled.png\" alt=\"The list of services in a blue box\" width=\"735\" height=\"526\" \/><\/p>\n<h3>Post Types and Taxonomies Take WordPress Further<\/h3>\n<p>Without custom post types and taxonomies, WordPress would be a pretty dull system. But with them, you can add your own content and structure your site around that, turning WordPress from a blogging platform into a CMS.<\/p>\n<p>In this part of the series you&#8217;ve learned how to register your own post types and taxonomies, how to create template files for them in your theme, and how to add links to taxonomy term archives in the loop.<\/p>\n<p>In the next part of this series, we&#8217;ll use the custom content we&#8217;ve created when coding\u00a0custom queries and loops. You&#8217;ll learn all about how the loop works and how to create your own custom queries.<\/p>\n<p>See you next time!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Custom post types and taxonomies are what make WordPress a Content Management System (CMS), and not just a blogging platform. With them, you can add your own post types, which you can then display using targeted template files. You can also create custom taxonomies that let you use more than just categories and tags to [&hellip;]<\/p>\n","protected":false},"author":347011,"featured_media":156933,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"blog_reading_time":"","wds_primary_category":0,"wds_primary_tutorials_categories":0,"footnotes":""},"categories":[557],"tags":[9770,10493],"tutorials_categories":[],"class_list":["post-155640","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-development","tag-development-2","tag-intermediate"],"_links":{"self":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/155640","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/users\/347011"}],"replies":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/comments?post=155640"}],"version-history":[{"count":23,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/155640\/revisions"}],"predecessor-version":[{"id":209715,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/posts\/155640\/revisions\/209715"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media\/156933"}],"wp:attachment":[{"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/media?parent=155640"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/categories?post=155640"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tags?post=155640"},{"taxonomy":"tutorials_categories","embeddable":true,"href":"https:\/\/wpmudev.com\/blog\/wp-json\/wp\/v2\/tutorials_categories?post=155640"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}