PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / trunk
WPML Multilingual & Multicurrency for WooCommerce vtrunk
5.3.8 5.3.9 5.4.3 5.4.4 5.4.5 5.5.1 5.5.1.1 5.5.2.2 5.5.2.3 5.5.3 5.5.3.1 5.5.4 5.5.5 5.5.6 trunk 0.9 1.0 1.1 1.2 1.3 1.4 1.5 2.0 2.2 2.3 2.3.1 2.3.2 3.0 3.0.1 3.1 3.2 3.2.1 3.2.2 3.3 3.3.1 3.3.2 3.3.3 3.3.4 3.4 3.4.1 3.4.2 3.4.3 3.5 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.6 3.6.1 3.6.10 3.6.11 3.6.2 3.6.3 3.6.4 3.6.5 3.6.5.1 3.6.6 3.6.7 3.6.8 3.6.9 3.7 3.7.1 3.7.10 3.7.11 3.7.12 3.7.13 3.7.14 3.7.15 3.7.16 3.7.2 3.7.3 3.7.4 3.7.5 3.7.6 3.7.7 3.7.8 3.7.9 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.9.0 3.9.1 3.9.1.1 3.9.2 3.9.3 3.9.4 3.9.5 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.10.4 4.11.2 4.11.3.2 4.11.5 4.11.6 4.12.1 4.12.4 4.12.5 4.12.6 4.2.0 4.2.0.1 4.2.1 4.2.1.1 4.2.10 4.2.2 4.2.3 4.2.4 4.2.5 4.2.6 4.2.7 4.2.7.1 4.2.8 4.2.8.1 4.2.9 4.3.0 4.3.1 4.3.2 4.3.2.1 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.4.0 4.4.1 4.4.2 4.4.2.1 4.5.0 4.6.0 4.6.1 4.6.2 4.6.2.1 4.6.3 4.6.5 4.6.6 4.6.7 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.7.5 4.7.6 4.7.7 4.7.8 4.7.9 4.8.0 4.9.0 4.9.1 5.0.1 5.0.2 5.1.1 5.1.2 5.1.3 5.2.0 5.2.1 5.3.2 5.3.3.1 5.3.4 5.3.5 5.3.6 5.3.7
woocommerce-multilingual / classes / Synchronization / Component / Attributes.php
woocommerce-multilingual / classes / Synchronization / Component Last commit date
Attachments.php 1 year ago Attributes.php 4 months ago DownloadableFiles.php 4 months ago Linked.php 10 months ago Meta.php 1 year ago Post.php 3 months ago Stock.php 1 year ago Synchronizer.php 1 year ago SynchronizerForMeta.php 9 months ago Taxonomies.php 4 months ago VariationAttachments.php 1 year ago VariationMeta.php 8 months ago VariationTaxonomies.php 8 months ago Variations.php 1 month ago
Attributes.php
240 lines
1 <?php
2
3 namespace WCML\Synchronization\Component;
4
5 use WCML\Utilities\DB;
6 use WCML\Utilities\WCTaxonomies;
7 use WPML\FP\Lst;
8 use WPML\FP\Obj;
9
10 class Attributes extends SynchronizerForMeta {
11
12 const DEFAULT_ATTRIBUTES_META_KEY = '_default_attributes';
13 const PRODUCT_ATTRIBUTES_META_KEY = '_product_attributes';
14
15 /**
16 * @param \WP_Post $product
17 * @param int[] $translationsIds
18 * @param array<int,string> $translationsLanguages
19 */
20 public function run( $product, $translationsIds, $translationsLanguages ) {
21 $productsIds = array_merge( [ $product->ID ], $translationsIds );
22 $storedAttributes = $this->getMeta( self::PRODUCT_ATTRIBUTES_META_KEY, $productsIds );
23
24 $this->runForAttributes( $product->ID, $translationsIds, $translationsLanguages, $storedAttributes );
25 $this->runForDefaultAttributes( $product->ID, $translationsIds, $translationsLanguages, $storedAttributes );
26 }
27
28 private function runForAttributes( $productId, $translationsIds, $translationsLanguages, $storedAttributes ) {
29 $productAttributes = $storedAttributes[ $productId ] ?? null;
30
31 if ( null === $productAttributes ) {
32 $translationsIdsToClear = array_intersect( $translationsIds, array_keys( $storedAttributes ) );
33 $this->clearTranslationsValue( $translationsIdsToClear, self::PRODUCT_ATTRIBUTES_META_KEY );
34 return;
35 }
36
37 if ( empty( $productAttributes ) ) {
38 $this->spreadEmptyValue( $translationsIds, $storedAttributes, self::PRODUCT_ATTRIBUTES_META_KEY );
39 return;
40 }
41
42 $hasLocalAttributes = (bool) Lst::find(
43 function( $attributeData ) {
44 return (bool) Obj::prop( 'is_taxonomy', $attributeData ) === false;
45 },
46 $productAttributes
47 );
48
49 $duplicationsIds = [];
50 if ( $hasLocalAttributes ) {
51 // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
52 $duplicationsIds = $this->wpdb->get_col(
53 $this->wpdb->prepare(
54 "
55 SELECT post_id
56 FROM {$this->wpdb->postmeta}
57 WHERE meta_key = %s
58 AND post_id IN (" . DB::prepareIn( $translationsIds ) . ")
59 LIMIT %d
60 ",
61 '_icl_lang_duplicate_of',
62 count( $translationsIds )
63 )
64 );
65 // phpcs:enable
66 }
67
68 $sanitizedAttributeNames = [];
69 foreach ( $productAttributes as $attribute => $attributeData ) {
70 $sanitizedAttributeNames[ $attribute ] = $attribute;
71 $sanitizedAttribute = $this->woocommerceWpml->attributes->getAttributeNameToSave( $attribute, $attributeData, $productId );
72 if ( $attribute !== $sanitizedAttribute ) {
73 $sanitizedAttributeNames[ $sanitizedAttribute ] = $attribute;
74 $productAttributes[ $sanitizedAttribute ] = $attributeData;
75 unset( $productAttributes[ $attribute ] );
76 }
77 }
78
79 $translationsIdsToInsert = [];
80 $translationsIdsToUpdate = [];
81 foreach ( $translationsIds as $translationId ) {
82 $translationAttributes = $productAttributes;
83 $storedTranslationAttributes = $storedAttributes[ $translationId ] ?? [];
84 foreach ( $translationAttributes as $attribute => $attributeData ) {
85 if ( $attributeData['is_taxonomy'] || in_array( $translationId, $duplicationsIds, true ) ) {
86 continue;
87 }
88
89 $attributeToSave = $sanitizedAttributeNames[ $attribute ];
90 if ( isset( $storedTranslationAttributes[ $attribute ] ) ) {
91 $translationAttributes[ $attributeToSave ]['value'] = $storedTranslationAttributes[ $attribute ]['value'];
92 } else if ( isset( $storedTranslationAttributes[ $attributeToSave ] ) ) {
93 $translationAttributes[ $attributeToSave ]['value'] = $storedTranslationAttributes[ $attributeToSave ]['value'];
94 } else if ( ! empty( $storedTranslationAttributes ) ) {
95 unset( $translationAttributes[ $attribute ] );
96 }
97 }
98 if ( maybe_serialize( $translationAttributes ) === maybe_serialize( $storedTranslationAttributes ) ) {
99 continue;
100 }
101 if ( array_key_exists( $translationId, $storedAttributes ) ) {
102 $translationsIdsToUpdate[ $translationId ] = $translationAttributes;
103 } else {
104 $translationsIdsToInsert[ $translationId ] = $translationAttributes;
105 }
106 }
107
108 $this->insertMeta( self::PRODUCT_ATTRIBUTES_META_KEY, $translationsIdsToInsert );
109 $this->updateMeta( self::PRODUCT_ATTRIBUTES_META_KEY, $translationsIdsToUpdate );
110 }
111
112 /**
113 * @param int $productId
114 * @param int[] $translationsIds
115 * @param array<int,string> $translationsLanguages
116 * @param array<int,array> $storedAttributes
117 */
118 private function runForDefaultAttributes( $productId, $translationsIds, $translationsLanguages, $storedAttributes ) {
119 $productsIds = array_merge( [ $productId ], $translationsIds );
120 $storedDefaultAttributes = $this->getMeta( self::DEFAULT_ATTRIBUTES_META_KEY, $productsIds );
121 $defaultAttributes = $storedDefaultAttributes[ $productId ] ?? null;
122
123 if ( null === $defaultAttributes ) {
124 $translationsIdsToClear = array_intersect( $translationsIds, array_keys( $storedDefaultAttributes ) );
125 $this->clearTranslationsValue( $translationsIdsToClear, self::DEFAULT_ATTRIBUTES_META_KEY );
126 return;
127 }
128
129 if ( empty( $defaultAttributes ) ) {
130 $this->spreadEmptyValue( $translationsIds, $storedDefaultAttributes, self::DEFAULT_ATTRIBUTES_META_KEY );
131 return;
132 }
133
134 $defaultAttributesToUpdate = [];
135 foreach ( $defaultAttributes as $attribute => $defaultAttributeValue ) {
136 if ( WCTaxonomies::isProductAttribute( $attribute ) ) {
137 if ( $this->woocommerceWpml->attributes->is_translatable_attribute( $attribute ) ) {
138 $sanitizedAttributeName = wc_sanitize_taxonomy_name( $attribute );
139 $defaultTerm = $this->woocommerceWpml->terms->wcml_get_term_by_slug( $defaultAttributeValue, $sanitizedAttributeName );
140 $defaultTermTranslations = $defaultTerm
141 ? $this->elementTranslations->get_element_translations( $defaultTerm->term_taxonomy_id, false, false )
142 : [];
143
144 foreach ( $translationsLanguages as $translationId => $language ) {
145 $translatedDefaultAttributes = $storedDefaultAttributes[ $translationId ] ?? [];
146 $translatedDefaultTermTaxonomyId = $defaultTermTranslations[ $language ] ?? null;
147 $translatedDefaultTerm = $translatedDefaultTermTaxonomyId
148 ? $this->woocommerceWpml->terms->wcml_get_term_by_taxonomy_id( $translatedDefaultTermTaxonomyId, $sanitizedAttributeName )
149 : null;
150 $translatedDefaultAttributeValue = $translatedDefaultTerm
151 ? $translatedDefaultTerm->slug
152 : 0;
153 if (
154 ! array_key_exists( $attribute, $translatedDefaultAttributes )
155 || $translatedDefaultAttributes[ $attribute ] !== $translatedDefaultAttributeValue
156 ) {
157 $defaultAttributesToUpdate[ $translationId ][ $attribute ] = $translatedDefaultAttributeValue;
158 }
159 }
160 } else {
161 foreach ( $translationsIds as $translationId ) {
162 $translatedDefaultAttributes = $storedDefaultAttributes[ $translationId ] ?? [];
163 if (
164 ! array_key_exists( $attribute, $translatedDefaultAttributes )
165 || $translatedDefaultAttributes[ $attribute ] !== $defaultAttributeValue
166 ) {
167 $defaultAttributesToUpdate[ $translationId ][ $attribute ] = $defaultAttributeValue;
168 }
169 }
170 }
171 unset( $defaultAttributes[ $attribute ] );
172 }
173 }
174
175 if ( ! empty( $defaultAttributes ) ) {
176 $productAttributes = $storedAttributes[ $productId ] ?? [];
177
178 foreach ( $defaultAttributes as $attribute => $defaultAttributeValue ) {
179 if ( ! array_key_exists( $attribute, $productAttributes ) ) {
180 continue;
181 }
182
183 $productAttributeValues = explode( '|', $productAttributes[ $attribute ]['value'] );
184 $productAttributeValues = array_map( 'trim', $productAttributeValues );
185
186 foreach ( $productAttributeValues as $attributeIndex => $attributeValue ) {
187 $attributeValueSanitized = strtolower( sanitize_title( $attributeValue ) );
188 if (
189 $attributeValueSanitized !== $defaultAttributeValue
190 && trim( $attributeValue ) !== trim( $defaultAttributeValue )
191 ) {
192 continue;
193 }
194 foreach ( $translationsIds as $translationId ) {
195 $translatedStoredAttributes = $storedAttributes[ $translationId ] ?? [];
196 if ( ! array_key_exists( $attribute, $translatedStoredAttributes ) ) {
197 continue;
198 }
199 $translatedAttributeValues = explode( '|', $translatedStoredAttributes[ $attribute ]['value'] );
200 if ( ! isset( $translatedAttributeValues[ $attributeIndex ] ) ) {
201 $defaultAttributesToUpdate[ $translationId ][ $attribute ] = '';
202 continue;
203 }
204 if ( $attributeValueSanitized === $defaultAttributeValue ) {
205 $translatedAttributeValue = strtolower( sanitize_title( trim( $translatedAttributeValues[ $attributeIndex ] ) ) );
206 } else {
207 $translatedAttributeValue = trim( $translatedAttributeValues[ $attributeIndex ] );
208 }
209 if ( $translatedAttributeValue !== Obj::path( [ $translationId, $attribute ], $storedDefaultAttributes ) ) {
210 $defaultAttributesToUpdate[ $translationId ][ $attribute ] = $translatedAttributeValue;
211 }
212 }
213 }
214 }
215 }
216
217 if ( ! empty( $defaultAttributesToUpdate ) ) {
218 $metaToInsert = [];
219 $metaToUpdate = [];
220 foreach ( $defaultAttributesToUpdate as $translationId => $translationAttributes ) {
221 if ( ! array_key_exists( $translationId, $storedDefaultAttributes ) ) {
222 $metaToInsert[ $translationId ] = $translationAttributes;
223 continue;
224 }
225 $translationDefaultAttributes = $storedDefaultAttributes[ $translationId ];
226 if ( ! empty( $translationDefaultAttributes ) ) {
227 $metaToUpdate[ $translationId ] = $storedDefaultAttributes[ $translationId ];
228 foreach ( $translationAttributes as $attribute => $attributeValue ) {
229 $metaToUpdate[ $translationId ][ $attribute ] = $attributeValue;
230 }
231 }
232 }
233
234 $this->insertMeta( self::DEFAULT_ATTRIBUTES_META_KEY, $metaToInsert );
235 $this->updateMeta( self::DEFAULT_ATTRIBUTES_META_KEY, $metaToUpdate );
236 }
237 }
238
239 }
240