I created a new custom post type 'Projects' and want the archive of all posts of this type to be available at mysite.com/projects. At the moment all project single posts are shown with a slug as follows mysite.com/projects/project-title, but when I go to mysite.com/projects I get a 404.

Here is how I built the custom post type:

   /* Create the Project Custom Post Type ------------------------------------------*/
 function create_post_type_project() 
$labels = array(
    'name' => __( 'Projects' ),
    'singular_name' => __( 'Project' ),
    'add_new' => __('Add New'),
    'add_new_item' => __('Add New Project'),
    'edit_item' => __('Edit Project'),
    'new_item' => __('New Project'),
    'view_item' => __('View Project'),
    'search_items' => __('Search Project'),
    'not_found' =>  __('No project found'),
    'not_found_in_trash' => __('No project found in Trash'), 
    'parent_item_colon' => ''

  $args = array(
    'labels' => $labels,
    'public' => true,
    'exclude_from_search' => true,
    'publicly_queryable' => true,
    'show_ui' => true, 
    'query_var' => true,
    'capability_type' => 'post',
    'hierarchical' => false,
    'menu_position' => null,
    // Uncomment the following line to change the slug; 
    // You must also save your permalink structure to prevent 404 errors
    'rewrite' => array( 'slug' => 'projects' ),
    'has_archive' => true,
    'supports' => array('title','editor','thumbnail'),


  register_post_type(__( 'project' ),$args);

2 Answers 2


Nothing appears to be incorrect - (and I assumed you've gone to saved your permalink structure to flush the rewrite rules as the comments suggest? :) ).

I would recommend using this plug-in to determine problems with your url-redirection: http://wordpress.org/extend/plugins/monkeyman-rewrite-analyzer/ - update your question with your findings and someone may be able to offer a solution

However (but this probably isn't the cause of your issue)., you should not translate the post type's name, have:


instead of

register_post_type(__( 'project' ),$args);

Translations are for the benefit of the user - and so should be on labels only - the WordPress internal names shouldn't depend on translation.

  • projects/?$ post_type: project (.?.+?)(/[0-9]+)?/?$ pagename: projects page: (.+?)/?$ category_name: projects
    – urok93
    May 14, 2012 at 16:55
  • im getting a blank white page now when i navigate to /projects
    – urok93
    May 14, 2012 at 16:56
  • I had an extra bracket. Removed now. Could you include a screenshot of the rewrite analyser page with these results? May 14, 2012 at 17:01
  • @drtranz- I've tested your code. It works. The problem must be another plug-in. Deactivate them all, switch to Twenty Eleven, flush rewrites - and then try the code. Reactivate a plug-in a time - flushing the rules and testing after each one until you find the culprit. Lastly - try the theme. May 14, 2012 at 17:04
  • Thanks I just got it to work, turns out I just needed to fix some template files on the current template. Silly mistake, thanks for your help!
    – urok93
    May 15, 2012 at 16:24

The code you have pasted does not apear to be incorrect, however what you are asking for will also work using 'rewrite' => true

http://codex.wordpress.org states:

has_archive (boolean or string) (optional) Enables post type archives. Will use $post_type as archive slug by default.

Default: false

Note: Will generate the proper rewrite rules if rewrite is enabled. Also use rewrite to > change the slug used.

A solution to your problem may be that the template for the custom post type isn't working or has not been created, you can either try adding the following code to your functions.php or plugins function:

function _post_type_template_smart(){

    global $post;

    $single_template_name = 'single-projects.php';
    $archive_template_name = 'archive-projects.php';

    if ( is_single() && 'projects' == get_post_type() ){

        $template = locate_template(array($single_template_name), true);

        if(empty($template)) {

          include(PLUGIN_DIR . 'template/' . $single_template_name);


    }else if( is_archive() && 'projects' == get_post_type() ){

        $template = locate_template(array($archive_template_name), true);

        if(empty($template)) {

          include(PLUGIN_DIR . 'template/' . $archive_template_name);



add_filter('template_redirect', '_post_type_template_smart');

and in your 'single-projects.php'/'archive-projects.php' pages, create a loop/query/get_pages (whichever you prefer) to bring in and display the content:

    $args = array(
        //'child_of' => 0,
        'sort_order' => 'ASC',
        'sort_column' => 'post_modified',
        'hierarchical' => 1,
        'parent' => 0,
        'post_type' => 'projects',
        'post_status' => 'publish'
    $pages = get_pages( $args );
    foreach ( $pages as $project ){
        $project_id = $project->ID;
        $project_link = get_page_link($project->ID);
        $project_title = $project->post_title;
        $content = $project->post_content;
        $author = $project->post_author;
        $posted_on = $project->post_date;

            $content = 'There is no description for this package';
        echo '<div class="content">';
        echo $content;
        echo '</div>';      


Hope this helps!

  • 1
    A 404 is not a template issue - the 404 page is only used if the content cannot be found / determined. If WordPress cannot find the template, it falls back to a more generic template as per the template hierarchy. Also - in the template you don't need to get_pages or get_posts - WordPress will have already retrieved the content from the database and just needs a have_posts() loop to display it. May 14, 2012 at 16:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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