I have following code


$sites = get_sites();
foreach ( $sites as $site ) {
    switch_to_blog( $site->blog_id );
    echo bloginfo('name');              
    $args = array(
         'public'   => true,
         '_builtin' => false
    $post_types = get_post_types( $args, '', 'and');
    foreach($post_types as $post_type){
<div class="col-lg-3 col-md-4 col-sm-6">
<div class="card card-default text-center wow slideInUp" data-wow-duration="2s" >
<h4 class="card-text"><?php echo $post_type->label; ?></h4>
<p class="card-text"><i class="fa fa-5x fa-<?php echo $post_type->menu_icon; ?>"></i></p>
<p class="card-text">
  <a href="" class="btn btn-success btn-small" href="#">Read more<i class="fa fa-arrow-circle-o-right"></i></a>


I want to grab all custom post created on sites in a network. When I checked the blog_id it changes with new blog. When I echoed bloginfo('name'), it also prints the name of different sites, But when I query for custom post, it shows custom post only from current site.

  • Are the post types defined in the various sites in your network?
    – Pat J
    Commented Jan 8, 2018 at 1:30

1 Answer 1


There appear to be a couple things at work here:

  1. The switch_to_blog() call does not switch plugins (see ticket #14941), so if your custom post types are defined in a plugin (as they most likely are and should be), then they won't be loaded in a switch_to_blog() scenario. (This is highly unlikely to changed, judging by the commentary on the ticket.)

  2. Also, the get_post_types() uses a global variable; it doesn't grab the CPTs registered in the site you switch to, but the list from the site you started from. Global variables don't seem to be updated on switch_to_blog(), presumably for reasons similar to the reasons plugins aren't unloaded/loaded on switch_to_blog().

I don't know that there's going to be an easy way to do what you're trying to do, I'm afraid.

A possible work-around

register_post_type() fires an action—registered_post_type—as it finishes up. You should be able to use this to build a list of custom post types on a given site.

Something like this (very simple, untested code):


add_action( 'registered_post_type', 'wpse_290292_post_types', 10, 2 );
function wpse_290292_post_types( $post_type_name, $post_type_object ) {
    $post_types = get_option( 'my_prefix_post_types', array() );
    if ( 
        ! isset( $post_types[ $post_type_name ] ) 
        || $post_type_object !== $post_types[ $post_type_name ] 
    ) {
        // Adds the $post_type_object to the array if it's a) not already there or b) changed since it was added.
        $post_types[ $post_type_name ] = $post_type_object;
        update_option( 'my_prefix_post_types', $post_types );

This will add any registered post types to the *_options table. You'll probably want to add in some checks to prevent adding the _builtin post types, etc.

Once this is set up—probably as a network-enabled plugin—you should be able to get a given site's CPTs using the my_prefix_post_types option (feel free to rename that as needed).

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.