Get all Custom Post Types

Easy list filtering

There’s the global $wp_post_types which is used for e.g. in get_post_type_object( $name );, register_post_type(), etc.

If you want to omit the ones delivered with core, you should filter the returned list and skip everything that has the _builtin key set to true. Just use wp_list_filter() for that

$cpts = wp_list_filter( $GLOBALS['wp_post_types'], array( '_builtin' => false, ) );

Runtime collection

A different way to go at this: At the end of the post type registration (register_post_type()) process, there’s an action running:

do_action( 'registered_post_type', $post_type, $args );

This action maybe is – depending on your use case – a nice place to fetch all post types, as core registers its own post types using create_initial_post_types() which uses register_post_type() by itself. It will also allow you to fetch post types that get registered late.

add_action( 'registered_post_type', function( $pt, $args )
    static $cpts = array();

    if (
        ! $args->_builtin 
        and ! in_array( $args->name, array_keys( $cpts ) ) 
        $cpts[ $args->name ] = $args;

    // here, $cpts gets constant updates as soon as a new post type is registered
    // ignores already added post types by name
    // also ignores cores `_builtin` post types

}, 20, 2 );