Skip to content

Conversation

@naman03malhotra
Copy link
Contributor

@naman03malhotra naman03malhotra commented Sep 10, 2025

Submission Review Guidelines:

Changes proposed in this Pull Request:

This PR add the support for COGS. The cogs value should migrate from Shopify even if the feature is disabled.

How to test the changes in this Pull Request:

Using the WooCommerce Testing Instructions Guide, include your detailed testing instructions:

  1. Verify that the cogs is being migrated when migrating the products, we have setup two such products. 1. Simple and 2. Variable.
  2. wp wc migrate products --product-type="Cycling Jersey" --status=active - Variable
  3. wp wc migrate products --product-type="Cap" --status=active - Simple
  4. else feel free to setup your own variable and simple products.
  5. Verify that the cogs value is being migrated when the feature is enabled.
  6. Verify that the cogs value is being migrated when the feature is disabled and then enabled again.
image image image

Testing that has already taken place:

Changelog entry

  • Automatically create a changelog entry from the details below.
  • This Pull Request does not require a changelog entry. (Comment required below)
Changelog Entry Details

Significance

  • Patch
  • Minor
  • Major

Type

  • Fix - Fixes an existing bug
  • Add - Adds functionality
  • Update - Update existing functionality
  • Dev - Development related task
  • Tweak - A minor adjustment to the codebase
  • Performance - Address performance issues
  • Enhancement - Improvement to existing functionality

Message

Changelog Entry Comment

Comment

@github-actions github-actions bot added the plugin: woocommerce Issues related to the WooCommerce Core plugin. label Sep 10, 2025
@naman03malhotra naman03malhotra changed the title Add/cogs support [Migrator]: Add/cogs support Sep 10, 2025
@naman03malhotra naman03malhotra changed the title [Migrator]: Add/cogs support [Migrator]: Add COGS support even if the feature is disabled Sep 11, 2025
@naman03malhotra naman03malhotra marked this pull request as ready for review September 11, 2025 19:51
@github-actions
Copy link
Contributor

github-actions bot commented Sep 11, 2025

Testing Guidelines

Hi @roccotripaldi ,

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.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR adds support for migrating Cost of Goods Sold (COGS) data from Shopify to WooCommerce, ensuring COGS values are preserved during migration even when the COGS feature is disabled in WooCommerce.

  • Extends Shopify GraphQL query to fetch unitCost data for inventory items
  • Adds COGS mapping logic for both simple and variable products in the Shopify mapper
  • Implements COGS value storage using both feature API (when enabled) and direct meta data approach (when disabled)

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
ShopifyFetcher.php Adds unitCost fields to GraphQL query for fetching COGS data from Shopify
ShopifyMapper.php Maps Shopify unitCost data to cost_of_goods field for simple and variable products
WooCommerceProductImporter.php Handles COGS import with feature detection and fallback meta storage
changelog/add-cogs-support Adds changelog entry for the new COGS migration functionality
Comments suppressed due to low confidence (1)

plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php:537

  • The docblock comment line @param array $attributes_data Standardized attribute data from mapper. appears to be orphaned after the removal and doesn't match any actual parameter. This should be removed or corrected.
	private function handle_variable_product( WC_Product_Variable $product, array $product_data ): void {

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

@github-actions
Copy link
Contributor

github-actions bot commented Sep 11, 2025

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.

Copy link
Contributor

@roccotripaldi roccotripaldi left a comment

Choose a reason for hiding this comment

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

Nice, Naman! I set up a dev store on Shopify, where I created a simple product and a variable product. I set the "cost per item" for the simple product and all the variants.

I migrated them with COGS disabled. And when I enabled COGs, the costs of goods values were present and correct.

I repeated the migration with COGS enabled, and same deal, the values were present and correct.

Great work - send it!

On Shopify On Woo
Screenshot 2025-09-13 at 7 42 36 PM Screenshot 2025-09-13 at 7 43 05 PM

Base automatically changed from fix/attribute-mapping to trunk September 15, 2025 17:09
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 15, 2025

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

Fetches Shopify variant unitCost, maps it into a new cost_of_goods field, and applies COGS during import by using the feature-aware API when available or falling back to writing _cogs_total_value post meta. Adds a changelog entry.

Changes

Cohort / File(s) Summary
Changelog
plugins/woocommerce/changelog/add-cogs-support
Adds a patch changelog entry: “Added cogs support even if the feature is disabled.”
Importer: COGS handling
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
Adds FeaturesUtil usage; when cost_of_goods present uses set_cogs_value if feature enabled, otherwise uses new private helper set_cogs_value_direct( WC_Product, float ) to update _cogs_total_value; variations update _cogs_total_value after save; minor doc formatting.
Shopify fetch query
plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php
Extends SHOPIFY_PRODUCT_QUERY to include inventoryItem { unitCost { amount, currencyCode } } for variants.
Shopify mapping
plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php
Populates cost_of_goods from variant.inventoryItem.unitCost.amount (guarded by existence/type checks) for simple and variable products; no other mapping changes.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant Shopify as Shopify API
  participant Fetcher as ShopifyFetcher
  participant Mapper as ShopifyMapper
  participant Importer as WooCommerceProductImporter
  participant Feature as FeaturesUtil
  participant Product as WC_Product
  participant Meta as Post Meta

  Shopify->>Fetcher: GraphQL products (variants.unitCost)
  Fetcher-->>Mapper: Product payloads (unitCost included)
  Mapper-->>Importer: Mapped data (includes cost_of_goods when available)

  Importer->>Feature: is_enabled('cost_of_goods_sold')?
  alt Feature enabled
    Importer->>Product: set_cogs_value((float) cost_of_goods)
  else Feature disabled
    Importer->>Meta: update_post_meta(_cogs_total_value, cost_of_goods)
  end

  opt Variations
    Importer->>Product: save variation
    Importer->>Meta: update variation _cogs_total_value if provided
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The PR title "[Migrator]: Add COGS support even if the feature is disabled" accurately and concisely summarizes the primary change — adding migrator support to import and preserve COGS values even when the COGS feature is disabled; it directly matches the changes in ShopifyFetcher, ShopifyMapper, and WooCommerceProductImporter and contains no extraneous noise.
Description Check ✅ Passed The PR description is directly related to the changeset: it explains the objective of migrating COGS from Shopify even when the feature is disabled, includes testing instructions and contextual details, and therefore satisfies the lenient requirement that the description relate to the changeset.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add/cogs-support

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
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: 2

♻️ Duplicate comments (2)
plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php (1)

452-456: Guard for missing amount; preserve zero; cast to float.

Current check can read a missing property and drops valid zero values.

-			if ( property_exists( $variant_node, 'inventoryItem' ) && is_object( $variant_node->inventoryItem ) && 
-				property_exists( $variant_node->inventoryItem, 'unitCost' ) && is_object( $variant_node->inventoryItem->unitCost ) 
-			) {
-				$simple_data['cost_of_goods'] = $variant_node->inventoryItem->unitCost->amount;
-			}
+			if (
+				property_exists( $variant_node, 'inventoryItem' )
+				&& is_object( $variant_node->inventoryItem )
+				&& property_exists( $variant_node->inventoryItem, 'unitCost' )
+				&& is_object( $variant_node->inventoryItem->unitCost )
+				&& isset( $variant_node->inventoryItem->unitCost->amount )
+				&& is_numeric( $variant_node->inventoryItem->unitCost->amount )
+			) {
+				$simple_data['cost_of_goods'] = (float) $variant_node->inventoryItem->unitCost->amount;
+			}
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (1)

816-818: Variation COGS should mirror feature-aware handling and keep zero values.

Currently always writes post meta after save and skips 0.0. Align with the simple-product logic.

-				if ( ! empty( $var_data['cost_of_goods'] ) ) {
-					update_post_meta( $saved_variation_id, '_cogs_total_value', (float) $var_data['cost_of_goods'] );
-				}
+				if ( array_key_exists( 'cost_of_goods', $var_data ) ) {
+					$cogs = (float) $var_data['cost_of_goods'];
+					if ( FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' ) ) {
+						$variation->set_cogs_value( $cogs );
+						$variation->save(); // ensure persisted when feature enabled
+					} else {
+						update_post_meta( $saved_variation_id, '_cogs_total_value', $cogs );
+					}
+				}
🧹 Nitpick comments (5)
plugins/woocommerce/changelog/add-cogs-support (1)

4-4: Clarify and standardize wording (“COGS”, mention migration).

Suggest tightening the entry and using “COGS” consistently.

-Added cogs support even if the feature is disabled
+Added COGS migration support even if the feature is disabled.
plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php (2)

543-547: Same fix for variations: check amount, allow 0, cast.

Mirrors the simple path.

-				if ( property_exists( $variant_node, 'inventoryItem' ) && is_object( $variant_node->inventoryItem ) && 
-					property_exists( $variant_node->inventoryItem, 'unitCost' ) && is_object( $variant_node->inventoryItem->unitCost ) 
-				) {
-					$variation_data['cost_of_goods'] = $variant_node->inventoryItem->unitCost->amount;
-				}
+				if (
+					property_exists( $variant_node, 'inventoryItem' )
+					&& is_object( $variant_node->inventoryItem )
+					&& property_exists( $variant_node->inventoryItem, 'unitCost' )
+					&& is_object( $variant_node->inventoryItem->unitCost )
+					&& isset( $variant_node->inventoryItem->unitCost->amount )
+					&& is_numeric( $variant_node->inventoryItem->unitCost->amount )
+				) {
+					$variation_data['cost_of_goods'] = (float) $variant_node->inventoryItem->unitCost->amount;
+				}

452-456: Currency is fetched upstream but ignored here; confirm strategy.

Shopify returns unitCost.amount + currencyCode. If store currency differs, migrating raw amounts can be wrong. Either convert to the WooCommerce store currency during mapping/import, or persist the currency alongside the amount and reconcile later.

Would you like a small helper that converts MoneyV2 to store currency (with fallback to storing the currency separately)?

Also applies to: 543-547

plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php (1)

92-95: We fetch currencyCode but don’t use it.

Keep only needed fields or wire currency through the mapper/importer.

If we keep it, please add a follow-up to handle conversion or storage; otherwise remove currencyCode from the query to reduce payload.

plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (1)

493-531: Add tests for COGS import paths (enabled/disabled, simple/variation, zero values).

Please cover:

  • Simple product: feature disabled → meta persisted pre-save; enabled → set_cogs_value called.
  • Variation: both branches; zero amounts retained.

I can scaffold PHPUnit tests for the importer and a CLI E2E exercising wp-cli flows; want me to push a test skeleton?

Also applies to: 694-828

📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ab60ef4 and 87200bb.

📒 Files selected for processing (4)
  • plugins/woocommerce/changelog/add-cogs-support (1 hunks)
  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (5 hunks)
  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php (1 hunks)
  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php (2 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php
  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit configuration file

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.

Files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyMapper.php
  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
  • plugins/woocommerce/src/Internal/CLI/Migrator/Platforms/Shopify/ShopifyFetcher.php
🧠 Learnings (3)
📚 Learning: 2025-08-29T14:38:18.023Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60641
File: plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts:410-480
Timestamp: 2025-08-29T14:38:18.023Z
Learning: The "sold individually" variation functionality (where the Product Quantity block should hide when a variation is sold individually) mentioned in issue #59443 objectives is not implemented in PR #60641 and will be addressed in a future PR.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
📚 Learning: 2025-08-29T10:13:44.287Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60667
File: plugins/woocommerce/src/Blocks/BlockTypes/AddToCartForm.php:122-125
Timestamp: 2025-08-29T10:13:44.287Z
Learning: In WooCommerce, the ProductType class in plugins/woocommerce/src/Enums/ProductType.php contains string constants (not a PHP backed enum), so ProductType::VARIATION directly returns the string 'variation' and can be passed directly to methods like WC_Product::is_type() without needing ->value.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
📚 Learning: 2025-09-08T15:12:20.201Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60767
File: plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/grouped-product-selector/frontend.ts:121-126
Timestamp: 2025-09-08T15:12:20.201Z
Learning: In WooCommerce, 'variation' is the product type used for variable products' children, while 'variable' is the type of the parent product. These are two distinct product types in the WooCommerce system.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
🧬 Code graph analysis (1)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (2)
plugins/woocommerce/src/Utilities/FeaturesUtil.php (1)
  • FeaturesUtil (14-102)
plugins/woocommerce/includes/abstracts/abstract-wc-product.php (1)
  • set_cogs_value (2347-2352)
🔇 Additional comments (3)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (3)

18-18: Importing FeaturesUtil is appropriate.


588-589: Docblock nit is fine.


522-530: Resolved — _cogs_total_value is the per‑unit COGS meta (no change required). Verified: the product data store persists the product COGS to _cogs_total_value, get_cogs_total_value() is used as the per‑unit cost in order/item calculations, and the importer writes that meta (via set_cogs_value or set_cogs_value_direct) when importing.

naman03malhotra and others added 3 commits September 15, 2025 23:00
…ProductImporter.php

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Copy link
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

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/CLI/Migrator/Core/WooCommerceProductImporter.php (1)

122-122: Fix fatal: find_existing_product is called with 2 args but accepts 1.

This will throw at runtime. Drop the unused $source_data argument.

-			$existing_product_id = $this->find_existing_product( $product_data, $source_data );
+			$existing_product_id = $this->find_existing_product( $product_data );
♻️ Duplicate comments (1)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (1)

815-817: Variation COGS: don’t drop 0.0; align with feature detection used for simple products.

! empty(...) skips valid zero and ignores the feature‑enabled path. Apply the same logic as simple products. This also addresses past feedback.

-				if ( ! empty( $var_data['cost_of_goods'] ) ) {
-					update_post_meta( $saved_variation_id, '_cogs_total_value', (float) $var_data['cost_of_goods'] );
-				}
+				if ( array_key_exists( 'cost_of_goods', $var_data ) ) {
+					$raw_cogs = $var_data['cost_of_goods'];
+					if ( is_numeric( $raw_cogs ) ) {
+						$cogs = (float) $raw_cogs;
+						if ( FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' ) ) {
+							$variation->set_cogs_value( $cogs );
+							$variation->save();
+						} else {
+							update_post_meta( $saved_variation_id, '_cogs_total_value', $cogs );
+						}
+					}
+				}
🧹 Nitpick comments (1)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (1)

587-587: Doc nit: clarify parameter meaning.

Minor: tighten the description to reflect taxonomy/term creation and mapping.

-	 * @param array               $attributes_data              Standardized attribute data from mapper.
+	 * @param array               $attributes_data Standardized attribute data from the mapper (names/options); creates taxonomies/terms and updates current mapping.
📜 Review details

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95612ee and b78afb0.

📒 Files selected for processing (1)
  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (5 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{php,js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/code-quality.mdc)

**/*.{php,js,jsx,ts,tsx}: Guard against unexpected inputs
Sanitize and validate any potentially dangerous inputs
Ensure code is backwards compatible
Write code that is readable and intuitive
Ensure code has unit or E2E tests where applicable

Files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
**/*.{php,js,ts,jsx,tsx}

⚙️ CodeRabbit configuration file

**/*.{php,js,ts,jsx,tsx}: Don't trust that extension developers will follow the best practices, make sure the code:

  • Guards against unexpected inputs.
  • Sanitizes and validates any potentially dangerous inputs.
  • Is backwards compatible.
  • Is readable and intuitive.
  • Has unit or E2E tests where applicable.

Files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
🧠 Learnings (3)
📚 Learning: 2025-08-29T14:38:18.023Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60641
File: plugins/woocommerce/client/blocks/tests/e2e/tests/add-to-cart-with-options/add-to-cart-with-options.block_theme.spec.ts:410-480
Timestamp: 2025-08-29T14:38:18.023Z
Learning: The "sold individually" variation functionality (where the Product Quantity block should hide when a variation is sold individually) mentioned in issue #59443 objectives is not implemented in PR #60641 and will be addressed in a future PR.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
📚 Learning: 2025-08-29T10:13:44.287Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60667
File: plugins/woocommerce/src/Blocks/BlockTypes/AddToCartForm.php:122-125
Timestamp: 2025-08-29T10:13:44.287Z
Learning: In WooCommerce, the ProductType class in plugins/woocommerce/src/Enums/ProductType.php contains string constants (not a PHP backed enum), so ProductType::VARIATION directly returns the string 'variation' and can be passed directly to methods like WC_Product::is_type() without needing ->value.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
📚 Learning: 2025-09-08T15:12:20.201Z
Learnt from: Aljullu
PR: woocommerce/woocommerce#60767
File: plugins/woocommerce/client/blocks/assets/js/blocks/add-to-cart-with-options/grouped-product-selector/frontend.ts:121-126
Timestamp: 2025-09-08T15:12:20.201Z
Learning: In WooCommerce, 'variation' is the product type used for variable products' children, while 'variable' is the type of the parent product. These are two distinct product types in the WooCommerce system.

Applied to files:

  • plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
🧬 Code graph analysis (1)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (3)
plugins/woocommerce/src/Utilities/FeaturesUtil.php (1)
  • FeaturesUtil (14-102)
plugins/woocommerce/includes/abstracts/abstract-wc-product.php (1)
  • set_cogs_value (2347-2352)
plugins/woocommerce/includes/abstracts/abstract-wc-data.php (1)
  • update_meta_data (463-504)
🔇 Additional comments (2)
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (2)

18-18: Good: feature flag import wired.

Importing FeaturesUtil here is correct for feature detection.


1235-1243: Good: meta API ensures persistence pre‑save.

Switching to $product->update_meta_data() makes this work for unsaved products and matches WC data patterns.

Comment on lines +521 to +529

if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
$cogs_is_enabled = FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' );
if ( $cogs_is_enabled ) {
$product->set_cogs_value( (float) $product_data['cost_of_goods'] );
} else {
$this->set_cogs_value_direct( $product, (float) $product_data['cost_of_goods'] );
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Guard against non‑numeric COGS; don’t coerce invalid input to 0.0.

array_key_exists correctly preserves 0.0. Add an is_numeric check to avoid persisting accidental 0.0 from non‑numeric strings.

-		if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
-			$cogs_is_enabled = FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' );
-			if ( $cogs_is_enabled ) {
-				$product->set_cogs_value( (float) $product_data['cost_of_goods'] );
-			} else {
-				$this->set_cogs_value_direct( $product, (float) $product_data['cost_of_goods'] );
-			}
-		}
+		if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
+			$raw_cogs = $product_data['cost_of_goods'];
+			if ( is_numeric( $raw_cogs ) ) {
+				$cogs = (float) $raw_cogs;
+				if ( FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' ) ) {
+					$product->set_cogs_value( $cogs );
+				} else {
+					$this->set_cogs_value_direct( $product, $cogs );
+				}
+			}
+		}

To verify coverage for enabled/disabled and zero values:


🏁 Script executed:

#!/bin/bash
# Look for tests covering COGS migration scenarios (enabled/disabled, zero)
rg -n -C2 -S 'cost_of_goods|_cogs_total_value|set_cogs_value' --type=php plugins/woocommerce

Length of output: 128005


Guard against non‑numeric COGS; preserve explicit zeros.

Persist only when cost_of_goods is numeric — avoid coercing non‑numeric strings to 0.0. Fix in plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php (≈lines 522–529). Also address the variation branch at ≈815–816 where !empty(...) will drop '0'.

-		if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
-			$cogs_is_enabled = FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' );
-			if ( $cogs_is_enabled ) {
-				$product->set_cogs_value( (float) $product_data['cost_of_goods'] );
-			} else {
-				$this->set_cogs_value_direct( $product, (float) $product_data['cost_of_goods'] );
-			}
-		}
+		if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
+			$raw_cogs = $product_data['cost_of_goods'];
+			if ( is_numeric( $raw_cogs ) ) {
+				$cogs = (float) $raw_cogs;
+				if ( FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' ) ) {
+					$product->set_cogs_value( $cogs );
+				} else {
+					$this->set_cogs_value_direct( $product, $cogs );
+				}
+			}
+		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
$cogs_is_enabled = FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' );
if ( $cogs_is_enabled ) {
$product->set_cogs_value( (float) $product_data['cost_of_goods'] );
} else {
$this->set_cogs_value_direct( $product, (float) $product_data['cost_of_goods'] );
}
}
if ( array_key_exists( 'cost_of_goods', $product_data ) ) {
$raw_cogs = $product_data['cost_of_goods'];
if ( is_numeric( $raw_cogs ) ) {
$cogs = (float) $raw_cogs;
if ( FeaturesUtil::feature_is_enabled( 'cost_of_goods_sold' ) ) {
$product->set_cogs_value( $cogs );
} else {
$this->set_cogs_value_direct( $product, $cogs );
}
}
}
🤖 Prompt for AI Agents
In
plugins/woocommerce/src/Internal/CLI/Migrator/Core/WooCommerceProductImporter.php
around lines 521–529, ensure cost_of_goods is persisted only when it is numeric
while preserving explicit zeros: replace the current array_key_exists + cast
logic with a numeric guard (use is_numeric on the raw value) and then set the
COGS using the existing feature branch; likewise, update the variation branch
around lines ~815–816 to stop using !empty(...) (which drops "0") and instead
check presence with array_key_exists and validate with is_numeric before
assigning so "0" or "0.0" are preserved and non‑numeric strings are ignored.

@naman03malhotra naman03malhotra merged commit 9e0ea61 into trunk Sep 15, 2025
26 checks passed
@naman03malhotra naman03malhotra deleted the add/cogs-support branch September 15, 2025 18:28
@github-actions github-actions bot added this to the 10.3.0 milestone Sep 15, 2025
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.

3 participants