Add categories to custom post type and display based on categories

user4260940 picture user4260940 · Jan 12, 2015 · Viewed 33.6k times · Source

I am working on a wordpress site with theme name flozo . It has a custom post type named work. I wanted to display the works in my template based on each category.

Here is the code:

<?php
$args = array( 'post_type' => 'work', 'posts_per_page' => 15 );
$loop = new WP_Query( $args );
$count = 0;
echo '<ul>';
while ( $loop->have_posts() ) : $loop->the_post();

    $count++;
    $class = ($count % 3 == 1) ? 'first' : '';

    echo '<li class="'.$class.'">';
    echo '<a href="';
    the_permalink();
    echo '">';
    echo '<div class="overlay" style="background-color:'.ot_get_option( 'main_colour' ).';"></div>';
    the_post_thumbnail('full');
    echo '</a>';

    echo '<br />';

    echo '<h2><a href="';
    the_permalink();
    echo '">';
    the_title();
    echo '</a></h2>';

    echo '<div class="entry-content">';
    echo limit_words(get_the_excerpt(), '30'); 
    echo '..</div>';
    echo '</li>';
endwhile;
echo '</ul>';
?>

I've added

 $args = array( 'post_type' => 'work', 'tag_ID' => 15 ,'posts_per_page' => 15 );

where 15 is the id of my category, but it didn't work

I've also tried

<?php
$catquery = new WP_Query( 'cat=15&posts_per_page=3' );
while($catquery->have_posts()) : $catquery->the_post();
?>
<ul class="last-cat">
<li><a href="<?php the_permalink() ?>" rel="bookmark"><?php the_post_thumbnail(); ?> <p><?php     the_title(); ?></p><span><?php echo get_the_date(); ?></span></a></li></ul>
<?php endwhile; ?>

which also didn't help.

Edit:

The category url is

http://jointviews.com/wp-admin/edit-tags.php?action=edit&taxonomy=categories&tag_ID=15&post_type=work

The post type registration code is :

add_action('init', 'work_register');   

function work_register() {   

$labels = array( 
    'name' => _x('Work', 'post type general name'), 
    'singular_name' => _x('Work Item', 'post type singular name'), 
    'add_new' => _x('Add New', 'work item'), 
    'add_new_item' => __('Add New Work Item'), 
    'edit_item' => __('Edit Work Item'), 
    'new_item' => __('New Work Item'), 

    'view_item' => __('View Work Item'), 
    'search_items' => __('Search Work'), 
    'not_found' => __('Nothing found'), 
    'not_found_in_trash' => __('Nothing found in Trash'), 
    'parent_item_colon' => '' 
);   

$args = array( 
    'labels' => $labels, 
    'public' => true, 
    'publicly_queryable' => true, 
    'show_ui' => true, 
    'query_var' => true, 
    'menu_icon' => get_stylesheet_directory_uri() . '/article16.png', 
    'rewrite' => array( 'slug' => 'work', 'with_front'=> false ), 'capability_type' => 'post', 
    'hierarchical' => true, 
    'menu_position' => null, 
    'supports' => array('title','editor','thumbnail') 
);   

register_post_type( 'work' , $args ); 

register_taxonomy("categories", array("work"), array("hierarchical" => true, "label" => "Categories", "singular_label" => "Category", "rewrite" => array( 'slug' => 'work', 'with_front'=> false )));



}

Answer

Pieter Goosen picture Pieter Goosen · Jan 12, 2015

Both of the other answers are incorrect, specially the one from the OP. query_posts should NEVER EVER be used, it is even stated in the codex, so please, read the codex. Also, you should never replace the main query with custom queries.

The solution is simple as I have described below and it is the correct way of doing it.

ORIGINAL ANSWER

You have a couple of flaws here

  • For your custom post type to have an archive, you need to set the has_archive parameter to true in your custom post type registration arguments. See register_post_type()

  • If you are not going to use your custom post type like pages, set the hierarchical parameter to false. Setting this to true will considerably slow down your backend as your posts increase as Wordpress will try to build a tree for each post like it does for pages

  • Never use custom queries in place of the main query. It is always more troublesome and a waste of resources. See this post for a full explanation on where and when to use custom queries correctly.

  • This point is an extension of the previous one. If you need to change the main query, use pre_get_posts to do so. It uses the same exact parameters as WP_Query as the main query uses WP_Query to fetch posts. This is all explained in the linked post above

  • Your main flaw in your custom query is your lack of understanding what the difference is between categories, tags and custom taxonomies. I have written a complete post ( which you can read here ) on this and actually entered it into the codex as well. You are making use of a custom taxonomy, so the category parameters won't work. You need to use a tax_query for custom taxonomies

To solve your issue, follow the following steps

  • Add the has_achive parameter to your arguments when registering your custom post type and set it to true. If you want, set the hierarchical parameter to false as well in your custom post type. (Do not set this for your custom taxonomy, this will make your taxonomy behave like normal tags)

  • After this, flush your rewrite rules by visiting the permalink page under "Settings" and clicking "Update"

  • Visit your homepage just to make sure your new rules is saved

  • Delete your custom query and go back to the default loop. Your archive-work.php should look like this

    if( have_posts() ) {
        while( have_posts() ) {
            the_post();
    
            // Your custom markup and template tags
    
        }
    }
    
  • If you need to display posts from a specific term, create a taxonomy.php, taxonomy-{$taxonomy}.php or taxonomy-{$taxonomy}-{$term}.php template. Check the Template Hierarchy for more info

EDIT 1

If you only need to show a specific term on your custom post type archive term, after you have done the above, use pre_get_posts to alter the main query the correct way

add_action( 'pre_get_posts', function ( $q ) {

    if( !is_admin() && $q->is_main_query() && is_post_type_archive( 'work' ) ) {
        $q->set( 'categories', 'slides' );
    }

});

EDIT 2

Here is code to solve this

Copy and paste the following code in place of your code where you register your post type. I have added the has_archive parameter. I have also changed the rewrite rule for your taxonomy to categories. It is really troublesome to have the same slug for both custom post type and taxonomy. This does not work by default and completely throws everything off target

add_action( 'init', 'work_register' );   

function work_register() {   

    $labels = array( 
        'name' => _x('Work', 'post type general name'), 
        'singular_name' => _x('Work Item', 'post type singular name'), 
        'add_new' => _x('Add New', 'work item'), 
        'add_new_item' => __('Add New Work Item'), 
        'edit_item' => __('Edit Work Item'), 
        'new_item' => __('New Work Item'), 

        'view_item' => __('View Work Item'), 
        'search_items' => __('Search Work'), 
        'not_found' => __('Nothing found'), 
        'not_found_in_trash' => __('Nothing found in Trash'), 
        'parent_item_colon' => '' 
    );   

    $args = array( 
        'labels' => $labels, 
        'public' => true, 
        'publicly_queryable' => true, 
        'show_ui' => true, 
        'query_var' => true, 
        'menu_icon' => get_stylesheet_directory_uri() . '/article16.png', 
        'rewrite' => array( 'slug' => 'work', 'with_front'=> false ), 
        'capability_type' => 'post', 
        'hierarchical' => true,
        'has_archive' => true,  
        'menu_position' => null, 
        'supports' => array('title','editor','thumbnail') 
    );   

    register_post_type( 'work' , $args ); 

    register_taxonomy( 'categories', array('work'), array(
        'hierarchical' => true, 
        'label' => 'Categories', 
        'singular_label' => 'Category', 
        'rewrite' => array( 'slug' => 'categories', 'with_front'=> false )
        )
    );

    register_taxonomy_for_object_type( 'categories', 'work' ); // Better be safe than sorry
}

In your archive-work.php, replace your custom query with this code

<?php

$count = 0;
echo '<ul>';
while ( have_posts() ) : the_post();

    $count++;
    $class = ($count % 3 == 1) ? 'first' : '';

    echo '<li class="'.$class.'">';
    echo '<a href="';
    the_permalink();
    echo '">';
    echo '<div class="overlay" style="background-color:'.ot_get_option( 'main_colour' ).';"></div>';
    the_post_thumbnail('full');
    echo '</a>';

    echo '<br />';

    echo '<h2><a href="';
    the_permalink();
    echo '">';
    the_title();
    echo '</a></h2>';

    echo '<div class="entry-content">';
    echo limit_words(get_the_excerpt(), '30'); 
    echo '..</div>';
    echo '</li>';
endwhile;
echo '</ul>';
?>

VERY IMPORTANT -> OK, now visit Settings >> Permalinks in the back end (admin area) and click Save Changes. This will flush your permalinks and set your new permalink structure

You should now see all your post from your custom post type when you visit

http://example.com/work/