HomeDesign / DevWordPress custom post types

    WordPress custom post types

    While not the most common reason for using WordPress, using the popular CMS for developing functional and advanced web apps can be a great choice for many reasons, including speed, quality, safety and last but not least, drawing on the community for examples, plugins and the general support that is available due to the popularity of WordPress.


    Before we start, let’s briefly touch on what exactly is meant by custom post types where WordPress is concerned.

    - Advertisement -

    Anyone who’s been using WP has probably encountered the “Posts” page, visible in the control panel. Similar to this are “Pages,” which are just a slightly different version of posts. With WordPress being set-up mainly for bloggers, this setup works well in many cases, but if you want a portfolio that’s easy to manage, a directory of businesses, products or something else, using the custom post types is a great way to categorize and manage entries with special data or unique display rules.

    In combination with custom post types, meta fields and plugins, WordPress delivers everything needed to create awesome web apps. The benefit of using WP in this regard, is that all back-end development is already there for us to tap into, all safety measures, such as sanitizing user input etc. are taken care of as well, and there’s plenty of free themes available to display our front-end results.

    What this means is that we can focus fully on developing the core features of our web app, leaving WordPress to take care of all the “boring” stuff, while being perfectly safe and protected by doing so.

    - Advertisement -

    Ok, let’s get started with developing a simple web app that lists WordPress themes as post types for our example!

    1. First, we will add a new custom post type to our WordPress file. There are a few different ways of doing so, 2 of the most popular are using Plugins, or adding the code to “functions.php” from the active theme.
      For the sake of ease, let’s use the themes function.php file for this.
    2. Go to “Appearance -> Editor” then choose “functions.php” from the list.
    3. Add the above code in the very bottom of the file.
    4. If you are using a specific text_domain, replace “your_text_domain” with the real one, so you can translate the fields and labels into other languages later on.
    // Register Custom Post Type
    function theme_list() {
    $labels = array(
     'name' => _x( 'Themes', 'Post Type General Name', 'your_text_domain' ),
     'singular_name' => _x( 'Theme', 'Post Type Singular Name', 'your_text_domain' ),
     'menu_name' => __( 'Themes', 'your_text_domain' ),
     'name_admin_bar' => __( 'Theme', 'your_text_domain' ),
     'archives' => __( 'Theme Archives', 'your_text_domain' ),
     'parent_item_colon' => __( 'Parent Item:', 'your_text_domain' ),
     'all_items' => __( 'All Items', 'your_text_domain' ),
     'add_new_item' => __( 'Add New Item', 'your_text_domain' ),
     'add_new' => __( 'Add New', 'your_text_domain' ),
     'new_item' => __( 'New Item', 'your_text_domain' ),
     'edit_item' => __( 'Edit Item', 'your_text_domain' ),
     'update_item' => __( 'Update Item', 'your_text_domain' ),
     'view_item' => __( 'View Item', 'your_text_domain' ),
     'search_items' => __( 'Search Item', 'your_text_domain' ),
     'not_found' => __( 'Not found', 'your_text_domain' ),
     'not_found_in_trash' => __( 'Not found in Trash', 'your_text_domain' ),
     'featured_image' => __( 'Featured Image', 'your_text_domain' ),
     'set_featured_image' => __( 'Set featured image', 'your_text_domain' ),
     'remove_featured_image' => __( 'Remove featured image', 'your_text_domain' ),
     'use_featured_image' => __( 'Use as featured image', 'your_text_domain' ),
     'insert_into_item' => __( 'Insert into item', 'your_text_domain' ),
     'uploaded_to_this_item' => __( 'Uploaded to this item', 'your_text_domain' ),
     'items_list' => __( 'Items list', 'your_text_domain' ),
     'items_list_navigation' => __( 'Items list navigation', 'your_text_domain' ),
     'filter_items_list' => __( 'Filter items list', 'your_text_domain' ),
     $rewrite = array(
     'slug' => 'themes',
     'with_front' => true,
     'pages' => true,
     'feeds' => true,
     $args = array(
     'label' => __( 'Theme', 'your_text_domain' ),
     'description' => __( 'List of themes', 'your_text_domain' ),
     'labels' => $labels,
     'supports' => array( 'title', 'editor', 'thumbnail', ),
     'taxonomies' => array( 'category', 'post_tag' ),
     'hierarchical' => false,
     'public' => true,
     'show_ui' => true,
     'show_in_menu' => true,
     'menu_position' => 5,
     'show_in_admin_bar' => true,
     'show_in_nav_menus' => true,
     'can_export' => true,
     'has_archive' => true, 
     'exclude_from_search' => false,
     'publicly_queryable' => true,
     'rewrite' => $rewrite,
     'capability_type' => 'page',
     register_post_type( 'theme_list', $args );
    add_action( 'init', 'theme_list', 0 );


    Great! Now we have a new post type, available in the WordPress control panel, and we can now add them, display them on the front-end and manipulate them in the same way as normal posts.

    Let’s now add some extra functionality to this, by creating a few meta fields that will be displayed for each theme.

    1. Go to “Appearance -> Editor”
    2. Choose “functions.php
    3. Paste the following into the bottom of the file:
    class theme_info_Meta_Box {
    public function __construct() {
     if ( is_admin() ) {
     add_action( 'load-post.php', array( $this, 'init_metabox' ) );
     add_action( 'load-post-new.php', array( $this, 'init_metabox' ) );
    public function init_metabox() {
     add_action( 'add_meta_boxes', array( $this, 'add_metabox' ) );
     add_action( 'save_post', array( $this, 'save_metabox' ), 10, 2 );
    public function add_metabox() {
     __( 'Theme Info', 'your_text_domain' ),
     array( $this, 'render_metabox' ),
    public function render_metabox( $post ) {
    // Add nonce for security and authentication.
     wp_nonce_field( 'theme_nonce_action', 'theme_nonce' );
    // Retrieve an existing value from the database.
     $theme_version = get_post_meta( $post->ID, 'theme_version', true );
     $theme_responsive = get_post_meta( $post->ID, 'theme_active_development', true );
     $theme_link = get_post_meta( $post->ID, 'theme_responsive', true );
     // Set default values.
     if( empty( $theme_version ) ) $theme_version = '';
     if( empty( $theme_responsive ) ) $theme_responsive = '';
     if( empty( $theme_link ) ) $theme_link = '';
    // Form fields.
     echo '<table class="form-table">';
    echo ' <tr>';
     echo ' <th><label for="theme_version" class="theme_version_label">' . __( 'Theme Version', 'your_text_domain' ) . '</label></th>';
     echo ' <td>';
     echo ' <input type="number" id="theme_version" name="theme_version" class="theme_version_field" placeholder="' . esc_attr__( '', 'your_text_domain' ) . '" value="' . esc_attr__( $theme_version ) . '">';
     echo ' </td>';
     echo ' </tr>';
    // Form fields
     echo ' <tr>';
     echo ' <th><label for="theme_responsive" class="theme_responsive_label">' . __( 'Is the theme responsive?', 'your_text_domain' ) . '</label></th>';
     echo ' <td>';
     echo ' <select id="theme_responsive" name="theme_responsive" class="theme_responsive_field">';
     echo ' <option value="Yes" ' . selected( $theme_responsive, 'Yes', false ) . '> ' . __( 'Yes', 'your_text_domain' );
     echo ' <option value="No" ' . selected( $theme_responsive, 'No', false ) . '> ' . __( 'No', 'your_text_domain' );
     echo ' </select>';
     echo ' </td>';
     echo ' </tr>'; 
     // Form fields
     echo ' <tr>';
     echo ' <th><label for="theme_link" class="theme_link_label">' . __( 'Link to website', 'your_text_domain' ) . '</label></th>';
     echo ' <td>'; 
     echo ' <input type="text" id="theme_link" name="theme_link" class="theme_link_field" placeholder="' . esc_attr__( '', 'your_text_domain' ) . '" value="' . esc_attr__( $theme_link ) . '">';
     echo ' </td>';
     echo ' </tr>'; 
     echo '</table>';
    public function save_metabox( $post_id, $post ) {
    // Add nonce for security and authentication.
     $nonce_name = $_POST['theme_nonce'];
     $nonce_action = 'theme_nonce_action';
    // Check if a nonce is set.
     if ( ! isset( $nonce_name ) )
    // Check if a nonce is valid.
     if ( ! wp_verify_nonce( $nonce_name, $nonce_action ) )
    // Check if the user has permissions to save data.
     if ( ! current_user_can( 'edit_post', $post_id ) )
    // Check if it's not an autosave.
     if ( wp_is_post_autosave( $post_id ) )
    // Check if it's not a revision.
     if ( wp_is_post_revision( $post_id ) )
    // Sanitize user input.
     $theme_new_version = isset( $_POST[ 'theme_version' ] ) ? sanitize_text_field( $_POST[ 'theme_version' ] ) : '';
     $theme_new_link = isset( $_POST[ 'theme_link' ] ) ? $_POST[ 'theme_link' ] : '';
     $theme_new_responsive = isset( $_POST[ 'theme_responsive' ] ) ? $_POST[ 'theme_responsive' ] : '';
     // Update the meta field in the database.
     update_post_meta( $post_id, 'theme_version', $theme_new_version );
     update_post_meta( $post_id, 'theme_responsive', $theme_new_responsive );
     update_post_meta( $post_id, 'theme_link', $theme_new_link );
    new theme_info_Meta_Box;


    READ ALSO:  Joomla,Drupal or Wordpress - which one is the best CMS?

    Awesome, now we have a custom post type called “Themes” that has 3 new fields attached to every post created. This makes it easy to create new posts, using the same layout and structure, without having to memorize the names of the custom fields, and it is particularly useful when you have many contributors and authors registered in WordPress, this way all information they need to input is easily understood and shown.

    Now we just need to do one more thing; show the new data on the posts page!

    1. Go to “Appearance -> Editor” and choose “single.php
    2. Here comes the funny part, choosing where and how to display the new meta fields
    3. Depending on your theme and how you want to show the meta fields, add the following code somewhere in the “single.php”
    $theme_version_value = get_post_meta( get_the_ID(), 'theme_version', true );
    $theme_link_value = get_post_meta( get_the_ID(), 'theme_link', true );
    $theme_responsive_value = get_post_meta( get_the_ID(), 'theme_responsive', true );
    echo $theme_version_value;
    echo $theme_link_value;
    echo $theme_responsive_value;


    With this code, you should now be up and running, having a new Menu called “Themes”, 3 new meta fields in the custom post, and it should also display the 3 fields on the post pages on the front-end. Of course there are many ways of doing this, you could also used Advanced Custom Fields, and a plugin for new Post Types, but this is the developers way of handling things.

    It is worth to note, that if you change the theme, all this will not be shown in your new theme. If you expect that you might change themes soon, consider reading up on how to transfer the above code into a new custom plugin, so the post types and meta fields can be shown regardless of what theme is active at any given time.

    Author info:

    Mark Pedersen has been working with web and app development for more than 15 years, originally getting his feet wet with PHP in PHPNuke, before moving on to Joomla, and ultimately settling with WordPress. These days he also develops apps at Nodes.

    - Advertisement -
    Owner of WPTidBits. Totally in love with WordPress!


    Please enter your comment!
    Please enter your name here