Skip to content

Instantly share code, notes, and snippets.

What would you like to do?
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(
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(
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 );
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' );
Copy link

OpsAndresRosales commented May 5, 2020

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(
				'subscription.activated' => array(
			), $webhook );

	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());


Copy link

rickysullivan commented Jul 17, 2020

@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": "[]"

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!

Copy link

Meloman-zz commented Jul 30, 2021

Hi all,

Anybody can help me make it for order.cancelled ?


Copy link

onetarek commented Nov 16, 2021

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

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