Skip to content

[Performance] Orders: reduce the number of SQLs required to persist an order#63372

Merged
kalessil merged 15 commits intotrunkfrom
performance/63118-reduce-sqls-number-iteration-5
Feb 21, 2026
Merged

[Performance] Orders: reduce the number of SQLs required to persist an order#63372
kalessil merged 15 commits intotrunkfrom
performance/63118-reduce-sqls-number-iteration-5

Conversation

@kalessil
Copy link
Copy Markdown
Contributor

@kalessil kalessil commented Feb 19, 2026

Submission Review Guidelines:

Changes proposed in this Pull Request:

Re-iterate on #63118 (#63110, WOOPLUG-6243)

Tune the logic of saving CoGS meta for the orders. For the checkout page, the numbers are as follows:

  • without object cache 111 SQLs -> 106 SQLs (-5 SQLs, -5%)
  • with object cache 57 SQLs -> 52 SQLs (-5 SQLs, -9%)

How to test the changes in this Pull Request:

  • Ensure your testing site has Query Monitor (or similar plugin), CoGS enabled, and products with both populated and not populated CoGS data
  • Using trunk, add to cart a product without CoGS data and navigate to the checkout page
  • Refresh the page until the number of SQLs stabilizes and memorize/note the number
  • Switch to this branch
  • Refresh the page until the number of SQLs stabilizes and verify the number reduction

Additionally, verify that adding a product with CoGS data to the cart and completing the checkout populates the orders' CoGS data.

@kalessil kalessil self-assigned this Feb 19, 2026
@github-actions github-actions Bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Feb 19, 2026
@kalessil kalessil changed the title [Performance] Order: reduce the number of SQLs whe saving order [Performance] Order: reduce the number of SQLs required to persist an order Feb 19, 2026
@kalessil kalessil changed the title [Performance] Order: reduce the number of SQLs required to persist an order [Performance] Orders: reduce the number of SQLs required to persist an order Feb 19, 2026
@kalessil kalessil requested a review from Konamiman February 20, 2026 08:58
@kalessil kalessil marked this pull request as ready for review February 20, 2026 08:58
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 20, 2026

Testing Guidelines

Hi @Konamiman @woocommerce/flux,

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.

@woocommercebot woocommercebot requested a review from a team February 20, 2026 08:59
@kalessil kalessil removed the request for review from a team February 20, 2026 08:59
@kalessil kalessil added this to the 10.7.0 milestone Feb 20, 2026
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Feb 20, 2026

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.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 20, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

persist_order_to_db now signals whether CoGS was changed via the order API; save_cogs_data uses the original stored CoGS value (pre-filter) and only writes or deletes the _cogs_total_value meta when the API-change flag is set or the filtered value differs from the stored value, avoiding unnecessary metadata writes.

Changes

Cohort / File(s) Summary
Changelog entry
plugins/woocommerce/changelog/performance-63118-reduce-sqls-number-iteration-5
Adds a changelog note for a minor performance improvement reducing SQL queries when persisting draft orders with CoGS enabled.
Static analysis baseline
plugins/woocommerce/phpstan-baseline.neon
Removes a PHPStan baseline rule that suppressed a missing-return-type report for the Orders data store method.
Orders data store implementation
plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php
persist_order_to_db() now passes an additional boolean indicating if CoGS was changed via the order API. save_cogs_data() signature updated to save_cogs_data(WC_Abstract_Order $order, bool $cogs_value_changed): void. Introduces $cogs_value_original, applies filters against the original value, uses strict null checks, and computes `$sync_meta = $cogs_value_changed

Sequence Diagram(s)

sequenceDiagram
    participant Checkout as Checkout / Caller
    participant DataStore as OrdersTableDataStore
    participant Filters as WP Filters
    participant DB as Database

    Checkout->>DataStore: persist_order_to_db($order, $changes)
    DataStore->>DataStore: compute $cogs_value_changed = ! $only_changes || array_key_exists('cogs_total_value',$changes)
    DataStore->>DataStore: $cogs_value_original = get_meta('_cogs_total_value') // pre-filter
    DataStore->>Filters: apply_filters('woocommerce_cogs_total_value', $cogs_value_original, $order)
    Filters-->>DataStore: $cogs_value_filtered
    DataStore->>DataStore: $sync_meta = $cogs_value_changed || ($cogs_value_original !== (float)$cogs_value_filtered)
    alt $sync_meta == true
        DataStore->>DB: update or delete `_cogs_total_value` meta
    else $sync_meta == false
        DataStore-->>Checkout: skip meta write
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main performance optimization - reducing SQL queries during order persistence, which directly matches the changeset's primary objective.
Description check ✅ Passed The description is directly related to the changeset, providing context about the performance improvement, benchmarks, and testing instructions for verifying the SQL reduction.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch performance/63118-reduce-sqls-number-iteration-5

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php (1)

2167-2175: Missing (float) cast on $cogs_value after the null check — inconsistent with item-level counterpart

The item-level save_cogs_data in abstract-wc-order-item-type-data-store.php explicitly casts after the null check:

$cogs_value = (float) $cogs_value;

This method omits that cast. There are two downstream consequences:

  1. Line 2172 — $sync_meta strict-comparison (!==) may fire spuriously. If the filter returns an int or string that is numerically equal to $cogs_value_original, PHP's !== treats them as unequal (type mismatch), setting $sync_meta = true and triggering an unnecessary DB write — defeating the optimisation.

  2. Line 2175 — 0.0 === $cogs_value strict-comparison may miss the delete branch. If the filter returns 0 (int) instead of 0.0 (float), the delete branch is skipped; the code falls through to the update or add branch, storing the wrong type and leaving a stale meta row instead of removing it.

Both issues are guarded by the @param float|null docblock, but extension developers are not guaranteed to honour it.

🛡️ Proposed fix — add the cast immediately after the null check
  $cogs_value = apply_filters( 'woocommerce_save_order_cogs_value', $cogs_value_original, $order );
  if ( null === $cogs_value ) {
      return;
  }
+
+ $cogs_value = (float) $cogs_value;

  $sync_meta = $changed_via_order_object || $cogs_value_original !== $cogs_value;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
around lines 2167 - 2175, The $cogs_value returned from apply_filters in the
OrdersTableDataStore save routine must be normalized to a float after the null
check to match the item-level behavior and avoid type-strict comparison bugs; so
in the method handling $cogs_value (the block using $cogs_value_original,
$cogs_value, apply_filters('woocommerce_save_order_cogs_value', ...), $sync_meta
and the subsequent 0.0 === $cogs_value check and
data_store_meta->get_metadata_by_key($order, '_cogs_total_value')), cast
$cogs_value to (float) immediately after confirming it is not null so strict !==
and === comparisons behave correctly and deletions/updates are not skipped or
wrongly triggered.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2152-2153: Update the docblock for the parameter
$changed_via_order_object in OrdersTableDataStore (the save COGS/order save
routine) to fix typos: change "Where" to "Whether", "was changes" to "was
changed", and "api" to "API" so the `@param` reads that the boolean indicates
whether the COGS value was changed via the order object API; keep the parameter
name ($changed_via_order_object) and surrounding docblock format intact.

---

Nitpick comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2167-2175: The $cogs_value returned from apply_filters in the
OrdersTableDataStore save routine must be normalized to a float after the null
check to match the item-level behavior and avoid type-strict comparison bugs; so
in the method handling $cogs_value (the block using $cogs_value_original,
$cogs_value, apply_filters('woocommerce_save_order_cogs_value', ...), $sync_meta
and the subsequent 0.0 === $cogs_value check and
data_store_meta->get_metadata_by_key($order, '_cogs_total_value')), cast
$cogs_value to (float) immediately after confirming it is not null so strict !==
and === comparisons behave correctly and deletions/updates are not skipped or
wrongly triggered.

Comment thread plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php Outdated
…thub.com:woocommerce/woocommerce into performance/63118-reduce-sqls-number-iteration-5
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php (2)

2167-2175: Add a (float) cast after the null check — inconsistent with item data store and causes two correctness gaps.

apply_filters can return any type. Without a cast, two issues arise:

  1. $cogs_value_original !== $cogs_value (line 2172) is a strict comparison. If a filter returns int 0 or string "0" for a zero-CoGS order, 0.0 !== 0true$sync_meta = true → a write is forced on every subsequent save, defeating the optimisation.

  2. 0.0 === $cogs_value (line 2175) is a strict comparison. With int 0 the check is false, so the delete branch is bypassed and the elseif/else branch runs instead — updating or inserting meta with an integer value rather than deleting it.

The analogous save_cogs_data in abstract-wc-order-item-type-data-store.php (line 243) explicitly casts: $cogs_value = (float) $cogs_value; after the null check. This PR should do the same.

♻️ Proposed fix
     if ( null === $cogs_value ) {
         return;
     }

+    $cogs_value = (float) $cogs_value;
+
     $sync_meta = $changed_via_order_object || $cogs_value_original !== $cogs_value;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
around lines 2167 - 2175, After the null check on $cogs_value (right after
apply_filters in OrdersTableDataStore), cast the filter result to float (e.g.
$cogs_value = (float) $cogs_value;) so comparisons against $cogs_value_original
and the strict checks like 0.0 === $cogs_value behave consistently; update the
code around $cogs_value_original, $cogs_value and the metadata logic that calls
$this->data_store_meta->get_metadata_by_key to rely on the normalized float
value.

2183-2188: else branch creates a 0-value _cogs_total_value meta row that serves no purpose.

When $sync_meta = true (e.g., first checkout save with products having no CoGS set), $cogs_value = 0.0, and no existing meta: the else branch inserts a new row with value 0.0. read_cogs_data at line 1426 treats both "absent meta" and "meta = 0" identically, so the row has no semantic benefit. The item-level save_cogs_data in abstract-wc-order-item-type-data-store.php (lines 243–249) avoids this by only writing non-zero values.

♻️ Proposed fix
-    } else {
+    } elseif ( 0.0 !== $cogs_value ) {
         $meta        = new \WC_Meta_Data();
         $meta->key   = '_cogs_total_value';
         $meta->value = $cogs_value;
         $this->data_store_meta->add_meta( $order, $meta );
     }

Note: If the (float) cast from the previous suggestion is applied first, the 0.0 !== $cogs_value guard here is guaranteed to be a clean float comparison.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
around lines 2183 - 2188, The else branch in OrdersTableDataStore is inserting a
redundant _cogs_total_value meta row with 0.0; modify the logic so you only call
$this->data_store_meta->add_meta($order, $meta) when $cogs_value is non-zero
(use a strict float check, e.g. $cogs_value !== 0.0 after casting to float
earlier), matching the item-level save_cogs_data behavior and keeping
read_cogs_data semantics consistent; ensure you reference the same meta key
'_cogs_total_value' and the data_store_meta->add_meta call when making the
change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2167-2175: After the null check on $cogs_value (right after
apply_filters in OrdersTableDataStore), cast the filter result to float (e.g.
$cogs_value = (float) $cogs_value;) so comparisons against $cogs_value_original
and the strict checks like 0.0 === $cogs_value behave consistently; update the
code around $cogs_value_original, $cogs_value and the metadata logic that calls
$this->data_store_meta->get_metadata_by_key to rely on the normalized float
value.
- Around line 2183-2188: The else branch in OrdersTableDataStore is inserting a
redundant _cogs_total_value meta row with 0.0; modify the logic so you only call
$this->data_store_meta->add_meta($order, $meta) when $cogs_value is non-zero
(use a strict float check, e.g. $cogs_value !== 0.0 after casting to float
earlier), matching the item-level save_cogs_data behavior and keeping
read_cogs_data semantics consistent; ensure you reference the same meta key
'_cogs_total_value' and the data_store_meta->add_meta call when making the
change.

Comment thread plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php Outdated
Comment thread plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php (1)

2155-2190: ⚠️ Potential issue | 🟡 Minor

Add unit tests for the $cogs_value_changed=false branching paths in save_cogs_data.

The new $cogs_value_changed optimization introduces code paths that aren't explicitly tested: (1) value unchanged by API, filter unchanged → no meta write, and (2) value unchanged by API, filter modifies it → meta write. All existing COGS tests call set_cogs_total_value() before save(), so $cogs_value_changed is always true. A test that saves an order without calling set_cogs_total_value() but with the filter returning a different value would verify the optimization works correctly and prevent regressions if the changes-tracking mechanism is modified.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
around lines 2155 - 2190, Add unit tests covering the save_cogs_data(
WC_Abstract_Order $order, bool $cogs_value_changed ) branching when
$cogs_value_changed is false: create one test where you do not call
set_cogs_total_value() and the woocommerce_save_order_cogs_value filter returns
the same value so no meta is written, and another test where you do not call
set_cogs_total_value() but the filter returns a different value so the
_cogs_total_value meta is added/updated; assert meta presence/absence using the
data store meta helpers (matching the logic in save_cogs_data) and ensure you
exercise the delete/update/add branches (existing_meta true/false and zero-value
deletion) so regressions in the change-tracking optimization are caught.
🧹 Nitpick comments (2)
plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php (2)

2173-2189: else branch adds a redundant 0.0 meta entry when CoGS is zero and no existing meta.

When $sync_meta = true (e.g., because $cogs_value_changed = true), $cogs_value = 0.0, and $existing_meta is empty, the else branch fires and executes an unnecessary add_meta call. Since read_cogs_data defaults to 0 when no _cogs_total_value meta exists, storing 0.0 is semantically equivalent to storing nothing — and costs one SQL against the optimization goal of this PR.

♻️ Proposed fix
-		} else {
+		} elseif ( 0.0 !== $cogs_value ) {
 			$meta        = new \WC_Meta_Data();
 			$meta->key   = '_cogs_total_value';
 			$meta->value = $cogs_value;
 			$this->data_store_meta->add_meta( $order, $meta );
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
around lines 2173 - 2189, The code currently calls add_meta in the else branch
even when $cogs_value === 0.0 and no existing meta, creating a redundant
zero-valued meta; update the logic in OrdersTableDataStore (the block using
$sync_meta, $cogs_value and $existing_meta) so that you only call
$this->data_store_meta->add_meta($order, $meta) when $cogs_value is not 0.0
(e.g., add a guard like if ( 0.0 !== $cogs_value ) before constructing and
adding the new \WC_Meta_Data), leaving the existing delete_meta path intact for
existing zero metas and skipping any insert when value is zero and no meta
exists.

2143-2143: Add guard to prevent storing CoGS meta when value is 0 on new orders.

The else branch at lines 2183–2188 adds _cogs_total_value meta even when the value is 0.0, but only for new orders (when no existing meta exists). The delete branch at lines 2173–2176 correctly removes the meta when the value is 0.0 and existing meta is present. To maintain consistency and avoid unnecessary database writes, guard the else clause to skip adding meta for zero values:

Suggested fix
} elseif ( 0.0 !== $cogs_value ) {
    $meta        = new \WC_Meta_Data();
    $meta->key   = '_cogs_total_value';
    $meta->value = $cogs_value;
    $this->data_store_meta->add_meta( $order, $meta );
}

This aligns with the behavior in the existing test test_saving_order_saves_cogs_value_if_not_zero_and_cogs_enabled (lines 3861–3865), which expects no meta to be stored when CoGS is set to 0.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`
at line 2143, The else branch in OrdersTableDataStore::save_cogs_data currently
adds a _cogs_total_value meta even when $cogs_value is 0.0; update the branch
that constructs a new \WC_Meta_Data and calls $this->data_store_meta->add_meta(
$order, $meta ) to only run when $cogs_value !== 0.0 (or 0.0 !== $cogs_value),
so zero values do not create the meta and mirror the delete behavior that
removes existing zero-value meta.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2155-2190: Add unit tests covering the save_cogs_data(
WC_Abstract_Order $order, bool $cogs_value_changed ) branching when
$cogs_value_changed is false: create one test where you do not call
set_cogs_total_value() and the woocommerce_save_order_cogs_value filter returns
the same value so no meta is written, and another test where you do not call
set_cogs_total_value() but the filter returns a different value so the
_cogs_total_value meta is added/updated; assert meta presence/absence using the
data store meta helpers (matching the logic in save_cogs_data) and ensure you
exercise the delete/update/add branches (existing_meta true/false and zero-value
deletion) so regressions in the change-tracking optimization are caught.

---

Nitpick comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2173-2189: The code currently calls add_meta in the else branch
even when $cogs_value === 0.0 and no existing meta, creating a redundant
zero-valued meta; update the logic in OrdersTableDataStore (the block using
$sync_meta, $cogs_value and $existing_meta) so that you only call
$this->data_store_meta->add_meta($order, $meta) when $cogs_value is not 0.0
(e.g., add a guard like if ( 0.0 !== $cogs_value ) before constructing and
adding the new \WC_Meta_Data), leaving the existing delete_meta path intact for
existing zero metas and skipping any insert when value is zero and no meta
exists.
- Line 2143: The else branch in OrdersTableDataStore::save_cogs_data currently
adds a _cogs_total_value meta even when $cogs_value is 0.0; update the branch
that constructs a new \WC_Meta_Data and calls $this->data_store_meta->add_meta(
$order, $meta ) to only run when $cogs_value !== 0.0 (or 0.0 !== $cogs_value),
so zero values do not create the meta and mirror the delete behavior that
removes existing zero-value meta.

@Konamiman Konamiman self-requested a review February 20, 2026 10:12
Konamiman
Konamiman previously approved these changes Feb 20, 2026
@kalessil kalessil marked this pull request as draft February 20, 2026 11:01
@github-actions github-actions Bot dismissed Konamiman’s stale review February 20, 2026 11:01

This approval has been dismissed due to the PR being moved to draft status. Please request a new review when ready.

@kalessil kalessil marked this pull request as ready for review February 20, 2026 11:39
@kalessil kalessil requested a review from Konamiman February 20, 2026 11:39
@woocommercebot woocommercebot requested a review from a team February 20, 2026 11:39
@kalessil kalessil removed the request for review from a team February 20, 2026 11:44
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2175-2188: The save_cogs_data branch incorrectly uses a strict
float comparison (0.0 === $cogs_value) which can miss integer zero values and
causes an update instead of delete, and the insert (else) branch unconditionally
calls add_meta even when $cogs_value is zero; update save_cogs_data to use a
non-strict check (== 0) or cast to float before comparing so both int(0) and 0.0
are treated as zero when deciding to call delete_meta($order, $existing_meta),
and in the else (add_meta) branch skip creating/adding the new \WC_Meta_Data if
$cogs_value == 0 to avoid inserting redundant zero rows; adjust logic around
$existing_meta, $cogs_value, and calls to data_store_meta->delete_meta,
->update_meta, and ->add_meta accordingly.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@plugins/woocommerce/src/Internal/DataStores/Orders/OrdersTableDataStore.php`:
- Around line 2175-2188: The code in OrdersTableDataStore handling $cogs_value
can insert or update a zero value instead of deleting/omitting the meta; fix by
treating any numeric zero (int(0) or float(0.0) or "0") as "no meta":
coerce/check with a strict numeric-zero guard (e.g. cast or use == 0.0 or
is_numeric + floatval(...) === 0.0) before branching so that when the computed
$cogs_value is zero you always call $this->data_store_meta->delete_meta(...) or
skip add_meta/update_meta; ensure the else branch only calls add_meta when the
normalized float value is non-zero and the elseif branch only updates when the
normalized float is non-zero, referencing $cogs_value, $existing_meta,
OrdersTableDataStore and the data_store_meta methods
delete_meta/update_meta/add_meta to locate the logic to change.

@kalessil kalessil merged commit c247382 into trunk Feb 21, 2026
35 checks passed
@kalessil kalessil deleted the performance/63118-reduce-sqls-number-iteration-5 branch February 21, 2026 09:05
samnajian pushed a commit that referenced this pull request Mar 11, 2026
…n order (#63372)

Added guarding conditions for updating CoGS meta when persisting an order to reduce the number of SQLs on the checkout page.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

plugin: woocommerce Issues related to the WooCommerce Core plugin.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants