PluginProbe ʕ •ᴥ•ʔ
WPML Multilingual & Multicurrency for WooCommerce / 5.5.7
WPML Multilingual & Multicurrency for WooCommerce v5.5.7
5.5.7 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 / compatibility / WcProductAddons / class-wcml-product-addons.php
woocommerce-multilingual / compatibility / WcProductAddons Last commit date
Factory.php 4 weeks ago JobHooks.php 4 weeks ago MulticurrencyHooks.php 4 weeks ago SharedHooks.php 4 weeks ago class-wcml-product-addons.php 4 weeks ago
class-wcml-product-addons.php
352 lines
1 <?php
2
3 use WCML\Compatibility\WcProductAddons\SharedHooks;
4 use WCML\Options\WPML;
5 use WCML\PointerUi\Factory;
6 use WPML\FP\Obj;
7 use WPML\FP\Str;
8
9 class WCML_Product_Addons implements IWPML_Action {
10
11 const ADDONS_OPTION_KEY = SharedHooks::ADDONS_OPTION_KEY;
12 const ADDON_PREFIX = 'addon_';
13
14 const TRANSLATION_DOMAIN = 'wc_product_addons_strings';
15
16 public $sitepress;
17
18 protected $pointerFactory;
19
20 public function __construct( SitePress $sitepress, Factory $pointerFactory ) {
21 $this->sitepress = $sitepress;
22 $this->pointerFactory = $pointerFactory;
23 }
24
25 public function add_hooks() {
26 add_filter( 'get_product_addons_product_terms', [ $this, 'addons_product_terms' ] );
27 add_action( 'wcml_product_addons_global_updated', [ $this, 'register_addons_strings' ], 10, 4 );
28 add_filter( 'wpml_tm_translation_job_data', [ $this, 'append_addons_to_translation_package' ], 10, 2 );
29
30 if ( WPML::useAte() ) {
31 add_action( 'wpml_pro_translation_completed', [ $this, 'save_addons_to_translation' ], 10, 3 );
32 }
33
34 if ( is_admin() ) {
35
36 if ( SharedHooks::isGlobalAddonEditPage() ) {
37 if ( ! isset( $_GET['edit'] ) ) {
38 add_action( 'admin_notices', [ $this, 'inf_translate_strings' ] );
39 }
40 }
41
42 if ( ! WPML::useAte() ) {
43 add_action( 'wcml_gui_additional_box_html', [ $this, 'custom_box_html' ], 10, 3 );
44 add_filter( 'wcml_gui_additional_box_data', [ $this, 'custom_box_html_data' ], 10, 3 );
45 add_action( 'wcml_update_extra_fields', [ $this, 'addons_update' ], 10, 3 );
46 }
47
48 add_action( 'woocommerce_product_data_panels', [ $this, 'show_pointer_info' ] );
49
50 add_filter( 'wcml_do_not_display_custom_fields_for_product', [ $this, 'replace_tm_editor_custom_fields_with_own_sections' ] );
51 } else {
52 add_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10, 4 );
53 }
54
55 add_filter(
56 'get_product_addons_global_query_args',
57 [
58 $this,
59 'set_global_ids_in_query_args',
60 ]
61 );
62 }
63
64 public function register_addons_strings( $meta_id, $id, $meta_key, $addons ) {
65 if ( self::ADDONS_OPTION_KEY === $meta_key && 'global_product_addon' === get_post_type( $id ) ) {
66 foreach ( $addons as $addon ) {
67 $addon_data = wpml_collect( $addon );
68 $addon_type = $addon_data->get( 'type' );
69 $addon_position = $addon_data->get( 'position' );
70
71 do_action( 'wpml_register_single_string', self::TRANSLATION_DOMAIN, $id . '_addon_' . $addon_type . '_' . $addon_position . '_name', $addon_data->get( 'name' ) );
72 if ( $addon_data->offsetExists( 'description' ) ) {
73 do_action( 'wpml_register_single_string', self::TRANSLATION_DOMAIN, $id . '_addon_' . $addon_type . '_' . $addon_position . '_description', $addon_data->get( 'description' ) );
74 }
75 if ( $addon_data->offsetExists( 'placeholder' ) ) {
76 do_action( 'wpml_register_single_string', self::TRANSLATION_DOMAIN, $id . '_addon_' . $addon_type . '_' . $addon_position . '_placeholder', $addon_data->get( 'placeholder' ) );
77 }
78 if ( $addon_data->offsetExists( 'options' ) ) {
79 foreach ( $addon_data->get( 'options' ) as $key => $option ) {
80 do_action( 'wpml_register_single_string', self::TRANSLATION_DOMAIN, $id . '_addon_' . $addon_type . '_' . $addon_position . '_option_label_' . $key, wpml_collect( $option )->get( 'label' ) );
81 }
82 }
83 }
84 }
85 }
86
87 public function translate_addons_strings( $check, $object_id, $meta_key, $single ) {
88
89 if ( self::ADDONS_OPTION_KEY === $meta_key && 'global_product_addon' === get_post_type( $object_id ) ) {
90
91 remove_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10 );
92 $addons = get_post_meta( $object_id, $meta_key, true );
93 add_filter( 'get_post_metadata', [ $this, 'translate_addons_strings' ], 10, 4 );
94
95 if ( is_array( $addons ) ) {
96 foreach ( $addons as $key => $addon ) {
97 $addon_data = wpml_collect( $addon );
98 $addon_type = $addon_data->get( 'type' );
99 $addon_position = $addon_data->get( 'position' );
100
101 $addons[ $key ]['name'] = apply_filters( 'wpml_translate_single_string', $addon_data->get( 'name' ), self::TRANSLATION_DOMAIN, $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_name' );
102 if ( $addon_data->offsetExists( 'description' ) ) {
103 $addons[ $key ]['description'] = apply_filters( 'wpml_translate_single_string', $addon_data->get( 'description' ), self::TRANSLATION_DOMAIN, $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_description' );
104 }
105 if ( $addon_data->offsetExists( 'placeholder' ) ) {
106 $addons[ $key ]['placeholder'] = apply_filters( 'wpml_translate_single_string', $addon_data->get( 'placeholder' ), self::TRANSLATION_DOMAIN, $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_placeholder' );
107 }
108 if ( $addon_data->offsetExists( 'options' ) ) {
109 foreach ( $addon['options'] as $opt_key => $option ) {
110 $addons[ $key ]['options'][ $opt_key ]['label'] = apply_filters( 'wpml_translate_single_string', wpml_collect( $option )->get( 'label' ), self::TRANSLATION_DOMAIN, $object_id . '_addon_' . $addon_type . '_' . $addon_position . '_option_label_' . $opt_key );
111 }
112 }
113 }
114 }
115
116 return [ 0 => $addons ];
117 }
118
119 return $check;
120 }
121
122 public function addons_product_terms( $product_terms ) {
123 foreach ( $product_terms as $key => $product_term ) {
124 $product_terms[ $key ] = apply_filters( 'wpml_object_id', $product_term, 'product_cat', true, $this->sitepress->get_default_language() );
125 }
126
127 return $product_terms;
128 }
129
130 public function inf_translate_strings() {
131 $dashboardUrl = \WCML\Utilities\AdminUrl::getWPMLTMDashboardStringDomain( self::TRANSLATION_DOMAIN );
132 $this->pointerFactory
133 ->create( [
134 'content' => sprintf(
135 /* translators: %1$s and %2$s are opening and closing HTML link tags */
136 esc_html__( 'To translate global add-ons, go to the %1$sTranslation Dashboard%2$s.', 'woocommerce-multilingual' ),
137 '<a href="' . esc_url( $dashboardUrl ) . '">',
138 '</a>'
139 ),
140 'selectorId' => 'wpbody-content .woocommerce>h1',
141 'docLink' => WCML_Tracking_Link::getWcmlProductAddonsDoc(),
142 ] )
143 ->show();
144 }
145
146 public function append_addons_to_translation_package( $package, $post ) {
147 if ( 'product' === $post->post_type ) {
148 $add_field = function ( $name, $value ) use ( &$package ) {
149 if ( $value ) {
150 $package['contents'][ $name ] = [
151 'translate' => 1,
152 'data' => base64_encode( $value ),
153 'format' => 'base64',
154 ];
155 }
156 };
157
158 foreach ( SharedHooks::getProductAddons( $post->ID ) as $addon_id => $addon_data ) {
159 $add_field( self::get_job_field_name( $addon_id, 'name' ), Obj::prop( 'name', $addon_data ) );
160 $add_field( self::get_job_field_name( $addon_id, 'description' ), Obj::prop( 'description', $addon_data ) );
161 $add_field( self::get_job_field_name( $addon_id, 'placeholder' ), Obj::prop( 'placeholder', $addon_data ) );
162
163 foreach ( (array) Obj::prop( 'options', $addon_data ) as $option_id => $option ) {
164 $add_field( self::get_job_field_name( $addon_id, $option_id ), Obj::prop( 'label', $option ) );
165 }
166 }
167 }
168
169 return $package;
170 }
171
172 public function save_addons_to_translation( $post_id, $fields, $job ) {
173 if (
174 Str::startsWith( 'post_', $job->original_post_type )
175 && 'product' === get_post_type( $post_id )
176 ) {
177 $get_translation = function ( $field_name ) use ( $fields ) {
178 return Obj::path( [ $field_name, 'data' ], $fields );
179 };
180
181 $addons = SharedHooks::getProductAddons( $job->original_doc_id );
182
183 foreach ( $addons as $addon_id => $addon_data ) {
184 if ( isset( $addons[ $addon_id ]['name'] ) ) {
185 $addons[ $addon_id ]['name'] = $get_translation( self::get_job_field_name( $addon_id, 'name' ) );
186 $addons[ $addon_id ]['description'] = $get_translation( self::get_job_field_name( $addon_id, 'description' ) );
187 $addons[ $addon_id ]['placeholder'] = $get_translation( self::get_job_field_name( $addon_id, 'placeholder' ) );
188 }
189
190 foreach ( (array) Obj::prop( 'options', $addon_data ) as $option_id => $option ) {
191 if ( isset( $addons[ $addon_id ]['options'][ $option_id ]['label'] ) ) {
192 $addons[ $addon_id ]['options'][ $option_id ]['label'] = $get_translation( self::get_job_field_name( $addon_id, $option_id ) );
193 }
194 }
195 }
196
197 update_post_meta( $post_id, self::ADDONS_OPTION_KEY, $addons );
198 }
199 }
200
201 private static function get_job_field_name( $addon_id, $name_or_id ) {
202 return is_numeric( $name_or_id )
203 ? self::ADDON_PREFIX . $addon_id . '_option_' . $name_or_id . '_label'
204 : self::ADDON_PREFIX . $addon_id . '_' . $name_or_id;
205 }
206
207 public function custom_box_html( $obj, $product_id, $data ) {
208
209 $product_addons = SharedHooks::getProductAddons( $product_id );
210
211 if ( ! empty( $product_addons ) ) {
212 foreach ( $product_addons as $addon_id => $product_addon ) {
213 $addon_data = wpml_collect( $product_addon );
214
215 /* translators: %s is a product addon name */
216 $addons_section = new WPML_Editor_UI_Field_Section( sprintf( __( 'Product Add-ons Group "%s"', 'woocommerce-multilingual' ), $addon_data->get( 'name' ) ) );
217
218 $group = new WPML_Editor_UI_Field_Group( '', true );
219 $addon_field = new WPML_Editor_UI_Single_Line_Field( self::ADDON_PREFIX . $addon_id . '_name', __( 'Name', 'woocommerce-multilingual' ), $data, false );
220 $group->add_field( $addon_field );
221 $addon_field = new WPML_Editor_UI_Single_Line_Field( self::ADDON_PREFIX . $addon_id . '_description', __( 'Description', 'woocommerce-multilingual' ), $data, false );
222 $group->add_field( $addon_field );
223 if ( $addon_data->offsetExists( 'placeholder' ) ) {
224 $addon_field = new WPML_Editor_UI_Single_Line_Field( self::ADDON_PREFIX . $addon_id . '_placeholder', __( 'Placeholder', 'woocommerce-multilingual' ), $data, false );
225 $group->add_field( $addon_field );
226 }
227 $addons_section->add_field( $group );
228
229 if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
230
231 $labels_group = new WPML_Editor_UI_Field_Group( __( 'Options', 'woocommerce-multilingual' ), true );
232
233 foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
234 $option_label_field = new WPML_Editor_UI_Single_Line_Field( self::ADDON_PREFIX . $addon_id . '_option_' . $option_id . '_label', __( 'Label', 'woocommerce-multilingual' ), $data, false );
235 $labels_group->add_field( $option_label_field );
236 }
237 $addons_section->add_field( $labels_group );
238 }
239 $obj->add_field( $addons_section );
240 }
241 }
242 }
243
244 public function custom_box_html_data( $data, $product_id, $translation ) {
245
246 $product_addons = SharedHooks::getProductAddons( $product_id );
247
248 if ( ! empty( $product_addons ) ) {
249 foreach ( $product_addons as $addon_id => $product_addon ) {
250 $addon_data = wpml_collect( $product_addon );
251 $data[ self::ADDON_PREFIX . $addon_id . '_name' ] = [ 'original' => $addon_data->get( 'name' ) ];
252 $data[ self::ADDON_PREFIX . $addon_id . '_description' ] = [ 'original' => $addon_data->get( 'description' ) ];
253 $data[ self::ADDON_PREFIX . $addon_id . '_placeholder' ] = [ 'original' => $addon_data->get( 'placeholder' ) ];
254 if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
255 foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
256 $data[ self::ADDON_PREFIX . $addon_id . '_option_' . $option_id . '_label' ] = [ 'original' => wpml_collect( $option )->get( 'label' ) ];
257 }
258 }
259 }
260
261 if ( is_object( $translation ) ) {
262 $translated_product_addons = SharedHooks::getProductAddons( $translation->ID );
263 if ( ! empty( $translated_product_addons ) ) {
264 foreach ( $translated_product_addons as $addon_id => $translated_product_addon ) {
265 $translated_addon_data = wpml_collect( $translated_product_addon );
266 $data[ self::ADDON_PREFIX . $addon_id . '_name' ]['translation'] = $translated_addon_data->get( 'name' );
267 $data[ self::ADDON_PREFIX . $addon_id . '_description' ]['translation'] = $translated_addon_data->get( 'description' );
268 $data[ self::ADDON_PREFIX . $addon_id . '_placeholder' ]['translation'] = $translated_addon_data->get( 'placeholder' );
269 if ( $translated_addon_data->offsetExists( 'options' ) && $translated_addon_data->get( 'options' ) ) {
270 foreach ( $translated_addon_data->get( 'options' ) as $option_id => $option ) {
271 $data[ self::ADDON_PREFIX . $addon_id . '_option_' . $option_id . '_label' ]['translation'] = wpml_collect( $option )->get( 'label' );
272 }
273 }
274 }
275 }
276 }
277 }
278
279 return $data;
280 }
281
282 public function addons_update( $original_product_id, $product_id, $data ) {
283
284 $product_addons = SharedHooks::getProductAddons( $original_product_id );
285
286 if ( ! empty( $product_addons ) ) {
287
288 foreach ( $product_addons as $addon_id => $product_addon ) {
289 $addon_data = wpml_collect( $product_addon );
290 $product_addons[ $addon_id ]['name'] = $data[ md5( self::ADDON_PREFIX . $addon_id . '_name' ) ];
291 $product_addons[ $addon_id ]['description'] = $data[ md5( self::ADDON_PREFIX . $addon_id . '_description' ) ];
292 $product_addons[ $addon_id ]['placeholder'] = $data[ md5( self::ADDON_PREFIX . $addon_id . '_placeholder' ) ];
293
294 if ( $addon_data->offsetExists( 'options' ) && $addon_data->get( 'options' ) ) {
295 foreach ( $addon_data->get( 'options' ) as $option_id => $option ) {
296 $product_addons[ $addon_id ]['options'][ $option_id ]['label'] = $data[ md5( self::ADDON_PREFIX . $addon_id . '_option_' . $option_id . '_label' ) ];
297 }
298 }
299 }
300 }
301
302 update_post_meta( $product_id, self::ADDONS_OPTION_KEY, $product_addons );
303 }
304
305 public function show_pointer_info() {
306 $this->pointerFactory
307 ->create( [
308 'content' => sprintf(
309 /* translators: %1$s and %2$s are opening and closing HTML link tags */
310 esc_html__( 'To translate per-product add-ons, go to the %1$sTranslation Dashboard%2$s and send the associated product for translation.', 'woocommerce-multilingual' ),
311 '<a href="' . esc_url( \WCML\Utilities\AdminUrl::getWPMLTMDashboardProducts() ) . '">',
312 '</a>'
313 ),
314 'selectorId' => 'product_addons_data p:first',
315 'docLink' => WCML_Tracking_Link::getWcmlProductAddonsDoc(),
316 ] )
317 ->show();
318 }
319
320 public function replace_tm_editor_custom_fields_with_own_sections( $fields ) {
321 $fields[] = self::ADDONS_OPTION_KEY;
322
323 return $fields;
324 }
325
326 public function set_global_ids_in_query_args( $args ) {
327
328 if ( ! is_archive() ) {
329
330 remove_filter( 'get_terms_args', [ $this->sitepress, 'get_terms_args_filter' ], 10 );
331 remove_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
332 remove_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10 );
333
334 $matched_addons_ids = get_posts( $args );
335 if ( is_object( reset( $matched_addons_ids ) ) ) {
336 $matched_addons_ids = wp_list_pluck( $matched_addons_ids, 'ID' );
337 }
338
339 if ( $matched_addons_ids ) {
340 $args['include'] = $matched_addons_ids;
341 unset( $args['tax_query'] );
342 }
343
344 add_filter( 'get_terms_args', [ $this->sitepress, 'get_terms_args_filter' ], 10, 2 );
345 add_filter( 'get_term', [ $this->sitepress, 'get_term_adjust_id' ], 1 );
346 add_filter( 'terms_clauses', [ $this->sitepress, 'terms_clauses' ], 10, 3 );
347 }
348
349 return $args;
350 }
351 }
352