3

I am using save_post for a function to send an email when a post is updated by a user. This is firing twice and I am aware this is due to the post revisions and autosaves.

I have tried to prevent this from happening by wrapping my wp_mail within a conditional statement but this still fires twice. What adjustments do I need to make to ensure this only fires once when a user updates the post?

function updated_search_notification($post_id)
{

    $post_type = get_post_type($post_id);
    if ($post_type === 'utility-search') {

        if ((wp_is_post_revision($post_id)) || (wp_is_post_autosave($post_id))) {
            // post is autosave
        } else {

            // Message Variables
            $siteurl                 = get_option('siteurl');
            $post_url                = '' . $siteurl . '/wp-admin/post.php?post=' . $post_id . '&action=edit';
            $new_search_name         = '';
            //$new_search_email = get_option( 'new_search_email' );
            $new_search_email        = '[email]';
            $utility_search_customer = '';
            $subject                 = 'Your search has been updated';

            // Message Contents
            $message = "[Message Contents]";


            // Send Email    
            wp_mail($new_search_email, $subject, $message);
        }
    }


}
add_action('save_post', 'updated_search_notification', 10, 3);
1
4

First, you can use this hook to target only one custom type:
https://developer.wordpress.org/reference/hooks/save_post_post-post_type/

This hook (and save_post) is called the first time when you click on "new ..." and then the hook is called with $update = FALSE.

Then to send e-mail only when the object is updated, you can test $update like this:

const UTILITY_SEARCH_POST_TYPE = "utility-search";


add_action("save_post_" . UTILITY_SEARCH_POST_TYPE, function ($post_ID, $post, $update) {

    if (wp_is_post_autosave($post_ID)) {
        return;
    }

    if (!$update) { // if new object
        return;
    }


    // preparing e-mail
    ...

    // sending e-mail
    wp_mail(...);


}, 10, 3);
4
  • This worked perfectly, thank you. Also, a nice reminder for the use of const too!
    – Ben H
    Jul 15 '18 at 17:36
  • 1
    I tried this and it still sends the email twice.. May 8 '19 at 14:40
  • Just wanted to add to the fact that the reason the save_post fires when you click "new..." is because WP creates some "partial posts" in the database as a pre-publish version of it all, it assigns IDs and such. I assume it's for drafts.
    – coolpasta
    May 8 '19 at 19:50
  • You should also add if ( (defined( 'REST_REQUEST' ) && REST_REQUEST ) { return; } Since Gutenberg uses the Rest API to update/insert the post. May 11 at 15:38
5

The approved answer didn't work for me. I ended up trying several conditionals and the email would still get sent twice:

function xxx_send_mail($id, $post, $update){  

                if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
                    return;
                }

                if (wp_is_post_revision($id)) {
                    return;
                }

                if (wp_is_post_autosave($id)) {
                    return;
                }

                // if new post
                if (!$update) {
                    return;
                }

                wp_mail('john@doe.com', 'The subject', 'The message');
         }
add_action( 'save_post_{the_post_type}', 'xxx_send_mail', 10, 3 );

I ended up fixing this by adding a convinient function provided by WP called did_action():

    function xxx_send_mail($id, $post, $update){  

                        if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE ) {
                            return;
                        }

                        if (wp_is_post_revision($id)) {
                            return;
                        }

                        if (wp_is_post_autosave($id)) {
                            return;
                        }

                        // if new post
                        if (!$update) {
                            return;
                        }

                $times = did_action('save_post_{the_post_type}');
                if( $times === 1){
                        wp_mail('john@doe.com', 'The subject', 'The message');
                 }
    }
add_action( 'save_post_{the_post_type}', 'xxx_send_mail', 10, 3 );

Hope this helps someone

1
  • 3
    did_action() is exactly what I was searching for. To make sure the function is only called once, add an if ( did_action( 'save_post_{the_post_type}' ) > 1 ) return; on top of the function.
    – KittMedia
    Aug 5 '20 at 8:15
0

Try this piece of code inside your function:

if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;

Alternatively, you can use publish_post hook. If you just want to trigger this function when the post status is publish.

2
  • Thank you for the suggestion. When using this method and clicking the 'Update' button on a post, I still get two emails come through. I have a separate function for when a post is published.
    – Ben H
    Jul 15 '18 at 11:34
  • Did you put code on right spot? Did you try publish_post hook? Jul 15 '18 at 14:23
0

Already approved answers have not worked for me and comment from @Nico Pernice helped.

If conditions in my code look like these:

function reset_cpt_expire( $post_id, $post, $update ){

    // Check if it is a REST Request
    if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
        return;
    }

    // Check if it is an autosave or a revision.
    if ( wp_is_post_autosave( $post_id ) || wp_is_post_revision( $post_id ) ) {
        return;
    }

    // Check if it is a new post
    if ( ! $update ) {
        return;
    }

    // my reseting code...

}

add_action( 'save_post_cpt', 'reset_cpt_expire', 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.