I want that when every Custom Post Type is published, a hook is called (where I send an email notification to the administrator). I know I can use:

add_action('publish_{custom_post_type_name}', 'function_to_call');

but I don't know the custom_post_type_names (every site has different Custom Post Types registered). In addition, I can't take for granted that the Custom Post Types will always remain the same (because at any time other plugins or themes may register/deregister Custom Post Types).

Any hint?

  • Maybe get_post_types() can help you. You can get the custom post type (even filtering the list) and add the hook for each one. Feb 21, 2014 at 10:11
  • I have already tried but without success. Moreover, as I said, I can't take for granted that the Custom Post Types will always remain the same (because at any time other plugins or themes may register/deregister Custom Post Types).
    – User
    Feb 21, 2014 at 10:25
  • 1
    As codex says register_post_type calls registered_post_type. Maybe you can hook your 'publish hook' when the custom post type gets registered, using the the arguments of registered_post_type to get the name of custom post type Feb 21, 2014 at 10:57
  • Unfortunately, it seems that this function registered_post_type is called continuously, for all types of post (including WordPress private ones, like revision, attachment, nav_menu_item, and so on), so I can't use it for this purpose.
    – User
    Feb 21, 2014 at 13:51
  • 1
    You can exclude built in and private post types from whatever you want to do, therefore pages, posts, attachments etc won't be included. Feb 21, 2014 at 15:25

2 Answers 2


What about using save_post or wp_insert_post hook, both have

@param     int               $post_ID     Post ID.
@param     WP_Post     $post          Post object.
@param     bool            $update     Whether this is an existing post being updated or not.

as parameters. It is pretty self-explaining that the $update can be used to determine, if it is a new post or not. Additionally you will need to check for is it a custom post type, I use the is_custom_post_type() function by @toscho.

So here we go:

function wpse135423_function_to_call( $post_id, $post, $update ) {
    if ( wp_is_post_autosave( $post_id ) ) {
        return 'do nothing, because it is an autosave';
    if ( wp_is_post_revision( $post_id ) ) {
        return 'do nothing, because it is a revision';
    // if it is an update 
    if ( $update == TRUE ) {
        return 'do nothing, because it is an update';
    // if it is a custom post type 
    if ( is_custom_post_type() == TRUE ) {
        // code to do whatever you want
// Do NOT use both hooks!
add_action( 'save_post', 'wpse135423_function_to_call', 10, 3 );
add_action( 'wp_insert_post', 'wpse135423_function_to_call', 10, 3 );

Shortly, only newly created custom post type posts are addressed, while there is no need to know the custom post types name.


There isn't one hook that will fire when all custom post types are published. But we can accomplish the same thing using a combination of hooks and conditionals. There are at least two ways to do it, in addition to the other answer. The first is to hook into register_post_type and conditionally add a hook to publish_$post_type if the post type isn't a WordPress default. Below is a sample plugin that will do that.

namespace = StackExchange\WordPress;
class plugin {
  protected $defaultPostTypes = [
    'post', 'page', 'attachment', 'revision',
    'nav_menu_item', 'custom_css', 'customize_changeset',
  public function plugins_loaded() {
    \add_action( 'registered_post_type', [ $this, 'registered_post_type' ], 10, 2 );
  public function registered_post_type( string $post_type, \WP_Post_Type $post_type_object ) {
    if( in_array( $post_type, $this->defaultPostTypes ) ) return;
    \add_action( "publish_$post_type", [ $this, 'publish_post_type' ], 10, 3 );
  public function publish_post_type( int $post_ID, \WP_Post $post, bool $update ) {
    //* This method will execute whenever a custom post type is published.
\add_action( 'plugins_loaded', [ new plugin(), 'plugins_loaded' ] );

Or, we can use the transition_post_status hook

function wpse_135423_transition_post_status( $new_status, $old_status, $post ) {
  //* Make sure the new status is published
  if( 'publish' !== $new_status ) return;

  //* And that the post_type isn't one of the WordPress defaults
  $default = array(
  if( in_array( $post->post_type, $default ) ) return;

  //* A custom post type just got published.
add_action( 'transition_post_status', 'wpse_135423_transition_post_status', 10, 3 );

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.