15

How do I discover the custom post type slug when I'm on an archive page?

For instance if /products/ fires the archive-products.php template, how (pragmatically) do I get the post type slug?

Thanks

19

To get the current post type use get_post_type(). Then ask get_post_type_object() for all the data you need, for example the slug:

$post_type = get_post_type();
if ( $post_type )
{
    $post_type_data = get_post_type_object( $post_type );
    $post_type_slug = $post_type_data->rewrite['slug'];
    echo $post_type_slug;
}
| improve this answer | |
  • 1
    I think (hadn't tested) get_queried_object() would get to same info in less moves. – Rarst Oct 9 '12 at 1:15
  • @Rarst Maybe, but I think the code I suggested is easier to understand. – fuxia Oct 9 '12 at 1:18
  • 1
    Toscho's solutions is wrong, because get_post_type returns the post type of current page, and, when you are into archive page, this function alwasy return "page". I'm sarching to solve the same: When I am into archive page of 'books' (4 example), I want this: 'books'. When I get it I'll post it. – eMarine Jun 25 '13 at 9:58
  • 1
    unfortunately it's not that simple, though you'd be better off with just $posttype = get_query_var('post_type'); ... I've added a comprehensive alternative. – majick Jun 6 '16 at 18:56
  • I don think This is answer cover the whole story. You should check the install rewrite rules as many filters (like woocommerce shop page) is making changes. Use the Worpdress own mecanism instead, see my answer somewhere below. – Jonas Lundman Oct 21 '17 at 17:17
6

I'm using this outside of the loop on the archive.php template to get which custom post archive I'm on.

It's a combo of the methods that both @toscho and @Rarst recommended:

$post_type = get_queried_object();
echo $post_type->rewrite['slug'];

Update: @majick pointed out that this only works if you've set the rewrite slug for your CPT. Rewrite slug is optional when registering a CPT and defaults to post_type if not set.

| improve this answer | |
  • when I tried this I got Notice: Undefined property: stdClass::$rewrite in ***\wp-content\themes\marks-remarks\archive.php on line 4 – patrickzdb Oct 20 '15 at 13:37
  • this will only work if the rewrite slug is set for the registered CPT, as it is optional and defaults to the post_type – majick Jun 3 '16 at 3:23
  • Thanks for catching that @majick! I've updated the post to reflect your info. – Jerry Jun 3 '16 at 14:23
  • turns out that was the tip of the iceberg... check my new answer for the underwater part :-) – majick Jun 6 '16 at 18:53
4

The answers get confusing. And maybe Im as well but the headline question is:

Get custom post type slug for an archive page

If you mean post type archive landing-page, and when is_post_type_archive() returns true, you want the slug that responing to current viewing archive:

/* returns /products/ */

$responding_name = str_replace(get_home_url(), '', get_post_type_archive_link(get_query_var('post_type')));

/* continue to get 'products' without slug slashes */
$responding_name = str_replace('/', '', $responding_name);

-- END OF ANSWERING THE QUESTION --

Explanation:

You cant rely on the registered slug. Wordpress is not either. For example, when calling get_post_type_archive_link() Wordpress is checking the current rewrite rules for your install .

Wherever you are, inside or outside loop, current archive or single post, reverse the get_post_type_archive_link() mechanism. (Permalinks enabled.)

Considerations:

As mentioned here, the post type(s) in current query can be an array. You can go futher with your intensions with filter out the post type you look for, example:

$post_type = get_query_var('post_type'); 
if(is_array($post_type)) $post_type = reset($post_type);

or

if(isset($post_types[0])) $post_type = $post_types[0];

Another point of view:

Woocommerce example, is registered with 'products' post type object but in reality uses rewritten rule name (shop):

/* returns shop */
$responding_name = str_replace('/', '', str_replace(get_home_url(), '', get_post_type_archive_link('product')));

Mark, Im using $responding_name, because the objectives might vary. A post archive does not exists, its just a url.

| improve this answer | |
  • This made it very clear thank you. Was looking for this solution. If the question was not looking for "only just the post type name", this should be a woted up answer. – Jonas Lundman Oct 21 '17 at 18:36
2

t should be noted that if has_archive is set to true while registering the Custom Post Type, the post type archive /cptslug/ will be internally rewritten to ?post_type=cptslug. So this would also mean is_post_type_archive() will return true.

Unfortunately, where the registered rewrite slug is different to the post type, you are not actually reliably getting the post_type. eg. if your post type was myplugin_cars and your rewrite slug was cars and you need to be getting myplugin_cars then even this (to prevent errors if the current queried object is not a custom post type) will still fail:

$queryobject = get_queried_object();
if (has_property('rewrite',$queryobject)) {
    if (isset($queryobject->rewrite['slug'])) {
         $posttype = $queryobject->rewrite['slug'];
     }
 }

But because is_post_type_archive is true this is more reliable:

if (is_post_type_archive()) {
    $posttype = get_query_var('post_type');
    // which is basically the same as:
    // global $wp_query;
    // $posttype = $wp_query->query_vars['post_type'];
} 
else ($posttype = 'post';}

But hang on, there's more... turns out with a little testing it really isn't that simple either... what if you are on a taxonomy archive page with multiple post types in the taxonomy..? Or assign post tags to a custom post type other than post? Or are on an author archive page? Date archive page? ...or even have a complex tax_query or meta_query for WP_Query?

The only reliable answer (without testing for every possible archive case) is to loop the actual posts in the query... Here is the full function I came up with to work on both singular and archive pages, and allowing you to optionally pass a custom query object (or post object/post ID for singular posts):

function get_current_post_types($object=null) {

    // if a numeric value passed, assume it is a post ID
    if ( ($object) && (is_numeric($object)) ) {$object = get_post($object);}
    // if an object is passed, assume to be a post object
    if ( ($object) && (is_object($object)) ) {return get_post_type($object);}

    // standard single post type checks
    if (is_404()) {return '';}
    // update: removed this check, handled by is_singular
    // if (is_single()) {return 'post';}
    if (is_page()) {return 'page';}
    if (is_attachment()) {return 'attachment';}
    if (is_singular()) {return get_post_type();}

    // if a custom query object was not passed, use $wp_query global
    if ( (!$object) || (!is_object($object)) ) {
        global $wp_query; $object = $wp_query;
    }
    if (!is_object($object)) {return '';} // should not fail

    // if the post_type query var has been explicitly set
    // (or implicitly set on the cpt via a has_archive redirect)
    // ie. this is true for is_post_type_archive at least
    // $vqueriedposttype = get_query_var('post_type'); // $wp_query only
    if (property_exists($object,'query_vars')) {
        $posttype = $object->query_vars['post_type'];
        if ($posttype) {return $posttype;}
    }

    // handle all other cases by looping posts in query object
    $posttypes = array();
    if (method_exists($object,'found_posts')) {
        if ($object->found_posts > 0) {
            $queriedposts = $object->posts;
            foreach ($queriedposts as $queriedpost) {
                $posttype = $queriedpost->post_type;
                if (!in_array($posttype,$posttypes)) {$posttypes[] = $posttype;}
            }
            if (count($posttypes == 1)) {return $posttypes[0];}
            else {return $posttypes;}
         }
     }
     return ''; // nothin to see here
}

This will reliably (did I say that?) return an array of post types if more than one is present, or a string with the single post type if there is only one type. All you need to do is:

$posttypes = get_current_post_types();
// or pass a post ID 
$posttypes = get_current_post_types($postid);
// or pass a post object
$posttypes = get_current_post_types($post);
// or pass a custom query - that has been run
$posttypes = get_current_post_types($query);

Example Usage (just for fun):

add_filter('the_posts','myplugin_fading_thumbnails',10,2);
function myplugin_fading_thumbnails($posts,$query) {
    if (!is_archive()) {return $posts;}
    $cptslug = 'myplugin_slug'; $dosomethingcool = false;
    $posttypes = get_current_post_types($query);
    if ( (is_array($posttypes)) && (in_array($cptslug,$posttypes)) ) {$dosomethingcool = true;}
    elseif ($cptslug == $posttypes) {$dosomethingcool = true;}

    if ($dosomethingcool) {
        global $fadingthumbnails; $fadingthumbnails = $cptslug;
        if (!has_action('wp_footer','myplugin_cpt_script')) {
            add_action('wp_footer','myplugin_cpt_script');
        }
    }

    function myplugin_cpt_script() {
        global $fadingthumbnails;
        echo "<script>var thumbnailclass = 'img.thumbtype-".$fadingthumbnails."';
        function fadeoutthumbnails() {jQuery(thumbnailclass).fadeOut(3000,fadeinthumbnails);}
        function fadeinthumbnails() {jQuery(thumbnailclass).fadeIn(3000,fadeoutthumbnails);}
        jQuery(document).ready(function() {fadeoutthumbnails();});
        </script>";
    }

    return $posts;
 }

To see the effect, change the custom post type in the code to post, and add a thumbtype-post class attribute to your post thumbnail images...

| improve this answer | |
1

You can use this code and this code is working for me,

 $t_slug = get_query_var('term');
| improve this answer | |
0

You can use this code:

$queried_object = get_queried_object();
$posttype_slug = $queried_object->query_var;
echo $posttype_slug;

use $posttype_slug var whatever you need

| improve this answer | |
  • it needs to $queried_object->query_var['post_type']; for this to work... – majick Jun 6 '16 at 18:57
  • No. $queried_object->query_var containe only string of post type. it's not object or array. look at this image: prntscr.com/bd58e1 – Guy Ytzhak Jun 6 '16 at 19:33
  • ok but only if the queried object is definitely a custom post type object, you will get a different corresponding object and thus empty value for category/tax/tag/author archive pages for example. even for ?post_type=post I get empty. compare with get_query_var('post_type'); – majick Jun 6 '16 at 20:31
-4
if( get_post_type( get_the_ID() ) == 'projects' )
{
  //enter code for this post type
}
| improve this answer | |

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.