PluginProbe ʕ •ᴥ•ʔ
پارسی دیت – Parsi Date / 6.2.1
پارسی دیت – Parsi Date v6.2.1
6.2.1 6.2 6.1 5.1.6 5.1.7 5.1.8 5.1.8.2 6.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 2.0.0-alpha 2.1 2.1.1 2.1.2 2.1.3 2.1.5 2.1.6 2.1.7 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0.1 2.3.0.2 2.3.1 2.3.2 2.3.3 2.3.4 3.0.1 3.0.2 3.0.3 4.0.0 4.0.1 4.0.2 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5
wp-parsidate / inc / App / Integration / WooCommerce.php
wp-parsidate / inc / App / Integration Last commit date
ACF 3 weeks ago WooCommerce 3 weeks ago ACF.php 3 weeks ago BulkyBulkEditProductsWooCommerce.php 3 weeks ago EDD.php 3 weeks ago Elementor.php 3 weeks ago Formello.php 3 weeks ago Integration.php 3 weeks ago JetEngine.php 3 weeks ago LimitLoginAttempts.php 3 weeks ago MonsterInsights.php 3 weeks ago RankMath.php 3 weeks ago SchemaPro.php 3 weeks ago UltimateMember.php 3 weeks ago WooCommerce.php 3 weeks ago
WooCommerce.php
866 lines
1 <?php
2 /**
3 * Makes WooCommerce compatible with WP-Parsidate plugin
4 *
5 * @package WP-Parsidate
6 * @subpackage Plugins/WooCommerce
7 */
8
9 namespace WPParsidate\App\Integration;
10
11 defined( 'ABSPATH' ) || exit;
12
13 use Automattic\WooCommerce\Utilities\FeaturesUtil;
14 use WPParsidate\Addons\Addon;
15 use WPParsidate\App\Integration\WooCommerce\{WcGateways, WooCommerceCitySelect};
16 use WPParsidate\Helper\{Assets, Date, Number};
17 use WPParsidate\Settings\Settings;
18
19 class WooCommerce extends Addon {
20 public string $addonID = 'woocommerce';
21
22 public string $currentTab = 'woocommerce';
23
24 public function initM1Action(): void {
25 add_filter( 'wp_parsidate_' . $this->addonID . '_settings', [ $this, 'addTabSettings' ] );
26 add_filter( 'wp_parsidate_' . $this->addonID . '_tab_display_notice', '__return_false' );
27 add_filter( 'wp_parsidate_' . $this->addonID . '_tab_content_display_notice', '__return_true' );
28
29 add_action( 'before_woocommerce_init', [ $this, 'beforeWooCommerceInit' ] );
30
31 WcGateways::getInstance();
32 }
33
34 public function initAction(): void {
35 add_filter( 'woocommerce_reports_get_order_report_query', [ $this, 'fixOrderReportQueryDate' ] );
36
37 if ( get_locale() === 'fa_IR' ) {
38 if ( $this->getSetting( 'fix_prices', false ) ) {
39 add_filter( 'wc_price', [ $this, 'fixNumbersToPersian' ] );
40 add_filter( 'woocommerce_get_price_html', [ $this, 'fixNumbersToPersian' ] );
41 add_filter( 'woocommerce_cart_item_price', [ $this, 'fixNumbersToPersian' ] );
42 add_filter( 'woocommerce_cart_item_subtotal', [ $this, 'fixNumbersToPersian' ] );
43 add_filter( 'woocommerce_cart_subtotal', [ $this, 'fixNumbersToPersian' ] );
44 add_filter( 'woocommerce_cart_totals_coupon_html', [ $this, 'fixNumbersToPersian' ] );
45 add_filter( 'woocommerce_cart_shipping_method_full_label', [ $this, 'fixNumbersToPersian' ] );
46 add_filter( 'woocommerce_cart_total', [ $this, 'fixNumbersToPersian' ] );
47 }
48
49 if ( Settings::get( 'persian_date', false ) ) {
50 add_action( 'wp_head', [ $this, 'fixDateTimeDirection' ] );
51 add_filter( 'woocommerce_email_styles', [ $this, 'fixEmailTime' ], 9999, 2 );
52
53 // Jalali datepicker
54 add_action( 'admin_enqueue_scripts', [ $this, 'adminEnqueueScripts' ] );
55
56 // Convert order_date using js
57 add_action( 'woocommerce_process_shop_order_meta', [ $this, 'changeOrderDateOnSave' ], 1000 );
58 add_filter( 'woocommerce_process_product_meta', [ $this, 'validateNonVariableProductDates' ], 1000 );
59 add_action( 'woocommerce_ajax_save_product_variations', [ $this, 'validateVariableProductDates' ], 1000 );
60 add_action( 'woocommerce_process_shop_coupon_meta', [ $this, 'validateCouponsDate' ], 1000 );
61 add_filter( 'get_post_metadata', [ $this, 'changeOrderDateAndCouponExpiresMeta' ], 10, 4 );
62
63 add_filter( 'manage_edit-shop_coupon_columns', [ $this, 'removeCouponExpiryDateColumn' ] );
64 add_action( 'manage_shop_coupon_posts_custom_column', [ $this, 'printCouponExpiryDateColumn' ], 10, 2 );
65
66 add_action( 'admin_footer', [ $this, 'fixShowCreatedOrderDate' ] );
67 add_action( 'admin_init', [ $this, 'changeReportDates' ], 1000 );
68 }
69
70 add_filter( 'woocommerce_checkout_process', [ $this, 'acceptPersianNumbersInCheckout' ], 20 );
71 add_filter( 'woocommerce_checkout_posted_data', [ $this, 'convertNonPersianValuesInCheckout' ] );
72
73 add_filter( 'woocommerce_format_postcode', [ $this, 'acceptPersianNumbersInPostCode' ], 9999, 2 );
74 // add_filter( 'woocommerce_order_get_shipping_postcode', [ $this, 'fixPersianNumbersInPostCode' ], 9999, 2 );
75
76 // WC_Order class, get_address_prop method, Filter: 'woocommerce_order_get_[billing|shipping]_[prop]'
77 add_filter( 'woocommerce_order_get_shipping_phone', [ $this, 'fixPersianNumbersInPhone' ], 9999, 2 );
78
79 if ( $this->getSetting( 'validate_postcode', false ) ) {
80 add_filter( 'woocommerce_validate_postcode', [ $this, 'validatePostcode' ], 10, 3 );
81 }
82
83 if ( $this->getSetting( 'validate_phone', false ) ) {
84 add_action( 'woocommerce_after_checkout_validation', [ $this, 'validatePhoneNumber' ], 10, 2 );
85 add_filter( 'woocommerce_validate_phone', [ $this, 'validatePhone' ], 10, 3 );
86 }
87 }
88 }
89
90 /**
91 * Init Before WooCommerce Loaded
92 */
93 public function beforeWooCommerceInit(): void {
94 // Include City Translate
95 if ( $this->getSetting( 'dropdown_cities', false ) ) {
96 new WooCommerceCitySelect();
97 }
98
99 if ( class_exists( FeaturesUtil::class ) ) {
100 FeaturesUtil::declare_compatibility( 'custom_order_tables', WP_PARSI_ROOT, true );
101 FeaturesUtil::declare_compatibility( 'product_instance_caching', WP_PARSI_ROOT, true );
102 }
103 }
104
105 /**
106 * @param $data
107 * @param \WP_Error $errors WP Error
108 *
109 * @return void
110 */
111 public function validatePhoneNumber( $data, $errors ): void {
112 // This pattern ensures the phone number follows the specified structure for both mobile and landline numbers
113 if ( ! preg_match( '/^(0|0098|\+98)?(9\d{9}|[1-8]\d{9,10})$/', Number::toEnglish( wc_get_post_data_by_key( 'billing_phone' ) ) ) ) {
114 $errors->add( 'invalid_phone', __( '<strong>Phone number</strong> is invalid.', 'wp-parsidate' ) );
115 }
116 }
117
118 /**
119 * Validate phone number
120 *
121 * @param bool $valid Whether the phone number passed the default validation.
122 * @param string $phone The phone number being validated.
123 * @param string|null $country The country code the phone is being validated for, or null if unknown.
124 */
125 public function validatePhone( $valid, $phone, $country ): bool {
126 if ( $valid ) {
127 return $valid;
128 }
129
130 $phone = Number::toEnglish( $phone );
131
132 return (bool) preg_match( '/^(0|0098|\+98)?(9\d{9}|[1-8]\d{9,10})$/', $phone );
133 }
134
135 /**
136 * Validate Iranian customer postal code
137 *
138 * @param $valid
139 * @param $postcode
140 * @param $country
141 *
142 * @return bool
143 */
144 public function validatePostcode( $valid, $postcode, $country ): bool {
145 if ( 'IR' !== $country ) {
146 return $valid;
147 }
148
149 return \WPParsidate\Helper\WooCommerce::isPostalCode( $postcode,
150 apply_filters( 'wp_parsidate_validate_postal_code_checksum', false ) );
151 }
152
153 /**
154 * Convert Non-Persian Values in checkout to Persian
155 *
156 * @method convertNonPersianValuesInCheckout
157 * @param array $data
158 *
159 * @return array modified $data
160 * @version 1.0.0
161 * @since 4.0.1
162 */
163 public function convertNonPersianValuesInCheckout( $data ): array {
164 $persian_fields = array(
165 'billing_postcode',
166 'billing_city',
167 'billing_address_1',
168 'billing_address',
169 'billing_address_2',
170 'billing_state',
171 'shipping_postcode',
172 'shipping_city',
173 'shipping_address_1',
174 'shipping_address',
175 'shipping_address_2',
176 'shipping_state',
177 'billing_first_name',
178 'billing_last_name',
179 'billing_company',
180 'billing_email',
181 'shipping_first_name',
182 'shipping_last_name',
183 'shipping_company',
184 );
185
186 /**
187 * here we pass those fields we want to convert from arabic to persian
188 * other developers can hook into this filter and add their fields too
189 *
190 * @var array $persian_fields
191 */
192 $supported_persian_fields = apply_filters( "wpp_woocommerce_checkout_persian_fields", $persian_fields );
193
194 foreach ( $supported_persian_fields as $field ) {
195 if ( isset( $data[ $field ] ) ) {
196 $data[ $field ] = self::fixPersianCharacters( $data[ $field ] );
197 }
198 }
199
200 return apply_filters( "wpp_woocommerce_checkout_modified_persian_fields", $data );
201 }
202
203 /**
204 * replace Arabic characters with equivalent character in Persian
205 *
206 * @method fixPersianCharacters
207 * @param string $string
208 *
209 * @return string filtered $string
210 * @version 1.0.0
211 * @since 4.0.1
212 */
213 public static function fixPersianCharacters( $string ): string {
214 $characters = array(
215 'ك' => 'ک',
216 'دِ' => 'د',
217 'بِ' => 'ب',
218 'زِ' => 'ز',
219 'ذِ' => 'ذ',
220 'شِ' => 'ش',
221 'سِ' => 'س',
222 'ى' => 'ی',
223 'ي' => 'ی',
224 '١' => '۱',
225 '٢' => '۲',
226 '٣' => '۳',
227 '٤' => '۴',
228 '٥' => '۵',
229 '٦' => '۶',
230 '٧' => '۷',
231 '٨' => '۸',
232 '٩' => '۹',
233 '٠' => '۰',
234 );
235
236 $characters = apply_filters( "wpp_arabic_persian_characters_list", $characters );
237
238 return str_replace( array_keys( $characters ), array_values( $characters ), $string );
239 }
240
241 /**
242 * Fix persian postal code & phone numbers in WooCommerce checkout
243 *
244 * @since 4.1.0
245 */
246 public function acceptPersianNumbersInCheckout(): void {
247 if ( $this->getSetting( 'fix_persian_postcode', false ) ) {
248 if ( isset( $_POST['billing_postcode'] ) ) {
249 $_POST['billing_postcode'] = Number::toEnglish( wc_get_post_data_by_key( 'billing_postcode' ) );
250 }
251
252 if ( isset( $_POST['shipping_postcode'] ) ) {
253 $_POST['shipping_postcode'] = Number::toEnglish( wc_get_post_data_by_key( 'shipping_postcode' ) );
254 }
255 }
256
257 if ( $this->getSetting( 'fix_persian_phone', false ) ) {
258 if ( isset( $_POST['billing_phone'] ) ) {
259 $_POST['billing_phone'] = Number::toEnglish( wc_get_post_data_by_key( 'billing_phone' ) );
260 }
261
262 if ( isset( $_POST['shipping_phone'] ) ) {
263 $_POST['shipping_phone'] = Number::toEnglish( wc_get_post_data_by_key( 'shipping_phone' ) );
264 }
265 }
266 }
267
268 /**
269 * Fix persian postal code in WooCommerce checkout
270 *
271 * @since 6.0
272 */
273 public function acceptPersianNumbersInPostCode( $postcode, $country ) {
274 if ( 'IR' === $country && $this->getSetting( 'fix_persian_postcode', false ) ) {
275 $postcode = Number::toEnglish( $postcode );
276 }
277
278 return $postcode;
279 }
280
281 /**
282 * Fix non-persian digits in checkout phone field
283 *
284 * @param string $phone The address property value.
285 * @param \WC_Order $order The order object being read.
286 *
287 * @since 6.0
288 */
289 public function fixPersianNumbersInPhone( $phone, $order ): string {
290 if ( $order->get_shipping_country() === 'IR' && $this->getSetting( 'fix_persian_phone', false ) ) {
291 $phone = Number::toEnglish( $phone );
292 }
293
294 return $phone;
295 }
296
297
298 /**
299 * Changes gregorian dates to Jalali date on wc report screen
300 *
301 * @since 4.0.0
302 */
303 public function changeReportDates(): void {
304 $page = sanitize_text_field( wp_unslash( $_GET['page'] ?? '' ) );
305 $startDate = sanitize_text_field( wp_unslash( $_GET['start_date'] ?? '' ) );
306 $endDate = sanitize_text_field( wp_unslash( $_GET['end_date'] ?? '' ) );
307
308 if ( ! empty( $page ) && 'wc-reports' === $page ) {
309 if ( ! empty( $startDate ) ) {
310 $_GET['start_date'] = gregdate( 'Y-m-d', Number::toEnglish( wc_clean( $startDate ) ) );
311 }
312
313 if ( ! empty( $endDate ) ) {
314 $_GET['end_date'] = gregdate( 'Y-m-d', Number::toEnglish( wc_clean( $endDate ) ) );
315 }
316 }
317 }
318
319 /**
320 * Changes order_date field in "Edit order" screen using JS
321 *
322 * @since 4.0.0
323 */
324 public function fixShowCreatedOrderDate(): void {
325 $current_screen = $this->getCurrentScreen();
326
327 if ( 'edit_order' === $current_screen ) {
328 if ( ! \WPParsidate\Helper\WooCommerce::hposEnabled() ) {
329 global $post;
330
331 if ( ! $post ) {
332 $jalali_date = parsidate( 'Y-m-d', date( 'Y-m-d' ), 'eng' );
333 } else {
334 $jalali_date = parsidate( 'Y-m-d', date( 'Y-m-d', strtotime( $post->post_date ) ), 'eng' );
335 }
336 } else {
337 global $theorder;
338
339 if ( ! $theorder ) {
340 $jalali_date = parsidate( 'Y-m-d', date( 'Y-m-d' ), 'eng' );
341 } else {
342 $jalali_date = parsidate( 'Y-m-d', ! is_null( $theorder->get_date_created() ) ? $theorder->get_date_created()->getOffsetTimestamp() : '', 'eng' );
343 }
344 }
345
346 wp_add_inline_script( 'wpp_jalali_datepicker', 'jQuery("input[name=order_date]").val("' . $jalali_date . '")' );
347
348 } elseif ( 'legacy_report' === $current_screen ) {
349 $startDate = sanitize_text_field( wp_unslash( $_GET['start_date'] ?? '' ) );
350 $endDate = sanitize_text_field( wp_unslash( $_GET['end_date'] ?? '' ) );
351
352 $jalali_start_date = ! empty( $startDate ) ? parsidate( 'Y-m-d',
353 date( 'Y-m-d', strtotime( $startDate ) ), 'eng' ) : '';
354 $jalali_end_date = ! empty( $endDate ) ? parsidate( 'Y-m-d',
355 date( 'Y-m-d', strtotime( $endDate ) ), 'eng' ) : '';
356
357 wp_add_inline_script( 'wpp_jalali_datepicker', 'jQuery("input[name=start_date]").val("' . $jalali_start_date . '");jQuery("input[name=end_date]").val("' . $jalali_end_date . '");' );
358
359 } elseif ( 'product' === $current_screen ) {
360 global $post;
361
362 if ( ! $post ) {
363 return;
364 }
365
366 $product = wc_get_product( $post->ID );
367
368 if ( ! $product ) {
369 return;
370 }
371
372 if ( ! $product->is_type( 'variable' ) ) {
373 $sale_price_dates_from_timestamp = $product->get_date_on_sale_from( 'edit' ) ? $product->get_date_on_sale_from( 'edit' )->getOffsetTimestamp() : false;
374 $sale_price_dates_to_timestamp = $product->get_date_on_sale_to( 'edit' ) ? $product->get_date_on_sale_to( 'edit' )->getOffsetTimestamp() : false;
375
376 $sale_price_dates_from = $sale_price_dates_from_timestamp ? Number::toEnglish( date_i18n( 'Y-m-d', $sale_price_dates_from_timestamp ) ) : '';
377 $sale_price_dates_to = $sale_price_dates_to_timestamp ? Number::toEnglish( date_i18n( 'Y-m-d', $sale_price_dates_to_timestamp ) ) : '';
378
379 wp_add_inline_script( 'wpp_jalali_datepicker', 'jQuery("#_sale_price_dates_from").val("' . $sale_price_dates_from . '");jQuery("#_sale_price_dates_to").val("' . $sale_price_dates_to . '");' );
380
381 } else {
382 $dates = array();
383 $loop = 0;
384 $available_variations = $product->get_available_variations();
385
386 foreach ( $available_variations as $variation ) {
387 $variation_id = $variation['variation_id'];
388 $variation_obj = new \WC_Product_Variation( $variation_id );
389
390 $sale_price_dates_from_timestamp = $variation_obj->get_date_on_sale_from( 'edit' ) ? $variation_obj->get_date_on_sale_from( 'edit' )->getOffsetTimestamp() : false;
391 $sale_price_dates_to_timestamp = $variation_obj->get_date_on_sale_to( 'edit' ) ? $variation_obj->get_date_on_sale_to( 'edit' )->getOffsetTimestamp() : false;
392
393 $sale_price_dates_from = $sale_price_dates_from_timestamp ? Number::toEnglish( date_i18n( 'Y-m-d', $sale_price_dates_from_timestamp ) ) : '';
394 $sale_price_dates_to = $sale_price_dates_to_timestamp ? Number::toEnglish( date_i18n( 'Y-m-d', $sale_price_dates_to_timestamp ) ) : '';
395 $dates[ $loop ] = array(
396 'start' => esc_attr( $sale_price_dates_from ),
397 'end' => esc_attr( $sale_price_dates_to ),
398 );
399
400 $loop ++;
401 }
402
403 if ( ! empty( $dates ) ) {
404 wp_add_inline_script( 'wpp_jalali_datepicker',
405 'const wppVariationsDates = ' . wp_json_encode( $dates ) . '
406 jQuery("#woocommerce-product-data").on("woocommerce_variations_loaded", function(e) {
407 wppVariationsDates.forEach((date, index) => {
408 jQuery(`input[name="variable_sale_price_dates_from[${index}]"]`).val(date.start)
409 jQuery(`input[name="variable_sale_price_dates_to[${index}]"]`).val(date.end)
410 })
411 })'
412 );
413 }
414 }
415 }
416 }
417
418 /**
419 * Remove default wc expire date column in coupons screen and add our custom column
420 *
421 * @param $columns
422 *
423 * @return mixed
424 * @since 4.0.0
425 */
426 public function removeCouponExpiryDateColumn( $columns ) {
427 unset( $columns['expiry_date'] );
428
429 $columns['wpp_expiry_date'] = esc_html__( 'Expiry date', 'wp-parsidate' );
430
431 return $columns;
432 }
433
434 /**
435 * Fill our custom date expires column value
436 *
437 * @param $column
438 * @param $postID
439 *
440 * @since 4.0.0
441 */
442 public function printCouponExpiryDateColumn( $column, $postID ): void {
443 if ( $column === 'wpp_expiry_date' ) {
444 $date = get_post_meta( $postID, 'date_expires', true );
445
446 echo ! empty( $date ) ? esc_html( parsidate( 'Y-m-d', $date ) ) : '-';
447 }
448 }
449
450 /**
451 * Changes coupon expire date on load coupon data
452 * We use $wpdb to avoid creating an infinite loop
453 *
454 * @param $metadata
455 * @param $object_id
456 * @param $meta_key
457 * @param $single
458 *
459 * @return int|mixed|string
460 *
461 * @since 4.0.0
462 */
463 public function changeOrderDateAndCouponExpiresMeta( $metadata, $object_id, $meta_key, $single ) {
464 global $wpdb;
465
466 $post_type = get_post_type( $object_id );
467 $editAction = sanitize_text_field( wp_unslash( $_GET['action'] ?? '' ) ) === 'edit';
468
469 if ( $editAction && 'shop_coupon' === $post_type && 'date_expires' === $meta_key ) {
470 $metadata = $wpdb->get_var(
471 $wpdb->prepare(
472 "
473 SELECT meta_value
474 From $wpdb->postmeta
475 WHERE post_id = %d
476 AND meta_key = %s
477 ",
478 $object_id,
479 $meta_key
480 )
481 );
482
483 if ( ! empty( $metadata ) ) {
484 return parsidate( 'Y-m-d', $metadata, 'eng' );
485 }
486 }
487
488 return $metadata;
489 }
490
491 public function validateCouponsDate( $coupon_id ): void {
492 $expiry_date = Number::toEnglish( wc_get_post_data_by_key( 'expiry_date' ) );
493
494 if ( empty( $expiry_date ) ) {
495 return;
496 }
497
498 $coupon = new \WC_Coupon( $coupon_id );
499 $fixed_expiry_date = strtotime( gregdate( 'Y-m-d 23:59:59', $expiry_date ) );
500
501 $coupon->set_props( array( 'date_expires' => $fixed_expiry_date ) );
502 $coupon->save();
503 }
504
505 /**
506 * Converts variations selected Jalali dates to gregorian
507 *
508 * @param $product_id
509 *
510 * @since 4.0.0
511 */
512 public function validateVariableProductDates( $product_id ): void {
513 if ( ! isset( $_POST['variable_post_id'] ) ) {
514 return;
515 }
516
517 $max_loop = max( array_keys( wp_unslash( $_POST['variable_post_id'] ) ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
518 $parent = wc_get_product( $product_id );
519 $data_store = $parent->get_data_store();
520
521 $data_store->sort_all_product_variations( $parent->get_id() );
522
523 for ( $i = 0; $i <= $max_loop; $i ++ ) {
524 if ( ! isset( $_POST['variable_post_id'][ $i ] ) ) {
525 continue;
526 }
527
528 $variation_id = absint( $_POST['variable_post_id'][ $i ] );
529 $variation = wc_get_product_object( 'variation', $variation_id );
530 $props = array();
531
532 if ( isset( $_POST['variable_sale_price_dates_from'][ $i ] ) ) {
533 $date_on_sale_from = Number::toEnglish( sanitize_text_field( wp_unslash( $_POST['variable_sale_price_dates_from'][ $i ] ) ) );
534
535 if ( ! empty( $date_on_sale_from ) ) {
536 $props['date_on_sale_from'] = gregdate( 'Y-m-d 00:00:00', $date_on_sale_from );
537 }
538 }
539
540 if ( isset( $_POST['variable_sale_price_dates_to'][ $i ] ) ) {
541 $date_on_sale_to = Number::toEnglish( sanitize_text_field( wp_unslash( $_POST['variable_sale_price_dates_to'][ $i ] ) ) );
542
543 if ( ! empty( $date_on_sale_to ) ) {
544 $props['date_on_sale_to'] = gregdate( 'Y-m-d 23:59:59', $date_on_sale_to );
545 }
546 }
547
548 if ( empty( $props ) ) {
549 continue;
550 }
551
552 $variation->set_props( $props );
553 $variation->save();
554 }
555 }
556
557 /**
558 * Convert selected Jalali dates to gregorian on woocommerce save non-variable products
559 *
560 * @param $product_id $
561 *
562 * @return void
563 * @author HamidReza Yazdani
564 *
565 * @since 4.0.0
566 */
567 public function validateNonVariableProductDates( $product_id ) {
568 $props = array();
569
570 if ( isset( $_POST['_sale_price_dates_from'] ) ) {
571 $date_on_sale_from = Number::toEnglish( wc_get_post_data_by_key( '_sale_price_dates_from' ) );
572 $salePriceTimesFrom = sanitize_text_field( wp_unslash( $_POST['_sale_price_times_from'] ?? '' ) );
573 $time_on_sale_from = ! empty( $salePriceTimesFrom ) && Date::isTimeString( $salePriceTimesFrom ) ? Date::isTimeString( $salePriceTimesFrom ) : '00:00:00';
574
575 if ( ! empty( $date_on_sale_from ) ) {
576 $props['date_on_sale_from'] = date( 'Y-m-d ' . $time_on_sale_from,
577 strtotime( gregdate( 'Y-m-d', $date_on_sale_from ) ) );
578 }
579 }
580
581 if ( isset( $_POST['_sale_price_dates_to'] ) ) {
582 $date_on_sale_to = Number::toEnglish( wc_get_post_data_by_key( '_sale_price_dates_to' ) );
583 $salePriceTimesTo = sanitize_text_field( wp_unslash( $_POST['_sale_price_times_to'] ?? '' ) );
584 $time_on_sale_to = ! empty( $salePriceTimesTo ) && Date::isTimeString( $salePriceTimesTo ) ? Date::isTimeString( $salePriceTimesTo ) : '23:59:59';
585
586 if ( ! empty( $date_on_sale_to ) ) {
587 $props['date_on_sale_to'] = date( 'Y-m-d ' . $time_on_sale_to, strtotime( gregdate( 'Y-m-d', $date_on_sale_to ) ) );
588 }
589 }
590
591 if ( empty( $props ) ) {
592 return;
593 }
594
595 $product = wc_get_product( $product_id );
596
597 $product->set_props( $props );
598 $product->save();
599 }
600
601 /**
602 * Convert order date to gregorian before saved at database
603 *
604 * @param $order_id
605 *
606 * @throws \WC_Data_Exception
607 * @since 5.0.2
608 */
609 public function changeOrderDateOnSave( $order_id ): void {
610 $order_date = wc_get_post_data_by_key( 'order_date' );
611
612 if ( empty( $order_date ) ) {
613 return;
614 }
615
616 $order = wc_get_order( $order_id );
617
618 if ( ! $order ) {
619 return;
620 }
621
622 $hour = str_pad( (int) wc_get_post_data_by_key( 'order_date_hour' ), 2, '0', STR_PAD_LEFT );
623 $minute = str_pad( (int) wc_get_post_data_by_key( 'order_date_minute' ), 2, '0', STR_PAD_LEFT );
624 $second = str_pad( (int) wc_get_post_data_by_key( 'order_date_second' ), 2, '0', STR_PAD_LEFT );
625 $time_stamp = "$order_date $hour:$minute:$second";
626 $fixed_date = gregdate( 'Y-m-d H:i:s', $time_stamp );
627 $date = gmdate( 'Y-m-d H:i:s', strtotime( $fixed_date ) );
628
629 $order->set_date_created( $date );
630 $order->save();
631 }
632
633 /**
634 * enqueue jalali date picker assets
635 *
636 * @since 4.0.0
637 */
638 public function adminEnqueueScripts(): void {
639 $screen = get_current_screen();
640 $current_screen = is_null( $screen ) ? false : $screen->id;
641 $pluginVersion = Assets::getVersion();
642 $debugName = WP_PARSI_DEBUG_MODE ? '' : '.min';
643
644 $allowed_screens = array(
645 'product',
646 'shop_order',
647 'woocommerce_page_wc-orders',
648 'woocommerce_page_wc-reports',
649 'shop_coupon',
650 );
651
652 if ( in_array( $current_screen, $allowed_screens, true ) && Settings::get( 'persian_date' ) ) {
653 wp_enqueue_script( 'wpp_jalali_datepicker', Assets::url( 'js-admin/jalalidatepicker.min.js' ), array( 'jquery-ui-datepicker' ), $pluginVersion, [ 'in_footer' => true ] );
654 wp_enqueue_style( 'wpp_jalali_datepicker', Assets::url( "css-admin/jalalidatepicker$debugName.css" ), null, $pluginVersion );
655
656 do_action( 'wpp_jalali_datepicker_enqueued', 'wc' );
657 }
658 }
659
660 /**
661 * Fixes jalali order date direction in WooCommerce emails (Issue: https://github.com/wordpress-parsi/wp-parsidate/issues/154)
662 *
663 * @param $style
664 * @param $email
665 *
666 * @return string
667 * @since 5.0.0
668 */
669 public function fixEmailTime( $style, $email ): string {
670 return $style . 'time{unicode-bidi:embed!important}';
671 }
672
673 /**
674 * Fixes jalali order date direction in WooCommerce my-account endpoints (Issue: https://github.com/wordpress-parsi/wp-parsidate/issues/154)
675 *
676 * @return void
677 * @since 5.0.0
678 */
679 public function fixDateTimeDirection(): void {
680 if ( is_woocommerce() || is_wc_endpoint_url() || is_cart() || is_checkout() ) {
681 echo '<style>mark.order-date,time{unicode-bidi:embed!important}</style>';
682 }
683 }
684
685 public function fixNumbersToPersian( $content ): string {
686 return Number::fixNumber( $content );
687 }
688
689 /**
690 * @param $report_data
691 *
692 * @return mixed
693 */
694 public function fixOrderReportQueryDate( $report_data ) {
695 $report_data['where'] = preg_replace_callback( "/posts.post_date\s.=?\s'([^']+)'/i",
696 [ __CLASS__, 'fixOrderReportQueryDateCallback' ], $report_data['where'] );
697
698 return $report_data;
699 }
700
701 /**
702 * @param $date
703 *
704 * @return array|mixed|string|string[]
705 */
706 public function fixOrderReportQueryDateCallback( $date ) {
707 $startDate = sanitize_text_field( wp_unslash( $_GET['start_date'] ?? '' ) );
708 $endDate = sanitize_text_field( wp_unslash( $_GET['end_date'] ?? '' ) );
709
710 if ( empty( $startDate ) || empty( $endDate ) ) {
711 return $date[0];
712 }
713
714 if ( strpos( $date[0], '=' ) === false ) {
715 if ( (int) $endDate > 1900 ) {
716 return $date[0];
717 }
718
719 $dt = gregdate( 'Y-m-d', $endDate );
720 $dt = date( 'Y-m-d', strtotime( "$dt +1 day" ) );
721 } else {
722 if ( (int) $startDate > 1900 ) {
723 return $date[0];
724 }
725
726 $dt = gregdate( 'Y-m-d', $startDate );
727 }
728
729 return substr_replace( $date[0], $dt, - 20, 10 );
730 }
731
732 /**
733 * Check the current screen is the WooCommerce order edit page
734 *
735 * @return string
736 */
737 private function getCurrentScreen(): ?string {
738 if ( 'woocommerce_before_order_object_save' === current_action() ) {
739 global $pagenow;
740
741 if ( \WPParsidate\Helper\WooCommerce::hposEnabled() ) {
742 $postID = (int) sanitize_text_field( wp_unslash( $_POST['post_ID'] ?? 0 ) );
743
744 return $postID && 'shop_order' === get_post_type( $postID ) ? 'edit_order' : '';
745 }
746
747 return is_admin() && 'post.php' === $pagenow && isset( $_POST['post_type'] ) && 'shop_order' === $_POST['post_type'] && ! empty( $_POST['order_date'] ) ? 'edit_order' : '';
748 }
749
750 if ( 'admin_footer' === current_action() ) {
751 $screen = get_current_screen();
752 $current_screen = is_null( $screen ) ? '' : $screen->id;
753
754 if ( in_array( $current_screen, array( 'shop_order', 'woocommerce_page_wc-orders' ) ) ) {
755 return 'edit_order';
756 }
757
758 if ( 'woocommerce_page_wc-reports' === $current_screen ) {
759 return 'legacy_report';
760 }
761
762 return $current_screen;
763 }
764
765 return null;
766 }
767
768 public function addTabSettings(): array {
769 $settings = array(
770 'title' => esc_html__( 'WooCommerce', 'wp-parsidate' ),
771 'desc' => esc_html__( 'ParsiDate integration for WooCommerce', 'wp-parsidate' ),
772 'settings_key' => $this->addonID,
773 'settings' => [
774 'woo_product_start_grid' => array(
775 'id' => 'woo_product_start_grid',
776 'title' => esc_html__( 'Products', 'wp-parsidate' ),
777 'type' => 'startGrid',
778 ),
779 'fix_prices' => array(
780 'id' => 'fix_prices',
781 'title' => esc_html__( 'Fix prices', 'wp-parsidate' ),
782 'type' => 'toggle',
783 'default' => false,
784 'sanitize' => 'bool'
785 ),
786 'woo_product_end_grid' => array(
787 'type' => 'endGrid',
788 ),
789 'woo_checkout_start_grid' => array(
790 'id' => 'woo_checkout_start_grid',
791 'title' => esc_html__( 'Checkout page', 'wp-parsidate' ),
792 'type' => 'startGrid',
793 ),
794 'fix_persian_postcode' => array(
795 'id' => 'fix_persian_postcode',
796 'title' => esc_html__( 'Fix persian postcode', 'wp-parsidate' ),
797 'type' => 'toggle',
798 'default' => false,
799 'sanitize' => 'bool'
800 ),
801 'fix_persian_phone' => array(
802 'id' => 'fix_persian_phone',
803 'title' => esc_html__( 'Fix persian phone', 'wp-parsidate' ),
804 'type' => 'toggle',
805 'default' => false,
806 'sanitize' => 'bool'
807 ),
808 'dropdown_cities' => array(
809 'id' => 'dropdown_cities',
810 'title' => esc_html__( 'Display cities as a drop-down list', 'wp-parsidate' ),
811 'type' => 'toggle',
812 'default' => false,
813 'sanitize' => 'bool'
814 ),
815 'validate_postcode' => array(
816 'id' => 'validate_postcode',
817 'title' => esc_html__( 'Postcode validation', 'wp-parsidate' ),
818 'type' => 'toggle',
819 'default' => false,
820 'sanitize' => 'bool'
821 ),
822 'validate_phone' => array(
823 'id' => 'validate_phone',
824 'title' => esc_html__( 'Phone number validation', 'wp-parsidate' ),
825 'type' => 'toggle',
826 'default' => false,
827 'sanitize' => 'bool'
828 ),
829 'woo_checkout_end_grid' => array(
830 'type' => 'endGrid',
831 )
832 ]
833 );
834
835 return apply_filters( 'wp_parsidate_' . $this->addonID . '_settings_options', $settings );
836 }
837
838 public function info(): array {
839 $icon = '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" x="0" y="0" viewBox="0 0 183.6 47.5"><style>.st0{fill-rule:evenodd;clip-rule:evenodd;fill:#873eff}</style><path d="M77.4 0c-4.3 0-7.1 1.4-9.6 6.1L56.4 27.6V8.5c0-5.7-2.7-8.5-7.7-8.5s-7.1 1.7-9.6 6.5L28.3 27.6V8.7c0-6.1-2.5-8.7-8.6-8.7H7.3C2.6 0 0 2.2 0 6.2s2.5 6.4 7.1 6.4h5.1v24.1c0 6.8 4.6 10.8 11.2 10.8s9.6-2.6 12.9-8.7l7.2-13.5v11.4c0 6.7 4.4 10.8 11.1 10.8s9.2-2.3 13-8.7l16.6-28C87.8 4.7 85.3 0 77.3 0zM108.6 0C95 0 84.7 10.1 84.7 23.8s10.4 23.7 23.9 23.7 23.8-10.1 23.9-23.7c0-13.7-10.4-23.8-23.9-23.8m0 32.9c-5.1 0-8.6-3.8-8.6-9.1s3.5-9.2 8.6-9.2 8.6 3.9 8.6 9.2-3.4 9.1-8.6 9.1M159.7 0c-13.5 0-23.9 10.1-23.9 23.8s10.4 23.7 23.9 23.7 23.9-10.1 23.9-23.7S173.2 0 159.7 0m0 32.9c-5.2 0-8.5-3.8-8.5-9.1s3.4-9.2 8.5-9.2 8.6 3.9 8.6 9.2-3.4 9.1-8.6 9.1" class="st0"/></svg>';
840 $menuIcon = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 183.6 47.5"><path d="M70.141 3.572c-3.638 0-6.011 1.187-8.125 5.167L52.36 26.945V10.77c0-4.827-2.287-7.198-6.521-7.198-4.237 0-6.014 1.439-8.132 5.504l-9.145 17.869V10.94c0-5.167-2.119-7.368-7.284-7.368H10.776c-3.981 0-6.182 1.864-6.182 5.25 0 3.389 2.116 5.422 6.013 5.422h4.319v20.41c0 5.757 3.895 9.146 9.486 9.146 5.59 0 8.13-2.203 10.924-7.37l6.097-11.431v9.655c0 5.671 3.726 9.146 9.402 9.146 5.674 0 7.79-1.949 11.011-7.37l14.055-23.711c3.051-5.167.933-9.147-5.842-9.147h.082Zm36.908 0c-11.517 0-20.24 8.554-20.24 20.157 0 11.601 8.806 20.071 20.24 20.071s20.157-8.553 20.242-20.071c0-11.603-8.808-20.157-20.242-20.157m0 27.863c-4.319 0-7.283-3.217-7.283-7.706 0-4.49 2.964-7.792 7.283-7.792 4.32 0 7.285 3.302 7.285 7.792 0 4.489-2.879 7.706-7.285 7.706m51.794-27.863c-11.431 0-20.242 8.554-20.242 20.157 0 11.601 8.811 20.071 20.242 20.071 11.435 0 20.241-8.553 20.241-20.071s-8.806-20.157-20.241-20.157m0 27.863c-4.404 0-7.197-3.217-7.197-7.706 0-4.49 2.879-7.792 7.197-7.792 4.319 0 7.284 3.302 7.284 7.792 0 4.489-2.88 7.706-7.284 7.706" style="stroke:#3c3c3c;fill:none;paint-order:fill;stroke-width:7px;fill-rule:evenodd;clip-rule:evenodd"/></svg>';
841
842 return array(
843 'id' => $this->addonID,
844 'title' => esc_html__( 'WooCommerce', 'wp-parsidate' ),
845 'desc' => esc_html__( 'ParsiDate integration for WooCommerce', 'wp-parsidate' ),
846 'force_enable' => true,
847 'has_page' => true,
848 'icon' => $icon,
849 'menu_icon' => $menuIcon,
850 'image_link' => 'https://wordpress.org/plugins/woocommerce/',
851 'tags' => [ esc_html__( 'WooCommerce', 'wp-parsidate' ) ],
852 'cat' => 'integration',
853 'settings_key' => $this->addonID,
854 'requires_plugins' => [
855 'woocommerce/woocommerce.php' => array(
856 'is_wp_plugin' => true,
857 'is_free' => true,
858 'plugin_link' => 'https://wordpress.org/plugins/woocommerce/',
859 'function_check' => '',
860 'class_check' => 'WooCommerce',
861 )
862 ]
863 );
864 }
865 }
866