WooCommerce cross- and up sells bi-directional update
If your would like one added (and removed) cross (or up) sell product in WooCommerce to automatically ad the ‘current’ product as an up- or cross sell to the connected code. The following code will inspire you:
class RelationalProductFields { public function register(): void { if (is_admin() === false) { return; } // is triggered after a product object is created or updated but before the product is saved add_action('woocommerce_admin_process_product_object', [$this, 'saveRelationalProductFields']); } /** * Save relational product fields. * * @param WC_Product $product */ public function saveRelationalProductFields(WC_Product $product): void { // product state before save. $originalProduct = wc_get_product($product->get_id()); // Upsell arrays $originalUpsells = $originalProduct->get_upsell_ids(); $newUpsells = $product->get_upsell_ids(); $addedUpsells = array_diff($newUpsells, $originalUpsells); $removedUpsells = array_diff($originalUpsells, $newUpsells); $changedUpsells = array_merge($addedUpsells, $removedUpsells); // cross-sell arrays $originalCrossSels = $originalProduct->get_cross_sell_ids(); $newCrossSells = $product->get_cross_sell_ids(); $addedCrossSells = array_diff($newCrossSells, $originalCrossSels); $removedCrossSells = array_diff($originalCrossSels, $newCrossSells); $changedCrossSells = array_merge($addedCrossSells, $removedCrossSells); // Loop through removed and added upsells foreach ($changedUpsells as $changedUpsellId) { $relatedUpsellProduct = wc_get_product($changedUpsellId); if (!$relatedUpsellProduct) { continue; } if ($relatedUpsellProduct->get_type() === 'variation') { $relatedUpsellProduct = wc_get_product($relatedUpsellProduct->get_parent_id()); } // Add or remove the product as upsell $upsellIds = $relatedUpsellProduct->get_upsell_ids(); if (in_array($changedUpsellId, $addedUpsells, true)) { $upsellIds[] = $product->get_id(); // add $upsellIds = array_unique($upsellIds); $relatedUpsellProduct->set_upsell_ids($upsellIds); } elseif (in_array($changedUpsellId, $removedUpsells, true)) { $upsellIds = array_diff($upsellIds, [$product->get_id()]); //remove $relatedUpsellProduct->set_upsell_ids($upsellIds); } $relatedUpsellProduct->save(); } // Loop through removed and added upsells foreach ($changedCrossSells as $changedCrossSellId) { $relatedCrossSellProduct = wc_get_product($changedCrossSellId); if (!$relatedCrossSellProduct) { continue; } if ($relatedCrossSellProduct->get_type() === 'variation') { $relatedCrossSellProduct = wc_get_product($relatedCrossSellProduct->get_parent_id()); } // Add or remove the product as upsell $crossSellIds = $relatedCrossSellProduct->get_upsell_ids(); if (in_array($changedCrossSellId, $addedCrossSells, true)) { $crossSellIds[] = $product->get_id(); // add $crossSellIds = array_unique($crossSellIds); $relatedCrossSellProduct->set_cross_sell_ids($crossSellIds); } elseif (in_array($changedCrossSellId, $removedCrossSells, true)) { $crossSellIds = array_diff($crossSellIds, [$product->get_id()]); //remove $relatedCrossSellProduct->set_cross_sell_ids($crossSellIds); } $relatedCrossSellProduct->save(); } } }