Prevent function from triggering again when post in specific category gets another category?

We can utilize the add_term_relationship action to check if the current post is already assigned as popular. add_term_relationship fires before a term is inserted.

I also think that you are using the wrong hook here to send your mail on. added_term_relationship fires quite early before any error checking. You can still encounter a failure after added_term_relationship which means that the term insertion will not happen successfully and will return an error. set_object_terms is a better hook to use as it only fires if a term was successfully inserted.

/**
 * Fires immediately before an object-term relationship is added.
 *
 * @since 2.9.0
 *
 * @param int $object_id Object ID.
 * @param int $tt_id     Term taxonomy ID.
 */
do_action( 'add_term_relationship', $object_id, $tt_id );
$wpdb->insert( $wpdb->term_relationships, array( 'object_id' => $object_id, 'term_taxonomy_id' => $tt_id ) );

/**
 * Fires immediately after an object-term relationship is added.
 *
 * @since 2.9.0
 *
 * @param int $object_id Object ID.
 * @param int $tt_id     Term taxonomy ID.
 */
do_action( 'added_term_relationship', $object_id, $tt_id );

We can try the following (NOTE: This is untested)

add_action( 'add_term_relationship', function ( $object_id, $tt_id )
{
    // Check if the post is already in the popular term, if so, bail
    if ( has_term( 'popular', 'song_category', $object_id ) ) 
        return;

    // Check if our post is going to be added as popular, if not, bail 
    if ( 1 !== $tt_id ) // Set the correct ID for popular term
        return;

    /**
     * We are now sure that our post is not yet popular, and we will be 
     * making it popular, so lets continue
     *
     * We will be sending a mail when the term is inserted. We will use the 
     * set_object_terms hook as it fires on successful insertion of the term 
     */
    add_action( 'set_object_terms', function ( $object_id )
    {
        $post    = get_post( $object_id );
        $author  = get_userdata( $post->post_author );
        $terms   = get_the_terms( $post->ID, 'song_category' );
        $email   = get_post_meta( $post->ID, 'custom_email', true );
        $message="Hi " . $author->display_name;

        wp_mail( $email, "Your song is now in the popular section!", $message );
    });
}, 10, 2 );

EDIT

Make sure that you change 1 in 1 !== $tt_id to the exact ID of your term. I have also just copied and pasted your code into my code, so I’m not sure if that is your complete code or if that is working as-is

EDIT 2

You can use the following if you do not know the ID of the popular term (I accept that popular ids the term slug)

$term_object = get_term_by( 'slug', 'popular', 'song_category' );
$term_id     = $term_object->term_id;

Lets rewrite the code to incorporate that

add_action( 'add_term_relationship', function ( $object_id, $tt_id )
{
    // Check if the post is already in the popular term, if so, bail
    if ( has_term( 'popular', 'song_category', $object_id ) ) 
        return;

    // Get the term ID of the popular term. We will get the term object by term slug. 
    $term_object = get_term_by( 'slug', 'popular', 'song_category' );
    $term_id     = $term_object->term_id;

    // Check if our post is going to be added as popular, if not, bail 
    if ( $term_id != $tt_id ) // Set the correct ID for popular term
        return;

    /**
     * We are now sure that our post is not yet popular, and we will be 
     * making it popular, so lets continue
     *
     * We will be sending a mail when the term is inserted. We will use the 
     * set_object_terms hook as it fires on successful insertion of the term 
     */
    add_action( 'set_object_terms', function ( $object_id )
    {
        $post    = get_post( $object_id );
        $author  = get_userdata( $post->post_author );
        $terms   = get_the_terms( $post->ID, 'song_category' );
        $email   = get_post_meta( $post->ID, 'custom_email', true );
        $message="Hi " . $author->display_name;

        wp_mail( $email, "Your song is now in the popular section!", $message );
    });
}, 10, 2 );

Leave a Comment