1

I have created a function to send out an email to authors when there post is added in the popular category for custom post type.

IT WORKS but there is 1 major issue. If the post that is in the popular category gets added to a new category while still in the popular category it sends off another email.

I do under stand why this happens. It is because a new term relationship was added. I haven't found a way to handle this and have been trying for a couple days. So I figured it would best to ask the community here.

Is there a way to prevent this email from sending again?

Here is a simplified version

<?php

/**
* Sends out an email when song goes into popular category
*
* @param int $post_id of the song
*/


function emailNotificationSongPopular( $post_id ) {

  if ( has_term( 'popular', 'song_category' ) ) {

    $post    = get_post( $post_id );
    $author  = get_userdata( $post->post_author );
    $terms   = get_the_terms( $post->ID, 'song_category' );
    $email   = get_post_meta( get_the_ID(), 'custom_email', true );
    $message = 'Hi ' . $author->display_name;

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

  }
}
add_action( 'added_term_relationship', 'emailNotificationSongPopular' );
3
  • could it also be the case that a song enters the popular category multiple times?
    – Milo
    Commented Jan 31, 2016 at 4:07
  • Well if the song goes in popular category on and off then they will get another email. But that isn't the case here @Milo . That could very well be the case if it was automated but these are selected manually by me so I am positive that is not the issue. This happens when song is already in popular section and gets new category added to it. Commented Jan 31, 2016 at 5:24
  • I meant the question only as a consideration for possible solution, not an issue with the code you posted. consider maybe storing whether or not an author has been notified in post meta data, then you don't have to worry about the term issues, you can verify that the meta entry does not exist before sending an email.
    – Milo
    Commented Jan 31, 2016 at 16:51

1 Answer 1

2

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 );
7
  • Hi @Pieter-Goosen thank you kindly for the explanation and help. I tried the following code and got PHP Parse error: syntax error, unexpected ':' . My guess is the : should be a semi colon. I changed it to a semi colon but doesn't seem to be working. Nothing sends now. I apoligize in advance if this is a silly question but do I need to pass in values for $object_id, $tt_id ? Commented Jan 31, 2016 at 5:53
  • I put echo "test"; die(); in a few places to see if it gets triggered. It works all the way up until this part >>>> if ( 1 !== $tt_id ) . If I put "test"; die(); below that part and add to popular nothing happens. Commented Jan 31, 2016 at 6:01
  • Also it seems to be working without if ( 1 !== $tt_id ) return; . I am going to test around more. Would love to hear your genius thoughts! :) Commented Jan 31, 2016 at 6:04
  • Hi I am not able to get this to work. I am looking in the wp_term_taxonomy table in the database at the first column term_taxonomy_id. I even tried term_id but that didn't work either. The code gets to here and then bails 1 !== $tt_id . Commented Jan 31, 2016 at 7:52
  • Okay so been testing for a little and can't get it to work. If I have no categorys selected and then select popular and press update and if I print the info before the " check if ( $term_id != $tt_id ) " I get the following out put >>>> print_r($term_id); is returning 94 and print_r($tt_id); is returning 99. If I take out if ( $term_id != $tt_id ) the function works. The only caveot I found with taking it out was that if you add multiple categories AT ONCE it will do whatever code you put multiple times. But if its in popular and you add new category nothing happens which is good. Commented Jan 31, 2016 at 8:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.