Pages :

  • Home - set as static home page;
  • blog - for blog posts;
  • About ;
  • Contact;
  • Projects;

List of templates:

  • front-page.php - for Home page;
  • home.php - for blog page;
  • about.php;
  • contact.php;
  • projects.php

I have dummy text set up for About and Contact page which shows up when respective pages are opened. Now, I want that :

When Projects page is opened it shows all the project posts through loop, the same way it shows posts in blog page (whose content type is post). My question is for blog page posts we simply click "Add New" in Posts and publish it. How do I add posts and description for my projects page?

Here is loop code in projects.php file :


$args = array(
'post_type' => 'projects'

$the_query = new WP_Query($args);


<?php if(have_posts()) : while($the_query->have_posts()) : $the_query->the_post(); ?>

<h3><a href="<?php the_permalink();?>"><?php the_title(); ?></a></h3>
<?php the_field('description'); ?>

<?php endwhile; else: ?>
    <p>There are no posts or pages here</p>
<?php endif; ?>

2 Answers 2


The best way is to register a custom post type then loop through that type within your projects page template.

CPT from GenerateWP.

if ( ! function_exists('projects') ) {

// Register Custom Post Type
function projects() {

    $labels = array(
        'name'                  => _x( 'Projects', 'Post Type General Name', 'text_domain' ),
        'singular_name'         => _x( 'Project', 'Post Type Singular Name', 'text_domain' ),
        'menu_name'             => __( 'Projects', 'text_domain' ),
        'name_admin_bar'        => __( 'Projects', 'text_domain' ),
        'parent_item_colon'     => __( 'Parent Project:', 'text_domain' ),
        'all_items'             => __( 'All Projects', 'text_domain' ),
        'add_new_item'          => __( 'Add New Project', 'text_domain' ),
        'add_new'               => __( 'Add New', 'text_domain' ),
        'new_item'              => __( 'New Project', 'text_domain' ),
        'edit_item'             => __( 'Edit Project', 'text_domain' ),
        'update_item'           => __( 'Update Project', 'text_domain' ),
        'view_item'             => __( 'View Project', 'text_domain' ),
        'search_items'          => __( 'Search Projects', 'text_domain' ),
        'not_found'             => __( 'Not found', 'text_domain' ),
        'not_found_in_trash'    => __( 'Not found in Trash', 'text_domain' ),
        'items_list'            => __( 'Projects list', 'text_domain' ),
        'items_list_navigation' => __( 'Projects list navigation', 'text_domain' ),
        'filter_items_list'     => __( 'Filter project list', 'text_domain' ),
    $rewrite = array(
        'slug'                  => 'project',
        'with_front'            => true,
        'pages'                 => true,
        'feeds'                 => true,
    $args = array(
        'label'                 => __( 'Project', 'text_domain' ),
        'description'           => __( 'A Single Project', 'text_domain' ),
        'labels'                => $labels,
        'supports'              => array( 'title', 'editor', 'excerpt', 'author', 'thumbnail', 'comments', 'custom-fields', ),
        'taxonomies'            => array( 'category', 'post_tag' ),
        'hierarchical'          => false,
        'public'                => true,
        'show_ui'               => true,
        'show_in_menu'          => true,
        'menu_position'         => 5,
        'menu_icon'             => 'dashicons-media-document',
        '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( 'projects', $args );

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


In your Projects Template run your custom loop.

 * Template Name: Projects Page Template
 * Description: Page template to display projects custom post types

 get_header(); ?>

   <div id="primary" class="content-area">
     <main id="main" class="site-main" role="main">

       // WP_Query arguments
        $args = array (
            'post_type' => 'projects',

        // The Query
        $query = new WP_Query( $args );

        // The Loop
        if ( $query->have_posts() ) {
            while ( $query->have_posts() ) {

            // PROJECT
                $query->the_post(); ?>
            <h3><a href="<?php the_permalink();?>"><?php the_title(); ?></a></h3>
            <?php the_field('description'); ?>

        } else { ?>
            <p>There are no posts or pages here</p>
        <?php }

        // Restore original Post Data

        // The Content
        echo apply_filters( 'the_content', get_the_content() );

     </main><!-- .site-main -->
   </div><!-- .content-area -->

 <?php get_sidebar(); ?>
 <?php get_footer(); ?>

You can create a page /projects and set the template to Projects Template which will list all your projects as /project/project-title.

But if you're looking to just add extra fields to a post and tag them as a project then that's more of a loop question.


From your question and code I accept that you have already registered a custom post type called projects and you have already published some projects.

If that is not the case, you would need to register a custom post type called projects. There are two very important parameters that you should keep in mind

  • public which you should set to true

  • has_archive which you should ignore or set to false (which is default). The reason for this is, you want to use a page template to display projects (which has the same slug as the post type), and not the normal templates in the hierarchy like archive-projects.php, archive.php or index.php. Setting has_archive to true will simply load post type posts on the templates in hierarchy, and your custom page will never load

Just always remember to flush rewrite rules when registering a post type for the first time or when you adjust values inside the function.

If you have have properly registered your post type and have correctly set up your projects page, then you should be able to publish projects in the backend under the Projects tab and you will be able to see it as the code in OP is fine.

One important detail overlooked, and not just by you ;-), is that you are missing the main loop on your page. If you are going to add a title or some descriptions in the backend editor to display on the front end when one visits the project page, you will need to add the main loop where you would want to display these descriptions and title for the page.

The main loop will display the page object which is inside the main query object. so anywhere where you would want to display anything from the page you have entered in the back end editor when you have created the page, simply add the following (which I would suspect would be before the custom query which should display the projects)

if ( have_posts() ) {
    while ( have_posts() ) {

        // Blah blah blah plus Mark Up


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.