PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 3.6.0
Tutor LMS – eLearning and online course solution v3.6.0
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / includes / tutor-general-functions.php
tutor / includes Last commit date
droip 1 year ago theme-compatibility 4 years ago country.php 1 year ago ecommerce-functions.php 1 year ago tinymce_translate.php 1 year ago translate-text.php 1 year ago tutor-general-functions.php 1 year ago tutor-template-functions.php 1 year ago tutor-template-hook.php 4 years ago
tutor-general-functions.php
1792 lines
1 <?php
2 /**
3 * Tutor general functions
4 *
5 * @package TutorFunctions
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 use Tutor\Cache\FlashMessage;
12 use Tutor\Ecommerce\OptionKeys;
13 use Tutor\Ecommerce\Settings;
14 use TUTOR\Input;
15 use Tutor\Models\CourseModel;
16 use Tutor\Course;
17
18 if ( ! defined( 'ABSPATH' ) ) {
19 exit;
20 }
21
22 /**
23 * Tutor input sanitization
24 */
25
26 if ( ! function_exists( 'tutor_sanitize_data' ) ) {
27 /**
28 * Escaping for Sanitize data.
29 *
30 * @since 1.9.13
31 *
32 * @param string $input.
33 * @param string $type.
34 * @return string|array|object
35 */
36 function tutor_sanitize_data( $input = null, $type = null ) {
37 $array = array();
38 $object = new stdClass();
39
40 if ( is_string( $input ) ) {
41
42 if ( 'textarea' == $type ) {
43 $input = sanitize_textarea_field( $input );
44 } elseif ( 'kses' == $type ) {
45 $input = wp_kses_post( $input );
46 } else {
47 $input = sanitize_text_field( $input );
48 }
49
50 return $input;
51
52 } elseif ( is_object( $input ) && count( get_object_vars( $input ) ) ) {
53
54 foreach ( $input as $key => $value ) {
55 if ( is_object( $value ) ) {
56 $object->$key = tutor_sanitize_data( $value );
57 } else {
58 $key = sanitize_text_field( $key );
59 $value = sanitize_text_field( $value );
60 $object->$key = $value;
61 }
62 }
63 return $object;
64 } elseif ( is_array( $input ) && count( $input ) ) {
65 foreach ( $input as $key => $value ) {
66 if ( is_array( $value ) ) {
67 $array[ $key ] = tutor_sanitize_data( $value );
68 } else {
69 $key = sanitize_text_field( $key );
70 $value = sanitize_text_field( $value );
71 $array[ $key ] = $value;
72 }
73 }
74
75 return $array;
76 }
77 }
78 }
79
80 if ( ! function_exists( 'tutor_placeholder_img_src' ) ) {
81 function tutor_placeholder_img_src() {
82 $src = tutor()->url . 'assets/images/placeholder.svg';
83 return apply_filters( 'tutor_placeholder_img_src', $src );
84 }
85 }
86
87 /**
88 * @return string
89 *
90 * Get course categories selecting UI
91 *
92 * @since v.1.3.4
93 */
94
95 if ( ! function_exists( 'tutor_course_categories_dropdown' ) ) {
96 function tutor_course_categories_dropdown( $post_ID = 0, $args = array() ) {
97
98 $default = array(
99 'classes' => '',
100 'name' => 'tax_input[course-category]',
101 'multiple' => true,
102 );
103
104 $args = apply_filters( 'tutor_course_categories_dropdown_args', array_merge( $default, $args ) );
105
106 $multiple_select = '';
107
108 if ( tutor_utils()->array_get( 'multiple', $args ) ) {
109 if ( isset( $args['name'] ) ) {
110 $args['name'] = $args['name'] . '[]';
111 }
112 $multiple_select = "multiple='multiple'";
113 }
114
115 extract( $args );
116
117 $classes = (array) $classes;
118 $classes = implode( ' ', $classes );
119
120 $categories = tutor_utils()->get_course_categories();
121
122 $output = '';
123 $output .= '<select name="' . $name . '" ' . $multiple_select . ' class="' . $classes . '" data-placeholder="' . __( 'Search Course Category. ex. Design, Development, Business', 'tutor' ) . '">';
124 $output .= '<option value="">' . __( 'Select a category', 'tutor' ) . '</option>';
125 $output .= _generate_categories_dropdown_option( $post_ID, $categories, $args );
126 $output .= '</select>';
127
128 return $output;
129 }
130 }
131
132 /**
133 * @return string
134 *
135 * Get course tags selecting UI
136 *
137 * @since v.1.3.4
138 */
139
140 if ( ! function_exists( 'tutor_course_tags_dropdown' ) ) {
141 function tutor_course_tags_dropdown( $post_ID = 0, $args = array() ) {
142
143 $default = array(
144 'classes' => '',
145 'name' => 'tax_input[course-tag]',
146 'multiple' => true,
147 );
148
149 $args = apply_filters( 'tutor_course_tags_dropdown_args', array_merge( $default, $args ) );
150
151 $multiple_select = '';
152
153 if ( tutor_utils()->array_get( 'multiple', $args ) ) {
154 if ( isset( $args['name'] ) ) {
155 $args['name'] = $args['name'] . '[]';
156 }
157 $multiple_select = "multiple='multiple'";
158 }
159
160 extract( $args );
161
162 $classes = (array) $classes;
163 $classes = implode( ' ', $classes );
164
165 $tags = tutor_utils()->get_course_tags();
166
167 $output = '';
168 $output .= '<select name=' . $name . ' ' . $multiple_select . ' class="' . $classes . '" data-placeholder="' . __( 'Search Course Tags. ex. Design, Development, Business', 'tutor' ) . '">';
169 $output .= '<option value="">' . __( 'Select a tag', 'tutor' ) . '</option>';
170 $output .= _generate_tags_dropdown_option( $post_ID, $tags, $args );
171 $output .= '</select>';
172
173 return $output;
174 }
175 }
176
177 /**
178 * @param $categories
179 * @param string $parent_name
180 *
181 * @return string
182 *
183 * Get selecting options, recursive supports
184 *
185 * @since v.1.3.4
186 */
187
188 if ( ! function_exists( '_generate_categories_dropdown_option' ) ) {
189 function _generate_categories_dropdown_option( $post_ID = 0, $categories = array(), $args = array(), $depth = 0 ) {
190 $output = '';
191
192 if ( ! tutor_utils()->count( $categories ) ) {
193 return $output;
194 }
195
196 if ( ! is_numeric( $post_ID ) || $post_ID < 1 ) {
197 return $output;
198 }
199
200 foreach ( $categories as $category_id => $category ) {
201 if ( ! $category->parent ) {
202 $depth = 0;
203 }
204
205 $childrens = tutor_utils()->array_get( 'children', $category );
206 $has_in_term = has_term( $category->term_id, 'course-category', $post_ID );
207
208 $depth_seperator = '';
209 if ( $depth ) {
210 for ( $depth_i = 0; $depth_i < $depth; $depth_i++ ) {
211 $depth_seperator .= '-';
212 }
213 }
214
215 $output .= '<option value="' . $category->term_id . '" ' . selected( $has_in_term, true, false ) . '> ' . $depth_seperator . ' ' . $category->name . '</option>';
216
217 if ( tutor_utils()->count( $childrens ) ) {
218 $depth++;
219 $output .= _generate_categories_dropdown_option( $post_ID, $childrens, $args, $depth );
220 }
221 }
222
223 return $output;
224 }
225 }
226 /**
227 * @param $tags
228 * @param string $parent_name
229 *
230 * @return string
231 *
232 * Get selecting options, recursive supports
233 *
234 * @since v.1.3.4
235 */
236
237 if ( ! function_exists( '_generate_tags_dropdown_option' ) ) {
238 function _generate_tags_dropdown_option( $post_ID = 0, $tags = array(), $args = array(), $depth = 0 ) {
239 $output = '';
240
241 if ( ! tutor_utils()->count( $tags ) ) {
242 return $output;
243 }
244
245 if ( ! is_numeric( $post_ID ) || $post_ID < 1 ) {
246 return $output;
247 }
248
249 foreach ( $tags as $tag ) {
250
251 $has_in_term = has_term( $tag->term_id, CourseModel::COURSE_TAG, $post_ID );
252
253 $output .= '<option value="' . esc_attr( $tag->name ) . '" ' . selected( $has_in_term, true, false ) . '>' . esc_html( $tag->name ) . '</option>';
254
255 }
256
257 return $output;
258 }
259 }
260
261 /**
262 * @param array $args
263 *
264 * @return string
265 *
266 * Generate course categories checkbox
267 * @since v.1.3.4
268 */
269
270 if ( ! function_exists( 'tutor_course_categories_checkbox' ) ) {
271 function tutor_course_categories_checkbox( $post_ID = 0, $args = array() ) {
272 $default = array(
273 'name' => 'tax_input[course-category]',
274 );
275
276 $args = apply_filters( 'tutor_course_categories_checkbox_args', array_merge( $default, $args ) );
277
278 if ( isset( $args['name'] ) ) {
279 $args['name'] = $args['name'] . '[]';
280 }
281
282 extract( $args );
283
284 $categories = tutor_utils()->get_course_categories();
285 $output = '';
286 $output .= __tutor_generate_categories_checkbox( $post_ID, $categories, $args );
287
288 return $output;
289 }
290 }
291
292 /**
293 * @param array $args
294 *
295 * @return string
296 *
297 * Generate course tags checkbox
298 * @since v.1.3.4
299 */
300
301 if ( ! function_exists( 'tutor_course_tags_checkbox' ) ) {
302 function tutor_course_tags_checkbox( $post_ID = 0, $args = array() ) {
303 $default = array(
304 'name' => 'tax_input[course-tag]',
305 );
306
307 $args = apply_filters( 'tutor_course_tags_checkbox_args', array_merge( $default, $args ) );
308
309 if ( isset( $args['name'] ) ) {
310 $args['name'] = $args['name'] . '[]';
311 }
312
313 extract( $args );
314
315 $tags = tutor_utils()->get_course_tags();
316 $output = '';
317 $output .= __tutor_generate_tags_checkbox( $post_ID, $tags, $args );
318
319 return $output;
320 }
321 }
322
323 /**
324 * @param $categories
325 * @param string $parent_name
326 * @param array $args
327 *
328 * @return string
329 *
330 * Internal function to generate course categories checkbox
331 *
332 * @since v.1.3.4
333 */
334 if ( ! function_exists( '__tutor_generate_categories_checkbox' ) ) {
335 function __tutor_generate_categories_checkbox( $post_ID = 0, $categories = array(), $args = array() ) {
336
337 $output = '';
338 $input_name = tutor_utils()->array_get( 'name', $args );
339
340 if ( tutor_utils()->count( $categories ) ) {
341 $output .= '<ul class="tax-input-course-category">';
342 foreach ( $categories as $category_id => $category ) {
343 $childrens = tutor_utils()->array_get( 'children', $category );
344 $has_in_term = has_term( $category->term_id, 'course-category', $post_ID );
345
346 $output .= '<li class="tax-input-course-category-item tax-input-course-category-item-' . $category->term_id . '"><label class="course-category-checkbox"> <input type="checkbox" name="' . $input_name . '" value="' . $category->term_id . '" ' . checked( $has_in_term, true, false ) . '/> <span>' . $category->name . '</span> </label>';
347
348 if ( tutor_utils()->count( $childrens ) ) {
349 $output .= __tutor_generate_categories_checkbox( $post_ID, $childrens, $args );
350 }
351 $output .= ' </li>';
352 }
353 $output .= '</ul>';
354 }
355
356 return $output;
357
358 }
359 }
360 /**
361 * @param $tags
362 * @param string $parent_name
363 * @param array $args
364 *
365 * @return string
366 *
367 * Internal function to generate course tags checkbox
368 *
369 * @since v.1.3.4
370 */
371 if ( ! function_exists( '__tutor_generate_tags_checkbox' ) ) {
372 function __tutor_generate_tags_checkbox( $post_ID = 0, $tags = array(), $args = array() ) {
373
374 $output = '';
375 $input_name = tutor_utils()->array_get( 'name', $args );
376
377 if ( tutor_utils()->count( $tags ) ) {
378 $output .= '<ul class="tax-input-course-tag">';
379 foreach ( $tags as $tag ) {
380 $has_in_term = has_term( $tag->term_id, CourseModel::COURSE_TAG, $post_ID );
381
382 $output .= '<li class="tax-input-course-tag-item tax-input-course-tag-item-' . $tag->term_id . '"><label class="course-tag-checkbox"> <input type="checkbox" name="' . $input_name . '" value="' . $tag->term_id . '" ' . checked( $has_in_term, true, false ) . ' /> <span>' . $tag->name . '</span> </label>';
383
384 $output .= ' </li>';
385 }
386 $output .= '</ul>';
387 }
388
389 return $output;
390 }
391 }
392
393 /**
394 * @param string $content
395 * @param string $title
396 *
397 * @return string
398 *
399 * Wrap course builder sections within div for frontend
400 *
401 * @since v.1.3.4
402 */
403
404 if ( ! function_exists( 'course_builder_section_wrap' ) ) {
405 function course_builder_section_wrap( $content = '', $title = '', $echo = true ) {
406 $template = trailingslashit( tutor()->path . 'templates' ) . 'metabox-wrapper.php';
407 if ( $echo ) {
408 if ( file_exists( $template ) ) {
409 include $template;
410 } else {
411 echo esc_html( $template ) . esc_html__( 'file not exists', 'tutor' );
412 }
413 } else {
414 ob_start();
415 if ( file_exists( $template ) ) {
416 include $template;
417 } else {
418 echo esc_html( $template ) . esc_html__( 'file not exists', 'tutor' );
419 }
420 $html = ob_get_clean();
421 return $html;
422 }
423 }
424 }
425
426
427 if ( ! function_exists( 'get_tutor_header' ) ) {
428 function get_tutor_header( $fullScreen = false ) {
429 $enable_spotlight_mode = tutor_utils()->get_option( 'enable_spotlight_mode' );
430
431 if ( $enable_spotlight_mode || $fullScreen ) {
432 ?>
433 <!doctype html>
434 <html <?php language_attributes(); ?>>
435
436 <head>
437 <meta charset="<?php bloginfo( 'charset' ); ?>" />
438 <meta name="viewport" content="width=device-width, initial-scale=1" />
439 <link rel="profile" href="https://gmpg.org/xfn/11" />
440 <?php wp_head(); ?>
441 </head>
442
443 <body <?php body_class(); ?>>
444 <div id="tutor-page-wrap" class="tutor-site-wrap site">
445 <?php
446 } else {
447 tutor_utils()->tutor_custom_header();
448 }
449 }
450 }
451
452 if ( ! function_exists( 'get_tutor_footer' ) ) {
453 function get_tutor_footer( $fullScreen = false ) {
454 $enable_spotlight_mode = tutor_utils()->get_option( 'enable_spotlight_mode' );
455 if ( $enable_spotlight_mode || $fullScreen ) {
456 ?>
457 </div>
458 <?php wp_footer(); ?>
459
460 </body>
461
462 </html>
463 <?php
464 } else {
465 tutor_utils()->tutor_custom_footer();
466 }
467 }
468 }
469
470 /**
471 * @param null $key
472 * @param bool $default
473 *
474 * @return array|bool|mixed
475 *
476 * Get tutor option by this helper function
477 *
478 * @since v.1.3.6
479 */
480 if ( ! function_exists( 'get_tutor_option' ) ) {
481 function get_tutor_option( $key = null, $default = false ) {
482 return tutor_utils()->get_option( $key, $default );
483 }
484 }
485
486 /**
487 * @param null $key
488 * @param bool $value
489 *
490 * Update tutor option by this helper function
491 *
492 * @since v.1.3.6
493 */
494 if ( ! function_exists( 'update_tutor_option' ) ) {
495 function update_tutor_option( $key = null, $value = false ) {
496 tutor_utils()->update_option( $key, $value );
497 }
498 }
499 /**
500 * @param int $course_id
501 * @param null $key
502 * @param bool $default
503 *
504 * @return array|bool|mixed
505 *
506 * Get tutor course settings by course ID
507 *
508 * @since v.1.4.1
509 */
510 if ( ! function_exists( 'get_tutor_course_settings' ) ) {
511 function get_tutor_course_settings( $course_id = 0, $key = null, $default = false ) {
512 return tutor_utils()->get_course_settings( $course_id, $key, $default );
513 }
514 }
515
516 /**
517 * @param int $lesson_id
518 * @param null $key
519 * @param bool $default
520 *
521 * @return array|bool|mixed
522 *
523 * Get lesson content drip settings
524 */
525
526 if ( ! function_exists( 'get_item_content_drip_settings' ) ) {
527 function get_item_content_drip_settings( $lesson_id = 0, $key = null, $default = false ) {
528 return tutor_utils()->get_item_content_drip_settings( $lesson_id, $key, $default );
529 }
530 }
531
532 /**
533 * @param null $msg
534 * @param string $type
535 * @param bool $echo
536 *
537 * @return string
538 *
539 * Print Alert by tutor_alert()
540 *
541 * @since v.1.4.1
542 */
543 if ( ! function_exists( 'tutor_alert' ) ) {
544 function tutor_alert( $msg = null, $type = 'warning', $echo = true ) {
545 if ( ! $msg ) {
546
547 if ( $type === 'any' ) {
548 if ( ! $msg ) {
549 $type = 'warning';
550 $msg = tutor_flash_get( $type );
551 }
552 if ( ! $msg ) {
553 $type = 'danger';
554 $msg = tutor_flash_get( $type );
555 }
556 if ( ! $msg ) {
557 $type = 'success';
558 $msg = tutor_flash_get( $type );
559 }
560 } else {
561 $msg = tutor_flash_get( $type );
562 }
563 }
564 if ( ! $msg ) {
565 return $msg;
566 }
567
568 $html = '<div class="tutor-alert tutor-' . esc_attr( $type ) . '">
569 <div class="tutor-alert-text">
570 <span class="tutor-alert-icon tutor-fs-4 tutor-icon-circle-info tutor-mr-12"></span>
571 <span>' . wp_kses( $msg, array( 'div', 'span' ) ) . '</span>
572 </div>
573 </div>';
574 if ( $echo ) {
575 echo tutor_kses_html( $html ); //phpcs:ignore
576 }
577 return $html;
578 }
579 }
580
581
582 /**
583 * @param bool $echo
584 *
585 * Simply call tutor_nonce_field() to generate nonce field
586 *
587 * @since v.1.4.2
588 */
589
590 if ( ! function_exists( 'tutor_nonce_field' ) ) {
591 function tutor_nonce_field( $echo = true ) {
592 wp_nonce_field( tutor()->nonce_action, tutor()->nonce, $echo );
593 }
594 }
595
596 /**
597 * @param null $key
598 * @param string $message
599 *
600 * Set Flash Message
601 */
602
603 if ( ! function_exists( 'tutor_flash_set' ) ) {
604 function tutor_flash_set( $key = null, $message = '' ) {
605 if ( ! $key ) {
606 return;
607 }
608 // ensure session is started
609 if ( session_status() !== PHP_SESSION_ACTIVE ) {
610 session_start();
611 }
612 $_SESSION[ $key ] = $message;
613 }
614 }
615
616 /**
617 * @param null $key
618 *
619 * @return array|bool|mixed|null
620 *
621 * @since v.1.4.2
622 *
623 * Get flash message
624 */
625
626 if ( ! function_exists( 'tutor_flash_get' ) ) {
627 function tutor_flash_get( $key = null ) {
628 if ( $key ) {
629 // ensure session is started
630 if ( session_status() !== PHP_SESSION_ACTIVE ) {
631 @session_start();
632 }
633 if ( empty( $_SESSION ) ) {
634 return null;
635 }
636 $message = tutor_utils()->array_get( $key, $_SESSION );
637 if ( $message ) {
638 unset( $_SESSION[ $key ] );
639 }
640 return $message;
641 }
642 return $key;
643 }
644 }
645
646 if ( ! function_exists( 'tutor_redirect_back' ) ) {
647 /**
648 * @param null $url
649 *
650 * Redirect to back or a specific URL and terminate
651 *
652 * @since v.1.4.3
653 */
654 function tutor_redirect_back( $url = null ) {
655 if ( ! $url ) {
656 $url = tutor_utils()->referer();
657 }
658 wp_safe_redirect( $url );
659 exit();
660 }
661 }
662
663 /**
664 * @param string $action
665 * @param bool $echo
666 *
667 * @return string
668 *
669 * @since v.1.4.3
670 */
671
672 if ( ! function_exists( 'tutor_action_field' ) ) {
673 function tutor_action_field( $action = '', $echo = true ) {
674 $output = '';
675 if ( $action ) {
676 $output = '<input type="hidden" name="tutor_action" value="' . esc_attr( $action ) . '">';
677 }
678
679 if ( $echo ) {
680 echo wp_kses(
681 $output,
682 array(
683 'input' => array(
684 'type' => true,
685 'name' => true,
686 'value' => true,
687 ),
688 )
689 );
690 } else {
691 return $output;
692 }
693 }
694 }
695
696
697 if ( ! function_exists( 'tutor_time' ) ) {
698 /**
699 * Return current Time from WordPress time
700 *
701 * @return int|string
702 * @since v.1.4.3
703 */
704 function tutor_time() {
705 $gmt_offset = get_option( 'gmt_offset' );
706 return time() + ( $gmt_offset * HOUR_IN_SECONDS );
707 }
708 }
709
710 /**
711 * Toggle maintenance mode for the site.
712 *
713 * Creates/deletes the maintenance file to enable/disable maintenance mode.
714 *
715 * @since v.1.4.6
716 *
717 * @global WP_Filesystem_Base $wp_filesystem Subclass
718 *
719 * @param bool $enable True to enable maintenance mode, false to disable.
720 */
721 if ( ! function_exists( 'tutor_maintenance_mode' ) ) {
722 function tutor_maintenance_mode( $enable = false ) {
723 $file = ABSPATH . '.tutor_maintenance';
724 if ( $enable ) {
725 // Create maintenance file to signal that we are upgrading
726 $maintenance_string = '<?php $upgrading = ' . time() . '; ?>';
727
728 if ( ! file_exists( $file ) ) {
729 file_put_contents( $file, $maintenance_string );
730 }
731 } else {
732 if ( file_exists( $file ) ) {
733 unlink( $file );
734 }
735 }
736 }
737 }
738
739 /**
740 * @return bool
741 *
742 * Check if the current page is course single page
743 *
744 * @since v.1.6.0
745 */
746
747 if ( ! function_exists( 'is_single_course' ) ) {
748 function is_single_course( $check_spotlight = false ) {
749 global $wp_query;
750 $course_post_type = tutor()->course_post_type;
751
752 $post_types = array( $course_post_type );
753 if ( $check_spotlight ) {
754 $post_types = array_merge(
755 $post_types,
756 array(
757 'lesson',
758 'tutor_quiz',
759 'tutor_assignments',
760 'tutor_zoom_meeting',
761 )
762 );
763 }
764
765 if ( is_single() && ! empty( $wp_query->query['post_type'] ) && in_array( $wp_query->query['post_type'], $post_types ) ) {
766 return true;
767 }
768 return false;
769 }
770 }
771
772 /**
773 * Require wp_date form return js date format.
774 * this is helpful for date picker
775 *
776 * @return string
777 *
778 * @since 1.9.7
779 */
780 if ( ! function_exists( 'tutor_js_date_format_against_wp' ) ) {
781 function tutor_js_date_format_against_wp() {
782 $wp_date_format = get_option( 'date_format' );
783 $default_format = 'Y-M-d';
784
785 $formats = array(
786 'Y-m-d' => 'Y-M-d',
787 'm/d/Y' => 'M-d-Y',
788 'd/m/Y' => 'd-M-Y',
789 'F j, Y' => 'MMMM d, yyyy',
790 'j F Y' => 'MMMM d, yyyy',
791 );
792 return isset( $formats[ $wp_date_format ] ) ? $formats[ $wp_date_format ] : $default_format;
793 }
794 }
795
796 if ( ! function_exists( 'tutor_get_formated_date' ) ) {
797 /**
798 * Convert date to desire format
799 *
800 * NOTE: mysql query use formated date from here
801 * that's why date_i18n need to be ignore
802 *
803 * @param string $require_format string If empty Y-m-d is used.
804 * @param string $user_date string Date.
805 *
806 * @return string ( date )
807 */
808 function tutor_get_formated_date( string $require_format = '', string $user_date = '' ) {
809 $require_format = $require_format ?: 'Y-m-d';
810
811 $date = date_create( str_replace( '/', '-', $user_date ) );
812 if ( is_a( $date, 'DateTime' ) ) {
813 $formatted_date = date_format( $date, $require_format );
814 } else {
815 $formatted_date = gmdate( $require_format, strtotime( $user_date ) );
816 }
817 return $formatted_date;
818 }
819 }
820
821 /**
822 * Get translated date
823 *
824 * @since v2.0.2
825 *
826 * @param string $date date in string from to translate & format.
827 * @param string $format optional date format, default is wp date time format.
828 *
829 * @return string translated date
830 */
831 if ( ! function_exists( 'tutor_i18n_get_formated_date' ) ) {
832 function tutor_i18n_get_formated_date( string $date, string $format = '' ) {
833 if ( '' === $format ) {
834 $format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
835 }
836 return date_i18n( $format, strtotime( $date ) );
837 }
838 }
839
840 if ( ! function_exists( '_tutor_search_by_title_only' ) ) {
841 /**
842 * Search SQL filter for matching against post title only.
843 *
844 * @link http://wordpress.stackexchange.com/a/11826/1685
845 *
846 * @param string $search
847 * @param WP_Query $wp_query
848 */
849 function _tutor_search_by_title_only( $search, $wp_query ) {
850 if ( ! empty( $search ) && ! empty( $wp_query->query_vars['search_terms'] ) ) {
851 global $wpdb;
852
853 $q = $wp_query->query_vars;
854 $n = ! empty( $q['exact'] ) ? '' : '%';
855
856 $search = array();
857
858 foreach ( (array) $q['search_terms'] as $term ) {
859 $search[] = $wpdb->prepare( "$wpdb->posts.post_title LIKE %s", $n . $wpdb->esc_like( $term ) . $n );
860 }
861
862 if ( ! is_user_logged_in() ) {
863 $search[] = "$wpdb->posts.post_password = ''";
864 }
865
866 $search = ' AND ' . implode( ' AND ', $search );
867 }
868
869 return $search;
870 }
871 }
872
873 if ( ! function_exists( 'get_request' ) ) {
874 /**
875 * Function to get_request
876 *
877 * @param array $var .
878 * @return array
879 */
880 function get_request( $var ) {
881 return isset( $_REQUEST[ $var ] ) ? sanitize_text_field( $_REQUEST[ $var ] ) : false;
882
883 }
884 }
885
886 if ( ! function_exists( 'tutor_kses_allowed_html' ) ) {
887 function tutor_kses_allowed_html( $allowed_tags, $context ) {
888 $tags = array( 'input', 'style', 'script', 'select', 'form', 'option', 'optgroup', 'iframe', 'bdi', 'source', 'a' );
889 $atts = array( 'min', 'max', 'maxlength', 'type', 'method', 'enctype', 'action', 'selected', 'class', 'id', 'disabled', 'checked', 'readonly', 'name', 'aria-*', 'style', 'role', 'placeholder', 'value', 'data-*', 'src', 'width', 'height', 'frameborder', 'allow', 'fullscreen', 'title', 'multiple', 'tutor-hide-course-single-sidebar', 'href' );
890
891 foreach ( $tags as $tag ) {
892 $tag_attrs = array();
893
894 foreach ( $atts as $att ) {
895 $tag_attrs[ $att ] = true;
896 }
897
898 $allowed_tags[ $tag ] = $tag_attrs;
899 }
900
901 return $allowed_tags;
902 }
903 }
904
905 if ( ! function_exists( 'tutor_kses_allowed_css' ) ) {
906 function tutor_kses_allowed_css( $styles ) {
907 $styles[] = 'display';
908 $styles[] = '--progress-value';
909 return $styles;
910 }
911 }
912
913 if ( ! function_exists( 'tutor_kses_html' ) ) {
914 function tutor_kses_html( $content ) {
915
916 return $content;
917 add_filter( 'wp_kses_allowed_html', 'tutor_kses_allowed_html', 10, 2 );
918 add_filter( 'safe_style_css', 'tutor_kses_allowed_css' );
919
920 $content = preg_replace( '/<!--(.|\s)*?-->/', '', $content );
921 $content = wp_kses_post( $content );
922 $content = str_replace( '&amp;', '&', $content );
923
924 remove_filter( 'safe_style_css', 'tutor_kses_allowed_css' );
925 remove_filter( 'wp_kses_allowed_html', 'tutor_kses_allowed_html' );
926
927 return $content;
928 }
929 }
930
931 /**
932 * @return array
933 *
934 * Get all Withdraw Methods available on this system
935 *
936 * @since v.1.5.7
937 */
938 if ( ! function_exists( 'get_tutor_all_withdrawal_methods' ) ) {
939 function get_tutor_all_withdrawal_methods() {
940 return apply_filters( 'tutor_withdrawal_methods_all', array() );
941 }
942 }
943
944
945 if ( ! function_exists( 'tutor_log' ) ) {
946 /**
947 * Logging data.
948 *
949 * @since 1.0.0
950 * @since 3.0.0 exception logging support added.
951 *
952 * @return void
953 */
954 function tutor_log() {
955 $arg_list = func_get_args();
956
957 foreach ( $arg_list as $data ) {
958 ob_start();
959
960 if ( $data instanceof Exception ) {
961 var_dump( $data->getMessage() );
962 var_dump( $data->getTraceAsString() );
963 } else {
964 var_dump( $data );
965 }
966
967 error_log( ob_get_clean() );
968 }
969 }
970 }
971
972 if ( ! function_exists( 'tutor_wc_price_currency_format' ) ) {
973 function tutor_wc_price_currency_format( $amount ) {
974
975 $symbol = get_woocommerce_currency_symbol();
976 $position = get_option( 'woocommerce_currency_pos', 'left' );
977
978 switch ( $position ) {
979 case 'left':
980 $amount = $symbol . $amount;
981 break;
982 case 'left_space':
983 $amount = $symbol . ' ' . $amount;
984 break;
985
986 case 'right':
987 $amount = $amount . $symbol;
988 break;
989 case 'right_space':
990 $amount = $amount . ' ' . $symbol;
991 break;
992
993 default:
994 $amount = $symbol . $amount;
995 break;
996 }
997
998 return $amount;
999 }
1000 }
1001
1002 if ( ! function_exists( 'tutor_meta_box_wrapper' ) ) {
1003 /**
1004 * Tutor meta box wrapper
1005 *
1006 * @since v2.0.2
1007 *
1008 * @param string $id id of meta box.
1009 * @param string $title meta box title.
1010 * @param mixed $callback callback function that meta box will call.
1011 * @param string $screen which screen meta box should appear.
1012 * @param string $context optional param. Where meta box should appear.
1013 * @param string $priority optional.
1014 * @param string $custom_class optional. If provide it will add this class along
1015 * with div id.
1016 *
1017 * @return void if class provided then filter hook will return class.
1018 */
1019 function tutor_meta_box_wrapper(
1020 $id,
1021 $title,
1022 $callback,
1023 $screen,
1024 $context = 'advanced',
1025 $priority = 'default',
1026 $custom_class = ''
1027 ) {
1028 add_meta_box(
1029 $id,
1030 $title,
1031 $callback,
1032 $screen,
1033 $context,
1034 $priority
1035 );
1036 if ( '' !== $custom_class ) {
1037 $post_type = tutor()->course_post_type;
1038 add_filter(
1039 "postbox_classes_{$post_type}_{$id}",
1040 function( $classes ) use ( $custom_class ) {
1041 if ( ! in_array( $custom_class, $classes ) ) {
1042 $classes[] = $custom_class;
1043 }
1044 return $classes;
1045 }
1046 );
1047 }
1048 }
1049 }
1050
1051 if ( ! function_exists( 'tutor_closeable_alert_msg' ) ) {
1052 /**
1053 * Create a close-able alert message
1054 *
1055 * @since 2.1.9
1056 *
1057 * @param string $message alert message.
1058 * @param string $alert alert key like: success, warning, danger, etc.
1059 * @param array $allowed_tags allowed tags to use with WP_KSES.
1060 *
1061 * @return void
1062 */
1063 function tutor_closeable_alert_msg( string $message, string $alert = 'success', $allowed_tags = array() ) {
1064 ?>
1065 <div class="tutor-alert tutor-<?php echo esc_attr( $alert ); ?> tutor-mb-12 tutor-alert tutor-success tutor-mb-12 tutor-d-flex tutor-align-center tutor-justify-between">
1066 <span>
1067 <?php echo is_array( $allowed_tags ) && count( $allowed_tags ) ? wp_kses( $message, $allowed_tags ) : esc_html( $message ); ?>
1068 </span>
1069 <span class="tutor-icon-times" area-hidden="true" onclick="this.closest('div').remove()" style="cursor: pointer;"></span>
1070 </div>
1071 <?php
1072 }
1073 }
1074
1075 if ( ! function_exists( 'tutor_set_flash_message' ) ) {
1076 /**
1077 * Utility API Set flash message to show somewhere
1078 *
1079 * It will call set_cache method of FlashMessage class to set cache
1080 *
1081 * @param mixed $message message to show.
1082 * @param string $alert alert type as FlashMessage::$alert_types.
1083 *
1084 * @return void
1085 */
1086 function tutor_set_flash_message( $message = '', $alert = 'success' ) {
1087 $flash_msg = new FlashMessage( $message, $alert );
1088 $flash_msg->set_cache();
1089 }
1090 }
1091
1092
1093 if ( ! function_exists( 'tutor_snackbar' ) ) {
1094 /**
1095 * Reuseable snackbar to show on the frontend
1096 *
1097 * Create a snackbar based on title, action buttons
1098 *
1099 * @since 2.2.0
1100 *
1101 * @param string $title title to show.
1102 * @param array $action_buttons 2 dimensional array of action buttons to show.
1103 * Supported attrs: [ [title => title, id => '', class => '' url => '', target => ''] ].
1104 * @param string $title_icon_class title icon to show before title.
1105 *
1106 * @return void
1107 */
1108 function tutor_snackbar( string $title, array $action_buttons = array(), $title_icon_class = '' ) {
1109 ?>
1110 <div id="tutor-reuseable-snackbar" class="tutor-snackbar-wrapper">
1111 <div class="tutor-snackbar">
1112 <p>
1113 <?php if ( ! empty( $title_icon_class ) ) : ?>
1114 <i class="tutor-snackbar-title-icon <?php echo esc_attr( $title_icon_class ); ?>"></i>
1115 <?php endif; ?>
1116 <?php echo esc_html( $title ); ?>
1117 </p>
1118 <div>
1119 <?php foreach ( $action_buttons as $attr => $button ) : ?>
1120 <a
1121 <?php foreach ( $button as $attr => $value ) : ?>
1122 <?php if ( ! empty( $value ) ) : ?>
1123 <?php echo esc_attr( $attr ) . '="' . esc_attr( $value ) . '" '; ?>
1124 <?php endif; ?>
1125 <?php endforeach; ?>
1126 >
1127 <?php echo esc_html( isset( $button['title'] ) ? $button['title'] : '' ); ?>
1128 </a>
1129 <?php endforeach; ?>
1130 <span class="tutor-icon-times" area-hidden="true" onclick="this.closest('#tutor-reuseable-snackbar').remove()" style="cursor: pointer;"></span>
1131 </div>
1132 </div>
1133 </div>
1134 <?php
1135 }
1136 }
1137
1138 if ( ! function_exists( 'tutor_is_rest' ) ) {
1139 /**
1140 * Checks if the current request is a WP REST API request.
1141 *
1142 * @since 2.6.0
1143 *
1144 * Case #1: After WP_REST_Request initialisation
1145 * Case #2: Support "plain" permalink settings and check if `rest_route` starts with `/`
1146 * Case #3: It can happen that WP_Rewrite is not yet initialized,
1147 * so do this (wp-settings.php)
1148 * Case #4: URL Path begins with wp-json/ (your REST prefix)
1149 * Also supports WP installations in subfolders
1150 *
1151 * @see https://wordpress.stackexchange.com/questions/221202/does-something-like-is-rest-exist
1152 * @returns boolean
1153 */
1154 function tutor_is_rest() {
1155 $rest_route = Input::get( 'rest_route' );
1156 if ( defined( 'REST_REQUEST' ) && REST_REQUEST || $rest_route && strpos( $rest_route, '/', 0 ) === 0 ) {
1157 return true;
1158 }
1159
1160 // (#3)
1161 global $wp_rewrite;
1162 if ( null === $wp_rewrite ) {
1163 $wp_rewrite = new WP_Rewrite();
1164 }
1165
1166 // (#4)
1167 $rest_url = wp_parse_url( trailingslashit( rest_url() ) );
1168 $current_url = wp_parse_url( add_query_arg( array() ) );
1169 return strpos( $current_url['path'] ?? '/', $rest_url['path'], 0 ) === 0;
1170 }
1171 }
1172
1173 if ( ! function_exists( 'tutor_getallheaders' ) ) {
1174 /**
1175 * Wrapper of PHP getallheaders with a fallback if getallheaders not available
1176 *
1177 * @since 2.6.0
1178 *
1179 * @see https://www.php.net/manual/en/function.getallheaders.php
1180 *
1181 * @return array of headers
1182 */
1183 function tutor_getallheaders() {
1184 $headers = array();
1185 if ( function_exists( 'getallheaders' ) ) {
1186 $headers = getallheaders();
1187 }
1188
1189 if ( ! $headers ) {
1190 foreach ( $_SERVER as $name => $value ) {
1191 if ( substr( $name, 0, 5 ) == 'HTTP_' ) {
1192 $headers[ str_replace( ' ', '-', ucwords( strtolower( str_replace( '_', ' ', substr( $name, 5 ) ) ) ) ) ] = $value;
1193 }
1194 }
1195 }
1196
1197 return $headers;
1198 }
1199 }
1200
1201 if ( ! function_exists( 'tutor_entry_box_buttons' ) ) {
1202 /**
1203 * Tutor conditional buttons for the enrollment box
1204 *
1205 * @since 2.6.0
1206 *
1207 * @param int $course_id course id.
1208 * @param int $user_id user id.
1209 *
1210 * @return object
1211 */
1212 function tutor_entry_box_buttons( int $course_id = 0, int $user_id = 0 ) {
1213 $conditional_buttons = (object) array(
1214 'show_enroll_btn' => false,
1215 'show_add_to_cart_btn' => false,
1216 'show_view_cart_btn' => false,
1217 'show_start_learning_btn' => false,
1218 'show_continue_learning_btn' => false,
1219 'show_complete_course_btn' => false,
1220 'show_retake_course_btn' => false,
1221 'show_certificate_view_btn' => false,
1222 'show_course_fully_booked_btn' => false,
1223 );
1224
1225 $course_id = tutor_utils()->get_post_id( $course_id );
1226 $user_id = tutor_utils()->get_user_id( $user_id );
1227
1228 $has_course_access = tutor_utils()->has_user_course_content_access( $user_id, $course_id );
1229
1230 $is_public_course = get_post_meta( $course_id, '_tutor_is_public_course', true );
1231
1232 $is_enabled_retake = tutor_utils()->get_option( 'course_retake_feature' );
1233
1234 $is_enrolled = tutor_utils()->is_enrolled( $course_id, $user_id );
1235
1236 if ( 'yes' === $is_public_course ) {
1237 $conditional_buttons->show_start_learning_btn = true;
1238 } else {
1239 // Admin & instructor can manage posts.
1240 if ( $is_enrolled || $has_course_access ) {
1241 $can_complete_course = CourseModel::can_complete_course( $course_id, $user_id );
1242 $is_completed_course = tutor_utils()->is_completed_course( $course_id, $user_id );
1243 $course_progress = (int) tutor_utils()->get_course_completed_percent( $course_id, $user_id );
1244
1245 if ( $course_progress > 0 && $course_progress < 100 ) {
1246 $conditional_buttons->show_continue_learning_btn = true;
1247 }
1248
1249 if ( 0 === $course_progress ) {
1250 $conditional_buttons->show_start_learning_btn = true;
1251 }
1252
1253 if ( $can_complete_course ) {
1254 $conditional_buttons->show_complete_course_btn = true;
1255 }
1256
1257 if ( $is_completed_course ) {
1258 $conditional_buttons->show_certificate_view_btn = true;
1259 }
1260
1261 if ( $is_enabled_retake && $is_completed_course ) {
1262 $conditional_buttons->show_retake_course_btn = true;
1263 }
1264 } else {
1265 $is_paid_course = tutor_utils()->is_course_purchasable( $course_id );
1266 if ( $is_paid_course ) {
1267 if ( tutor_is_item_in_cart( $course_id ) ) {
1268 $conditional_buttons->show_view_cart_btn = true;
1269 } else {
1270 $conditional_buttons->show_add_to_cart_btn = true;
1271 }
1272 } else {
1273 $conditional_buttons->show_enroll_btn = true;
1274 }
1275 }
1276 }
1277
1278 if ( ! $is_public_course && ! ( $is_enrolled || $has_course_access ) ) {
1279 $is_fully_booked = tutor_utils()->is_course_fully_booked( $course_id );
1280 if ( $is_fully_booked ) {
1281 $conditional_buttons->show_course_fully_booked_btn = true;
1282 }
1283 }
1284
1285 return apply_filters( 'tutor_enrollment_buttons', $conditional_buttons );
1286 }
1287 }
1288
1289 if ( ! function_exists( 'tutor_global_timezone_lists' ) ) {
1290 /**
1291 * Get list of global timezones
1292 *
1293 * @return array
1294 */
1295 function tutor_global_timezone_lists() {
1296 return array(
1297 'Pacific/Midway' => '(GMT-11:00) Midway Island, Samoa ',
1298 'Pacific/Pago_Pago' => '(GMT-11:00) Pago Pago ',
1299 'Pacific/Honolulu' => '(GMT-10:00) Hawaii ',
1300 'America/Anchorage' => '(GMT-8:00) Alaska ',
1301 'America/Vancouver' => '(GMT-7:00) Vancouver ',
1302 'America/Los_Angeles' => '(GMT-7:00) Pacific Time (US and Canada) ',
1303 'America/Tijuana' => '(GMT-7:00) Tijuana ',
1304 'America/Phoenix' => '(GMT-7:00) Arizona ',
1305 'America/Edmonton' => '(GMT-6:00) Edmonton ',
1306 'America/Denver' => '(GMT-6:00) Mountain Time (US and Canada) ',
1307 'America/Mazatlan' => '(GMT-6:00) Mazatlan ',
1308 'America/Regina' => '(GMT-6:00) Saskatchewan ',
1309 'America/Guatemala' => '(GMT-6:00) Guatemala ',
1310 'America/El_Salvador' => '(GMT-6:00) El Salvador ',
1311 'America/Managua' => '(GMT-6:00) Managua ',
1312 'America/Costa_Rica' => '(GMT-6:00) Costa Rica ',
1313 'America/Tegucigalpa' => '(GMT-6:00) Tegucigalpa ',
1314 'America/Winnipeg' => '(GMT-5:00) Winnipeg ',
1315 'America/Chicago' => '(GMT-5:00) Central Time (US and Canada) ',
1316 'America/Mexico_City' => '(GMT-5:00) Mexico City ',
1317 'America/Panama' => '(GMT-5:00) Panama ',
1318 'America/Bogota' => '(GMT-5:00) Bogota ',
1319 'America/Lima' => '(GMT-5:00) Lima ',
1320 'America/Caracas' => '(GMT-4:30) Caracas ',
1321 'America/Montreal' => '(GMT-4:00) Montreal ',
1322 'America/New_York' => '(GMT-4:00) Eastern Time (US and Canada) ',
1323 'America/Indianapolis' => '(GMT-4:00) Indiana (East) ',
1324 'America/Puerto_Rico' => '(GMT-4:00) Puerto Rico ',
1325 'America/Santiago' => '(GMT-4:00) Santiago ',
1326 'America/Halifax' => '(GMT-3:00) Halifax ',
1327 'America/Montevideo' => '(GMT-3:00) Montevideo ',
1328 'America/Araguaina' => '(GMT-3:00) Brasilia ',
1329 'America/Argentina/Buenos_Aires' => '(GMT-3:00) Buenos Aires, Georgetown ',
1330 'America/Sao_Paulo' => '(GMT-3:00) Sao Paulo ',
1331 'Canada/Atlantic' => '(GMT-3:00) Atlantic Time (Canada) ',
1332 'America/St_Johns' => '(GMT-2:30) Newfoundland and Labrador ',
1333 'America/Godthab' => '(GMT-2:00) Greenland ',
1334 'Atlantic/Cape_Verde' => '(GMT-1:00) Cape Verde Islands ',
1335 'Atlantic/Azores' => '(GMT+0:00) Azores ',
1336 'UTC' => '(GMT+0:00) Universal Time UTC ',
1337 'Etc/Greenwich' => '(GMT+0:00) Greenwich Mean Time ',
1338 'Atlantic/Reykjavik' => '(GMT+0:00) Reykjavik ',
1339 'Africa/Nouakchott' => '(GMT+0:00) Nouakchott ',
1340 'Europe/Dublin' => '(GMT+1:00) Dublin ',
1341 'Europe/London' => '(GMT+1:00) London ',
1342 'Europe/Lisbon' => '(GMT+1:00) Lisbon ',
1343 'Africa/Casablanca' => '(GMT+1:00) Casablanca ',
1344 'Africa/Bangui' => '(GMT+1:00) West Central Africa ',
1345 'Africa/Algiers' => '(GMT+1:00) Algiers ',
1346 'Africa/Tunis' => '(GMT+1:00) Tunis ',
1347 'Europe/Belgrade' => '(GMT+2:00) Belgrade, Bratislava, Ljubljana ',
1348 'CET' => '(GMT+2:00) Sarajevo, Skopje, Zagreb ',
1349 'Europe/Oslo' => '(GMT+2:00) Oslo ',
1350 'Europe/Copenhagen' => '(GMT+2:00) Copenhagen ',
1351 'Europe/Brussels' => '(GMT+2:00) Brussels ',
1352 'Europe/Berlin' => '(GMT+2:00) Amsterdam, Berlin, Rome, Stockholm, Vienna ',
1353 'Europe/Amsterdam' => '(GMT+2:00) Amsterdam ',
1354 'Europe/Rome' => '(GMT+2:00) Rome ',
1355 'Europe/Stockholm' => '(GMT+2:00) Stockholm ',
1356 'Europe/Vienna' => '(GMT+2:00) Vienna ',
1357 'Europe/Luxembourg' => '(GMT+2:00) Luxembourg ',
1358 'Europe/Paris' => '(GMT+2:00) Paris ',
1359 'Europe/Zurich' => '(GMT+2:00) Zurich ',
1360 'Europe/Madrid' => '(GMT+2:00) Madrid ',
1361 'Africa/Harare' => '(GMT+2:00) Harare, Pretoria ',
1362 'Europe/Warsaw' => '(GMT+2:00) Warsaw ',
1363 'Europe/Prague' => '(GMT+2:00) Prague Bratislava ',
1364 'Europe/Budapest' => '(GMT+2:00) Budapest ',
1365 'Africa/Tripoli' => '(GMT+2:00) Tripoli ',
1366 'Africa/Cairo' => '(GMT+2:00) Cairo ',
1367 'Africa/Johannesburg' => '(GMT+2:00) Johannesburg ',
1368 'Europe/Helsinki' => '(GMT+3:00) Helsinki ',
1369 'Africa/Nairobi' => '(GMT+3:00) Nairobi ',
1370 'Europe/Sofia' => '(GMT+3:00) Sofia ',
1371 'Europe/Istanbul' => '(GMT+3:00) Istanbul ',
1372 'Europe/Athens' => '(GMT+3:00) Athens ',
1373 'Europe/Bucharest' => '(GMT+3:00) Bucharest ',
1374 'Asia/Nicosia' => '(GMT+3:00) Nicosia ',
1375 'Asia/Beirut' => '(GMT+3:00) Beirut ',
1376 'Asia/Damascus' => '(GMT+3:00) Damascus ',
1377 'Asia/Jerusalem' => '(GMT+3:00) Jerusalem ',
1378 'Asia/Amman' => '(GMT+3:00) Amman ',
1379 'Europe/Moscow' => '(GMT+3:00) Moscow ',
1380 'Asia/Baghdad' => '(GMT+3:00) Baghdad ',
1381 'Asia/Kuwait' => '(GMT+3:00) Kuwait ',
1382 'Asia/Riyadh' => '(GMT+3:00) Riyadh ',
1383 'Asia/Bahrain' => '(GMT+3:00) Bahrain ',
1384 'Asia/Qatar' => '(GMT+3:00) Qatar ',
1385 'Asia/Aden' => '(GMT+3:00) Aden ',
1386 'Africa/Khartoum' => '(GMT+3:00) Khartoum ',
1387 'Africa/Djibouti' => '(GMT+3:00) Djibouti ',
1388 'Africa/Mogadishu' => '(GMT+3:00) Mogadishu ',
1389 'Europe/Kiev' => '(GMT+3:00) Kiev ',
1390 'Asia/Dubai' => '(GMT+4:00) Dubai ',
1391 'Asia/Muscat' => '(GMT+4:00) Muscat ',
1392 'Asia/Tehran' => '(GMT+4:30) Tehran ',
1393 'Asia/Kabul' => '(GMT+4:30) Kabul ',
1394 'Asia/Baku' => '(GMT+5:00) Baku, Tbilisi, Yerevan ',
1395 'Asia/Yekaterinburg' => '(GMT+5:00) Yekaterinburg ',
1396 'Asia/Tashkent' => '(GMT+5:00) Tashkent ',
1397 'Asia/Karachi' => '(GMT+5:00) Islamabad, Karachi ',
1398 'Asia/Calcutta' => '(GMT+5:30) India ',
1399 'Asia/Kolkata' => '(GMT+5:30) Mumbai, Kolkata, New Delhi ',
1400 'Asia/Kathmandu' => '(GMT+5:45) Kathmandu ',
1401 'Asia/Novosibirsk' => '(GMT+6:00) Novosibirsk ',
1402 'Asia/Almaty' => '(GMT+6:00) Almaty ',
1403 'Asia/Dacca' => '(GMT+6:00) Dacca ',
1404 'Asia/Dhaka' => '(GMT+6:00) Astana, Dhaka ',
1405 'Asia/Krasnoyarsk' => '(GMT+7:00) Krasnoyarsk ',
1406 'Asia/Bangkok' => '(GMT+7:00) Bangkok ',
1407 'Asia/Saigon' => '(GMT+7:00) Vietnam ',
1408 'Asia/Jakarta' => '(GMT+7:00) Jakarta ',
1409 'Asia/Irkutsk' => '(GMT+8:00) Irkutsk, Ulaanbaatar ',
1410 'Asia/Shanghai' => '(GMT+8:00) Beijing, Shanghai ',
1411 'Asia/Hong_Kong' => '(GMT+8:00) Hong Kong ',
1412 'Asia/Taipei' => '(GMT+8:00) Taipei ',
1413 'Asia/Kuala_Lumpur' => '(GMT+8:00) Kuala Lumpur ',
1414 'Asia/Singapore' => '(GMT+8:00) Singapore ',
1415 'Australia/Perth' => '(GMT+8:00) Perth ',
1416 'Asia/Yakutsk' => '(GMT+9:00) Yakutsk ',
1417 'Asia/Seoul' => '(GMT+9:00) Seoul ',
1418 'Asia/Tokyo' => '(GMT+9:00) Osaka, Sapporo, Tokyo ',
1419 'Australia/Darwin' => '(GMT+9:30) Darwin ',
1420 'Australia/Adelaide' => '(GMT+9:30) Adelaide ',
1421 'Asia/Vladivostok' => '(GMT+10:00) Vladivostok ',
1422 'Pacific/Port_Moresby' => '(GMT+10:00) Guam, Port Moresby ',
1423 'Australia/Brisbane' => '(GMT+10:00) Brisbane ',
1424 'Australia/Sydney' => '(GMT+10:00) Canberra, Melbourne, Sydney ',
1425 'Australia/Hobart' => '(GMT+10:00) Hobart ',
1426 'Asia/Magadan' => '(GMT+10:00) Magadan ',
1427 'SST' => '(GMT+11:00) Solomon Islands ',
1428 'Pacific/Noumea' => '(GMT+11:00) New Caledonia ',
1429 'Asia/Kamchatka' => '(GMT+12:00) Kamchatka ',
1430 'Pacific/Fiji' => '(GMT+12:00) Fiji Islands, Marshall Islands ',
1431 'Pacific/Auckland' => '(GMT+12:00) Auckland, Wellington',
1432 );
1433 }
1434
1435 if ( ! function_exists( 'tutor_get_all_active_payment_gateways' ) ) {
1436 /**
1437 * Get all active payment gateways including manual & automate
1438 *
1439 * @since 3.0.0
1440 *
1441 * @return array
1442 */
1443 function tutor_get_all_active_payment_gateways() {
1444 $payment_settings = Settings::get_payment_settings();
1445 $payment_methods = ! empty( $payment_settings['payment_methods'] ) ? $payment_settings['payment_methods'] : array();
1446
1447 $active_gateways = array();
1448
1449 foreach ( $payment_methods as $method ) {
1450 $is_active = $method['is_active'] ?? false;
1451 $is_manual = $method['is_manual'] ?? false;
1452 if ( ! $is_active ) {
1453 continue;
1454 }
1455
1456 $name = $method['name'];
1457 $basename = "tutor-{$name}/tutor-{$name}.php";
1458 $is_plugin_activated = is_plugin_active( $basename );
1459 if ( ! $is_manual && 'paypal' !== $name && ! $is_plugin_activated ) {
1460 continue;
1461 }
1462
1463 $fields = $method['fields'];
1464 unset( $method['fields'] );
1465
1466 $gateway = $method;
1467 if ( $is_manual ) {
1468 foreach ( $fields as $field ) {
1469 if ( 'payment_instructions' === $field['name'] || 'additional_details' === $field['name'] ) {
1470 $gateway[ $field['name'] ] = $field['value'];
1471 }
1472 }
1473 }
1474
1475 $active_gateways[] = $gateway;
1476 }
1477
1478 return $active_gateways;
1479 }
1480 }
1481
1482 if ( ! function_exists( 'tutor_get_subscription_supported_payment_gateways' ) ) {
1483 /**
1484 * Get all supported gateways
1485 *
1486 * This function will return only subscription supported gateways if
1487 * plan id provided.
1488 *
1489 * @since 3.0.0
1490 * @since 3.4.0 plan_id param removed
1491 *
1492 * @return array
1493 */
1494 function tutor_get_subscription_supported_payment_gateways() {
1495 $payment_gateways = tutor_get_all_active_payment_gateways();
1496
1497 $supported_gateways = array();
1498 foreach ( $payment_gateways as $gateway ) {
1499 $support_subscription = $gateway['support_subscription'] ?? false;
1500
1501 if ( ! $support_subscription ) {
1502 continue;
1503 }
1504
1505 $supported_gateways[] = array(
1506 'name' => $gateway['name'] ?? '',
1507 'label' => $gateway['label'] ?? '',
1508 'icon' => $gateway['icon'] ?? '',
1509 'support_subscription' => $gateway['support_subscription'] ?? '',
1510 'is_manual' => $gateway['is_manual'] ?? '',
1511 'additional_details' => $gateway['additional_details'] ?? '',
1512 'payment_instructions' => $gateway['payment_instructions'] ?? '',
1513 );
1514 }
1515
1516 return $supported_gateways;
1517 }
1518 }
1519
1520 if ( ! function_exists( 'tutor_get_manual_payment_gateways' ) ) {
1521 /**
1522 * Get manual payment gateways
1523 *
1524 * @since 3.0.0
1525 *
1526 * @return array
1527 */
1528 function tutor_get_manual_payment_gateways() {
1529 $payments = tutor_utils()->get_option( 'payment_settings' );
1530 $payments = json_decode( stripslashes( $payments ) );
1531
1532 $manual_methods = array();
1533
1534 if ( $payments ) {
1535 foreach ( $payments->payment_methods as $method ) {
1536 if ( isset( $method->is_manual ) && 1 === (int) $method->is_manual ) {
1537 $manual_methods[] = $method;
1538 }
1539 }
1540 }
1541
1542 return apply_filters( 'tutor_manual_payment_methods', $manual_methods );
1543 }
1544 }
1545 }
1546
1547 if ( ! function_exists( 'tutor_get_course_formatted_price_html' ) ) {
1548 /**
1549 * Get course formatted price
1550 * Only for monetized by tutor.
1551 *
1552 * @since 3.0.0
1553 *
1554 * @param int $course_id Course price.
1555 * @param boolean $echo Whether to echo content.
1556 *
1557 * @return string|void
1558 */
1559 function tutor_get_course_formatted_price_html( $course_id, $echo = true ) {
1560 $price_data = tutor_utils()->get_raw_course_price( $course_id );
1561
1562 if ( ! $price_data->regular_price ) {
1563 return;
1564 }
1565 ob_start();
1566 ?>
1567 <div class="list-item-price tutor-item-price">
1568 <?php if ( $price_data->sale_price ) : ?>
1569 <span><?php tutor_print_formatted_price( $price_data->display_price ); ?></span>
1570 <del><?php tutor_print_formatted_price( $price_data->regular_price ); ?></del>
1571 <?php else : ?>
1572 <span><?php tutor_print_formatted_price( $price_data->display_price ); ?></span>
1573 <?php endif; ?>
1574 </div>
1575 <?php if ( $price_data->show_price_with_tax ) : ?>
1576 <div class="tutor-course-price-tax tutor-fs-8 tutor-fw-normal tutor-color-black"><?php esc_html_e( 'Incl. tax', 'tutor' ); ?></div>
1577 <?php endif; ?>
1578 <?php
1579 $content = apply_filters( 'tutor_course_formatted_price', ob_get_clean() );
1580 if ( $echo ) {
1581 echo $content; // PHPCS:ignore
1582 } else {
1583 return $content;
1584 }
1585 }
1586 }
1587
1588 if ( ! function_exists( 'tutor_get_formatted_price' ) ) {
1589 /**
1590 * Get course formatted price
1591 *
1592 * Formatting as per ecommerce price settings
1593 *
1594 * @since 3.0.0
1595 *
1596 * @param mixed $price Raw price.
1597 *
1598 * @return string|void
1599 */
1600 function tutor_get_formatted_price( $price ) {
1601 $price = floatval( Input::sanitize( $price ) );
1602
1603 $currency_symbol = Settings::get_currency_symbol_by_code( tutor_utils()->get_option( OptionKeys::CURRENCY_CODE, 'USD' ) );
1604 $currency_position = tutor_utils()->get_option( OptionKeys::CURRENCY_POSITION, 'left' );
1605 $thousand_separator = tutor_utils()->get_option( OptionKeys::THOUSAND_SEPARATOR, ',' );
1606 $decimal_separator = tutor_utils()->get_option( OptionKeys::DECIMAL_SEPARATOR, '.' );
1607 $no_of_decimal = tutor_utils()->get_option( OptionKeys::NUMBER_OF_DECIMALS, '2' );
1608
1609 $price = number_format( $price, $no_of_decimal, $decimal_separator, $thousand_separator );
1610 $price = 'left' === $currency_position ? $currency_symbol . $price : $price . $currency_symbol;
1611
1612 return $price;
1613 }
1614 }
1615
1616 if ( ! function_exists( 'tutor_print_formatted_price' ) ) {
1617 /**
1618 * A clone copy of `tutor_get_formatted_price` helper
1619 * To print formated price with output scaping.
1620 *
1621 * @since 3.0.0
1622 *
1623 * @param mixed $price price.
1624 *
1625 * @return void
1626 */
1627 function tutor_print_formatted_price( $price ) {
1628 echo esc_html( tutor_get_formatted_price( $price ) );
1629 }
1630 }
1631
1632 if ( ! function_exists( 'tutor_get_locale_price' ) ) {
1633 /**
1634 * Get price as per locale format
1635 *
1636 * For locale settings currency code will be used
1637 *
1638 * @since 3.0.0
1639 *
1640 * @param mixed $price Raw price.
1641 *
1642 * @return mixed raw price.
1643 */
1644 function tutor_get_locale_price( $price ) {
1645 // TODO: implement price formation.
1646 return $price;
1647 }
1648 }
1649
1650 if ( ! function_exists( 'tutor_is_json' ) ) {
1651 /**
1652 * Check a string is valid JSON.
1653 *
1654 * @param string $string string.
1655 *
1656 * @return boolean
1657 */
1658 function tutor_is_json( $string ) {
1659 json_decode( $string );
1660 return json_last_error() === JSON_ERROR_NONE;
1661 }
1662 }
1663
1664 if ( ! function_exists( 'tutor_is_dev_mode' ) ) {
1665 /**
1666 * Check tutor is in development mode or not.
1667 *
1668 * @since 3.0.0
1669 *
1670 * @return bool True if the current environment is local, false otherwise.
1671 */
1672 function tutor_is_dev_mode() {
1673 return defined( 'TUTOR_DEV_MODE' ) && TUTOR_DEV_MODE;
1674 }
1675 }
1676
1677 if ( ! function_exists( 'tutor_redirect_after_payment' ) ) {
1678 /**
1679 * Redirect after payment with status and message
1680 *
1681 * @since 3.0.0
1682 *
1683 * @param string $status Success or error status of payment.
1684 * @param int $order_id Order ID.
1685 * @param string $message Success/error message to display.
1686 *
1687 * @return void
1688 */
1689 function tutor_redirect_after_payment( $status, $order_id, $message = '' ) {
1690 $query_params = array(
1691 'tutor_order_placement' => $status,
1692 'order_id' => $order_id,
1693 );
1694
1695 if ( $message ) {
1696 if ( 'success' === $status ) {
1697 $query_params['success_message'] = $message;
1698 } else {
1699 $query_params['error_message'] = $message;
1700 }
1701 }
1702
1703 wp_safe_redirect( apply_filters( 'tutor_redirect_url_after_checkout', add_query_arg( $query_params, home_url() ), $status, $order_id ) );
1704 exit();
1705 }
1706 }
1707
1708 if ( ! function_exists( 'tutor_split_amounts' ) ) {
1709 /**
1710 * Split amounts into parts for admin & instructor
1711 *
1712 * Amount split will be proportionally based on
1713 * admin commission rate & instructor commission rate.
1714 *
1715 * @since 3.0.0
1716 *
1717 * @param array $amounts Single amount or list of amount array. For ex: [12,20,100].
1718 *
1719 * @return array
1720 */
1721 function tutor_split_amounts( $amounts ) {
1722 $amounts = is_array( $amounts ) ? $amounts : array( $amounts );
1723
1724 $admin_amount = 0;
1725 $instructor_amount = 0;
1726
1727 $sharing_enabled = tutor_utils()->get_option( 'enable_revenue_sharing' );
1728 $instructor_rate = $sharing_enabled ? tutor_utils()->get_option( 'earning_instructor_commission' ) : 0;
1729 $admin_rate = $sharing_enabled ? tutor_utils()->get_option( 'earning_admin_commission' ) : 100;
1730
1731 foreach ( $amounts as $amount ) {
1732 $instructor_amount = $instructor_rate > 0 ? ( ( $amount * $instructor_rate ) / 100 ) : 0;
1733 $admin_amount = $admin_rate > 0 ? ( ( $amount * $admin_rate ) / 100 ) : 0;
1734 }
1735
1736 return array(
1737 'admin' => $admin_amount,
1738 'instructor' => $instructor_amount,
1739 );
1740 }
1741 }
1742
1743 if ( ! function_exists( 'tutor_is_local_env' ) ) {
1744 /**
1745 * Check if the current environment is local.
1746 *
1747 * @since 3.2.0
1748 *
1749 * @return bool True if the current environment is local, false otherwise.
1750 */
1751 function tutor_is_local_env() {
1752 $site_url = site_url();
1753 return (
1754 strpos( $site_url, '.local' ) !== false ||
1755 strpos( $site_url, 'localhost' ) !== false
1756 );
1757 }
1758 }
1759
1760
1761
1762 if ( ! function_exists( 'get_tutor_post_types') ) {
1763 /**
1764 * Get tutor post type list
1765 *
1766 * @since 3.6.0
1767 *
1768 * @param string $post_type the post type to get single tutor valid post type
1769 *
1770 * @return array|string
1771 */
1772 function get_tutor_post_types( $post_type = '' ) {
1773 $valid_post_types = array(
1774 'course' => tutor()->course_post_type,
1775 'bundle' => tutor()->bundle_post_type,
1776 'lesson' => tutor()->lesson_post_type,
1777 'topics' => tutor()->topics_post_type,
1778 'quiz' => tutor()->quiz_post_type,
1779 'assignment' => tutor()->assignment_post_type,
1780 'zoom' => tutor()->zoom_post_type,
1781 'meet' => tutor()->meet_post_type,
1782 'enrollment' => tutor()->enrollment_post_type,
1783 'announcement' => tutor()->announcement_post_type,
1784 );
1785
1786 if ( $post_type && isset( $valid_post_types[ $post_type ] ) ) {
1787 return $valid_post_types[ $post_type ];
1788 }
1789
1790 return $valid_post_types;
1791 }
1792 }