17

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

7 Answers 7

23

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;
}
5
  • 2
    I think (hadn't tested) get_queried_object() would get to same info in less moves.
    – Rarst
    Oct 9, 2012 at 1:15
  • @Rarst Maybe, but I think the code I suggested is easier to understand.
    – fuxia
    Oct 9, 2012 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, 2013 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, 2016 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. Oct 21, 2017 at 17:17
7

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.

4
  • 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, 2015 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, 2016 at 3:23
  • Thanks for catching that @majick! I've updated the post to reflect your info.
    – Jerry
    Jun 3, 2016 at 14:23
  • turns out that was the tip of the iceberg... check my new answer for the underwater part :-)
    – majick
    Jun 6, 2016 at 18:53
6

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.

2
  • 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. Oct 21, 2017 at 18:36
  • 1
    Yes! $post_type_link = get_post_type_archive_link( get_query_var( 'post_type' ) ); was all I needed. Nov 25, 2020 at 17:11
3

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

 $t_slug = get_query_var('term');
1
  • This is better than get_post_type(), as this will return the correct value even when the archive is empty Mar 29, 2021 at 5:11
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...

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

3
  • it needs to $queried_object->query_var['post_type']; for this to work...
    – majick
    Jun 6, 2016 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, 2016 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, 2016 at 20:31
-4
if( get_post_type( get_the_ID() ) == 'projects' )
{
  //enter code for this post type
}
0

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.