woocommerce icon indicating copy to clipboard operation
woocommerce copied to clipboard

Fix tax-inclusive prices incorrectly inflating when no base tax rate …

Open Ferdev opened this issue 6 months ago β€’ 12 comments

Submission Review Guidelines:

Changes proposed in this Pull Request:

~~Original approach: Added special handling for empty base tax rates in wc_get_price_including_tax() and WC_Cart_Totals to prevent incorrectly adding customer taxes on top of tax-inclusive prices when no base rate exists.~~

Updated approach: After a deeper analysis, we determined this is a UX and configuration issue rather than a code bug. The documented behavior explicitly states that "prices entered with tax" should include the base location's tax rate, and prices are automatically adjusted for other locations.

This PR now implements UX improvements to help merchants understand and properly configure this setting:

  1. Reverted previous code changes (2 commits):

    • Removed special handling for empty base tax rates
    • Restored default location-based price adjustment behavior
  2. Updated setting description to clearly state: "If you select 'Yes', ensure a tax rate is configured for your base location."

  3. Added admin validation notice that displays when:

    • "Prices entered with tax" is enabled
    • No base tax rate is configured
    • Includes direct link to configure tax rates

Closes #WOOPLUG-5511

Screenshots or screen recordings:

Before After
Setting description: "This option is important as it will affect how you input prices. Changing it will not update existing products." Setting description: "This option is important as it will affect how you input prices. If you select 'Yes', ensure a tax rate is configured for your base location. Changing this option will not update existing products."

How to test the changes in this Pull Request:

  1. Navigate to WooCommerce > Settings > Tax
  2. Enable "Calculate tax" if not already enabled
  3. Set "Prices entered with tax" to "Yes, I will enter prices inclusive of tax"
  4. Check that the question mark hint now mentions that only the base tax rate is considered in this case.
  5. Do not configure any tax rates for your base location
  6. Save the settings and refresh the page
  7. Expected: You should see a warning notice at the top of the page stating "Tax configuration incomplete" with a link to configure tax rates
  8. Click the link and add a tax rate for your base location (e.g., 10% for your country/state)
  9. Return to WooCommerce > Settings > Tax
  10. Expected: The warning notice should no longer appear

Testing that has already taken place:

  • Verified notice appears only on WooCommerce settings pages
  • Verified notice disappears when base tax rate is configured
  • Verified notice doesn't appear when "Prices entered with tax" is set to "No"
  • Tested with multiple tax classes

Milestone

  • [x] Automatically assign milestone for the next WooCommerce version

Changelog entry

  • [x] Automatically create a changelog entry from the details below.
Changelog Entry Details

Significance

  • [x] Patch

Type

  • [x] Tweak - A minor adjustment to the codebase

Message

Improve UX for tax-inclusive pricing configuration by adding validation notice and clearer setting description when base tax rate is not configured.

Ferdev avatar Oct 17 '25 09:10 Ferdev

[!NOTE]

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

πŸ“ Walkthrough

Walkthrough

Adds a changelog entry, updates an E2E test tip text, and implements an admin validation notice in WooCommerce tax settings that warns when prices are entered inclusive of tax but the store's base location has no configured standard tax rates.

Changes

Cohort / File(s) Summary
Changelog Entry
plugins/woocommerce/changelog/61471-wooplug-5511-product-prices-entered-inclusive-of-tax-are-displayed
Adds a patch-level changelog entry describing a fix where tax-inclusive product prices incorrectly had customer taxes added when no base tax rate was configured.
Tax Settings Validation
plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php
Adds an admin_notices hook in the WC_Settings_Tax constructor to call a new public function tax_configuration_validation_notice(): void; implements logic to run only on WooCommerce settings pages, skip when taxes are disabled or prices are entered with tax disabled, respect the woocommerce_adjust_non_base_location_prices option-filter, check the store base country, and show a warning with a link if no standard tax rate exists; adds helper private function has_standard_tax_rate_for_country( $country ) that queries woocommerce_tax_rates.
E2E Test Tip Update
plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js
Updates the UI tip text for the "Prices entered with tax" setting to clarify that selecting "Yes" requires entering prices including the base location's tax rate as the baseline.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

  • Verify the database query in has_standard_tax_rate_for_country( $country ) is securely prepared, uses proper table prefixes, and includes LIMIT for efficiency.
  • Confirm the admin-notice is correctly scoped (settings page detection), and early-return conditions (taxes enabled, prices-entered-with-tax option, filter behavior) are correct.
  • Review notice copy and the generated link target to the standard tax rates admin screen.
  • Ensure the new public method signature and any visibility changes align with coding standards and unit/e2e test expectations.
  • Check the E2E test text update doesn't break selectors or assertions.

Pre-merge checks and finishing touches

βœ… Passed checks (3 passed)
Check name Status Explanation
Title check βœ… Passed The title accurately summarizes the main changeβ€”addressing tax-inclusive prices being incorrectly inflated when no base tax rate is configured.
Description check βœ… Passed The description is comprehensive and directly related to the changeset, explaining the UX-focused approach, implementation details, testing steps, and changes to settings description and admin notice.
Docstring Coverage βœ… Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • [ ] πŸ“ Generate docstrings
πŸ§ͺ Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment
  • [ ] Commit unit tests in branch wooplug-5511-product-prices-entered-inclusive-of-tax-are-displayed

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❀️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

coderabbitai[bot] avatar Oct 17 '25 09:10 coderabbitai[bot]

Testing Guidelines

Hi @samnajian @ralucaStan @ayushpahwa @woocommerce/developer-advocacy @woocommerce/ballade,

Apart from reviewing the code changes, please make sure to review the testing instructions (Guide) and verify that relevant tests (E2E, Unit, Integration, etc.) have been added or updated as needed.

Reminder: PR reviewers are required to document testing performed. This includes:

  • πŸ–ΌοΈ Screenshots or screen recordings.
  • πŸ“ List of functionality tested / steps followed.
  • 🌐 Site details (environment attributes such as hosting type, plugins, theme, store size, store age, and relevant settings).
  • πŸ” Any analysis performed, such as assessing potential impacts on environment attributes and other plugins, conducting performance profiling, or using LLM/AI-based analysis.

⚠️ Within the testing details you provide, please ensure that no sensitive information (such as API keys, passwords, user data, etc.) is included in this public issue.

github-actions[bot] avatar Oct 17 '25 09:10 github-actions[bot]

Test using WordPress Playground

The changes in this pull request can be previewed and tested using a WordPress Playground instance. WordPress Playground is an experimental project that creates a full WordPress instance entirely within the browser.

Test this pull request with WordPress Playground.

Note that this URL is valid for 30 days from when this comment was last updated. You can update it by closing/reopening the PR or pushing a new commit.

github-actions[bot] avatar Oct 17 '25 10:10 github-actions[bot]

Hey @Ferdev apologies for the late review here, I didn't get a chance to complete the review during the meetup. I have gone through the code and it looks good! I was not able to however follow the testing steps. This is an old setup and I selected I don't charge sales tax during the onboarding. NOw I don't see the tax option in the settings. Is there a way to get the options now or do I need to re-setup the store? image

ayushpahwa avatar Oct 28 '25 10:10 ayushpahwa

Hey @Ferdev apologies for the late review here, I didn't get a chance to complete the review during the meetup. I have gone through the code and it looks good! I was not able to however follow the testing steps. This is an old setup and I selected I don't charge sales tax during the onboarding. NOw I don't see the tax option in the settings. Is there a way to get the options now or do I need to re-setup the store? image

Hey @ayushpahwa :wave: Do you have this setting available and enabled? I think that may be the problem: shot-2025-10-28-18-47-31

Ferdev avatar Oct 28 '25 17:10 Ferdev

Claude finished @Ferdev's task β€”β€” View job


BC Review Complete

Overall Risk: Low βœ…

This PR introduces UX improvements only - no core tax calculation logic has been changed. The changes add a new public method and admin warning notice to guide users when tax-inclusive pricing is enabled without a base tax rate configured.


Summary

The PR shifts from modifying tax calculation behavior to implementing preventive UX guidance. All changes are additive (new method, new hook, updated tooltip) with no modifications to existing public APIs, hooks, or business logic. The risk of breaking changes is minimal.

Key Points:

  • βœ… No changes to public/protected API signatures
  • βœ… No removed or modified hooks
  • βœ… No template modifications
  • βœ… No database/schema changes
  • βœ… No REST API changes
  • βœ… No JavaScript/Block changes
  • βœ… Comprehensive test coverage added

πŸ“‹ Detailed Analysis

Changes by Category

1. New Public Method (WC_Settings_Tax::tax_configuration_validation_notice())

  • File: plugins/woocommerce/includes/admin/settings/class-wc-settings-tax.php:375-429
  • Visibility: public
  • BC Impact: None - purely additive
  • Purpose: Displays admin warning when tax-inclusive pricing is enabled without base tax rate
  • Hook: Hooked to admin_notices (line 35)

API Usage:

get_current_screen()              // WordPress core
get_option()                       // WordPress core
wc_get_base_location()            // WooCommerce core (stable API)
WC_Tax::get_tax_classes()         // Public static method
WC_Tax::get_base_tax_rates()      // Public static method

Risk Assessment: βœ… No risk

  • Uses only stable, public WordPress/WooCommerce APIs
  • Method is public but won't conflict (unique name, scoped to settings context)
  • Output is admin-only HTML notice (no frontend impact)

2. Hook Addition (line 35)

add_action( 'admin_notices', array( $this, 'tax_configuration_validation_notice' ) );

BC Impact: None

  • New hook registration with no priority specified (defaults to 10)
  • Only fires when wc_tax_enabled() is true
  • Notice is conditional (only shows when specific conditions met)

3. Setting Tooltip Update

  • File: plugins/woocommerce/includes/admin/settings/views/settings-tax.php:24
  • Change: Updated desc_tip text for woocommerce_prices_include_tax setting

Before:

'desc_tip' => __( 'This option is important as it will affect how you input prices. Changing it will not update existing products.', 'woocommerce' )

After:

'desc_tip' => __( 'This option is important as it will affect how you input prices. If you select "Yes", ensure a tax rate is configured for your base location. Changing this option will not update existing products.', 'woocommerce' )

BC Impact: None

  • Admin UI text change only (translatable string)
  • No functional behavior change
  • Backwards compatible with existing translations (new string will use source text until translated)

4. Test Coverage

  • File: plugins/woocommerce/tests/php/includes/settings/class-wc-settings-tax-test.php
  • Added: 4 new test methods (lines 177-298)

Tests cover:

  1. Notice shows when prices include tax but no base rate exists βœ…
  2. Notice does NOT show when base rate exists βœ…
  3. Notice does NOT show when prices are not tax-inclusive βœ…
  4. Notice does NOT show on non-WooCommerce admin pages βœ…

BC Impact: None - test-only changes


πŸ” Ecosystem Impact Analysis

Payment Gateways

Risk: None βœ…

No changes to payment-related functionality. Gateways that read tax settings will see identical behavior.

WooCommerce Extensions

Risk: None βœ…

Extensions analyzed:

  • WooCommerce Subscriptions: No impact - tax calculation logic unchanged
  • WooCommerce Bookings: No impact - uses same tax APIs (no changes)
  • WooCommerce Memberships: No impact
  • Product Bundles/Composite Products: No impact

Potential considerations:

  • Extensions hooking into admin_notices will see new notice (intended behavior)
  • Extensions that parse settings arrays won't be affected (only desc_tip text changed)

Themes/Templates

Risk: None βœ…

No template file changes. Themes customizing admin settings pages will continue to work.

Custom Implementations

Risk: None βœ…

Scenarios:

  1. Code extending WC_Settings_Tax: New public method won't conflict with overrides (unique name)
  2. Code calling WC_Settings_Tax methods: No signature changes to existing methods
  3. Code filtering woocommerce_tax_settings: Settings structure unchanged (only tooltip text updated)

πŸ§ͺ Testing Focus

Recommended Regression Testing

1. Admin Settings Page

  • [ ] Navigate to WooCommerce > Settings > Tax
  • [ ] Verify notice appears when:
    • "Prices entered with tax" is set to "Yes"
    • No tax rate configured for base location
  • [ ] Verify notice does NOT appear when:
    • "Prices entered with tax" is set to "No"
    • Base tax rate is configured
    • On non-settings pages

2. Tax Calculation (Existing Behavior)

Scenario: Tax-inclusive pricing with no base rate

  • Store base: US:CA (no tax rate configured)
  • Customer location: Austria (20% tax configured)
  • Product price: $100 (tax-inclusive)

Expected (unchanged): $120 at checkout

  • This is existing WooCommerce behavior (as clarified by PR author in comment on Nov 21)
  • PR does NOT change calculation logic, only adds warning UI

3. Extension Compatibility

  • [ ] Test with WooCommerce Subscriptions active
  • [ ] Test with WooCommerce Bookings active
  • [ ] Verify admin notices display correctly with other plugins

4. Translation/Localization

  • [ ] Verify new strings are translatable
  • [ ] Test with non-English locale (notice should display in English until translated)

Confidence: 95%

Justification: High confidence based on:

  1. Zero modifications to existing public APIs or core logic
  2. Additive changes only (new method, new hook registration, text update)
  3. Comprehensive test coverage validates notice behavior
  4. Admin-only impact - no frontend or checkout changes
  5. Uses stable, public APIs - no reliance on internal/unstable methods

Remaining 5% uncertainty:

  • Potential edge cases in multi-site WordPress environments (untested)
  • Possible plugin conflicts with aggressive admin notice styling (cosmetic only)

βœ… Verdict: No Breaking Changes Detected

This PR is safe to merge from a backwards compatibility perspective. The changes are purely additive UX improvements that guide users toward correct tax configuration without altering any existing behavior or APIs.


claude[bot] avatar Nov 11 '25 22:11 claude[bot]

hey @samnajian , I noticed there were some discrepancies in my local setup in the cart when testing this PR, and I found another issue that I've fixed. Could you please give it another review whenever you can? Thanks! :pray:

Ferdev avatar Nov 12 '25 19:11 Ferdev

hey @ralucaStan , thank you so much for taking the time to give this PR a second thought. I really appreciate it :bow:

All you said makes a lot of sense and I think that's the proper way to deal with this problem. I wasn't aware of that filter, so also thanks to Mike for the tip. I'm gonna go ahead and implement a fix using that filter instead of the current solution :+1:

Ferdev avatar Nov 20 '25 12:11 Ferdev

I've been reviewing this problem closely today, and after reading @ralucaStan comment, and checking the WooCommerce docs more carefully, I've come to the conclusion the issue we're facing here is the customers facing this problem haven't read the docs. The docs state clearly that "prices inclusive of tax" only consider the store's base tax rate, and not any local ones. For the example we've been showcasing, if the store has prices inclusive of tax, the product's price is $100 and base tax is missing (ie, 0%), then the final price for a customer in a country with a local 20% tax would be $120. WooCommerce has been functioning like this for a long time, and I don't think it makes sense to change it now.

What I propose, though, is some changes in the UI to make more clear what the docs say: that price inclusive of tax only includes the base tax. Specifically:

  • Update the setting hint to explicitly mention that a base tax rate is required
  • Add a warning notice when someone enables "prices with tax" without configuring their base location's tax rate
  • Clarify that prices will be adjusted for customers in different locations

I'll update this PR to implement these UX improvements instead of changing the tax calculation logic. I'll also add a comment on the Linear ticket explaining these findings.

Ferdev avatar Nov 21 '25 15:11 Ferdev

I've implemented the changes described in my previous comment, and updated the pull request description with updated testing instructions.

Ferdev avatar Nov 21 '25 18:11 Ferdev

I've tested the PR:

* the notice appears when there is no tax defined for the store base country

* the text is changed for the info is changed

Some things I noticed:

* if I enter a tax line for my store country (DE) with the tax value 0 the notice is not visible. I think that is ok.

* if I enter a more localized tax line for my store country, see below, the notice is visible. Shouldn't it be hidden?
Image

Extensibility:

* should the notice be visible if a plugin is using `woocommerce_adjust_non_base_location_prices`?

Hey @ralucaStan , I've implemented all your suggestions. I couldn't reproduce your problem with your local taxes... I've introduced a fix that may solve it, but let me know if it doesn't. Thanks!

Ferdev avatar Dec 04 '25 15:12 Ferdev

Pre-approved since it works as advertised, but I assume that you'll take care of the PHPStan and linting issues. Also:

  • Added a comment about a missing @internal annotation.
  • I have seen a @since 10.4.0 that should be updated to 10.5.0.

Konamiman avatar Dec 05 '25 09:12 Konamiman