-
Notifications
You must be signed in to change notification settings - Fork 9
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
base: trunk
Are you sure you want to change the base?
Changes from all commits
45942fa
4f0b842
277167d
f665807
c9e10a7
51d93bd
f95af7d
3beeb06
235fd1d
344a2a7
5d320f6
b10816f
41c85d8
23de016
d480fb3
8bc38f4
a7796b4
c7a3410
a1a8aa8
4c6e132
74b36fd
46d9c1e
4e569c3
ae96951
e49c6b4
6f1b741
3d3b2af
c3e6d8d
c5ab52a
d5fe986
79a4e28
ef72054
539cbc2
2ba4519
fb3f2f5
692f19c
a5afdb1
3bdd65f
3700856
eff9924
b749aea
c756618
22a1f5e
c15f204
4c6c390
5013533
7439434
08856d8
f0ede25
bb991ef
9846a16
00f1bdd
67a9e55
0dd016f
6e4fb66
9239a92
218fb05
aeaa7d6
9dd7e7f
b81f7e1
d08b0db
7c6afe6
91c27d5
02d0f43
769b0e2
3d5a617
db245d9
1d40484
bc2d941
84fcb81
158e041
83f0b20
d194709
268a216
eec517d
7e57e87
3748828
0c593c1
5ac6a65
33b1eac
568230d
306d1bf
0c81bab
535af2f
4256504
d9833b9
5ed09f5
85ee8c4
bfef00d
d2725b9
e516c35
c5ec9ef
6f3dde0
11f883d
f63e00e
d2a3c89
a7f6e4f
4942e33
63df232
a2593a2
3b60296
0ec5e01
efa7d66
5036cc2
9485c0a
ed80611
5c1644a
5ee9a88
d3fb826
49eb1aa
e949832
51532ee
122ca65
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -81,12 +81,76 @@ public static function update_catalog_item( CatalogObject $catalog_object, \WC_P | |||||
$item_data->setReportingCategory( $square_category ); | ||||||
} | ||||||
|
||||||
$catalog_variations = $item_data->getVariations() ?: array(); | ||||||
$attributes = $product->get_attributes(); | ||||||
|
||||||
$product_variation_ids = $product->get_children(); | ||||||
$catalog_variations = $item_data->getVariations() ? $item_data->getVariations() : array(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since PHP 7.0 we can change this to:
Suggested change
|
||||||
|
||||||
// if dealing with a variable product, try and match the variations | ||||||
if ( $product->is_type( 'variable' ) ) { | ||||||
|
||||||
$product_variation_ids = $product->get_children(); | ||||||
/** | ||||||
* If there are multiple variations, it must be a considered as Dynamic Options supported product. | ||||||
* Create/Update and Assign Dynamic Options only if a product | ||||||
* has multiple attributes OR options already exists in Square. | ||||||
*/ | ||||||
if ( | ||||||
count( $attributes ) > 1 | ||||||
) { | ||||||
$options_ids = array(); | ||||||
$result = wc_square()->get_api()->retrieve_options_data(); | ||||||
$options_data = isset( $result[1] ) ? $result[1] : array(); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same as above:
Suggested change
|
||||||
|
||||||
// Set the product as a dynamic options product. | ||||||
update_post_meta( $product->get_id(), '_dynamic_options', true ); | ||||||
|
||||||
// Loop through the attributes to create options and values at Square. | ||||||
foreach ( $attributes as $attribute_id => $attribute ) { | ||||||
|
||||||
$attribute_name = $attribute->get_name(); | ||||||
// Check if its a taxonomy-based attribute. | ||||||
$attribute_option_values = array(); | ||||||
if ( taxonomy_exists( $attribute_id ) ) { | ||||||
$terms = get_terms( $attribute_id ); | ||||||
$attribute_option_values = wp_list_pluck( $terms, 'name' ); | ||||||
} else { | ||||||
$attribute_option_values = $attribute->get_options(); | ||||||
} | ||||||
|
||||||
// Check if Square already has the option created with the same name. | ||||||
// To do so, we can check if we already have the name in options/transient, | ||||||
// if yes, use the relative Square ID. | ||||||
$option_id = false; | ||||||
foreach ( $options_data as $transient_option_id => $option_data_transient ) { | ||||||
if ( $option_data_transient['name'] === $attribute_name ) { | ||||||
$option_id = $transient_option_id; | ||||||
break; | ||||||
} | ||||||
} | ||||||
|
||||||
// If name does not exist, create a new option in Square. | ||||||
// If name exists, check if all values are present in Square. | ||||||
// If not, create the missing values. | ||||||
$option = wc_square()->get_api()->create_options_and_values( $option_id, $attribute_name, $attribute_option_values ); | ||||||
$options_ids[] = $option->getId(); | ||||||
} | ||||||
|
||||||
// Set the item_option_id for each option to the product. | ||||||
$product_options = array(); | ||||||
|
||||||
foreach ( $options_ids as $option_id ) { | ||||||
$item_option = new \Square\Models\CatalogItemOptionForItem(); | ||||||
$item_option->setItemOptionId( $option_id ); | ||||||
$product_options[] = $item_option; | ||||||
} | ||||||
|
||||||
$catalog_object->getItemData()->setItemOptions( $product_options ); | ||||||
} else { | ||||||
// If the product has only one attribute, it's not a dynamic options product. | ||||||
// So, remove the dynamic options meta. | ||||||
delete_post_meta( $product->get_id(), '_dynamic_options' ); | ||||||
$catalog_object->getItemData()->setItemOptions( null ); | ||||||
} | ||||||
|
||||||
if ( is_array( $catalog_variations ) ) { | ||||||
|
||||||
|
@@ -157,6 +221,8 @@ public static function update_catalog_item( CatalogObject $catalog_object, \WC_P | |||||
} | ||||||
|
||||||
$catalog_variations = array( self::update_catalog_variation( $variation_object, $product ) ); | ||||||
|
||||||
$catalog_object->getItemData()->setItemOptions( null ); | ||||||
} | ||||||
|
||||||
$item_data->setVariations( array_values( $catalog_variations ) ); | ||||||
|
@@ -225,7 +291,111 @@ public static function update_catalog_variation( CatalogObject $catalog_object, | |||||
* @see https://github.com/woocommerce/woocommerce-square/issues/570 | ||||||
*/ | ||||||
if ( 'variation' === $product->get_type() ) { | ||||||
$variation_data->setName( $product->get_name() ); | ||||||
$result = wc_square()->get_api()->retrieve_options_data(); | ||||||
$options_data = isset( $result[1] ) ? $result[1] : array(); | ||||||
$parent_product = wc_get_product( $product->get_parent_id() ); | ||||||
$attributes = $parent_product->get_attributes(); | ||||||
$variation_items = $product->get_attributes(); | ||||||
$variation_item_values = array(); | ||||||
|
||||||
if ( 1 === count( $attributes ) ) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see that these changes contain multiple "actions" that could be new methods to make reading easier. Basically, every time we have a comment here, the following code could be a new method named after the explanation. But this is optional |
||||||
// Set the name of the variation if it's a single variation. | ||||||
$variation_data->setName( reset( $variation_items ) ); | ||||||
$variation_data->setItemOptionValues( null ); | ||||||
} else { | ||||||
// If there are multiple attributes, the name of the variation is the combination of all attribute values. | ||||||
$variation_name = array(); | ||||||
|
||||||
/** | ||||||
* Set the `item_option_values` for the variation. | ||||||
* | ||||||
* Retrieve the options data from the transient. At this point, the options data | ||||||
* should already be available, as we have already created the necessary options | ||||||
* and values in the parent product above. | ||||||
*/ | ||||||
foreach ( $variation_items as $attribute_id => $attribute_value ) { | ||||||
// If the attribute value is empty, set it to 'Any'. | ||||||
$attribute_value = empty( $attribute_value ) ? 'Any' : $attribute_value; | ||||||
|
||||||
// Check if it's a global attribute (taxonomy-based, e.g., "pa_color") | ||||||
$taxonomy_exists = false; | ||||||
if ( taxonomy_exists( $attribute_id ) ) { | ||||||
// Use wc_attribute_label for global attributes | ||||||
$attribute_name = $attribute_id; | ||||||
$variation_name[] = $attribute_value = 'Any' === $attribute_value ? 'Any' : get_term_by( 'slug', $attribute_value, $attribute_id )->name; | ||||||
$taxonomy_exists = true; | ||||||
} else { | ||||||
// For custom attributes, simply use the cleaned-up attribute ID | ||||||
$attribute_name = ucwords( str_replace( '-', ' ', $attribute_id ) ); | ||||||
$attribute_id = $attribute_name; | ||||||
$variation_name[] = $attribute_value; | ||||||
} | ||||||
|
||||||
foreach ( $options_data as $option_id_transient => $option_data_transient ) { | ||||||
$option_id = ''; | ||||||
$option_value_id = ''; | ||||||
|
||||||
// Check for the Square ID of $attribute_name. | ||||||
if ( $option_data_transient['name'] === $attribute_id ) { // @TODO: If merchant changes the name of the attribute, this will create a new item at Square. Think of a way to handle this. | ||||||
$option_id = $option_id_transient; | ||||||
// Check for the Square ID of $attribute_value. | ||||||
foreach ( $option_data_transient['value_ids'] as $value_id => $value_name ) { | ||||||
if ( $value_name === $attribute_value ) { | ||||||
$option_value_id = $value_id; | ||||||
break; | ||||||
} | ||||||
} | ||||||
break; | ||||||
} | ||||||
} | ||||||
|
||||||
if ( $option_id && $option_value_id ) { | ||||||
$option_value_object = new \Square\Models\CatalogItemOptionValueForItemVariation(); | ||||||
$option_value_object->setItemOptionId( $option_id ); | ||||||
$option_value_object->setItemOptionValueId( $option_value_id ); | ||||||
|
||||||
$variation_item_values[] = $option_value_object; | ||||||
} else { | ||||||
|
||||||
if ( $taxonomy_exists ) { | ||||||
// Get all attribute terms from Woo taxonomy. | ||||||
$attribute_option_values = get_terms( $attribute_id ); | ||||||
$attribute_option_values = wp_list_pluck( $attribute_option_values, 'name' ); | ||||||
} else { | ||||||
// Get all attribute values from the parent product. | ||||||
$attribute_option_values = $parent_product->get_attribute( $attribute_id ); | ||||||
$attribute_option_values = array_map( 'trim', explode( '|', $attribute_option_values ) ); | ||||||
} | ||||||
|
||||||
// If the attribute value is 'Any', add it to the attribute option values. | ||||||
if ( 'Any' === $attribute_value && ! in_array( 'Any', $attribute_option_values, true ) ) { | ||||||
$attribute_option_values[] = 'Any'; | ||||||
} | ||||||
|
||||||
$option = wc_square()->get_api()->create_options_and_values( $option_id, $attribute_name, $attribute_option_values ); | ||||||
$option_id = $option->getId(); | ||||||
|
||||||
// Get the Square ID of the attribute value. | ||||||
$updated_option_values = $option->getItemOptionData()->getValues(); | ||||||
foreach ( $updated_option_values as $option_value ) { | ||||||
if ( $option_value->getItemOptionValueData()->getName() === $attribute_value ) { | ||||||
$option_value_id = $option_value->getId(); | ||||||
break; | ||||||
} | ||||||
} | ||||||
|
||||||
$option_value_object = new \Square\Models\CatalogItemOptionValueForItemVariation(); | ||||||
$option_value_object->setItemOptionId( $option_id ); | ||||||
$option_value_object->setItemOptionValueId( $option_value_id ); | ||||||
|
||||||
$variation_item_values[] = $option_value_object; | ||||||
} | ||||||
} | ||||||
|
||||||
// Set the name of the variation as the combination of all attribute values. | ||||||
$variation_data->setName( implode( ', ', $variation_name ) ); | ||||||
$variation_data->setItemOptionValues( $variation_item_values ); | ||||||
} | ||||||
} | ||||||
|
||||||
if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) { | ||||||
|
@@ -307,6 +477,4 @@ public static function set_catalog_object_location_ids( CatalogObject $catalog_o | |||||
|
||||||
return $catalog_object; | ||||||
} | ||||||
|
||||||
|
||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can any of the getters return
null
values? If so, it would be nice to add some checks to avoid errors.