I'm currently trying to work with webhooks without using any plugins, and I'd like to avoid them if possible.
The webhook should be triggered when a change is made to the Custom Post Type "event." So far, so good.
Now, I want to differentiate between:
- a brand-new post
- a modified already-existing post
And here's where it gets complicated!
When a new post is published, the function is triggered 3 times with the following statuses:
[10-Oct-2023 19:18:43 UTC] New Status: auto-draft [10-Oct-2023 19:18:43 UTC] Old Status: new [10-Oct-2023 19:19:04 UTC] New Status: publish [10-Oct-2023 19:19:04 UTC] Old Status: auto-draft [10-Oct-2023 19:19:06 UTC] New Status: publish [10-Oct-2023 19:19:06 UTC] Old Status: publish When an existing post is modified, the function is triggered twice:
[10-Oct-2023 19:23:04 UTC] New Status: publish [10-Oct-2023 19:23:04 UTC] Old Status: publish [10-Oct-2023 19:23:05 UTC] New Status: publish [10-Oct-2023 19:23:05 UTC] Old Status: publish I can certainly ensure in the receiving program that things are not processed twice. However, I simply cannot find a criterion to differentiate between a new post and an existing one.
At the moment I try to get it with the function "transition_post_status".
I also tried the function "save_post", but on save_post the update boolean is always 1. Regardless if I create a new post or modify an existing.
Happy for any hint!
functions.php:
// Add a custom REST API endpoint for the webhook function custom_webhook_endpoint() { register_rest_route('custom-webhooks/v1', '/trigger', array( 'methods' => 'POST', 'callback' => 'custom_webhook_callback', )); } // Callback function to handle incoming webhook requests function custom_webhook_callback($request) { // Process the webhook data and trigger your Python script or other actions // Example: $data = $request->get_json_params(); // Implement your logic here // Return a response if needed return rest_ensure_response(array('message' => 'Webhook received successfully')); } add_action('rest_api_init', 'custom_webhook_endpoint'); function trigger_webhook_on_new_event($new_status, $old_status, $post) { // Check if the post type is 'event' error_log('New Status: ' . $new_status); error_log('Old Status: ' . $old_status); if ($post->post_type === 'event') { // Check if the post is being published (new or update) if ($post->post_type === 'event' && $new_status === 'publish' && $old_status !== 'publish') { // This is a new post // Set up the URL for your Python web handler for new posts $webhook_base = 'http://localhost:5000/webhook/add'; } elseif ($new_status === 'publish') { // This is an update that changes the post_status to publish // Set up the URL for your Python web handler for updates that publish $webhook_base = 'http://localhost:5000/webhook/modify'; } // Get post meta data $all_post_meta = get_post_meta($post->ID); $start = isset($all_post_meta['start'][0]) ? $all_post_meta['start'][0] : ''; // Define the data you want to send in the POST request $data = array( 'id' => $post->ID, 'description' => $post->post_content, 'excerpt' => $post->post_excerpt, 'title' => $post->post_title, 'url' => get_permalink($post->ID), 'start' => $start, ); // Send a POST request to your Python web handler $response = wp_safe_remote_post($webhook_base, array( 'body' => json_encode($data), 'headers' => array('Content-Type' => 'application/json'), )); // Check for errors in the response, if needed if (is_wp_error($response)) { // Handle errors here error_log('Webhook error: ' . $response->get_error_message()); } } } add_action('transition_post_status', 'trigger_webhook_on_new_event', 10, 3); function trigger_webhook_on_new_event($new_status, $old_status, $post) { // Check if the post type is 'event' error_log('New Status: ' . $new_status); error_log('Old Status: ' . $old_status); if ($post->post_type === 'event') { // Check if the post is being published (new or update) if ($post->post_type === 'event' && $new_status === 'publish' && $old_status !== 'publish') { // This is a new post // Set up the URL for your Python web handler for new posts $webhook_base = 'http://localhost:5000/webhook/add'; } elseif ($new_status === 'publish') { // This is an update that changes the post_status to publish // Set up the URL for your Python web handler for updates that publish $webhook_base = 'http://localhost:5000/webhook/modify'; } // Get post meta data $all_post_meta = get_post_meta($post->ID); $start = isset($all_post_meta['start'][0]) ? $all_post_meta['start'][0] : ''; // Define the data you want to send in the POST request $data = array( 'id' => $post->ID, 'description' => $post->post_content, 'excerpt' => $post->post_excerpt, 'title' => $post->post_title, 'url' => get_permalink($post->ID), 'start' => $start, ); // Send a POST request to your Python web handler $response = wp_safe_remote_post($webhook_base, array( 'body' => json_encode($data), 'headers' => array('Content-Type' => 'application/json'), )); // Check for errors in the response, if needed if (is_wp_error($response)) { // Handle errors here error_log('Webhook error: ' . $response->get_error_message()); } } } add_action('transition_post_status', 'trigger_webhook_on_new_event', 10, 3); webhandler.py:
from flask import Flask, request app = Flask(__name__) # Import the google_maps class here from google_maps import google_maps # Create an instance of the google_maps class google_maps_instance = google_maps() # Create variables to track the last post ID for modify and add webhooks # WordPress call save post twice. I don't know why. last_modify_post_id = None last_add_post_id = None @app.route('/webhook/modify', methods=['POST']) def receive_webhook_modify(): global last_modify_post_id # Get the JSON data from the incoming webhook request data = request.json # Check if the received post ID is the same as the last one for modify if data['id'] == last_modify_post_id: print("Webhook already processed for modify with post ID:", last_modify_post_id) return "Webhook already processed" # If it's a new post ID, process the webhook for modify last_modify_post_id = data['id'] print("Received Webhook on modify:") print(data) # You can add your custom logic here to process the webhook data for modify return "Webhook received successfully" @app.route('/webhook/add', methods=['POST']) def receive_webhook_add(): global last_add_post_id # Get the JSON data from the incoming webhook request data = request.json # Check if the received post ID is the same as the last one for add if data['id'] == last_add_post_id: print("Webhook already processed for add with post ID:", last_add_post_id) return "Webhook already processed" # If it's a new post ID, process the webhook for add last_add_post_id = data['id'] print("Received Webhook on add:") print(data) # You can add your custom logic here to process the webhook data for add google_maps_instance.create_event(data) return "Webhook received successfully" if __name__ == '__main__': app.run(port=5000)