Skip to content

Instantly share code, notes, and snippets.

@jessepearson
Last active September 14, 2023 10:27
Show Gist options
  • Star 23 You must be signed in to star a gist
  • Fork 9 You must be signed in to fork a gist
  • Save jessepearson/66a0e72706b99c15b52dee7ce59e1d31 to your computer and use it in GitHub Desktop.
Save jessepearson/66a0e72706b99c15b52dee7ce59e1d31 to your computer and use it in GitHub Desktop.
How to add a new custom Webhook topic in WooCommerce, with example of order filtering.
<?php // do not copy this line
/**
* add_new_topic_hooks will add a new webhook topic hook.
* @param array $topic_hooks Esxisting topic hooks.
*/
function add_new_topic_hooks( $topic_hooks ) {
// Array that has the topic as resource.event with arrays of actions that call that topic.
$new_hooks = array(
'order.custom_filter' => array(
'custom_order_filter',
),
);
return array_merge( $topic_hooks, $new_hooks );
}
add_filter( 'woocommerce_webhook_topic_hooks', 'add_new_topic_hooks' );
/**
* add_new_topic_events will add new events for topic resources.
* @param array $topic_events Existing valid events for resources.
*/
function add_new_topic_events( $topic_events ) {
// New events to be used for resources.
$new_events = array(
'custom_filter',
);
return array_merge( $topic_events, $new_events );
}
add_filter( 'woocommerce_valid_webhook_events', 'add_new_topic_events' );
/**
* add_new_webhook_topics adds the new webhook to the dropdown list on the Webhook page.
* @param array $topics Array of topics with the i18n proper name.
*/
function add_new_webhook_topics( $topics ) {
// New topic array to add to the list, must match hooks being created.
$new_topics = array(
'order.custom_filter' => __( 'Order Custom Filter', 'woocommerce' ),
);
return array_merge( $topics, $new_topics );
}
add_filter( 'woocommerce_webhook_topics', 'add_new_webhook_topics' );
/**
* my_order_item_check will check an order when it is created through the checkout form,
* if it has product ID 10603 as one of the items, it will fire off the action `custom_order_filter`
*
* @param int $order_id The ID of the order that was just created.
* @param array $posted_data Array of all of the data that was posted through checkout form.
* @param object $order The order object.
* @return null
*/
function my_order_item_check( $order_id, $posted_data, $order ) {
$order = wc_get_order( $order_id );
$items = $order->get_items();
foreach ( $items as $item ) {
if ( is_a( $item, 'WC_Order_Item_Product' ) ) {
if ( 10603 === $item->get_product_id() ) {
do_action( 'custom_order_filter', $order_id, $posted_data, $order );
return;
}
}
}
}
add_action( 'woocommerce_checkout_order_processed', 'my_order_item_check', 10, 3 );
/**
* The two below actions are what the order.created webhook is tied into, it is up to you to use these if you wish.
*/
// add_action( 'woocommerce_process_shop_order_meta', 'my_order_item_check' );
// add_action( 'woocommerce_api_create_order', 'my_order_item_check' );
@OpsAndresRosales
Copy link

OpsAndresRosales commented Feb 20, 2020

Hey there,

I'm trying to use this code to create a webhook for the existing WooCommerce Subscriptions event woocommerce_subscription_status_cancelled.

Here is the code I have as of right now:

 * add_new_topic_hooks will add a new webhook topic. 
 * @param array $topic_hooks Existing topic hooks.
 */
function add_new_topic_hooks( $topic_hooks ) {

	// Array that has the topic as resource.event with arrays of actions that call that topic.
	$new_hooks = array(
		'subscription.custom_cancel' => array(
			'woocommerce_subscription_status_cancelled',
			),
		);

	return array_merge( $topic_hooks, $new_hooks );
}
add_filter( 'woocommerce_webhook_topic_hooks', 'add_new_topic_hooks' );

/**
 * add_new_topic_events will add new events for topic resources.
 * @param array $topic_events Existing valid events for resources.
 */
function add_new_topic_events( $topic_events ) {

	// New events to be used for resources.
	$new_events = array(
		'custom_cancel',
		);

	return array_merge( $topic_events, $new_events );
}
add_filter( 'woocommerce_valid_webhook_events', 'add_new_topic_events' );

/**
 * add_new_webhook_topics adds the new webhook to the dropdown list on the Webhook page.
 * @param array $topics Array of topics with the i18n proper name.
 */
function add_new_webhook_topics( $topics ) {

	// New topic array to add to the list, must match hooks being created.
	$new_topics = array( 
		'subscription.custom_cancel' => __( 'Subscription Cancelled', 'woocommerce' ),
		);

	return array_merge( $topics, $new_topics );
}
add_filter( 'woocommerce_webhook_topics', 'add_new_webhook_topics' );

I have the new webhook appearing in the dropdown, but it doesn't appear to be triggered when I cancel a subscription.

In looking at your code, it appears that you are creating a webhook for a new action that you are creating yourself; how should I modify this to create a new Webhook for an existing action that doesn't already have a webhook?

Also, I don't see where you're declaring the custom_order_filter function in the attached code. Will the call to do_action pass those params to the webhook, or is custom_order_filter declared elsewhere?

Thanks!
Andres

@dhirenpatel22
Copy link

Hey there,

I'm trying to use this code to create a webhook for the existing WooCommerce Subscriptions event woocommerce_subscription_status_cancelled.

Here is the code I have as of right now:

 * add_new_topic_hooks will add a new webhook topic. 
 * @param array $topic_hooks Existing topic hooks.
 */
function add_new_topic_hooks( $topic_hooks ) {

	// Array that has the topic as resource.event with arrays of actions that call that topic.
	$new_hooks = array(
		'subscription.custom_cancel' => array(
			'woocommerce_subscription_status_cancelled',
			),
		);

	return array_merge( $topic_hooks, $new_hooks );
}
add_filter( 'woocommerce_webhook_topic_hooks', 'add_new_topic_hooks' );

/**
 * add_new_topic_events will add new events for topic resources.
 * @param array $topic_events Existing valid events for resources.
 */
function add_new_topic_events( $topic_events ) {

	// New events to be used for resources.
	$new_events = array(
		'custom_cancel',
		);

	return array_merge( $topic_events, $new_events );
}
add_filter( 'woocommerce_valid_webhook_events', 'add_new_topic_events' );

/**
 * add_new_webhook_topics adds the new webhook to the dropdown list on the Webhook page.
 * @param array $topics Array of topics with the i18n proper name.
 */
function add_new_webhook_topics( $topics ) {

	// New topic array to add to the list, must match hooks being created.
	$new_topics = array( 
		'subscription.custom_cancel' => __( 'Subscription Cancelled', 'woocommerce' ),
		);

	return array_merge( $topics, $new_topics );
}
add_filter( 'woocommerce_webhook_topics', 'add_new_webhook_topics' );

I have the new webhook appearing in the dropdown, but it doesn't appear to be triggered when I cancel a subscription.

In looking at your code, it appears that you are creating a webhook for a new action that you are creating yourself; how should I modify this to create a new Webhook for an existing action that doesn't already have a webhook?

Also, I don't see where you're declaring the custom_order_filter function in the attached code. Will the call to do_action pass those params to the webhook, or is custom_order_filter declared elsewhere?

Thanks!
Andres

Hey Andres,

I am looking for a similar solution but had the same issue. Have you found any solution for this?

@OpsAndresRosales
Copy link

Hey Andres,

I am looking for a similar solution but had the same issue. Have you found any solution for this?

Yes I did! I installed the Snippets plugin for WordPress and created a new snippet with the following code to create custom hooks for Subscription status change to cancelled and subscription status change to active:

function add_custom_filters_and_actions() {

	add_filter( 'woocommerce_webhook_topic_hooks', 'add_custom_wcs_topics', 30, 2 );

	add_filter( 'woocommerce_valid_webhook_events', 'add_custom_wcs_events', 20, 1 );

	add_filter( 'woocommerce_webhook_topics' , 'add_custom_wcs_topics_admin_menu', 20, 1 );
	
	add_action( 'woocommerce_subscription_status_pending-cancel_to_cancelled', 'add_subscription_cancelled_callback', 10, 1 );
	
	add_action( 'woocommerce_subscription_status_pending_to_active', 'add_subscription_active_callback', 10, 1 );
}

/**
 * Add Custom Subscription webhook topics
 */
function add_custom_wcs_topics( $topic_hooks, $webhook ) {
	
	switch ( $webhook->get_resource() ) {
		case 'subscription':
			$topic_hooks = apply_filters( 'woocommerce_subscriptions_webhook_topics', array(
				'subscription.cancelled' => array(
					'wcs_webhook_status_cancelled'
				),
				'subscription.activated' => array(
					'wcs_webhook_status_active'
				)
			), $webhook );
			break;
	}

	return $topic_hooks;
}

/**
 * Add Subscription topics to the Webhooks dropdown menu in when creating a new webhook.
 */
function add_custom_wcs_topics_admin_menu( $topics ) {

	$front_end_topics = array(
		'subscription.cancelled'  => __( 'Subscription Cancelled', 'woocommerce-subscriptions' ),
		'subscription.activated'  => __( 'Subscription Activated', 'woocommerce-subscriptions' )
	);

	return array_merge( $topics, $front_end_topics );
}

/**
 * Add webhook event for subscription switched.
 */
function add_custom_wcs_events( $events ) {
	$events[] = 'cancelled';
	$events[] = 'activated';

	return $events;
}

function add_subscription_cancelled_callback( $subscription ) {
	do_action( 'wcs_webhook_status_cancelled', $subscription->get_id());
}

function add_subscription_active_callback( $subscription ) {
	do_action( 'wcs_webhook_status_active', $subscription->get_id());
}

add_custom_filters_and_actions();

@rickysullivan
Copy link

@chris-schertenlieb Thanks for posting back.

@jtisler - We are ignoring the failed order payloads being sent to our endpoint. The issue is if the customer fixes the failed order after getting an error message (e.g. they fat fingered their credit card number or something), the webhook doesn't fire again and we don't get a "good" order payload resent since the order was already created. That's why we wanted to set up a trigger for only when the payment is complete and all is good.

We're planning on circling back to this and do some tests with again (great rainy Memorial Day weekend here) and see if we can create on for Payment Complete status.

@jaxne Did you find a solution? I've got a similar issue. I was using the order created webhook to notify our accounting software of new orders but because the customers card was declined, the webhook only fired once. At the other end of the process I check to see if the order status is "processing" before adding the order details to our accounting system. I've created a custom webhook, it fires when I want it to, but it's not sending any payload.

"bodyRaw": "[]"

@pfriedl
Copy link

pfriedl commented Apr 9, 2021

I'm selling licenses to a web app, and managing licenses in a separate table. So I need to perform a webhook on these events:

  • subscription created at checkout
  • subscription renewal payment failed
  • subscription canceled
  • subscription reactivated

I also need to send a payload of the order ID, billing data (name, email), subscription ID and SKU. Can somebody help with this? Willing to pay for some quick work!

@Meloman-zz
Copy link

Hi all,

Anybody can help me make it for order.cancelled ?
https://stackoverflow.com/questions/68556469/woocommerce-webhook-for-canceled-order-not-fired

Thanks.

@onetarek
Copy link

Thanks for posting this. We need to send the order payload that the Order Created action does now, but only when payment is complete. Can I use this somehow to add a "Payment Complete" action option on the webhook actions dropdown form that is tied to the woocommerce_payment_complete action trigger and send the order payload at that time?

We ran into a scenario that if a customer tries to checkout but the payment fails (i.e. card declined or something else) the failed order is still created and the webhook is fired with the status of "failure". If during this transaction the customer fixes the credit card or issue with payment and the payment is successful, the order is moved to processing BUT the webhook will not resend the payload since the order was already created. That is why we'd like to see if we can tie the order payload being sent when the woocommerce_payment_complete is triggered, i.e. after the payment has gone through and is successful. Any tips or guidance would be appreciated.

Thank you!

I needed to send webhook only on order completed. I solved it in my way.
Here is my gist https://gist.github.com/onetarek/6652c0ceb04c81918b78dca5e495c49a

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment