0

I have created a webhook which works, code is as follows:

function jon_save_post_webhook($post_id, $post)
{
    // Check to see if autosaving etc., if so ignore
    if ($post->post_status !== 'publish') {
        return;
    }
    $author = get_the_author_meta('display_name', $post->post_author);
    $post_ID = $post->ID;
    $post_title = $post->post_title;
    $post_date = $post->post_date;
    $post_modified = $post->post_modified;
    $post_guid = $post->guid;
    $post_slug = $post->post_name;
    $permalink = get_the_permalink($post->ID);
    $post_type = $post->post_type;
    $post_status = $post->post_status;
    $categories = jon_get_categories($post);
    $message = 'Post #' . $post_id . ' has been published, updated or deleted with title - ' . $post->post_title;
    $url = 'https://hook.integromat.com/1234';

    $args = array(
        'body' => array(
            'message' => $message,
            'author' => $author,
            'post_ID' => $post_ID,
            'post_title' => $post_title,
            'post_date' => $post_date,
            'post_modified' => $post_modified,
            'post_guid' => $post_guid,
            'post_slug' => $post_slug,
            'permalink' => $permalink,
            'post_type' => $post_type,
            'post_status' => $post_status,
            'categories' => $categories,
        )
    );

    wp_remote_post($url, $args);
    error_log(print_r($args, true));
}

function jon_get_categories($post)
{
    $term_obj_list = get_the_terms($post->ID, 'category');
    $terms_string  = join(', ', wp_list_pluck($term_obj_list, 'name'));
    return $terms_string;
}
add_action('save_post', 'jon_save_post_webhook', 10, 2);

But I've realised that I need post_status of both published and trash (and none of the others). I have tried tweaking my code in various ways but cannot get it to work, I think I'm simply getting the syntax wrong. Any ideas/help?

For example, tried this:

function jon_save_post_webhook($post_id, $post)
{
    // Check to see if autosaving etc., if so ignore
    if ($post->post_status !== 'publish') {
        return;
    }
    if ($post->post_status !== 'trash') {
        return;
    }

/// rest of code

EDIT I've updated my code now but still have two issues:

  • If a post is trashed that was never published (e.g. straight from Draft to Delete) the webhook still gets called
  • When you go into an individual post and trash it, I get two duplicate messages (this doesn't happen if hit trash from the All Posts view in Admin) Updated code:

// Hook works for all post status. Updated, deleted and publish.
add_action('wp_after_insert_post', 'jon_save_post_webhook', 10, 4);

/**
 * Callback function for the hook to run the processes of sending to API URL.
 *
 * @param int   $post_id Post ID.
 * @param mixed $post    Post Object.
 *
 * @return void
 */
function jon_save_post_webhook($post_id, $post)
{

    // Check to see if autosaving, revision pre-save etc., if so ignore
    if (wp_is_post_revision($post) || wp_is_post_autosave($post) || $post->post_status == 'auto-draft' || $post->post_status == 'draft') {
        return;
    }

    // Setup the variables to use in the application.
    $author        = get_the_author_meta('display_name', $post->post_author);
    $post_ID       = $post->ID;
    $post_title    = $post->post_title;
    $post_date     = $post->post_date;
    $post_modified = $post->post_modified;
    $post_guid     = $post->guid;
    $post_slug     = $post->post_name;
    $permalink     = get_the_permalink($post->ID);
    $post_type     = $post->post_type;
    $post_status   = $post->post_status;
    $categories    = jon_get_categories($post);
    $word_count = jon_get_wordcount($post);
    $message       = 'Post #' . $post_id . ' has been ' . $post->post_status .  'ed with title - ' . $post->post_title;

    // API URL.
    $url = 'https://hook.integromat.com/1234';

    $args = array(
        'body' => array(
            'message'       => $message,
            'author'        => $author,
            'post_ID'       => $post_ID,
            'post_title'    => $post_title,
            'post_date'     => $post_date,
            'post_modified' => $post_modified,
            'post_guid'     => $post_guid,
            'post_slug'     => $post_slug,
            'permalink'     => $permalink,
            'post_type'     => $post_type,
            'post_status'   => $post_status,
            'categories'    => $categories,
            'word_count' => $word_count,
        )
    );

    // Send the variables ot the URL.
    $sending = wp_remote_post($url, $args);

    // Log the results arise from sending.
    if (is_wp_error($sending)) {
        error_log(print_r($sending, true));
        return;
    }
    // Log all results to debug.
    error_log(print_r($args, true));
}

/**
 * Get all the post categories and make a comma seperated string out of them.
 *
 * @param mixed $post Post Object.
 *
 * @return $terms_string All categories in a comma seperated string.
 */
function jon_get_categories($post)
{
    $term_obj_list = get_the_terms($post->ID, 'category');
    $terms_string  = join(', ', wp_list_pluck($term_obj_list, 'name'));

    return $terms_string;
}

//Get the post/page, remove any unnecessary tags and then perform the word count
function jon_get_wordcount($post_id)
{
    $jon_wordcount = str_word_count(strip_tags(strip_shortcodes(get_post_field('post_content', $post_id))));
    return $jon_wordcount;
}

function jon_trash_post_webhook($post)
{
    jon_save_post_webhook($post->ID, $post);
}
add_action('publish_to_trash', 'jon_trash_post_webhook');

Edit 2

// Hook works for all post status. Updated, deleted and publish.
add_action('wp_after_insert_post', 'jon_save_post_webhook', 10, 4);

/**
 * Callback function for the hook to run the processes of sending to API URL.
 *
 * @param int   $post_id Post ID.
 * @param mixed $post    Post Object.
 *
 * @return void
 */
function jon_save_post_webhook($post_id, $post)
{

    // Check to see if autosaving, revision pre-save etc., if so ignore
    if ($post->post_status !== 'publish' && $post->post_status !== 'trash') {
        return;
    }

    // Setup the variables to use in the application.
    $author        = get_the_author_meta('display_name', $post->post_author);
    $post_ID       = $post->ID;
    $post_title    = $post->post_title;
    $post_date     = $post->post_date;
    $post_modified = $post->post_modified;
    $post_guid     = $post->guid;
    $post_slug     = $post->post_name;
    $permalink     = get_the_permalink($post->ID);
    $post_type     = $post->post_type;
    $post_status   = $post->post_status;
    $categories    = jon_get_categories($post);
    $word_count = jon_get_wordcount($post);
    $message       = 'Post #' . $post_id . ' has been ' . $post->post_status .  'ed with title - ' . $post->post_title;

    // API URL.
    $url = 'https://hook.integromat.com/j2bb8iey1hwgprdf39sigijao4lzjad3';

    $args = array(
        'body' => array(
            'message'       => $message,
            'author'        => $author,
            'post_ID'       => $post_ID,
            'post_title'    => $post_title,
            'post_date'     => $post_date,
            'post_modified' => $post_modified,
            'post_guid'     => $post_guid,
            'post_slug'     => $post_slug,
            'permalink'     => $permalink,
            'post_type'     => $post_type,
            'post_status'   => $post_status,
            'categories'    => $categories,
            'word_count' => $word_count,
        )
    );

    // Send the variables ot the URL.
    $sending = wp_remote_post($url, $args);

    // Log the results arise from sending.
    if (is_wp_error($sending)) {
        error_log(print_r($sending, true));
        return;
    }
    // Log all results to debug.
    error_log(print_r($args, true));
}

/**
 * Get all the post categories and make a comma seperated string out of them.
 *
 * @param mixed $post Post Object.
 *
 * @return $terms_string All categories in a comma seperated string.
 */
function jon_get_categories($post)
{
    $term_obj_list = get_the_terms($post->ID, 'category');
    $terms_string  = join(', ', wp_list_pluck($term_obj_list, 'name'));

    return $terms_string;
}

/**
 * Get the post/page, remove any unnecessary tags and then perform the word count
 * 
 * @param \WP_Post $post
 * @return int
 */
function jon_get_wordcount($post)
{
    $jon_wordcount = str_word_count(strip_tags(strip_shortcodes($post->post_content)));

    return $jon_wordcount;
}

1 Answer 1

1

The sample code

function jon_save_post_webhook($post_id, $post)
{
    // Check to see if autosaving etc., if so ignore
    if ($post->post_status !== 'publish') {
        return;
    }
    if ($post->post_status !== 'trash') {
        return;
    }

/// rest of code

Will always return early because while $post->post_status can be "trash" or "publish", it can never be both at the same time.

So if the post_status would be "publish", it would return early on the second if- statement, because it's not "draft".

if it would be "draft", it would return early on the first, because it's not "publish"

What you need to do is check if the post_status is neither "publish" nor "draft".

You could do something like this:

// If post_status is not draft and post_status is not publish, return early.
if ( $post->post_status !== 'draft' && $post->post_status !== 'publish' ) {
  return;
}

EDIT: So sorry. I misread "trash" for "draft" for some reason.

Following the suggestion by Pat J, here's my updated suggestion on how to handle it (although we'll be using the trashed_post hook instead of trash_post, because trash_post is triggered before the post status is actually changed.

The two hooks we'll use (save_post and trashed_post) are both passing the post_id, but trashed_post doesn't pass a second argument (post), so in order to use the same callback for both, we'll need to account for that.

Essentially, by setting $post = false in the function argument list, we're making it optional. If the second argument is not passed, it will be assigned the fallback value of false.

function jon_save_post_webhook( $post_id, $post = false )
{
    // If $post is false, we're being called from trash_post, and must get the post object manually.
    if ( ! $post ) {
       $post = get_post( $post_id );
    }

    // Check to see if autosaving etc., if so ignore
    if ( $post->post_status !== 'publish' && $post->post_status !== 'trash' ) {
        return;
    }
/// rest of the function
add_action( 'save_post', 'jon_save_post_webhook', 10, 2 );
add_action( 'trashed_post', 'jon_save_post_webhook' );

Be aware that with this logic, your function is going to trigger when posts are trashed regardless of what status the post had before it was trashed.

If you only wish to trigger this webhook when posts that were published are trashed, you could use the old_status_to_new_status hook.

This hook passes $post as first parameter though, so in order to avoid losing the semantic value of your input parameters, for this example, I've added another function to serve as intermediary.

function jon_save_post_webhook( $post_id, $post )
{
    // Check to see if autosaving etc., if so ignore
    if ( $post->post_status !== 'publish' && $post->post_status !== 'trash' ) {
        return;
    }
/// rest of the function
}

function jon_trash_post_webhook( $post ) {
   jon_save_post_webhook( $post->ID, $post );
}
add_action( 'save_post', 'jon_save_post_webhook', 10, 2 );
add_action( 'publish_to_trash', 'jon_trash_post_webhook' );

Update #2: Your new approach doesn't need the trashed hook at all. You can safely remove

function jon_trash_post_webhook($post)
{
    jon_save_post_webhook($post->ID, $post);
}
add_action('publish_to_trash', 'jon_trash_post_webhook');

and just fix the argument in jon_get_wordcount (you're not passing the post ID, you're passing the post- object) here:

/**
 * Get the post/page, remove any unnecessary tags and then perform the word count
 * 
 * @param \WP_Post $post
 * @return int
 */
function jon_get_wordcount( $post ) {
    $jon_wordcount = str_word_count( strip_tags( strip_shortcodes( $post->post_content ) ) );

    return $jon_wordcount;
}
7
  • Thanks for the response and explanation. But that still doesn't give me any data for posts that are deleted?
    – Jon Wright
    Commented Oct 11, 2022 at 19:30
  • It looks like save_post doesn't fire when a post is trashed, but you can use the trashed_post hook as well.
    – Pat J
    Commented Oct 12, 2022 at 3:31
  • Oh my bad. I misread the question.
    – fisknils
    Commented Oct 12, 2022 at 18:36
  • Hi - thanks for your response. I hadn't thought about deleted posts that were never published (not what I want). But I can't get your code to work. I've edited my original question to show you my latest code (with your function added), which has changed a bit as 'save_post' was causing me issues (not sending categories through on Publish), so I changed it to 'wp_after_insert_post'. Any thoughts on how I solve the two issues mentioned in my edit?
    – Jon Wright
    Commented Oct 13, 2022 at 17:14
  • I just tested your code on a clean wordpress installation. I set up an account on integromat and pointed the webhook there, and connected that to a google sheet. The only unexpected issue that I'm noticing is that trashing posts is triggered three times. We can get around that by switching hooks, but you're saying you don't get any results at all?
    – fisknils
    Commented Oct 15, 2022 at 12:05

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.