PluginProbe ʕ •ᴥ•ʔ
XML Feed for Skroutz & BestPrice for WooCommerce / 1.0.3
XML Feed for Skroutz & BestPrice for WooCommerce v1.0.3
trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.3 1.2.4
xml-feed-for-skroutz-for-woocommerce / admin / class-dc-skroutz-feed-data-helper.php
xml-feed-for-skroutz-for-woocommerce / admin Last commit date
css 1 year ago js 1 year ago class-dc-skroutz-feed-admin.php 1 year ago class-dc-skroutz-feed-creator.php 1 year ago class-dc-skroutz-feed-data-helper.php 1 year ago index.php 1 year ago mod_simplexml.php 1 year ago
class-dc-skroutz-feed-data-helper.php
713 lines
1 <?php
2
3 /**
4 * A helper class with useful functions for getting product data.
5 */
6 class Dicha_Skroutz_Feed_Data_Helper {
7
8 private array $options;
9 private string $feed_type;
10 private int $default_qty_for_instock;
11 private array $categories_to_exclude;
12 private string $default_vat;
13 private string $availability_meta_key;
14 private string $weight_unit_for_export;
15
16 /**
17 * Initializes the helper class.
18 *
19 * @param $options array The plugin options (user settings).
20 * @param $feed_type string The feed type.
21 */
22 public function __construct( array $options, string $feed_type ) {
23
24 $this->options = $options;
25 $this->feed_type = $feed_type;
26 $this->default_qty_for_instock = (int) apply_filters( 'dicha_skroutz_feed_default_qty_for_products_instock', 10, $this->feed_type );
27 $this->categories_to_exclude = apply_filters( 'dicha_skroutz_feed_excluded_cats_from_category_tree', [], $this->feed_type );
28 $this->default_vat = apply_filters( 'dicha_skroutz_feed_default_vat', '24', $this->feed_type );
29 $this->availability_meta_key = apply_filters( 'dicha_skroutz_feed_availability_meta_key', 'dicha_skroutz_feed_custom_availability', $this->feed_type );
30 $this->weight_unit_for_export = strtolower( trim( apply_filters( 'dicha_skroutz_feed_weight_unit_for_export', 'g', $this->feed_type ) ) );
31 $this->weight_unit_for_export = in_array( $this->weight_unit_for_export, [ 'g', 'kg' ] ) ? $this->weight_unit_for_export : 'g';
32 }
33
34
35 /**
36 * Checks if a product should be excluded from XML.
37 *
38 * @param $product WC_Product
39 *
40 * @return bool True to exclude.
41 */
42 public function skroutz_exclude_product_from_xml( WC_Product $product ): bool {
43
44 return (bool) apply_filters( 'dicha_skroutz_feed_exclude_product_from_xml', false, $product, $this->feed_type );
45 }
46
47
48 /**
49 * Checks if a variation should be excluded from XML.
50 *
51 * @param $variation WC_Product_Variation
52 * @param $parent_product WC_Product_Variable
53 *
54 * @return bool True to exclude.
55 */
56 public function skroutz_exclude_variation_from_xml( $variation, WC_Product_Variable $parent_product ): bool {
57
58 if ( ! $variation instanceof WC_Product_Variation ) return true;
59
60 return (bool) apply_filters( 'dicha_skroutz_feed_exclude_variation_from_xml', false, $variation, $parent_product, $this->feed_type );
61 }
62
63
64 /**
65 * Getter for product name.
66 *
67 * @param $product WC_Product
68 * @param $name_base string|NULL
69 *
70 * @return string
71 */
72 public function skroutz_get_name( WC_Product $product, ?string $name_base = NULL ): string {
73
74 // Find default name
75 $name_base = is_string( $name_base ) ? $name_base : $product->get_name();
76
77 /*
78 * Filter to short-circuit product name.
79 * This is useful for building an entirely new name from scratch.
80 * If you want to make minor changes to the final title, use the filter in the end of this function.
81 *
82 * If this filter is used and anything else than NULL is returned, then this value will be returned immediately.
83 * This saves time because the rest function code will not be executed at all.
84 */
85 $pre_product_name = apply_filters( 'dicha_skroutz_feed_custom_product_name_pre', NULL, $product, $name_base, $this->feed_type );
86
87 if ( NULL !== $pre_product_name ) {
88 return $pre_product_name;
89 }
90
91
92 // Find attributes or custom taxonomies to add to product name
93 $term_names_to_append = [];
94 $allowed_taxonomies_in_title = array_filter( array_map( 'sanitize_title', $this->options['title_attributes'] ) ); // checked ok with greek slugs
95 $attributes = $product->get_attributes();
96
97 if ( ! empty( $allowed_taxonomies_in_title ) ) {
98
99 // Get allowed attributes that are not used for variations (Variation attributes are included in $name_base already)
100 $attributes_to_add = array_filter(
101 $attributes,
102 function( $val, $key ) use( $allowed_taxonomies_in_title ) {
103 return in_array( $key, $allowed_taxonomies_in_title ) && ! $val->get_variation();
104 }, ARRAY_FILTER_USE_BOTH );
105
106 // transform WC_Product_Attribute objects to WP_Term objects
107 $terms_to_add = array_map( function( $wc_attribute ) { return $wc_attribute->get_terms(); }, $attributes_to_add );
108
109 // Add support for native WooCommerce Brands
110 if ( in_array( 'pa_woo__product_brand', $allowed_taxonomies_in_title ) ) {
111 $terms_to_add = array_merge( $terms_to_add, [ 'woo__product_brand' => $this->get_wc_brands_native( $product ) ] );
112 }
113 }
114
115 if ( ! empty( $terms_to_add ) ) {
116
117 // Split name to meaningful words to detect attribute names.
118 // Better than comparing whole string with strpos,
119 // because some attrs have small names like "S" (Small size) and won't be added if letter S exists in some random word.
120 // Search with strpos only when attribute name has more than one word.
121 $name_base_parts = preg_split( '/[\s,()]+/', $name_base, -1, PREG_SPLIT_NO_EMPTY );
122
123 foreach ( $terms_to_add as $term_objects ) {
124
125 foreach ( $term_objects as $term ) {
126
127 if ( count( explode( ' ', $term->name ) ) > 1 ) { // for multi-word names -> direct search in title
128 if ( strpos( $name_base, $term->name ) === false ) {
129 $term_names_to_append[] = $term->name;
130 }
131 }
132 elseif ( ! in_array( $term->name, $name_base_parts ) ) {
133 $term_names_to_append[] = $term->name;
134 }
135 }
136 }
137 }
138
139 $product_name = ! empty( $term_names_to_append ) ? $name_base . ' ' . implode( ' ', $term_names_to_append ) : $name_base;
140
141 return apply_filters( 'dicha_skroutz_feed_custom_product_name', $product_name, $product, $name_base, $allowed_taxonomies_in_title, $this->feed_type );
142 }
143
144
145 /**
146 * Getter for product link.
147 *
148 * @param $product WC_Product
149 * @param $remove_size_params bool
150 *
151 * @return string
152 */
153 public function skroutz_get_url( WC_Product $product, bool $remove_size_params = false ): string {
154
155 $link = $product->get_permalink();
156
157 if ( $remove_size_params && ! empty( $this->options['size'] ) ) {
158 $size_params = array_map( function( $size_slug ) { return "attribute_$size_slug"; }, $this->options['size'] );
159 $link = remove_query_arg( $size_params, $link );
160 }
161
162 return apply_filters( 'dicha_skroutz_feed_custom_link', $link, $product, $this->feed_type );
163 }
164
165
166 /**
167 * Getter for product main image URL.
168 *
169 * @param $product WC_Product
170 *
171 * @return string|WP_Error
172 */
173 public function skroutz_get_main_image_url( WC_Product $product ) {
174
175 $main_image = wp_get_attachment_url( $product->get_image_id() );
176 $main_image = apply_filters( 'dicha_skroutz_feed_custom_image', $main_image, $product, $this->feed_type );
177
178 if ( ! $main_image ) {
179 return new WP_Error( '40', 'Προϊόν χωρίς εικόνα.' );
180 }
181
182 return $main_image;
183 }
184
185
186 /**
187 * Getter for product gallery images URLs.
188 *
189 * @param $product WC_Product
190 *
191 * @return array
192 */
193 public function skroutz_get_additional_images( WC_Product $product ): array {
194
195 $additional_images = [];
196 $gallery_images = $product->get_gallery_image_ids();
197
198 if ( sizeof( $gallery_images ) > 0 ) {
199 foreach ( $gallery_images as $gallery_image_id ) {
200 $additional_images[] = wp_get_attachment_url( $gallery_image_id );
201 }
202 }
203
204 return apply_filters( 'dicha_skroutz_feed_custom_additional_images', $additional_images, $product, $this->feed_type );
205 }
206
207
208 /**
209 * Getter for product category tree.
210 *
211 * @param $product WC_Product
212 *
213 * @return string|WP_Error
214 */
215 public function skroutz_get_category( WC_Product $product ) {
216
217 /*
218 * Filter to short-circuit product category.
219 * This is useful for building an entirely new category tree from scratch.
220 * If you want to make minor changes to the final title, use the filter in the end of this function.
221 *
222 * If this filter is used and anything else than NULL is returned, then this value will be returned immediately.
223 * This saves time because the rest function code will not be executed at all.
224 */
225 $pre_main_product_cat = apply_filters( 'dicha_skroutz_feed_custom_category_pre', NULL, $product, $this->categories_to_exclude, $this->feed_type );
226
227 if ( NULL !== $pre_main_product_cat ) {
228 return $pre_main_product_cat;
229 }
230
231 $categories_trees = [];
232
233 $parent_id = $product->get_parent_id();
234 $id_to_search = $parent_id > 0 ? $parent_id : $product->get_id();
235
236 $product_cats = wp_get_post_terms(
237 $id_to_search,
238 'product_cat',
239 [
240 'fields' => 'ids',
241 'orderby' => 'none',
242 'exclude_tree' => $this->categories_to_exclude
243 ]
244 );
245
246 $separator = ' > ';
247
248 foreach ( $product_cats as $category_id ) {
249
250 $category_parent_list = get_term_parents_list(
251 $category_id,
252 'product_cat',
253 [
254 'separator' => $separator,
255 'link' => false,
256 ]
257 );
258
259 if ( ! empty( $category_parent_list ) && is_string( $category_parent_list ) ) {
260 $categories_trees[ $category_id ] = trim( $category_parent_list, $separator );
261 }
262 }
263
264 $main_product_cat = '';
265 $depth = 0;
266
267 if ( ! empty( $categories_trees ) ) {
268
269 foreach ( $categories_trees as $cat_tree ) {
270
271 $cur_depth = count( explode( $separator, $cat_tree ) );
272
273 if ( $cur_depth > $depth ) {
274 $main_product_cat = $cat_tree;
275 $depth = $cur_depth;
276 }
277 }
278 }
279
280 if ( empty( $main_product_cat ) ) {
281 return new WP_Error( '50', 'Προϊόν χωρίς κατηγορία.' );
282 }
283
284 return apply_filters( 'dicha_skroutz_feed_custom_category', $main_product_cat, $product, $this->categories_to_exclude, $this->feed_type );
285 }
286
287
288 /**
289 * Getter for product description.
290 *
291 * @param $product WC_Product
292 *
293 * @return string
294 */
295 public function skroutz_get_description( WC_Product $product ): string {
296
297 $description = $this->options['description'] === 'short' ? $product->get_short_description() : $product->get_description();
298 $description = apply_filters( 'dicha_skroutz_feed_custom_description', $description, $product, $this->options['description'], $this->feed_type );
299
300 return wp_filter_nohtml_kses( $description );
301 }
302
303
304 /**
305 * Getter for product EAN code.
306 *
307 * @param $product WC_Product
308 *
309 * @return string
310 */
311 public function skroutz_get_ean( WC_Product $product ): string {
312
313 $dicha_skroutz_feed_enable_ean_field = get_option( 'dicha_skroutz_feed_enable_ean_field' );
314
315 if ( wc_string_to_bool( $dicha_skroutz_feed_enable_ean_field ) ) {
316 $ean = $product->get_meta( 'dicha_skroutz_feed_ean_barcode' );
317 }
318 else {
319 $ean = $product->get_meta( '_global_unique_id' );
320 }
321
322 return apply_filters( 'dicha_skroutz_feed_custom_ean', $ean, $product, $this->feed_type );
323 }
324
325
326 /**
327 * Getter for product MPN (SKU) code.
328 *
329 * @param $product WC_Product
330 * @param $context string Options: 'view' or 'not_inherit_from_parent'.
331 *
332 * @return string
333 */
334 public function skroutz_get_mpn( WC_Product $product, string $context = 'view' ): string {
335
336 $mpn = $product->get_sku( $context );
337
338 return apply_filters( 'dicha_skroutz_feed_custom_mpn', $mpn, $product, $context, $this->feed_type );
339 }
340
341
342 /**
343 * Getter for product price.
344 *
345 * @param $product WC_Product
346 *
347 * @return string|WP_Error
348 */
349 public function skroutz_get_price( WC_Product $product ) {
350
351 $price_incl_tax = wc_get_price_including_tax( $product );
352
353 $price = apply_filters( 'dicha_skroutz_feed_custom_price', $price_incl_tax, $product, $this->feed_type );
354
355 if ( empty( $price ) ) {
356 return new WP_Error( '30', 'Η τιμή προϊόντος πρέπει να είναι μεγαλύτερη το�
357 0.' );
358 }
359
360 return wc_format_decimal( $price, 2, true );
361 }
362
363
364 /**
365 * Getter for product VAT.
366 *
367 * @param $product WC_Product
368 *
369 * @return float|string
370 */
371 public function skroutz_get_vat( WC_Product $product ) {
372
373 $vat = $this->default_vat;
374
375 if ( wc_tax_enabled() ) {
376
377 if ( $product->is_taxable() ) {
378 $tax_rates = WC_Tax::get_rates( $product->get_tax_class() );
379
380 if ( $tax_rates && is_array( $tax_rates ) ) {
381 $vat = end( $tax_rates )['rate'];
382 }
383 }
384 else {
385 $vat = 0;
386 }
387 }
388
389 return apply_filters( 'dicha_skroutz_feed_custom_vat', $vat, $product, $this->default_vat, $this->feed_type );
390 }
391
392
393 /**
394 * Getter for product manufacturer.
395 *
396 * @param $product WC_Product
397 *
398 * @return string
399 */
400 public function skroutz_get_manufacturer( WC_Product $product ): string {
401
402 $manufacturer = 'OEM';
403
404 if ( empty( $this->options['manufacturer'] ) || ! is_array( $this->options['manufacturer'] ) ) return $manufacturer;
405
406 foreach ( $this->options['manufacturer'] as $manufacturer_attribute ) {
407
408 if ( 'pa_woo__product_brand' === $manufacturer_attribute ) {
409 // Support for native WooCommerce Brands taxonomy
410 $manufacturer_name = implode( ', ', wp_list_pluck( $this->get_wc_brands_native( $product ), 'name' ) );
411 }
412 else {
413 // Get regular attribute value
414 $manufacturer_name = $product->get_attribute( $manufacturer_attribute );
415 }
416
417 // keep only the value from the first non-empty attribute/custom taxonomy
418 if ( ! empty( $manufacturer_name ) ) {
419 $manufacturer = $manufacturer_name;
420 break;
421 }
422 }
423
424 return apply_filters( 'dicha_skroutz_feed_custom_manufacturer', $manufacturer, $product, $this->options['manufacturer'], $this->feed_type );
425 }
426
427
428 /**
429 * Retrieves the native WooCommerce product brands associated with a given product.
430 *
431 * @param WC_Product $product
432 *
433 * @return array A WP_Term[] array with product brand term objects or an empty array if no brands are found or an error occurs.
434 */
435 private function get_wc_brands_native( WC_Product $product ): array {
436
437 $wc_brands = get_the_terms( $product->get_id(), 'product_brand' );
438
439 if ( empty( $wc_brands ) || is_wp_error( $wc_brands ) ) {
440 return [];
441 }
442
443 return $wc_brands;
444 }
445
446
447 /**
448 * Getter for product weight.
449 *
450 * @param $product WC_Product
451 *
452 * @return float|int|string
453 */
454 public function skroutz_get_weight( WC_Product $product ) {
455
456 $weight = wc_get_weight( $product->get_weight(), $this->weight_unit_for_export );
457 $weight = apply_filters( 'dicha_skroutz_feed_custom_weight', $weight, $product, $this->weight_unit_for_export, $this->feed_type );
458
459 if ( $weight == 0 ) return '';
460
461 return 'kg' === $this->weight_unit_for_export ? $weight . ' kg' : $weight;
462 }
463
464
465 /**
466 * Getter for product weight.
467 *
468 * @param $product WC_Product
469 *
470 * @return float|int|string
471 */
472 public function skroutz_get_shipping( WC_Product $product ) {
473
474 $shipping = '';
475
476 if ( isset( $this->options['flat_rate'] ) && $this->options['flat_rate'] != '' ) {
477
478 if ( ! empty( $this->options['flat_rate_free'] ) && floatval( $product->get_price() ) >= floatval( $this->options['flat_rate_free'] ) ) {
479 $shipping = 0;
480 }
481 else {
482 $shipping = wc_format_decimal( (float) $this->options['flat_rate'], 2, true );
483 }
484 }
485
486 return apply_filters( 'dicha_skroutz_feed_custom_shipping', $shipping, $product, $this->options['flat_rate'], $this->options['flat_rate_free'], $this->feed_type );
487 }
488
489
490 /**
491 * Getter for product quantity.
492 *
493 * @param $product WC_Product
494 *
495 * @return int|WP_Error
496 */
497 public function skroutz_get_quantity( WC_Product $product ) {
498
499 $product_type = $product->get_type();
500
501 if ( 'simple' === $product_type || 'variation' === $product_type ) {
502
503 if ( $product->is_on_backorder( 1 ) ) {
504
505 // skip if backorders should be excluded (from settings)
506 // this really only applies to variations, because simple products are already excluded from the initial products query
507 if ( ! wc_string_to_bool( $this->options['include_backorders'] ) ) {
508 return new WP_Error( '10-2', 'Τα προϊόντα σε λίστα αναμονής (backorder) εξαιρούνται από το XML βάσει ρ�
509 θμίσεων' );
510 }
511
512 $quantity = apply_filters( 'dicha_skroutz_feed_default_qty_for_products_on_backorder', 5, $product, $this->feed_type );
513 }
514 elseif ( $product->managing_stock() ) {
515 $quantity = max( $product->get_stock_quantity(), 0 );
516 }
517 else {
518 $quantity = $product->is_in_stock() ? $this->default_qty_for_instock : 0;
519 }
520 }
521 else {
522 return new WP_Error( '90-1', 'Η μέθοδος `skroutz_get_quantity` δεν πρέπει να καλείται σε WC_Product_Variable objects' );
523 }
524
525 $quantity = (int) apply_filters( 'dicha_skroutz_feed_custom_quantity', $quantity, $product, $this->default_qty_for_instock, $this->feed_type );
526
527 return min( $quantity, 10000000 );
528 }
529
530
531 /**
532 * Getter for product color.
533 *
534 * @param $product WC_Product
535 *
536 * @return string
537 */
538 public function skroutz_get_color( WC_Product $product ): string {
539
540 $color = '';
541
542 if ( empty( $this->options['color'] ) || ! is_array( $this->options['color'] ) ) return $color;
543
544 $product_type = $product->get_type();
545
546 if ( 'simple' === $product_type || 'variable' === $product_type ) {
547
548 foreach ( $this->options['color'] as $color_attribute ) {
549
550 $color_names = $product->get_attribute( $color_attribute );
551
552 if ( ! empty( $color_names ) ) {
553 // if multiple color options exist, then keep only first for skroutz
554 $color = explode( ',', $color_names, 2 )[0];
555 break;
556 }
557 }
558 }
559 elseif ( 'variation' === $product_type ) {
560
561 $variation_colors = [];
562
563 // if a variation has multiple size attributes, keep all of them and separate with "/"
564 foreach ( $this->options['color'] as $color_attribute ) {
565
566 $color_value = $product->get_attribute( $color_attribute );
567
568 /**
569 * Mod for greek (non-english) slugs.
570 *
571 * WC_Product_Variation::get_attribute() works differently from WC_Product::get_attribute()
572 * because it returns the option slug for attributes with greek slug, instead of name.
573 * So we need to fetch the term name for display ourselves.
574 */
575 if ( ! taxonomy_exists( sanitize_title( $color_attribute ) ) && taxonomy_exists( $color_attribute ) ) {
576
577 $term = get_term_by( 'slug', $color_value, $color_attribute );
578 $color_value = ! is_wp_error( $term ) && $term ? $term->name : $color_value;
579 }
580
581 if ( ! empty( $color_value ) ) {
582 $variation_colors[] = $color_value;
583 }
584 }
585
586 $color = implode( '/', $variation_colors );
587 }
588
589 return apply_filters( 'dicha_skroutz_feed_custom_color', $color, $product, $this->options['color'], $this->feed_type );
590 }
591
592
593 /**
594 * Getter for product size.
595 *
596 * @param $product WC_Product
597 *
598 * @return string
599 */
600 public function skroutz_get_size( WC_Product $product ): string {
601
602 $size = '';
603
604 if ( empty( $this->options['size'] ) || ! is_array( $this->options['size'] ) ) return $size;
605
606 $product_type = $product->get_type();
607
608 if ( 'simple' === $product_type || 'variable' === $product_type ) {
609
610 foreach ( $this->options['size'] as $size_attribute ) {
611
612 $size_values = $product->get_attribute( $size_attribute );
613
614 if ( ! empty( $size_values ) ) {
615 // if multiple size options exist in simple products, then keep only first for skroutz
616 $size = explode( ',', $size_values, 2 )[0];
617 break;
618 }
619 }
620 }
621 elseif ( 'variation' === $product_type ) {
622
623 $variation_sizes = [];
624
625 // if a variation has multiple size attributes, keep all of them and separate with "/"
626 foreach ( $this->options['size'] as $size_attribute ) {
627
628 $size_value = $product->get_attribute( $size_attribute );
629
630 /**
631 * Mod for greek (non-english) slugs.
632 *
633 * WC_Product_Variation::get_attribute() works differently from WC_Product::get_attribute()
634 * because it returns the option slug for attributes with greek slug, instead of name.
635 * So we need to fetch the term name for display ourselves.
636 */
637 if ( ! taxonomy_exists( sanitize_title( $size_attribute ) ) && taxonomy_exists( $size_attribute ) ) {
638
639 $term = get_term_by( 'slug', $size_value, $size_attribute );
640 $size_value = ! is_wp_error( $term ) && $term ? $term->name : $size_value;
641 }
642
643 if ( ! empty( $size_value ) ) {
644 $variation_sizes[] = $size_value;
645 }
646 }
647
648 $size = implode( '/', $variation_sizes );
649 }
650
651 return apply_filters( 'dicha_skroutz_feed_custom_size', $size, $product, $this->options['size'], $this->feed_type );
652 }
653
654
655 /**
656 * Getter for product availability.
657 *
658 * @param $product WC_Product
659 *
660 * @return string|WP_Error
661 */
662 public function skroutz_get_availability( WC_Product $product ) {
663
664 $availability_value = $product->get_meta( $this->availability_meta_key );
665
666 // if empty, try to get parent product's value
667 if ( empty( $availability_value ) ) {
668
669 $parent_id = $product->get_parent_id();
670
671 if ( $parent_id > 0 ) {
672 $availability_value = get_post_meta( $parent_id, $this->availability_meta_key, true );
673 }
674 }
675
676 // if still empty, get default value from settings
677 if ( empty( $availability_value ) ) {
678 $availability_value = $this->options['xml_availability'];
679 }
680
681 $availability_text = $this->skroutz_get_availability_text( $availability_value );
682
683 if ( is_wp_error( $availability_text ) ) return $availability_text;
684
685 return apply_filters( 'dicha_skroutz_feed_custom_availability', $availability_text, $product, $availability_value, $this->options['xml_availability'], $this->feed_type );
686 }
687
688
689 /**
690 * Get availability display text based on availability value.
691 *
692 * @param $availability_value string
693 *
694 * @return string|WP_Error
695 */
696 public function skroutz_get_availability_text( string $availability_value ) {
697
698 $availability_options = Dicha_Skroutz_Feed_Admin::skroutz_get_availability_options();
699 $availability_text = $availability_options[ $availability_value ] ?? '';
700
701 if ( empty( $availability_text ) ) {
702 return new WP_Error( '20', 'Μη έγκ�
703 ρη τιμή διαθεσιμότητας' );
704 }
705 elseif( '5' === $availability_value ) {
706 return new WP_Error( '60', 'Απόκρ�
707 ψη από το XML λόγω ρύθμισης' );
708 }
709
710 return $availability_text;
711 }
712
713 }