Tax Exempt
Mark any user or role as tax-exempt — WooCommerce removes taxes automatically at checkout. Full audit trail with reasons and timestamps. Built for wholesale, B2B, and non-profit stores.
Installation
- Download the plugin ZIP from your Addnetic account.
- In WordPress, go to Plugins → Add New → Upload Plugin.
- Select the ZIP file and click Install Now.
- Click Activate Plugin.
After activation, a new Tax Exemptions submenu appears under WooCommerce in the admin sidebar.
Requirements
| Requirement | Minimum version |
|---|---|
| WordPress | 6.2 |
| WooCommerce | 8.2 (must be active) |
| PHP | 8.1 |
Compatibility
- HPOS (High-Performance Order Storage) — fully compatible, declared via
FeaturesUtil - Cart & Checkout Blocks — fully compatible, with dedicated Store API integration
- Tax calculation plugins (TaxJar, Avalara, etc.) — compatible. The plugin uses WooCommerce's native
is_vat_exemptflag, which is respected by all major tax services - Redis / persistent object cache — safe. Exemption lookups use the WordPress object cache with automatic invalidation on changes
- Multisite — each site has its own exemption tables
Languages
The admin interface is translated into:
- English
- Italian
- French
- Spanish
- German
Additional translations can be added via standard WordPress .po/.mo files using the text domain adn-wc-tax-exempt.
Getting started
Navigate to WooCommerce → Tax Exemptions. The admin interface has two tabs:
- Users — exempt individual customers by searching their name, email, or billing company
- Roles — exempt entire WordPress roles with a single toggle
The plugin checks exemption status at checkout using two rules, in order:
- Is this specific user in the exempt users list?
- Does this user have an exempt role?
If either check is true, WooCommerce removes all taxes for that customer.
User exemptions
Adding a user
- Go to WooCommerce → Tax Exemptions → Users tab.
- Use the search field to find a customer by name, email, or billing company.
- Select the user from the results.
- Optionally enter an exemption reason (e.g., "Non-profit organization", "Reseller certificate #12345").
- Click Add Exemption.
The user is immediately exempt from taxes on their next checkout.
Editing the reason
Click the Edit button next to any exempt user to update the exemption reason. This is useful when the reason changes (e.g., a new certificate number) without needing to remove and re-add the exemption.
Removing a user
Click the Remove button next to any exempt user in the list. The exemption is revoked instantly — taxes apply again on their next checkout.
Searching exempt users
The Users tab supports paginated search across all exempt customers. You can search by:
- Email address
- Display name
- Billing company
Role exemptions
Toggling a role
- Go to WooCommerce → Tax Exemptions → Roles tab.
- All WordPress roles are listed with a toggle switch.
- Enable the toggle for any role (e.g.,
wholesale,b2b_customer).
Every user with that role — current and future — is automatically exempt. No need to add users individually.
Priority
If a user has both a per-user exemption and a role exemption, the result is the same: they are exempt. The plugin checks the user table first, then falls back to roles.
If you remove a role exemption but a user within that role has a per-user exemption, they remain exempt.
Audit trail
Every exemption is logged with:
- Who approved it (the admin user who added the exemption)
- When it was created (timestamp)
- Why (the optional exemption reason, if provided)
This data is visible in the Users tab and available via the REST API. It's designed for compliance — you can answer "who exempted this customer and why" at any time.
How it works
The plugin uses WooCommerce's native is_vat_exempt mechanism. When a customer is exempt:
- On
woocommerce_init, the plugin checks if the current user is exempt (by user or by role). - If exempt, it calls
WC()->customer->set_is_vat_exempt( true ). - WooCommerce then automatically removes all taxes from the cart and checkout.
This approach is compatible with any theme, checkout flow, and tax calculation plugin — because WooCommerce handles the actual tax removal.
Cart & Checkout Blocks
For the newer Cart & Checkout Blocks, the plugin also hooks into the Store API via woocommerce_store_api_checkout_update_order_from_request to ensure exemptions are applied correctly during block-based checkout.
Guest users
Tax exemptions only apply to logged-in users. Guest visitors always see standard tax calculations.
For developers
Hooks
The plugin fires custom action hooks when exemptions are applied or removed:
| Hook | Type | Parameters | Description |
|---|---|---|---|
adn_wc_tax_exempt_exemption_applied | Action | $user_id | Fired when tax exemption is applied at checkout |
adn_wc_tax_exempt_exemption_removed | Action | $user_id | Fired when tax exemption is removed at checkout |
adn_wc_tax_exempt_exemption_applied_store_api | Action | $user_id, $order | Fired when exemption is applied via Store API (Blocks) |
adn_wc_tax_exempt_exemption_removed_store_api | Action | $user_id, $order | Fired when exemption is removed via Store API (Blocks) |
REST API
The plugin exposes a REST API under the adn-wc-tax-exempt/v1 namespace. All endpoints require the manage_woocommerce capability and use standard WordPress REST authentication.
Users endpoints
GET /users — List exempt users with pagination and search.
Query parameters: page, per_page, search, orderby (created_at | user_id), order (ASC | DESC).
{
"data": [
{
"id": 1,
"user_id": 42,
"user_email": "[email protected]",
"display_name": "John Smith",
"billing_company": "Smith Wholesale Ltd",
"exemption_reason": "Reseller certificate #12345",
"created_at": "2026-03-15T10:30:00",
"created_by": 1,
"user_role": "Wholesale"
}
],
"meta": {
"total": 1,
"pages": 1,
"current_page": 1,
"per_page": 20
}
}
POST /users — Add a user exemption.
{
"user_id": 42,
"reason": "Reseller certificate #12345"
}
PUT /users/{user_id} — Update the exemption reason.
{
"reason": "Updated reseller certificate #67890"
}
DELETE /users/{user_id} — Remove a user exemption.
GET /users/search — Search WordPress users by name, email, or billing company.
Query parameters: query (min 2 characters), limit.
{
"data": [
{
"user_id": 42,
"user_email": "[email protected]",
"display_name": "John Smith",
"billing_company": "Smith Wholesale Ltd",
"label": "John Smith (Smith Wholesale Ltd) - [email protected]",
"is_exempt": false
}
]
}
Roles endpoints
GET /roles — List all WordPress roles with exemption status.
{
"data": [
{ "slug": "administrator", "name": "Administrator", "is_exempt": false },
{ "slug": "customer", "name": "Customer", "is_exempt": false },
{ "slug": "wholesale", "name": "Wholesale", "is_exempt": true, "created_at": "2026-03-15T10:30:00" }
]
}
POST /roles — Add a role exemption.
{
"role_slug": "wholesale"
}
PUT /roles/{role_slug} — Toggle role exemption.
{
"is_exempt": true
}
DELETE /roles/{role_slug} — Remove a role exemption.
Data storage
The plugin uses two custom database tables:
wp_adn_wc_tax_exempt_users— stores per-user exemptions with reason, timestamp, and the admin who created itwp_adn_wc_tax_exempt_roles— stores exempt role slugs with timestamp and the admin who created it
Deactivating the plugin keeps all data intact. Deleting the plugin removes both tables permanently.