PluginProbe
Timetics – Appointment Booking Calendar & Scheduling / 1.0.60
Timetics – Appointment Booking Calendar & Scheduling v1.0.60
1.0.61 1.0.60 1.0.59 1.0.58 1.0.57 1.0.56 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 All 62 releases
timetics / utils / global-helper.php

global-helper.php in Timetics – Appointment Booking Calendar & Scheduling 1.0.60, at utils/global-helper.php

935 lines 28.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 defined( 'ABSPATH' ) || exit;
3
4 use function Timetics\timetics;
5 use Timetics\Core\Bookings\Booking;
6 use Timetics\Core\Integrations\Google\Client;
7 use Timetics\Core\Integrations\Google\Service\Calendar;
8
9 /**
10 * Get timezone list.
11 *
12 * @since 1.0.0
13 *
14 * @return array
15 */
16 if ( ! function_exists( 'timetics_get_timezone_list' ) ) {
17 function timetics_get_timezone_list() {
18 $tzlist = wp_timezone_choice( 'UTC' );
19 $doc = new DOMDocument();
20 $doc->loadHTML( $tzlist );
21
22 $elements = $doc->getElementsByTagName( 'option' );
23 $timezones = [];
24
25 if ( ! empty( $elements ) ) {
26 foreach ( $elements as $element ) {
27 $data = [
28 'value' => $element->getAttribute( 'value' ),
29 'name' => $element->textContent, // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
30 ];
31
32 $timezones[] = $data;
33 }
34 }
35
36 return $timezones;
37 }
38 }
39
40 if ( ! function_exists( 'timetics_get_google_access_token' ) ) {
41 /**
42 * Get google access token
43 *
44 * @param integer $user_id Authenticate user id
45 *
46 * @since 1.0.0
47 *
48 * @return string
49 */
50 function timetics_get_google_access_token( $user_id = 0 ) {
51 $data = timetics_get_google_auth( $user_id );
52
53 if ( ! $data ) {
54 return false;
55 }
56
57 if ( ( $data['expires_in'] - 30 ) < time() ) {
58 $refresh_toekn = timetics_get_google_refresh_token( $user_id );
59 $client = timetics_get_google_client();
60
61 $data = $client->fetch_access_token_with_refresh_token( $refresh_toekn );
62
63 if ( ! $data ) {
64 return false;
65 }
66
67 timetics_update_google_auth( $user_id, $data );
68 }
69
70 return $data['access_token'];
71 }
72 }
73
74 if ( ! function_exists( 'timetics_get_google_refresh_token' ) ) {
75
76 /**
77 * Get google auth refresh token
78 *
79 * @param integer $user_id Authenticate user id
80 *
81 * @return string
82 */
83 function timetics_get_google_refresh_token( $user_id ) {
84 return get_user_meta( $user_id, 'timetics_google_refresh_token', true );
85 }
86 }
87
88 if ( ! function_exists( 'timetics_get_auth_redirect_uri' ) ) {
89 /**
90 * Get auth redirect uri
91 *
92 * @param string $auth
93 *
94 * @return string
95 */
96 function timetics_get_auth_redirect_uri( $auth = '' ) {
97 return site_url( 'timetics-integration/' . $auth );
98 }
99 }
100
101 if ( ! function_exists( 'timetics_update_google_auth' ) ) {
102 /**
103 * Update google auth token
104 *
105 * @param integer $user_id
106 * @param array $data
107 *
108 * @return void
109 */
110 function timetics_update_google_auth( $user_id = 0, $data = [] ) {
111 if ( ! empty( $data['code'] ) ) {
112 update_user_meta( $user_id, 'timetics_google_auth_code', $data['code'] );
113 }
114
115 if ( ! empty( $data['refresh_token'] ) ) {
116 update_user_meta( $user_id, 'timetics_google_refresh_token', $data['refresh_token'] );
117 }
118
119 $data['expires_in'] = $data['expires_in'] + time();
120
121 update_user_meta( $user_id, 'timetics_google_auth', $data );
122 }
123 }
124
125 if ( ! function_exists( 'timetics_get_google_auth' ) ) {
126 /**
127 * Get google auth
128 *
129 * @param integer $user_id
130 *
131 * @return array
132 */
133 function timetics_get_google_auth( $user_id = 0 ) {
134 return get_user_meta( $user_id, 'timetics_google_auth', true );
135 }
136 }
137
138 if ( ! function_exists( 'timetics_get_google_client' ) ) {
139 /**
140 * Get google auth client
141 *
142 * @return Timetics\Core\Integrations\Google\Client
143 */
144 function timetics_get_google_client() {
145 $client_id = timetics_get_option( 'google_app_client_id' );
146 $client_secret = timetics_get_option( 'google_app_client_secret' );
147
148 $redirect_uri = timetics_get_auth_redirect_uri( 'google-auth' );
149
150 $client = new Client();
151 $client->add_scope( Calendar::scope() );
152 $client->set_auth_config(
153 [
154 'client_id' => $client_id,
155 'client_secrete' => $client_secret,
156 ]
157 );
158
159 $client->set_redirect_uri( $redirect_uri );
160
161 return $client;
162 }
163 }
164
165 if ( ! function_exists( 'timetics_get_google_auth_url' ) ) {
166 /**
167 * Get google auth url
168 *
169 * @return string
170 */
171 function timetics_get_google_auth_url() {
172 $local_url = site_url( 'timetics-integration/google-auth' );
173
174 return wp_nonce_url( $local_url, 'timetics_auth_action', 'timetics_auth_nonce' );
175 }
176 }
177
178 if ( ! function_exists( 'timetics_get_posts' ) ) {
179 /**
180 * Get posts with date range
181 *
182 * @param array $args
183 *
184 * @return Object
185 */
186 function timetics_get_posts( $args = [] ) {
187 $defaults = [
188 'post_type' => 'post',
189 'post_status' => 'publish',
190 'nopaging' => true,
191 'date_range' => '',
192 ];
193
194 $args = wp_parse_args( $args, $defaults );
195
196 // Date range found.
197 if ( $args['date_range'] ) {
198 $from_date = $args['date_range']['start'];
199 $to_date = $args['date_range']['end'];
200
201 $args['date_query'] = [
202 'relation' => 'AND',
203 [
204 'before' => [
205 'year' => gmdate( 'Y', strtotime( $to_date ) ),
206 'month' => gmdate( 'm', strtotime( $to_date ) ),
207 'day' => gmdate( 'd', strtotime( $to_date ) ),
208 ],
209 'after' => [
210 'year' => gmdate( 'Y', strtotime( $from_date ) ),
211 'month' => gmdate( 'm', strtotime( $from_date ) ),
212 'day' => gmdate( 'd', strtotime( $from_date ) ),
213 ],
214 'inclusive' => true,
215 ],
216 ];
217 }
218
219 // The Query
220 $posts = new WP_Query( $args );
221
222 return $posts;
223 }
224 }
225
226 if ( ! function_exists( 'timetics_count_posts()' ) ) {
227 /**
228 * Count post with date range or without date range
229 *
230 * @param array $args Required query params
231 *
232 * @return integer
233 */
234 function timetics_count_posts( $args = [] ) {
235 $posts = timetics_get_posts( $args );
236
237 return $posts->post_count;
238 }
239 }
240
241 if ( ! function_exists( 'timetics_count_users' ) ) {
242 /**
243 * Count user by role and date range
244 *
245 * @param array $args Required query params
246 *
247 * @return integer
248 */
249 function timetics_count_users( $args = [] ) {
250 $defaults = [
251 'role' => '',
252 'date_range' => '',
253 'count_total' => true,
254 ];
255
256 $args = wp_parse_args( $args, $defaults );
257
258 // Date range found.
259 if ( $args['date_range'] ) {
260 $from_date = $args['date_range']['start'];
261 $to_date = $args['date_range']['end'];
262
263 $args['date_query'] = [
264 'relation' => 'AND',
265 [
266 'before' => [
267 'year' => gmdate( 'Y', strtotime( $to_date ) ),
268 'month' => gmdate( 'm', strtotime( $to_date ) ),
269 'day' => gmdate( 'd', strtotime( $to_date ) ),
270 ],
271 'after' => [
272 'year' => gmdate( 'Y', strtotime( $from_date ) ),
273 'month' => gmdate( 'm', strtotime( $from_date ) ),
274 'day' => gmdate( 'd', strtotime( $from_date ) ),
275 ],
276 'inclusive' => true,
277 ],
278 ];
279 }
280
281 // The Query
282 $user_query = new WP_User_Query( $args );
283
284 // Return total users.
285 return $user_query->total_users;
286 }
287 }
288
289 if ( ! function_exists( 'timetics_get_total_sale' ) ) {
290 /**
291 * Get total sale with date range or without date range
292 *
293 * @param array $args Sales Required Args
294 *
295 * @return integer
296 */
297 function timetics_get_total_sale( $args = [] ) {
298 $defaults = [
299 'post_type' => 'timetics-booking',
300 'post_status' => 'approved',
301 ];
302
303 $args = wp_parse_args( $args, $defaults );
304
305 $posts = timetics_get_posts( $args );
306
307 $total = 0;
308
309 foreach ( $posts->posts as $post ) {
310 $booking = new Booking( $post->ID );
311 $total += floatval( $booking->get_total() );
312 }
313
314 return $total;
315 }
316 }
317
318 if ( ! function_exists( 'timetics_get_staff_integrations' ) ) {
319 /**
320 * Get all staff integrations
321 *
322 * @return array
323 */
324 function timetics_get_staff_integrations( $user_id = 0 ) {
325 $google_auth = timetics_get_google_access_token( $user_id );
326 $google_credentials = timetics_get_google_credentials();
327 $is_setup = ! empty( $google_credentials['client_id'] ) && ! empty( $google_credentials['client_secret'] );
328 $current_user_id = ( $user_id == get_current_user_id() ) ? true : false;
329
330 $integrations = [
331 [
332 'id' => 'google-calendar-meet',
333 'name' => esc_html__( 'Google Meet', 'timetics' ),
334 'description' => esc_html__( 'Connect your Meet to sync your booked events.', 'timetics' ),
335 'auth_url' => timetics_get_google_auth_url(),
336 'connected' => ! empty( $google_auth ),
337 'setup' => $is_setup,
338 'current_user' => $current_user_id,
339 ],
340 [
341 'id' => 'google-calendar',
342 'name' => esc_html__( 'Google Calendar', 'timetics' ),
343 'description' => esc_html__( 'Connect your Meet to sync your booked events.', 'timetics' ),
344 'auth_url' => timetics_get_google_auth_url(),
345 'connected' => ! empty( $google_auth ),
346 'setup' => $is_setup,
347 'current_user' => $current_user_id,
348 ],
349 ];
350
351 $integrations = apply_filters( 'timetics_staff_integrations', $integrations, $user_id );
352
353 return $integrations;
354 }
355 }
356
357 if ( ! function_exists( 'timetics_get_google_credentials' ) ) {
358 /**
359 * Get google auth credentials
360 *
361 * @return array
362 */
363 function timetics_get_google_credentials() {
364 $client_id = timetics_get_option( 'google_app_client_id' );
365 $client_secret = timetics_get_option( 'google_app_client_secret' );
366
367 return [
368 'client_id' => $client_id,
369 'client_secret' => $client_secret,
370 ];
371 }
372 }
373
374 if ( ! function_exists( 'timetics_get_default_timezone' ) ) {
375 /**
376 * Get default timezone
377 *
378 * @return string
379 */
380 function timetics_get_default_timezone() {
381 $timezone = get_option( 'timezone_string' );
382 return $timezone;
383 }
384 }
385
386 if ( ! function_exists( 'timetics_get_currencies' ) ) {
387 /**
388 * Get currency list
389 *
390 * @return array
391 */
392 function timetics_get_currencies() {
393 $currencies = require_once dirname( __FILE__ ) . '/currency.php';
394
395 return $currencies;
396 }
397 }
398
399 if ( ! function_exists( 'timetics_update_default_settings' ) ) {
400
401 /**
402 * Update default settings
403 *
404 * @return void
405 */
406 function timetics_update_default_settings() {
407 $settings = [
408 'google_auth_redirect_uri' => timetics_get_auth_redirect_uri( 'google-auth' ),
409 'outlook_auth_redirect_uri'=> timetics_get_auth_redirect_uri( 'outlook-auth' ),
410 'default_booking_status' => 'pending',
411 'currency' => 'USD',
412 'primary_color' => '#3161F1',
413 'secondary_color' => '#6188ff',
414 ];
415
416 $settings = apply_filters( 'timetics_default_settings', $settings );
417
418 foreach ( $settings as $key => $value ) {
419 timetics_update_option( $key, $value );
420 }
421 }
422 }
423
424 if ( ! function_exists( 'timetics_google_setup' ) ) {
425
426 /**
427 * Checking google auth is configured or not
428 *
429 * @return bool
430 */
431 function timetics_google_setup() {
432 $client_id = timetics_get_option( 'google_app_client_id' );
433 $client_secret = timetics_get_option( 'google_app_client_secret' );
434
435 if ( $client_id && $client_secret ) {
436 return true;
437 }
438
439 return false;
440 }
441 }
442
443 if ( ! function_exists( 'timetics_get_post_status' ) ) {
444
445 /**
446 * Get post status
447 *
448 * @return array
449 */
450 function timetics_get_post_status() {
451 return [
452 'approved',
453 'pending',
454 'cancel',
455 'completed',
456 ];
457 }
458 }
459
460 if ( ! function_exists( 'timetics_get_payment_methods' ) ) {
461 /**
462 * Get payment methods
463 *
464 * @return array
465 */
466 function timetics_get_payment_methods() {
467 $payment_methods = [
468 [
469 'name' => esc_html__( 'Stripe', 'timetics' ),
470 'status' => timetics_get_option( 'stripe_status' ),
471 ],
472 [
473 'name' => esc_html__( 'Local Pay', 'timetics' ),
474 'status' => timetics_get_option( 'local_pay_status' ),
475 ],
476 [
477 'name' => esc_html__( 'Woocommerce', 'timetics' ),
478 'status' => timetics_is_woocommerce_active(),
479 ],
480 ];
481
482 return apply_filters( 'timetics_payment_methods', $payment_methods );
483 }
484 }
485
486 if ( ! function_exists( 'timetics_replace_placeholder' ) ) {
487 /**
488 * Replace string with placeholder
489 *
490 * @param array $placeholders
491 * @param string $text
492 *
493 * @return string
494 */
495 function timetics_replace_placeholder( $text, $placeholders = [] ) {
496
497 if ( ! $placeholders ) {
498 return $text;
499 }
500
501 foreach ( $placeholders as $placeholder => $replace_with ) {
502 $text = str_replace( $placeholder, $replace_with, $text );
503 }
504
505 return $text;
506 }
507 }
508
509 if ( ! function_exists( 'timetics_register_cron' ) ) {
510 /**
511 * Register timetics cron
512 *
513 * @return void
514 */
515 function timetics_register_cron() {
516 wp_schedule_event( time(), 'daily', 'timetics_booking_clear_schedule' );
517 }
518 }
519
520 if ( ! function_exists( 'timetics_is_woocommerce_active' ) ) {
521
522 /**
523 * Check woocommerce is active or not
524 *
525 * @return bool
526 */
527 function timetics_is_woocommerce_active() {
528
529 if ( function_exists( 'WC' ) && timetics_get_option( 'wc_integration' ) ) {
530 return true;
531 }
532
533 return false;
534 }
535 }
536
537 if ( ! function_exists( 'timetics_add_woocommerce_product_cat' ) ) {
538 /**
539 * Add woocommerce product category
540 *
541 * @return void
542 */
543 function timetics_add_woocommerce_product_cat() {
544 $category_name = __( 'Timetics Meeting', 'timetics' );
545
546 // Prepare category arguments
547 $category_args = array(
548 'taxonomy' => 'product_cat',
549 'cat_name' => $category_name,
550 'category_description' => __( 'Timetics meeting', 'timetics' ),
551 'slug' => 'timetics-meeting',
552 );
553
554 // Insert the category
555 wp_insert_term( $category_args['cat_name'], $category_args['taxonomy'], $category_args );
556 }
557 }
558
559 if ( ! function_exists( 'timetics_is_valid_timezone' ) ) {
560 /**
561 * Check a timezone is valid or not
562 *
563 * @param string $timezone
564 *
565 * @return bool
566 */
567 function timetics_is_valid_timezone( $timezone ) {
568 try {
569 new DateTimeZone( $timezone );
570 } catch ( Exception $e ) {
571 return false;
572 }
573
574 return true;
575 }
576 }
577
578 if ( ! function_exists( 'timetics_datetime' ) ) {
579
580 /**
581 * Timetics date time with timezone
582 *
583 * @param int | string $date
584 * @param string $timezone
585 *
586 * @return string
587 */
588 function timetics_datetime( $format, $date, $timezone = '' ) {
589 $date = is_int( $date ) ? gmdate( 'Y-m-d g:ia', $date ) : $date;
590
591 if ( ! $timezone ) {
592 $timezone = 'UTC';
593 }
594
595 // Create a DateTime object with the provided timestamp and time zone
596 $datetime = new \DateTime( $date, new \DateTimeZone( $timezone ) );
597
598 // Get the converted timestamp
599 return $datetime->format( $format );
600 }
601 }
602
603 if ( ! function_exists( 'timetics_convert_timezone' ) ) {
604
605 /**
606 * Convert date and time fron timezone to another timezone
607 *
608 * @param string $format
609 * @param string $date_time
610 * @param string $from
611 * @param string $to
612 *
613 * @return \DateTime
614 */
615 function timetics_convert_timezone( $date_time_string, $from, $to ) {
616
617 if ( empty( $from ) || empty( $to ) ) {
618 return new DateTime( $date_time_string );
619 }
620
621 $date_time_string = is_int( $date_time_string ) ? gmdate( 'Y-m-d g:ia', $date_time_string ) : gmdate( 'Y-m-d g:ia', strtotime( $date_time_string ) );
622
623 $datetime = new DateTime( $date_time_string, new DateTimeZone( $from ) );
624 $datetime->setTimezone( new DateTimeZone( $to ) );
625
626 return $datetime;
627 }
628 }
629
630 if ( ! function_exists( 'timetics_generate_username' ) ) {
631 /**
632 * Generate unique username
633 *
634 * @param string $email
635 *
636 * @return string
637 */
638 function timetics_generate_username( $email ) {
639 $username = strtok( $email, '@' );
640
641 if ( username_exists( $username ) ) {
642 $username = $username . wp_rand( 10, 100 );
643 }
644
645 return $username;
646 }
647 }
648
649 if ( ! function_exists( 'timetics_is_json' ) ) {
650 /**
651 * Check a string is valid json or not
652 *
653 * @param string $json_string
654 *
655 * @return bool
656 */
657 function timetics_is_json( $json_string ) {
658 if ( ! is_string( $json_string ) ) {
659 return false;
660 }
661
662 $data = json_decode( $json_string, true );
663
664 return $data !== null && json_last_error() === JSON_ERROR_NONE;
665 }
666 }
667
668 if ( ! function_exists( 'timetics_is_google_meet_connected' ) ) {
669
670 /**
671 * Check google meet is connected or not
672 *
673 * @param integer $user_id
674 *
675 * @return bool
676 */
677 function timetics_is_google_meet_connected( $user_id = 0 ) {
678 if ( ! $user_id ) {
679 $user_id = get_current_user_id();
680 }
681
682 $google_auth = timetics_get_google_access_token( $user_id );
683
684 return ! empty( $google_auth );
685 }
686 }
687
688 if ( ! function_exists( 'timetics_is_zoom_connected' ) ) {
689
690 /**
691 * Check google meet is connected or not
692 *
693 * @param integer $user_id
694 *
695 * @return bool
696 */
697 function timetics_is_zoom_connected( $user_id = 0 ) {
698 if ( ! $user_id ) {
699 $user_id = get_current_user_id();
700 }
701
702 if ( ! function_exists( 'timetics_get_zoom_access_token' ) ) {
703 return false;
704 }
705
706 $zoom_auth = timetics_get_zoom_access_token( $user_id );
707
708 return ! empty( $zoom_auth );
709 }
710 }
711
712 if ( ! function_exists( 'timetics_get_current_user' ) ) {
713 /**
714 * Get current user data
715 *
716 * @return array
717 */
718 function timetics_get_current_user() {
719 $user_id = get_current_user_id();
720 $user = get_userdata( $user_id );
721
722 $user_data = [
723 'id' => $user->ID,
724 'username' => $user->user_login,
725 'email' => $user->user_email,
726 'roles' => $user-> roles,
727 ];
728 return $user_data;
729 }
730 }
731
732 if ( ! function_exists( 'timetics_connected_platforms' ) ) {
733
734 /**
735 * Get connected platforms
736 *
737 * @param integer $id
738 *
739 * @return array Connected platform lists
740 */
741 function timetics_connected_platforms( $id ) {
742 $integrations = timetics_get_staff_integrations( $id );
743 $integration_names = [];
744
745 if ( $integrations ) {
746 foreach ( $integrations as $integration ) {
747 if ( $integration['connected'] ) {
748 $integration_names[] = $integration['id'];
749 }
750 }
751 }
752
753 return $integration_names;
754 }
755 }
756
757 if ( ! function_exists( 'timetics_modules_list' ) ) {
758 /**
759 * Get the master list of Arraytics plugins for the About Us page.
760 *
761 * Each entry describes an external Arraytics plugin that can be
762 * installed/activated/deactivated from within the Timetics admin.
763 *
764 * @return array
765 */
766 function timetics_modules_list(): array {
767 return [
768 'eventin' => [
769 'name' => 'eventin',
770 'slug' => 'wp-event-solution',
771 'type' => 'plugin',
772 'upgrade' => false,
773 'upgrade_link' => 'https://themewinter.com/eventin',
774 'status' => 'on',
775 'is_pro' => false,
776 'title' => __( 'Eventin', 'timetics' ),
777 'description' => __( 'Best Free WordPress Event Calendar Plugin to manage booking, registration, RSVPs, schedule recurring events and sell event tickets with WooCommerce.', 'timetics' ),
778 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'eventin' ),
779 'notice' => '',
780 'demo_link' => 'https://product.themewinter.com/eventin',
781 'settings_link' => '',
782 'doc_link' => 'https://support.themewinter.com/docs/plugins/docs/eventin/',
783 ],
784 'booktics' => [
785 'name' => 'booktics',
786 'slug' => 'booktics',
787 'type' => 'plugin',
788 'upgrade' => false,
789 'upgrade_link' => 'https://arraytics.com/booktics',
790 'status' => 'on',
791 'is_pro' => false,
792 'title' => __( 'Booktics', 'timetics' ),
793 'description' => __( 'The ultimate online booking plugin for WordPress — services, staff, schedules, and payments in one place.', 'timetics' ),
794 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'booktics' ),
795 'notice' => '',
796 'demo_link' => 'https://arraytics.com/booktics',
797 'settings_link' => '',
798 'doc_link' => 'https://docs.arraytics.com/docs/booktics/',
799 ],
800 'poptics' => [
801 'name' => 'poptics',
802 'slug' => 'poptics',
803 'type' => 'plugin',
804 'upgrade' => false,
805 'upgrade_link' => 'https://arraytics.com/poptics',
806 'status' => 'on',
807 'is_pro' => false,
808 'title' => __( 'Poptics', 'timetics' ),
809 'description' => __( 'Discover the ultimate popup mix with Poptics Popup Builder to boost your lead generation and sales conversions.', 'timetics' ),
810 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'poptics' ),
811 'notice' => '',
812 'demo_link' => 'https://arraytics.com/poptics',
813 'settings_link' => '',
814 'doc_link' => 'https://docs.aethonic.com/docs/getting-started/intro/',
815 ],
816 'wpcafe' => [
817 'name' => 'wpcafe',
818 'slug' => 'wp-cafe',
819 'type' => 'plugin',
820 'upgrade' => false,
821 'upgrade_link' => 'https://themewinter.com/wpcafe',
822 'status' => 'on',
823 'is_pro' => false,
824 'title' => __( 'WPCafe', 'timetics' ),
825 'description' => __( 'WPCafe — Restaurant plugin with Online Ordering, Delivery, Pickup, Food Menu, Reservations, and Table Management.', 'timetics' ),
826 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'wpcafe' ),
827 'notice' => '',
828 'demo_link' => 'https://product.themewinter.com/wpcafe',
829 'settings_link' => '',
830 'doc_link' => 'https://support.themewinter.com/docs/plugins/docs/wp-cafe/',
831 ],
832 'aisentic' => [
833 'name' => 'aisentic',
834 'slug' => 'aisentic',
835 'type' => 'plugin',
836 'upgrade' => false,
837 'upgrade_link' => '',
838 'status' => 'on',
839 'is_pro' => false,
840 'title' => __( 'Aisentic', 'timetics' ),
841 'description' => __( 'AI assistant for WordPress — automate content, replies and on-site tasks without leaving your dashboard.', 'timetics' ),
842 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'aisentic' ),
843 'notice' => '',
844 'demo_link' => '',
845 'settings_link' => '',
846 'doc_link' => 'https://support.themewinter.com/docs/plugins/docs/aisentic/',
847 'download_url' => 'https://github.com/themewinter/aisentic-public/releases/download/v1.0.0/aisentic-1.0.0.zip',
848 ],
849 'optiontics' => [
850 'name' => 'optiontics',
851 'slug' => 'optiontics',
852 'type' => 'plugin',
853 'upgrade' => false,
854 'upgrade_link' => '',
855 'status' => 'on',
856 'is_pro' => false,
857 'title' => __( 'Optiontics', 'timetics' ),
858 'description' => __( 'Product add-ons / extras for food items — let customers pick toppings, sizes and other paid options along with the products.', 'timetics' ),
859 'icon' => \Timetics\Core\Addon\Extension_Icon::get( 'optiontics' ),
860 'notice' => '',
861 'demo_link' => '',
862 'settings_link' => '',
863 'doc_link' => 'https://support.themewinter.com/docs/plugins/plugin-docs/optiontics/how-to-create-product-options/',
864 'download_url' => 'https://github.com/themewinter/optiontics-public/releases/download/release/optiontics.zip',
865 ],
866 ];
867 }
868 }
869
870 if ( ! function_exists( 'timetics_extension' ) ) {
871 /**
872 * Get the Timetics Extension manager instance (tools-sdk).
873 *
874 * @return \Arraytics\ToolsSdk\Extension
875 */
876 function timetics_extension(): \Arraytics\ToolsSdk\Extension {
877 return new \Arraytics\ToolsSdk\Extension( 'timetics_available_modules', timetics_modules_list() );
878 }
879 }
880
881 if ( ! function_exists( 'timetics_get_enabled_modules' ) ) {
882 /**
883 * Get list of enabled module slugs.
884 *
885 * @return array
886 */
887 function timetics_get_enabled_modules(): array {
888 $modules = get_option( 'timetics_available_modules', [] );
889
890 if ( empty( $modules ) || ! is_array( $modules ) ) {
891 return [];
892 }
893
894 $enabled = [];
895
896 foreach ( $modules as $slug => $data ) {
897 if ( is_array( $data ) && isset( $data['status'] ) && 'on' === $data['status'] ) {
898 $enabled[] = $slug;
899 } elseif ( is_string( $data ) && 'on' === $data ) {
900 $enabled[] = $slug;
901 }
902 }
903
904 return $enabled;
905 }
906 }
907
908 if ( ! function_exists( 'timetics_format_email_datetime' ) ) {
909 /**
910 * Format date, time and day according to WordPress admin settings
911 * Used in email templates to display consistent date/time formats
912 *
913 * @param string $start_date Start date (Y-m-d format)
914 * @param string $start_time Start time (h:i a format)
915 *
916 * @return array Array with 'day', 'time', 'date' keys
917 */
918 function timetics_format_email_datetime( $start_date, $start_time = '' ) {
919 $wp_date_format = get_option( 'date_format' );
920 $wp_time_format = get_option( 'time_format' );
921
922 $datetime = $start_time
923 ? $start_date . ' ' . $start_time
924 : $start_date;
925
926 $timestamp = strtotime( $datetime );
927
928 return [
929 'day' => date_i18n( 'l', $timestamp ),
930 'time' => date_i18n( $wp_time_format, $timestamp ),
931 'date' => date_i18n( $wp_date_format, $timestamp ),
932 ];
933 }
934 }
935