What action can I use in WordPress that triggers whenever a custom post is saved or updated?

31,539

Solution 1

Updated since 3.7.0 - props @Baptiste for the reminder Updated to include new Dev doc reference - props @stephendwolff

3.7.0 introduced the "save_post_{$post->post_type}" hook, which will be triggered by the post type. This allows you to add an action specific to your custom post type (or "page" or "post" etc). This saves you one line of the below.

The accepted method is to add an action on save_post_{post-type} (substituting your post type's slug for {post-type} in the example above). There are a number of checks you can / probably should still do within your action's callback, which I document in the example below:

from the Codex: (updated: Dev Reference)

/* Register a hook to fire only when the "my-cpt-slug" post type is saved */
add_action( 'save_post_my-cpt-slug', 'myplugin_save_postdata', 10, 3 );

/* When a specific post type's post is saved, saves our custom data
 * @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.
*/
function myplugin_save_postdata( $post_id, $post, $update ) {
  // verify if this is an auto save routine. 
  // If it is our form has not been submitted, so we dont want to do anything
  if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) 
      return;

  // verify this came from the our screen and with proper authorization,
  // because save_post can be triggered at other times

  if ( !wp_verify_nonce( $_POST['myplugin_noncename'], plugin_basename( __FILE__ ) ) )
      return;

  
  // Check permissions
  if ( 'page' == $post->post_type ) 
  {
    if ( !current_user_can( 'edit_page', $post_id ) )
        return;
  }
  else
  {
    if ( !current_user_can( 'edit_post', $post_id ) )
        return;
  }

  // OK, we're authenticated: we need to find and save the data

  $mydata = $_POST['myplugin_new_field'];

  // Do something with $mydata 
  // probably using add_post_meta(), update_post_meta(), or 
  // a custom table (see Further Reading section below)

   return $mydata;
}

If you are registering multiple custom post types and you would like to consolidate your save_post functionality into a single function, then hook on the generic save_post action. But then remember to do your post type check within your function if there is any differences in how those post types save their data.

eg: if ( 'my-cpt-1' == $post->post_type ){ // handle my-cpt-1 specific stuff here ...

Solution 2

WordPress 3.7 introduced a new way of handling this with the save_post_{$post_type} hook.

Let's say your custom post type is "member-directory". You can now run save_post on that post type only by using something like this:

function my_custom_save_post( $post_id ) {

    // do stuff here
}
add_action( 'save_post_member-directory', 'my_custom_save_post' );
Share:
31,539
Kyle Hotchkiss
Author by

Kyle Hotchkiss

Updated on August 05, 2022

Comments

  • Kyle Hotchkiss
    Kyle Hotchkiss almost 2 years

    Any way to have save_post for custom posts only? The way my functions.php is coded is tacking on lots of custom fields to normal posts and pages who don't need/use them.

  • gillespieza
    gillespieza almost 13 years
    How many times can you add add_action( 'save_post', 'myplugin_save_postdata' );? Should you add a new one for each new metabox (obviously changing the nonces and myplugin_save_postdata to whatever your function name is, each time)?
  • Tom Auger
    Tom Auger almost 13 years
    @Amanda: Other than a (slight) performance hit, the approach you suggest will work, and is probably easier to parse for humans because you can associate the "Save" operation with the same block of code in which you define the metabox, to keep things neat and tidy. The alternative approach is to define a single "Save" function callback for your entire theme or plugin, maybe even encapsulated within its own class or at least a separate file, and then use a switch statement to define the individual metabox saves. A matter of coding style and personal preference.
  • hallodom
    hallodom about 10 years
    Awesome, where did you find this out? I managed to figure this out myself through experimenting but didn't see anything about doing this in official documentation: codex.wordpress.org/Plugin_API/Action_Reference/save_post Only guessed to do it after looking at the new add_meta_boxes{post-type} action (see: codex.wordpress.org/Plugin_API/Action_Reference/add_meta_box‌​es).
  • mindctrl
    mindctrl about 10 years
    I was following the 3.7 development and noticed it. The commit where it was added is here. I don't think it's been documented in the Codex anywhere. At least it wasn't the last time I looked.
  • Baptiste
    Baptiste almost 9 years
    this approach is no longer necessary since 3.7, check the reply right underneath.
  • Tom Auger
    Tom Auger almost 9 years
    While you're correct about the new action hook, this example is misleading because you're missing a bunch of capabilities and context checks that should really be included. See stackoverflow.com/a/6270232/467386 for a more complete solution.
  • Tom Auger
    Tom Auger almost 9 years
    @Baptiste thanks for the reminder. I've updated my answer. New devs should take note of the additional security checks that the recommended approach includes - the save_post_{post-type} hook doesn't add ANY additional security checks than the generic save_post hook. (It appears directly below it in the source code - so there's no additional logic other than that it only fires on saving of that particular post type).
  • mindctrl
    mindctrl over 8 years
    Agreed, but the OP asked a very specific question and I only answered that specific part. With regards to checking for permissions for the post type, I think you can improve the checks with something like this to avoid all the conditionals for post type. $post_type = get_post_type_object( $post->post_type ); if ( ! current_user_can( $post_type->cap->edit_post, $post_id ) ) return $post_id;
  • stephendwolff
    stephendwolff over 2 years