Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Multiple Variations Support #235

Draft
wants to merge 74 commits into
base: trunk
Choose a base branch
from
Draft

Conversation

faisal-alvi
Copy link
Member

@faisal-alvi faisal-alvi commented Nov 13, 2024

All Submissions:

  • Does your code follow the WooCommerce Sniffs variant of WordPress coding standards?
  • Have you written new tests for your changes, as applicable?
  • Have you successfully run tests with your changes locally?
  • Will this change require new documentation or changes to existing documentation?

Changes proposed in this Pull Request:

This PR adds support for Multiple Variations.

Square and WooCommerce Attribute Types

  • Square options:

    • Dynamic Options: Shared across multiple items, similar to WooCommerce’s taxonomy attributes; variation names cannot be changed.
    • Static Options: Unique to individual items; variation names can be changed.
  • WooCommerce attributes:

    • Taxonomy: Defined globally across products.
    • Custom: Defined on a per-product basis.

Key Differences Between Dynamic and Static Options

Dynamic options can be shared across products and mirror WooCommerce’s taxonomy attributes, and variation names cannot be modified, as they are automatically generated by combining the attribute values. For example: “Red, Small.” Static options are unique to each item. If multiple options exist at Square, they must be dynamic.

Syncing Logic (Overview)

  1. WooCommerce to Square Sync:

    • Creates dynamic options if there are multiple WooCommerce attributes, regardless of the WooCommerce's attributes type.
    • For a single attribute, it creates a static option at Square.
  2. Square to WooCommerce Sync/Import:

    • Creates taxonomy attributes if the option slug matches an existing WooCommerce taxonomy attribute.
    • If only one option is received, it checks for an existing WooCommerce taxonomy attribute or creates a custom attribute if no match is found.

Syncing Logic for WooCommerce and Square (Detail)

From WooCommerce to Square:

  • If WooCommerce has more than one attribute and is set as the Source of Record (SOR), this PR will create dynamic options at Square, regardless of whether the attributes are taxonomy or custom. This is because we cannot create more than one static options for the single item (i.e product) at Square.
  • If there’s only one attribute, it creates a static option at Square.
  • If an attribute requires syncing, the PR creates an option at Square. New attribute values are also created at Square when synced from WooCommerce.

From Square to WooCommerce:

  • If the option name received from Square matches the slug of an existing WooCommerce taxonomy attribute, this PR creates a taxonomy attribute. If the merchant updates the slug in WooCommerce, it may not match next time and a custom attribute will be created instead.
  • If only one option is received, this PR checks against existing WooCommerce taxonomy attributes and attaches it if matched; otherwise, it creates a custom attribute at the product level. When creating a custom attribute, the PR reuses an existing custom attribute name, as Square does not provide the static option name. If no matching name exists, "Attribute" is assigned as the custom name.

Square API Limitations and Solutions

Square’s API only provides the option ID used in variations, not the display name. However, to match WooCommerce taxonomy attributes or to create a custom attribute, we need the option's display name. To address this, we fetch all options via another Square API (discussion link) and store the option names and their IDs in a transient (wc_square_options_data) with a 1-day expiration. The fetch_options_data() function initiates this before any import or sync process.

If a transient doesn’t have updated data, a sync may fail when creating an option with a name that already exists at Square, which would require a latest options data. This PR then stops the sync and sets the woocommerce_square_refresh_sync_cycle option to refresh the data.

Avoiding Attribute Name Conflicts

If WooCommerce’s taxonomy attribute is used, this PR passes the taxonomy name (e.g., “pa_color” rather than “Color”) to Square, preventing conflicts with custom attributes of the same name. The “pa_” prefix helps WooCommerce users distinguish between taxonomy and custom attributes, avoiding potential conflicts.

New Option for Tracking

This PR introduces a new _dynamic_options option with true/false values to track whether dynamic options are used for a product. This is not in use but may be useful in future.

Pending Tasks

  • Optimize API call iterations by storing data in transients.
  • Importing/Syncing from Square to Woocommerce, all the dynamic option values are added to the attribute, for example, for colour attribute, if there is only red and green options are selected at Square, after the import/sync, it adds all of the dynamic option values to the Woocommerce attribute regardless of what selection. This is not creating any issue to the purchases of the side, but this should be addressed.
  • Confirm whether syncing products with the same attribute name but different values causes conflicts: Create a 2 custom attributes at Woocommerce with the same name, but use in two different products, each should have different values, for example, one should have “A|B|C” the other should “X|Y|Z”, when Syncing them to the square, first one will create an option with the values “A|B|C”, but when the second one will sync, it will override the previous values with the “X|Y|Z”, this is a conflict, which is currently theoretically written, needs to verify if this is the case and fix or maybe document it for merchants that they do not use the same name?
  • Perform full tests with Square as SOR to confirm behavior.
  • We check all attributes and their values exists on square for each variation iteration! Make it smart enough not to keep checking in thousands of loops, maybe by storing the data in transient with short term expiry?
  • If merchant changes the name of the attribute, this will create a new item instead of using the previous one. Think of a way to handle this. This can be considered as a separate issue, and handled in a post-PR.

Notes for Merchants

  • Avoid leaving any variation dropdowns set to “Any” in products with multiple attributes, as Square does not support empty values for dynamic options.
  • Avoid changing taxonomy attribute slugs or attribute names in WooCommerce, or renaming dynamic options in Square.
  • Do not create custom attributes with names identical to existing taxonomy attributes.

Closes #6, Closes #31 and Closes #231.

Steps to test the changes in this Pull Request:

  1. Set WooCommerce as SOR.
  2. Create the following product types in WooCommerce:
    • Simple Product
    • Variable Product with:
      • 1 Custom Attribute
      • 1 Taxonomy Attribute
      • 2 Taxonomy Attributes
      • 2 Custom Attributes
      • 1 Custom + 1 Taxonomy Attribute
      • 2 Taxonomy Attributes + 1 Custom Attribute
  3. Confirm these products are auto-synced and correctly created in Square.
  4. Confirm the same for manual sync using the “Sync” button in settings.
  5. Import all products from Square to WooCommerce and verify they retain attributes without issues (e.g., taxonomy attribute not converted to custom).
  6. Make changes to the random products and confirm it syncs to the Square and Imports back to the Woo without and issues, few examples:
    1. add one more custom attribute to the “2 Taxonomy Attributes” product
    2. remove 1 taxonomy attribute from the “2 Taxonomy Attributes + 1 Custom Attribute” product
    3. add one more variation to any product
    4. remove one variation from any product
    5. change the dropdown of any variation in “1 Custom Attribute” product
    6. change the dropdown of all variations in “2 Taxonomy Attributes + 1 Custom Attribute” product
    7. add one more attribute value and create update the dropdown values of each variation
    8. etc.
  7. Set Square as SOR and perform all of the above steps (sorry :)) This time the chagnes from the point 6 should be made at Square.
  8. Important: Confirm no issues affect existing users by creating all product types in trunk and performing sync/import in the fix branch.

Changelog entry

Add - Multiple Variations Support

@faisal-alvi faisal-alvi added the type: enhancement The issue is a request for an enhancement. label Nov 13, 2024
@faisal-alvi faisal-alvi added this to the Future Release milestone Nov 13, 2024
@faisal-alvi faisal-alvi self-assigned this Nov 13, 2024
includes/Sync/Product_Import.php
-----------------------------------------------------------------------------------------------
FOUND 1 ERROR AND 0 WARNINGS AFFECTING 1 LINE
-----------------------------------------------------------------------------------------------
 92 | ERROR | Using short ternaries is not allowed as they are rarely used correctly (Universal.Operators.DisallowShortTernary.Found)
-----------------------------------------------------------------------------------------------
FILE: includes/Sync/Manual_Synchronization.php
-----------------------------------------------------------------------------------------------
FOUND 1 ERROR AND 0 WARNINGS AFFECTING 1 LINE
-----------------------------------------------------------------------------------------------
 1684 | ERROR | Using short ternaries is not allowed as they are rarely used correctly (Universal.Operators.DisallowShortTernary.Found)
-----------------------------------------------------------------------------------------------
FILE: includes/Handlers/Product/Woo_SOR.php
-----------------------------------------------------------------------------------------------
FOUND 14 ERRORS AND 0 WARNINGS AFFECTING 14 LINES
-----------------------------------------------------------------------------------------------
  87 | ERROR | Using short ternaries is not allowed as they are rarely used correctly (Universal.Operators.DisallowShortTernary.Found)
 113 | ERROR | The parameter "array( 'hide_empty' => false )" at position #2 of get_terms() has been deprecated since WordPress version 4.5.0. Instead do not pass the parameter. (WordPress.WP.DeprecatedParameters.Get_termsParam2Found)
 142 | ERROR | Variable "$CatalogItemOptionForItem" is not in valid snake_case format, try "$catalog_item_option_for_item" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 143 | ERROR | Variable "$CatalogItemOptionForItem" is not in valid snake_case format, try "$catalog_item_option_for_item" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 144 | ERROR | Variable "$CatalogItemOptionForItem" is not in valid snake_case format, try "$catalog_item_option_for_item" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 348 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 349 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 350 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 352 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 357 | ERROR | The parameter "array( 'hide_empty' => false )" at position #2 of get_terms() has been deprecated since WordPress version 4.5.0. Instead do not pass the parameter. (WordPress.WP.DeprecatedParameters.Get_termsParam2Found)
 378 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 379 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 380 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
 382 | ERROR | Variable "$CatalogItemOptionValueForItemVariation" is not in valid snake_case format, try "$catalog_item_option_value_for_item_variation" (WordPress.NamingConventions.ValidVariableName.VariableNotSnakeCase)
-----------------------------------------------------------------------------------------------
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: enhancement The issue is a request for an enhancement.
Projects
None yet
1 participant