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