| @@ -11,9 +11,9 @@ | ||
| 11 | 11 | use FluentCart\App\Models\WpModels\TermRelationship; |
| 12 | 12 | use FluentCart\App\Models\WpModels\TermTaxonomy; |
| 13 | 13 | use FluentCart\App\Vite; |
| 14 | 14 | use FluentCart\Framework\Database\Orm\Builder; |
| 15 | -use FluentCart\Framework\Database\Orm\Relations\hasOne; | |
| 15 | +use FluentCart\Framework\Database\Orm\Relations\HasOne; | |
| 16 | 16 | use FluentCart\Framework\Support\Arr; |
| 17 | 17 | use FluentCart\Framework\Support\Str; |
| 18 | 18 | |
| 19 | 19 | /** |
| @@ -148,11 +148,11 @@ | ||
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | /** |
| 151 | 151 | * One2One: Product belongs to one Post meta which is : Gallery Image |
| 152 | - * @return hasOne | |
| 152 | + * @return HasOne | |
| 153 | 153 | */ |
| 154 | - public function postmeta(): hasOne | |
| 154 | + public function postmeta(): HasOne | |
| 155 | 155 | { |
| 156 | 156 | return $this->hasOne(PostMeta::class, 'post_id', 'ID') |
| 157 | 157 | ->where('postmeta.meta_key', 'fluent-products-gallery-image'); |
| 158 | 158 | } |
| @@ -176,14 +176,8 @@ | ||
| 176 | 176 | return get_the_terms($this->ID, 'product-categories'); |
| 177 | 177 | } |
| 178 | 178 | |
| 179 | 179 | |
| 180 | - public function getTags() | |
| 181 | - { | |
| 182 | - return get_the_terms($this->ID, 'product-tags'); | |
| 183 | - } | |
| 184 | - | |
| 185 | - | |
| 186 | 180 | public function getMediaUrl($size = 'thumbnail') |
| 187 | 181 | { |
| 188 | 182 | return get_the_post_thumbnail_url($this->ID, $size); |
| 189 | 183 | } |
| @@ -192,14 +186,8 @@ | ||
| 192 | 186 | /* |
| 193 | 187 | * Transforming old getters with accessor |
| 194 | 188 | * Todo check |
| 195 | 189 | */ |
| 196 | - public function getTagsAttribute($value) | |
| 197 | - { | |
| 198 | - return get_the_terms($this->ID, 'product-tags'); | |
| 199 | - } | |
| 200 | - | |
| 201 | - | |
| 202 | 190 | public function getCategoriesAttribute($value) |
| 203 | 191 | { |
| 204 | 192 | return get_the_terms($this->ID, 'product-categories'); |
| 205 | 193 | } |
| @@ -259,14 +247,8 @@ | ||
| 259 | 247 | return $this->getTermByType('product-categories'); |
| 260 | 248 | } |
| 261 | 249 | |
| 262 | 250 | |
| 263 | - public function tags() | |
| 264 | - { | |
| 265 | - return $this->getTermByType('product-tags'); | |
| 266 | - } | |
| 267 | - | |
| 268 | - | |
| 269 | 251 | /* |
| 270 | 252 | * Todo: Discuss on below relation |
| 271 | 253 | */ |
| 272 | 254 | public function thumbUrl(): HasOne |
| @@ -697,16 +679,59 @@ | ||
| 697 | 679 | |
| 698 | 680 | $newVariant = ProductVariation::query()->create($variantData); |
| 699 | 681 | $variationIdMap[$originalVariant->id] = $newVariant->id; |
| 700 | 682 | |
| 683 | + // Copy the variant's thumbnail meta to the new variant. | |
| 684 | + // $originalVariant->media is hasOne on fct_product_meta | |
| 685 | + // where meta_key = 'product_thumbnail'; the old code | |
| 686 | + // foreach'd over it (treating a single Model as a | |
| 687 | + // collection — iterating its attribute scalars) and | |
| 688 | + // mis-routed the data through wp_set_object_terms (the | |
| 689 | + // WordPress taxonomy API, unrelated to fct_product_meta). | |
| 690 | + // Mirror the Pro AdvancedVariationService pattern: a | |
| 691 | + // fresh fct_product_meta row owned by the new variant id | |
| 692 | + // with the same meta_value payload. | |
| 701 | 693 | if ($originalVariant->media && $newVariant) { |
| 702 | - foreach ($originalVariant->media as $media) { | |
| 703 | - \wp_set_object_terms( | |
| 704 | - $newVariant->id, | |
| 705 | - $media->term_id ?? $media->id, | |
| 706 | - 'product_media' | |
| 707 | - ); | |
| 694 | + $media = $originalVariant->media; | |
| 695 | + ProductMeta::query()->create([ | |
| 696 | + 'object_id' => $newVariant->id, | |
| 697 | + 'object_type' => 'product_variant_info', | |
| 698 | + 'meta_key' => 'product_thumbnail', | |
| 699 | + 'meta_value' => $media->meta_value, | |
| 700 | + ]); | |
| 701 | + } | |
| 702 | + } | |
| 703 | + } | |
| 704 | + | |
| 705 | + // Mirror advanced-variation attribute relations onto the new | |
| 706 | + // variants. Without this, fct_atts_relations stays empty for | |
| 707 | + // the duplicated product so variant.attr_map is empty | |
| 708 | + // downstream — AdvancedVariationTable can't group by an | |
| 709 | + // attribute, the per-variant breadcrumb collapses to "—", and | |
| 710 | + // (with the Pro variation_title snapshot) future re-saves | |
| 711 | + // would compose blank titles. Re-key on the variationIdMap | |
| 712 | + // built above so each (old_variant_id, group_id, term_id) | |
| 713 | + // tuple becomes a (new_variant_id, group_id, term_id) tuple. | |
| 714 | + if (!empty($variationIdMap)) { | |
| 715 | + $originalVariantIds = array_keys($variationIdMap); | |
| 716 | + $relations = AttributeRelation::query() | |
| 717 | + ->whereIn('object_id', $originalVariantIds) | |
| 718 | + ->get(); | |
| 719 | + if ($relations->isNotEmpty()) { | |
| 720 | + $rows = []; | |
| 721 | + foreach ($relations as $rel) { | |
| 722 | + $newVariantId = Arr::get($variationIdMap, $rel->object_id); | |
| 723 | + if (!$newVariantId) { | |
| 724 | + continue; | |
| 708 | 725 | } |
| 726 | + $rows[] = [ | |
| 727 | + 'group_id' => (int) $rel->group_id, | |
| 728 | + 'term_id' => (int) $rel->term_id, | |
| 729 | + 'object_id' => (int) $newVariantId, | |
| 730 | + ]; | |
| 731 | + } | |
| 732 | + if (!empty($rows)) { | |
| 733 | + AttributeRelation::query()->insert($rows); | |
| 709 | 734 | } |
| 710 | 735 | } |
| 711 | 736 | } |
| 712 | 737 | |