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