For my first CPT, it seemed great that I could hook a function to post_updated_messages and customize the post messages. When I tried the same for 4 CPTs, only the last filter added was having any effect. Here’s my new DRY method.
function set_custom_messages( $messages ) { global $post, $post_ID; $post_type = get_post_type( $post_ID ); $obj = get_post_type_object( $post_type ); $singular = $obj->labels->singular_name; $messages[$post_type] = array( 0 => '', // Unused. Messages start at index 1. 1 => sprintf( __( $singular . ' updated. <a href="%s">View '.strtolower( $singular) . '</a>' ), esc_url( get_permalink( $post_ID ) ) ), 2 => __('Custom field updated . ' ), 3 => __('Custom field deleted . ' ), 4 => __( $singular . ' updated . ' ), 5 => isset( $_GET['revision']) ? sprintf( __( $singular . ' restored to revision from %s' ), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false, 6 => sprintf( __( $singular . ' published. <a href="%s">View '.strtolower( $singular) . '</a>' ), esc_url( get_permalink( $post_ID ) ) ), 7 => __('Page saved . ' ), 8 => sprintf( __( $singular . ' submitted. <a target="_blank" href="%s">Preview '.strtolower( $singular) . '</a>' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), 9 => sprintf( __( $singular . ' scheduled for: <strong>%1$s</strong>. <a target="_blank" href="%2$s">Preview '.strtolower( $singular) . '</a>' ), date_i18n( __( 'M j, Y @ G:i' ), strtotime( $post->post_date ) ), esc_url( get_permalink( $post_ID ) ) ), 10 => sprintf( __( $singular . ' draft updated. <a target="_blank" href="%s">Preview '.strtolower( $singular) . '</a>' ), esc_url( add_query_arg( 'preview', 'true', get_permalink( $post_ID ) ) ) ), ); return $messages; }