Stop WooCommerce Webhooks from Firing on Staging Sites

Webhooks are the silent danger of any WooCommerce staging environment. You clone your live site to a staging server, test a feature, place a few test orders, and a day later you find your email service has emailed real customers about “new orders” that never happened. Or your fulfillment provider is now processing duplicate shipments. Or your accounting tool has imported fake invoices into your books.

WooCommerce webhooks are stored in the database, so they migrate with every clone. By default they fire on any environment that loads them, including staging. The fix is short: detect that the current environment is staging, and tell WooCommerce not to deliver any webhooks. The snippet below uses URL pattern matching to handle the common hosting setups, but you can extend the check with any signal that reliably identifies staging.

/**
 * Prevent WooCommerce webhooks from being delivered on staging sites.
 *
 * Detects staging by URL pattern. Add your own host patterns to the array
 * if you use a host that isn't already covered.
 */
add_filter('woocommerce_webhook_should_deliver', 'carticy_block_webhooks_on_staging', 10, 1);
function carticy_block_webhooks_on_staging($should_deliver)
{
    $site_url = get_site_url();

    $staging_patterns = array(
        '.cloudwaysapps.com',
        '.wpstage.net',
        '.wpengine.com',
        '.kinsta.cloud',
        '.flywheelsites.com',
        '.staging.',
        'staging.',
        '.local',
        '.test',
    );

    foreach ($staging_patterns as $pattern) {
        if (strpos($site_url, $pattern) !== false) {
            return false;
        }
    }

    return $should_deliver;
}

The function checks the current site URL against a list of patterns that commonly identify staging or development environments. When any pattern matches, it returns false for woocommerce_webhook_should_deliver, which is the filter WooCommerce checks immediately before dispatching each webhook payload. Returning false stops the delivery without touching the webhook record itself, so when you eventually deploy this same code to production, your webhooks resume firing automatically.

Use an Environment Constant Instead

URL matching is convenient but fragile. If your staging URL happens to share a pattern with production, or if you use a custom domain on staging, you need a more reliable signal. The cleanest approach is to define a constant in wp-config.php on staging only.

// In wp-config.php on staging only:
define('WP_ENVIRONMENT_TYPE', 'staging');

// Then in your snippet:
add_filter('woocommerce_webhook_should_deliver', function ($should_deliver) {
    if (wp_get_environment_type() !== 'production') {
        return false;
    }
    return $should_deliver;
}, 10, 1);

WordPress 5.5 and later officially supports WP_ENVIRONMENT_TYPE. The valid values are local, development, staging, and production. With this in place, wp_get_environment_type() becomes your single source of truth for environment-aware code, not just for webhooks but for analytics tracking, email sending, payment gateway test modes, and anything else that should behave differently on staging.

What This Snippet Does Not Do

It only blocks WooCommerce webhooks registered in WooCommerce > Settings > Advanced > Webhooks. It doesn’t block REST API push events from other plugins, action-scheduler tasks that send email, third-party plugins that talk to external services (Klaviyo, Mailchimp, Omnisend, fulfillment integrations, etc.) on their own. Those usually need their own staging guards. The full pattern for a safe staging environment usually involves: blocking transactional emails (a plugin like WP Mail SMTP can route them to a single test inbox), disabling third-party tracking pixels, and stubbing out payment gateways to test mode.

Verification

  1. Add the snippet to your staging site’s child theme functions.php or a custom plugin
  2. Go to WooCommerce > Settings > Advanced > Webhooks and confirm at least one webhook exists and is active
  3. Place a test order on the storefront (or trigger whatever event the webhook listens for)
  4. Open the webhook log or check your receiving endpoint and confirm no delivery occurred
  5. Deploy the same code to production and confirm webhooks still fire normally

Need Help?

Learn how to add custom code to WordPress or reach out for custom development help.


About the Author

Ali Khallad

Ali Khallad

I’m Ali Khallad, a WordPress developer who’s been building custom plugins and WooCommerce solutions for over 10 years. I created Mega Forms and several extensions you’ll find on Carticy. I love solving tricky WordPress problems and sharing what I learn along the way. When I’m not coding, you’ll find me travelling, riding horses, or hunting down the best local food wherever I am.


More Code Snippets