PluginProbe
Tutor LMS – eLearning and online course solution / 1.8.10
Tutor LMS – eLearning and online course solution v1.8.10
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 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 All 191 releases
← All changes | classes/Utils.php +4130 -7688 trunk1.8.10 View file →
@@ -1,372 +1,116 @@
1 1 <?php
2 2 /**
3 3 * Tutor Utils Helper functions
4 + * @package TUTOR
4 5 *
5 - * @package Tutor\Utils
6 - * @author Themeum <support@themeum.com>
7 - * @link https://themeum.com
8 - * @since 1.0.0
6 + * @since v.1.0.0
9 7 */
10 8
11 9 namespace TUTOR;
12 10
13 -defined( 'ABSPATH' ) || exit;
11 +if ( ! defined( 'ABSPATH' ) )
12 + exit;
14 13
15 -use Tutor\Cache\TutorCache;
16 -use Tutor\Ecommerce\Ecommerce;
17 -use Tutor\Ecommerce\OptionKeys;
18 -use Tutor\Ecommerce\Settings;
19 -use Tutor\Ecommerce\Tax;
20 -use Tutor\Helpers\DateTimeHelper;
21 -use Tutor\Helpers\HttpHelper;
22 -use Tutor\Helpers\QueryHelper;
23 -use Tutor\Helpers\UrlHelper;
24 -use TUTOR\Icon;
25 -use Tutor\Models\CourseModel;
26 -use Tutor\Models\EnrollmentModel;
27 -use Tutor\Models\QuizModel;
28 -use Tutor\Options_V2;
29 -use Tutor\Traits\JsonResponse;
30 -
31 -/**
32 - * Utility methods
33 - *
34 - * @since 1.0.0
35 - */
36 14 class Utils {
37 - use JsonResponse;
38 -
39 15 /**
40 - * Compatibility for splitting utils functions to specific model
16 + * @param null $key
17 + * @param bool $default
41 18 *
42 - * @since 2.0.6
19 + * @return array|bool|mixed
43 20 *
44 - * @param string $method method name.
45 - * @param array $args args.
46 - *
47 - * @return mixed
48 - */
49 - public function __call( $method, $args ) {
50 - $classes = array(
51 - 'Tutor\Models\CourseModel',
52 - 'Tutor\Models\LessonModel',
53 - 'Tutor\Models\QuizModel',
54 - 'Tutor\Models\WithdrawModel',
55 - 'Tutor\Models\EnrollmentModel',
56 - );
57 -
58 - foreach ( $classes as $class ) {
59 - //phpcs:ignore
60 - if ( method_exists( $obj = new $class(), $method ) ) {
61 - return $obj->$method( ...$args );
62 - }
63 - }
64 - }
65 -
66 - /**
67 - * Check an array is sequential or associative
68 - *
69 - * @since 2.0.9
70 - *
71 - * @param array $array The array to check.
72 - *
73 - * @return bool true if the array is associative, false if it's sequential.
74 - */
75 - public function is_assoc( array $array ) {
76 - return array_keys( $array ) !== range( 0, count( $array ) - 1 );
77 - }
78 -
79 - /**
80 - * Redirect to URL
81 - *
82 - * @since 2.1.0
83 - *
84 - * @param string $url URL.
85 - * @param string $flash_message flash message.
86 - * @param string $flash_type flash type.
87 - *
88 - * @return void
89 - */
90 - public function redirect_to( string $url, $flash_message = null, $flash_type = 'success' ) {
91 - $url = esc_url( trim( $url ) );
92 -
93 - $available_types = array( 'success', 'error' );
94 - if ( ! empty( $flash_message ) && in_array( $flash_type, $available_types ) ) {
95 - set_transient( 'tutor_flash_type', $flash_type );
96 - set_transient( 'tutor_flash_message', $flash_message );
97 - }
98 -
99 - if ( ! headers_sent() ) {
100 - wp_safe_redirect( $url );
101 - } else {
102 - echo '<script>window.location.href = ' . "'" . esc_url( $url ) . "';" . '</script>';
103 - }
104 -
105 - exit;
106 - }
107 -
108 - /**
109 - * Handle flash message for redirect_to util helper
110 - *
111 - * @since 2.1.0
112 - *
113 - * @return void
114 - */
115 - public function handle_flash_message() {
116 - if ( false !== get_transient( 'tutor_flash_type' ) && false !== get_transient( 'tutor_flash_message' ) ) {
117 - $type = get_transient( 'tutor_flash_type' );
118 - $message = get_transient( 'tutor_flash_message' );
119 - if ( 'success' === $type && ! empty( $message ) ) {
120 - ?>
121 - <script type="text/javascript">
122 - window.onload = function(){
123 - const { __ } = wp.i18n;
124 - tutor_toast( __( 'Success!', 'tutor' ), '<?php echo esc_html( $message ); ?>', 'success' )
125 - };
126 - </script>
127 - <?php
128 - }
129 - if ( 'error' === $type && ! empty( $message ) ) {
130 - ?>
131 - <script type="text/javascript">
132 - window.onload = function(){
133 - const { __ } = wp.i18n;
134 - tutor_toast( __( 'Error!', 'tutor' ), '<?php echo esc_html( $message ); ?>', 'error' )
135 - };
136 - </script>
137 - <?php
138 - }
139 -
140 - // Delete flash message.
141 - delete_transient( 'tutor_flash_type' );
142 - delete_transient( 'tutor_flash_message' );
143 - }
144 - }
145 -
146 - /**
147 - * Add setting's option after a setting key
148 - *
149 - * @since 2.1.0
150 - *
151 - * @param string $target_key setting's key name like 'tutor_version'.
152 - * @param array $arr an multi-dimentional settings option array.
153 - * @param array $new_item new setting array. a 'key' needed.
154 - *
155 - * @return int|null inserted index number or null
156 - */
157 - public function add_option_after( string $target_key, array &$arr, array $new_item ) {
158 - if ( ! is_array( $arr ) || ! is_array( $new_item ) ) {
159 - return;
160 - }
161 -
162 - $found_index = null;
163 - foreach ( $arr as $index => $inner_arr ) {
164 - if ( is_array( $inner_arr ) && array_key_exists( 'key', $inner_arr ) && $inner_arr['key'] == $target_key ) {
165 - $found_index = $index;
166 - break;
167 - }
168 - }
169 -
170 - if ( null !== $found_index && array_key_exists( 'key', $new_item ) ) {
171 - $target_index = $found_index + 1;
172 - array_splice( $arr, $target_index, 0, array( $new_item ) );
173 - return $target_index;
174 - }
175 - }
176 -
177 - /**
178 - * Get human readable file size from file path
179 - *
180 - * @since 2.1.0
181 - *
182 - * @param string $file_path file path.
183 - *
184 - * @return string
185 - */
186 - public function get_readable_filesize( string $file_path ) {
187 - return size_format( file_exists( $file_path ) ? filesize( $file_path ) : 0 );
188 - }
189 -
190 - /**
191 - * Option recursive
192 - *
193 - * @since 1.0.0
194 - *
195 - * @param array $array array.
196 - * @param string $key option key.
197 - *
198 - * @return mixed
199 - */
200 - private function option_recursive( $array, $key ) {
201 - foreach ( $array as $option ) {
202 - $is_array = is_array( $option );
203 -
204 - if ( $is_array && isset( $option['key'], $option['default'] ) && $option['key'] == $key ) {
205 - $value = $option['default'];
206 - 'on' === $option['default'] ? $value = true : 0;
207 - 'off' === $option['default'] ? $value = false : 0;
208 -
209 - return $value;
210 - }
211 -
212 - $value = $is_array ? $this->option_recursive( $option, $key ) : null;
213 -
214 - if ( ! ( null === $value ) ) {
215 - return $value;
216 - }
217 - }
218 -
219 - return null;
220 - }
221 -
222 - /**
223 - * Get default value for a tutor option.
224 - *
225 - * @since 1.0.0
226 - *
227 - * @param string $key option key.
228 - * @param mixed $fallback fallback value.
229 - * @param mixed $from_options from option.
230 - *
231 - * @return mixed
232 - */
233 - private function get_option_default( $key, $fallback, $from_options ) {
234 - if ( ! $from_options ) {
235 - // Avoid infinity recursion.
236 - return $fallback;
237 - }
238 -
239 - $tutor_options_array = ( new Options_V2( false ) )->get_setting_fields();
240 - ! is_array( $tutor_options_array ) ? $tutor_options_array = array() : 0;
241 -
242 - $default_value = $this->option_recursive( $tutor_options_array, $key );
243 -
244 - return null === $default_value ? $fallback : $default_value;
245 - }
246 -
247 - /**
248 21 * Get option data
249 22 *
250 - * @since 1.0.0
251 - *
252 - * @param string $key key.
253 - * @param bool $default default.
254 - * @param bool $type if false return string.
255 - * @param bool $from_options from option.
256 - *
257 - * @return array|bool|mixed
23 + * @since v.1.0.0
258 24 */
259 - public function get_option( $key, $default = false, $type = true, $from_options = false ) {
260 - $option = (array) maybe_unserialize( get_option( 'tutor_option' ) );
25 + public function get_option( $key = null, $default = false ) {
26 + $option = (array) maybe_unserialize(get_option('tutor_option'));
261 27
262 28 if ( empty( $option ) || ! is_array( $option ) ) {
263 - // If the option array is not yet stored on database, then return default/fallback.
264 - return $this->get_option_default( $key, $default, $from_options );
29 + return $default;
265 30 }
266 -
267 - // Get option value by option key.
31 + if ( ! $key ) {
32 + return $option;
33 + }
268 34 if ( array_key_exists( $key, $option ) ) {
269 - // Convert off/on switch values to boolean.
270 - $value = $option[ $key ];
271 -
272 - if ( true == $type ) {
273 - 'off' === $value ? $value = false : 0;
274 - 'on' === $value ? $value = true : 0;
275 - }
276 -
277 - return apply_filters( $key, $value );
35 + return apply_filters( $key, $option[$key] );
278 36 }
279 -
280 - // Access array value via dot notation, such as option->get('value.subvalue').
281 - if ( strpos( $key, '.' ) ) {
37 + //Access array value via dot notation, such as option->get('value.subvalue')
38 + if ( strpos($key, '.') ) {
282 39 $option_key_array = explode( '.', $key );
283 40
284 41 $new_option = $option;
285 - foreach ( $option_key_array as $dot_key ) {
286 - if ( isset( $new_option[ $dot_key ] ) ) {
287 - $new_option = $new_option[ $dot_key ];
288 - } else {
289 - return $this->get_option_default( $key, $default, $from_options );
42 + foreach ( $option_key_array as $dotKey ) {
43 + if ( isset( $new_option[$dotKey] ) ) {
44 + $new_option = $new_option[$dotKey];
45 + }else{
46 + return $default;
290 47 }
291 48 }
292 -
293 - // Convert off/on switch values to boolean.
294 - $value = $new_option;
295 -
296 - if ( true == $type ) {
297 - 'off' === $value ? $value = false : 0;
298 - 'on' === $value ? $value = true : 0;
299 - }
300 -
301 - return apply_filters( $key, $value );
49 + return apply_filters( $key, $new_option );
302 50 }
303 51
304 - return $this->get_option_default( $key, $default, $from_options );
52 + return $default;
305 53 }
306 54
307 55 /**
56 + * @param null $key
57 + * @param bool $value
58 + *
308 59 * Update Option
309 60 *
310 - * @since 1.0.0
311 - *
312 - * @param null|string $key option key.
313 - * @param mixed $value option value.
314 - *
315 - * @return void
61 + * @since v.1.0.0
316 62 */
317 63 public function update_option( $key = null, $value = false ) {
318 - $option = (array) maybe_unserialize( get_option( 'tutor_option' ) );
319 - $option[ $key ] = $value;
64 + $option = (array) maybe_unserialize( get_option('tutor_option') );
65 + $option[$key] = $value;
320 66 update_option( 'tutor_option', $option );
321 67 }
322 68
323 69 /**
324 - * Get value by dot notation from array or object
70 + * @param null $key
71 + * @param array $array
325 72 *
326 - * @since 1.0.0
327 - * @since 1.4.1 default parameter added
73 + * @return array|bool|mixed
328 74 *
329 - * @param null $key option key.
330 - * @param array|object $data array or object.
331 - * @param mixed $default default value.
75 + * get array value by dot notation
332 76 *
333 - * @return array|bool|mixed
77 + * @since v.1.0.0
78 + *
79 + * @update v.1.4.1 (Added default parameter)
334 80 */
335 - public function avalue_dot( $key = null, $data = array(), $default = false ) {
336 - $array = is_object( $data ) ? (array) $data : $data;
337 -
338 - if ( '' === $key || null === $key || ! $this->count( $array ) ) {
81 + public function avalue_dot( $key = null, $array = array(), $default = false ) {
82 + $array = (array) $array;
83 + if ( ! $key || ! count($array) ) {
339 84 return $default;
340 85 }
86 + $option_key_array = explode( '.', $key );
341 87
342 - $keys = explode( '.', $key );
343 88 $value = $array;
344 89
345 - foreach ( $keys as $dot_key ) {
346 - if ( isset( $value[ $dot_key ] ) ) {
347 - $value = $value[ $dot_key ];
90 + foreach ( $option_key_array as $dotKey ) {
91 + if ( isset( $value[$dotKey] ) ) {
92 + $value = $value[$dotKey];
348 93 } else {
349 94 return $default;
350 95 }
351 96 }
352 -
353 97 return $value;
354 98 }
355 99
356 100 /**
357 - * Alias of avalue_dot method of utils
358 - * Get array value by key and recursive array value by dot notation key
101 + * @param null $key
102 + * @param array $array
359 103 *
360 - * Ex: $this->array_get('key.child_key', $array);
104 + * @return array|bool|mixed
361 105 *
362 - * @since 1.3.3
106 + * alias of avalue_dot method of utils
363 107 *
364 - * @param null $key key name.
365 - * @param array $array array.
366 - * @param mixed $default default value.
108 + * Get array value by key and recursive array value by dot notation key
367 109 *
368 - * @return array|bool|mixed
110 + * ex: tutor_utils()->array_get('key.child_key', $array);
111 + *
112 + * @since v.1.3.3
369 113 */
370 114 public function array_get( $key = null, $array = array(), $default = false ) {
371 115 return $this->avalue_dot( $key, $array, $default );
372 116 }
@@ -371,115 +115,106 @@
371 115 return $this->avalue_dot( $key, $array, $default );
372 116 }
373 117
374 118 /**
119 + * @return array
120 + *
375 121 * Get all pages
376 122 *
377 - * @since 1.0.0
378 - *
379 - * @return array
123 + * @since v.1.0.0
380 124 */
381 125 public function get_pages() {
382 - do_action( 'tutor_utils/get_pages/before' );
383 -
384 - $pages = array();
385 - $wp_pages = get_posts(
386 - array(
387 - 'post_type' => 'page',
388 - 'post_status' => 'publish',
389 - 'numberposts' => -1,
390 - )
391 - );
392 -
126 + $pages = array();
127 + $wp_pages = get_pages();
393 128 if ( is_array( $wp_pages ) && count( $wp_pages ) ) {
394 129 foreach ( $wp_pages as $page ) {
395 - $pages[ $page->ID ] = $page->post_title;
130 + $pages[$page->ID] = $page->post_title;
396 131 }
397 132 }
398 -
399 - do_action( 'tutor_utils/get_pages/after' );
400 -
401 133 return $pages;
402 134 }
403 135
404 136 /**
137 + * @return string
138 + *
405 139 * Get course archive URL
406 140 *
407 - * @since 1.0.0
408 - *
409 - * @return string
141 + * @since v.1.0.0
410 142 */
411 143 public function course_archive_page_url() {
412 144 $course_post_type = tutor()->course_post_type;
413 - $course_page_url = home_url( $this->get_option( 'course_permalink_base', $course_post_type ) );
145 + $course_page_url = trailingslashit( home_url() ) . $course_post_type;
414 146
415 - $course_archive_page = $this->get_option( 'course_archive_page' );
416 - if ( $course_archive_page && '-1' !== $course_archive_page ) {
417 - $course_archive_page = apply_filters( 'tutor_filter_course_archive_page', $course_archive_page );
418 - $course_page_url = get_permalink( $course_archive_page );
147 + $course_archive_page = $this->get_option('course_archive_page');
148 + if ( $course_archive_page && $course_archive_page !== '-1' ) {
149 + $course_page_url = get_permalink( $course_archive_page );
419 150 }
420 151 return trailingslashit( $course_page_url );
421 152 }
422 153
423 154 /**
424 - * Get profile URL.
155 + * @param int $student_id
425 156 *
426 - * @since 1.0.0
427 - * @since 2.1.7 changed param $student_id to $user.
157 + * @return string
428 158 *
429 - * @param int|object $user student ID or object.
430 - * @param bool $instructor_view instractior view.
431 - * @param string $fallback_url fallback URL.
159 + * Get student URL
432 160 *
433 - * @return string
161 + * @since v.1.0.0
434 162 */
435 - public function profile_url( $user = 0, $instructor_view = false, $fallback_url = '#' ) {
436 - $instructor_profile = $this->get_option( 'public_profile_layout' ) != 'private';
437 - $student_profile = $this->get_option( 'student_public_profile_layout' ) != 'private';
438 - if ( ( $instructor_view && ! $instructor_profile ) || ( ! $instructor_view && ! $student_profile ) ) {
439 - return $fallback_url;
440 - }
163 + public function profile_url( $student_id = 0 ) {
164 + $site_url = trailingslashit( home_url() ) . 'profile/';
165 + $student_id = $this->get_user_id( $student_id );
166 + $user_name = '';
167 + if ( $student_id ) {
168 + global $wpdb;
169 + $user = $wpdb->get_row( $wpdb->prepare(
170 + "SELECT user_nicename
171 + FROM {$wpdb->users}
172 + WHERE ID = %d;
173 + ",
174 + $student_id
175 + ) );
441 176
442 - $site_url = trailingslashit( home_url() ) . 'profile/';
443 - if ( ! is_object( $user ) ) {
444 - $user = get_userdata( $this->get_user_id( $user ) );
177 + if ($user) {
178 + $user_name = $user->user_nicename;
179 + }
180 +
181 + } else {
182 + $user_name = 'user_name';
445 183 }
446 184
447 - $user_name = ( is_object( $user ) && isset( $user->user_nicename ) ) ? $user->user_nicename : 'user_name';
448 -
449 - return add_query_arg( array( 'view' => $instructor_view ? 'instructor' : 'student' ), $site_url . $user_name );
185 + return $site_url.$user_name;
450 186 }
451 187
452 188 /**
453 - * Get user by user login
189 + * @param string $user_nicename
454 190 *
455 - * @since 1.0.0
191 + * @return array|null|object
456 192 *
457 - * @param string $user_nicename user nicename.
193 + * Get user by user login
458 194 *
459 - * @return array|null|object
195 + * @since v.1.0.0
460 196 */
461 197 public function get_user_by_login( $user_nicename = '' ) {
462 198 global $wpdb;
463 - $user_nicename = sanitize_text_field( $user_nicename );
464 - $user = $wpdb->get_row(
465 - $wpdb->prepare(
466 - "SELECT *
199 + $user_nicename = sanitize_text_field( $user_nicename );
200 + $user = $wpdb->get_row( $wpdb->prepare(
201 + "SELECT *
467 202 FROM {$wpdb->users}
468 203 WHERE user_nicename = %s;
469 204 ",
470 - $user_nicename
471 - )
472 - );
205 + $user_nicename
206 + ) );
473 207 return $user;
474 208 }
475 209
476 210 /**
211 + * @return bool
212 + *
477 213 * Check if WooCommerce Activated
478 214 *
479 - * @since 1.0.0
480 - *
481 - * @return bool
215 + * @since v.1.0.0
216 + * @updated @1.5.9
482 217 */
483 218 public function has_wc() {
484 219 return class_exists( 'WooCommerce' );
485 220 }
@@ -484,463 +219,605 @@
484 219 return class_exists( 'WooCommerce' );
485 220 }
486 221
487 222 /**
488 - * Determine if EDD plugin activated
223 + * @return bool
489 224 *
490 - * @since 1.0.0
225 + * determine if EDD plugin activated
491 226 *
492 - * @return bool
227 + * @since v.1.0.0
493 228 */
494 229 public function has_edd() {
495 - return class_exists( 'Easy_Digital_Downloads' );
230 + $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
231 + $depends = array( 'easy-digital-downloads/easy-digital-downloads.php' );
232 + $has_edd = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
233 + return $has_edd;
496 234 }
497 235
498 236 /**
237 + * @return bool
238 + *
499 239 * Determine if PMPro is activated
500 240 *
501 - * @since 1.3.6
502 - *
503 - * @param bool $check_monetization check monetization.
504 - *
505 - * @return bool
241 + * @since v.1.3.6
506 242 */
507 - public function has_pmpro( $check_monetization = false ) {
508 - $has_pmpro = $this->is_plugin_active( 'paid-memberships-pro/paid-memberships-pro.php' );
509 - return $has_pmpro && ( ! $check_monetization || get_tutor_option( 'monetize_by' ) == 'pmpro' );
243 + public function has_pmpro() {
244 + $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
245 + $depends = array( 'paid-memberships-pro/paid-memberships-pro.php' );
246 + $has_pmpro = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
247 + return $has_pmpro;
510 248 }
511 249
250 + public function has_wcs(){
251 + $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
252 + $depends = array( 'woocommerce-subscriptions/woocommerce-subscriptions.php' );
253 + $has_wcs = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
254 + return $has_wcs;
255 + }
256 +
512 257 /**
513 - * Check is monetize by tutor e-commerce
258 + * @return bool
514 259 *
515 - * @since 3.0.0
260 + * checking if BuddyPress exists and activated;
516 261 *
517 - * @return boolean
262 + * @since v.1.4.8
518 263 */
519 - public function is_monetize_by_tutor() {
520 - $monetize_by = $this->get_option( 'monetize_by' );
521 - return Ecommerce::MONETIZE_BY === $monetize_by;
264 + public function has_bp(){
265 + $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
266 + $depends = array( 'buddypress/bp-loader.php' );
267 + $has_bp = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
268 + return $has_bp;
522 269 }
523 270
524 271 /**
525 - * Check plugin active status.
272 + * @return mixed
526 273 *
527 - * @since 1.0.0
528 - *
529 - * @param string $plugin_path plugin path.
530 - *
531 - * @return boolean
274 + * @since v.1.0.0
532 275 */
533 - public function is_plugin_active( $plugin_path ) {
534 - $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
535 - $depends = is_array( $plugin_path ) ? $plugin_path : array( $plugin_path );
536 - $has_plugin = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
276 + public function languages() {
277 + $language_codes = array(
278 + 'en' => 'English' ,
279 + 'aa' => 'Afar' ,
280 + 'ab' => 'Abkhazian' ,
281 + 'af' => 'Afrikaans' ,
282 + 'am' => 'Amharic' ,
283 + 'ar' => 'Arabic' ,
284 + 'as' => 'Assamese' ,
285 + 'ay' => 'Aymara' ,
286 + 'az' => 'Azerbaijani' ,
287 + 'ba' => 'Bashkir' ,
288 + 'be' => 'Byelorussian' ,
289 + 'bg' => 'Bulgarian' ,
290 + 'bh' => 'Bihari' ,
291 + 'bi' => 'Bislama' ,
292 + 'bn' => 'Bengali/Bangla' ,
293 + 'bo' => 'Tibetan' ,
294 + 'br' => 'Breton' ,
295 + 'ca' => 'Catalan' ,
296 + 'co' => 'Corsican' ,
297 + 'cs' => 'Czech' ,
298 + 'cy' => 'Welsh' ,
299 + 'da' => 'Danish' ,
300 + 'de' => 'German' ,
301 + 'dz' => 'Bhutani' ,
302 + 'el' => 'Greek' ,
303 + 'eo' => 'Esperanto' ,
304 + 'es' => 'Spanish' ,
305 + 'et' => 'Estonian' ,
306 + 'eu' => 'Basque' ,
307 + 'fa' => 'Persian' ,
308 + 'fi' => 'Finnish' ,
309 + 'fj' => 'Fiji' ,
310 + 'fo' => 'Faeroese' ,
311 + 'fr' => 'French' ,
312 + 'fy' => 'Frisian' ,
313 + 'ga' => 'Irish' ,
314 + 'gd' => 'Scots/Gaelic' ,
315 + 'gl' => 'Galician' ,
316 + 'gn' => 'Guarani' ,
317 + 'gu' => 'Gujarati' ,
318 + 'ha' => 'Hausa' ,
319 + 'hi' => 'Hindi' ,
320 + 'hr' => 'Croatian' ,
321 + 'hu' => 'Hungarian' ,
322 + 'hy' => 'Armenian' ,
323 + 'ia' => 'Interlingua' ,
324 + 'ie' => 'Interlingue' ,
325 + 'ik' => 'Inupiak' ,
326 + 'in' => 'Indonesian' ,
327 + 'is' => 'Icelandic' ,
328 + 'it' => 'Italian' ,
329 + 'iw' => 'Hebrew' ,
330 + 'ja' => 'Japanese' ,
331 + 'ji' => 'Yiddish' ,
332 + 'jw' => 'Javanese' ,
333 + 'ka' => 'Georgian' ,
334 + 'kk' => 'Kazakh' ,
335 + 'kl' => 'Greenlandic' ,
336 + 'km' => 'Cambodian' ,
337 + 'kn' => 'Kannada' ,
338 + 'ko' => 'Korean' ,
339 + 'ks' => 'Kashmiri' ,
340 + 'ku' => 'Kurdish' ,
341 + 'ky' => 'Kirghiz' ,
342 + 'la' => 'Latin' ,
343 + 'ln' => 'Lingala' ,
344 + 'lo' => 'Laothian' ,
345 + 'lt' => 'Lithuanian' ,
346 + 'lv' => 'Latvian/Lettish' ,
347 + 'mg' => 'Malagasy' ,
348 + 'mi' => 'Maori' ,
349 + 'mk' => 'Macedonian' ,
350 + 'ml' => 'Malayalam' ,
351 + 'mn' => 'Mongolian' ,
352 + 'mo' => 'Moldavian' ,
353 + 'mr' => 'Marathi' ,
354 + 'ms' => 'Malay' ,
355 + 'mt' => 'Maltese' ,
356 + 'my' => 'Burmese' ,
357 + 'na' => 'Nauru' ,
358 + 'ne' => 'Nepali' ,
359 + 'nl' => 'Dutch' ,
360 + 'no' => 'Norwegian' ,
361 + 'oc' => 'Occitan' ,
362 + 'om' => '(Afan)/Oromoor/Oriya' ,
363 + 'pa' => 'Punjabi' ,
364 + 'pl' => 'Polish' ,
365 + 'ps' => 'Pashto/Pushto' ,
366 + 'pt' => 'Portuguese' ,
367 + 'qu' => 'Quechua' ,
368 + 'rm' => 'Rhaeto-Romance' ,
369 + 'rn' => 'Kirundi' ,
370 + 'ro' => 'Romanian' ,
371 + 'ru' => 'Russian' ,
372 + 'rw' => 'Kinyarwanda' ,
373 + 'sa' => 'Sanskrit' ,
374 + 'sd' => 'Sindhi' ,
375 + 'sg' => 'Sangro' ,
376 + 'sh' => 'Serbo-Croatian' ,
377 + 'si' => 'Singhalese' ,
378 + 'sk' => 'Slovak' ,
379 + 'sl' => 'Slovenian' ,
380 + 'sm' => 'Samoan' ,
381 + 'sn' => 'Shona' ,
382 + 'so' => 'Somali' ,
383 + 'sq' => 'Albanian' ,
384 + 'sr' => 'Serbian' ,
385 + 'ss' => 'Siswati' ,
386 + 'st' => 'Sesotho' ,
387 + 'su' => 'Sundanese' ,
388 + 'sv' => 'Swedish' ,
389 + 'sw' => 'Swahili' ,
390 + 'ta' => 'Tamil' ,
391 + 'te' => 'Tegulu' ,
392 + 'tg' => 'Tajik' ,
393 + 'th' => 'Thai' ,
394 + 'ti' => 'Tigrinya' ,
395 + 'tk' => 'Turkmen' ,
396 + 'tl' => 'Tagalog' ,
397 + 'tn' => 'Setswana' ,
398 + 'to' => 'Tonga' ,
399 + 'tr' => 'Turkish' ,
400 + 'ts' => 'Tsonga' ,
401 + 'tt' => 'Tatar' ,
402 + 'tw' => 'Twi' ,
403 + 'uk' => 'Ukrainian' ,
404 + 'ur' => 'Urdu' ,
405 + 'uz' => 'Uzbek' ,
406 + 'vi' => 'Vietnamese' ,
407 + 'vo' => 'Volapuk' ,
408 + 'wo' => 'Wolof' ,
409 + 'xh' => 'Xhosa' ,
410 + 'yo' => 'Yoruba' ,
411 + 'zh' => 'Chinese' ,
412 + 'zu' => 'Zulu' ,
413 + );
537 414
538 - return $has_plugin;
415 + return apply_filters( 'tutor/utils/languages', $language_codes );
539 416 }
540 417
541 418 /**
542 - * Check WC subscription activated.
419 + * @param string $value
543 420 *
544 - * @since 1.0.0
421 + * Check raw data
545 422 *
546 - * @return boolean
423 + * @since v.1.0.0
547 424 */
548 - public function has_wcs() {
549 - $has_wcs = $this->is_plugin_active( 'woocommerce-subscriptions/woocommerce-subscriptions.php' );
550 - return $has_wcs;
425 + public function print_view( $value = '' ) {
426 + echo '<pre>';
427 + print_r( $value );
428 + echo '</pre>';
551 429 }
552 430
553 431 /**
554 - * Check addon status.
432 + * @param array $excludes
555 433 *
556 - * @since 1.0.0
434 + * @return array|null|object
557 435 *
558 - * @param string $basename addon base name.
436 + * Get courses
559 437 *
560 - * @return boolean
438 + * @since v.1.0.0
561 439 */
562 - public function is_addon_enabled( $basename ) {
563 - if ( $this->is_plugin_active( 'tutor-pro/tutor-pro.php' ) ) {
564 - $addon_config = $this->get_addon_config( $basename );
440 + public function get_courses( $excludes = array(), $post_status = array( 'publish' ) ) {
441 + global $wpdb;
565 442
566 - return (bool) $this->avalue_dot( 'is_enable', $addon_config );
443 + $excludes = (array) $excludes;
444 + $exclude_query = '';
445 +
446 + if ( count( $excludes ) ) {
447 + $exclude_query = implode( "','", $excludes );
567 448 }
568 449
569 - return false;
450 + $post_status = array_map( function($element) {
451 + return "'" . $element . "'";
452 + }, $post_status );
453 +
454 + $post_status = implode( ',', $post_status );
455 + $course_post_type = tutor()->course_post_type;
456 +
457 + $query = $wpdb->get_results( $wpdb->prepare(
458 + "SELECT ID,
459 + post_author,
460 + post_title,
461 + post_name,
462 + post_status,
463 + menu_order
464 + FROM {$wpdb->posts}
465 + WHERE post_status IN ({$post_status})
466 + AND ID NOT IN('$exclude_query')
467 + AND post_type = %s;
468 + ",
469 + $course_post_type
470 + ) );
471 +
472 + return $query;
570 473 }
571 474
572 475 /**
573 - * Checking if BuddyPress exists and activated.
476 + * @param int $instructor_id
574 477 *
575 - * @since 1.4.8
478 + * @return array|null|object
576 479 *
577 - * @return bool
480 + * Get courses for instructors
481 + *
482 + * @since v.1.0.0
578 483 */
579 - public function has_bp() {
580 - $activated_plugins = apply_filters( 'active_plugins', get_option( 'active_plugins' ) );
581 - $depends = array( 'buddypress/bp-loader.php' );
582 - $has_bp = count( array_intersect( $depends, $activated_plugins ) ) == count( $depends );
583 - return $has_bp;
484 + public function get_courses_for_instructors( $instructor_id = 0 ) {
485 + global $wpdb;
486 +
487 + $instructor_id = $this->get_user_id( $instructor_id );
488 + $course_post_type = tutor()->course_post_type;
489 +
490 + $query = $wpdb->get_results( $wpdb->prepare(
491 + "SELECT ID,
492 + post_author,
493 + post_title,
494 + post_name,
495 + post_status,
496 + menu_order
497 + FROM {$wpdb->posts}
498 + WHERE post_author = %d
499 + AND post_status IN ('publish', 'pending')
500 + AND post_type = %s;
501 + ",
502 + $instructor_id,
503 + $course_post_type
504 + ) );
505 +
506 + return $query;
584 507 }
585 508
586 509 /**
587 - * Get languages list.
510 + * @param $instructor_id
588 511 *
589 - * @since 1.0.0
512 + * @return null|string
590 513 *
591 - * @return array
514 + * Get course count by instructor
515 + *
516 + * @since v.1.0.0
592 517 */
593 - public function languages() {
594 - $language_codes = array(
595 - 'en' => 'English',
596 - 'aa' => 'Afar',
597 - 'ab' => 'Abkhazian',
598 - 'af' => 'Afrikaans',
599 - 'am' => 'Amharic',
600 - 'ar' => 'Arabic',
601 - 'as' => 'Assamese',
602 - 'ay' => 'Aymara',
603 - 'az' => 'Azerbaijani',
604 - 'ba' => 'Bashkir',
605 - 'be' => 'Byelorussian',
606 - 'bg' => 'Bulgarian',
607 - 'bh' => 'Bihari',
608 - 'bi' => 'Bislama',
609 - 'bn' => 'Bengali/Bangla',
610 - 'bo' => 'Tibetan',
611 - 'br' => 'Breton',
612 - 'ca' => 'Catalan',
613 - 'co' => 'Corsican',
614 - 'cs' => 'Czech',
615 - 'cy' => 'Welsh',
616 - 'da' => 'Danish',
617 - 'de' => 'German',
618 - 'dz' => 'Bhutani',
619 - 'el' => 'Greek',
620 - 'eo' => 'Esperanto',
621 - 'es' => 'Spanish',
622 - 'et' => 'Estonian',
623 - 'eu' => 'Basque',
624 - 'fa' => 'Persian',
625 - 'fi' => 'Finnish',
626 - 'fj' => 'Fiji',
627 - 'fo' => 'Faeroese',
628 - 'fr' => 'French',
629 - 'fy' => 'Frisian',
630 - 'ga' => 'Irish',
631 - 'gd' => 'Scots/Gaelic',
632 - 'gl' => 'Galician',
633 - 'gn' => 'Guarani',
634 - 'gu' => 'Gujarati',
635 - 'ha' => 'Hausa',
636 - 'hi' => 'Hindi',
637 - 'hr' => 'Croatian',
638 - 'hu' => 'Hungarian',
639 - 'hy' => 'Armenian',
640 - 'ia' => 'Interlingua',
641 - 'ie' => 'Interlingue',
642 - 'ik' => 'Inupiak',
643 - 'in' => 'Indonesian',
644 - 'is' => 'Icelandic',
645 - 'it' => 'Italian',
646 - 'iw' => 'Hebrew',
647 - 'ja' => 'Japanese',
648 - 'ji' => 'Yiddish',
649 - 'jw' => 'Javanese',
650 - 'ka' => 'Georgian',
651 - 'kk' => 'Kazakh',
652 - 'kl' => 'Greenlandic',
653 - 'km' => 'Cambodian',
654 - 'kn' => 'Kannada',
655 - 'ko' => 'Korean',
656 - 'ks' => 'Kashmiri',
657 - 'ku' => 'Kurdish',
658 - 'ky' => 'Kirghiz',
659 - 'la' => 'Latin',
660 - 'ln' => 'Lingala',
661 - 'lo' => 'Laothian',
662 - 'lt' => 'Lithuanian',
663 - 'lv' => 'Latvian/Lettish',
664 - 'mg' => 'Malagasy',
665 - 'mi' => 'Maori',
666 - 'mk' => 'Macedonian',
667 - 'ml' => 'Malayalam',
668 - 'mn' => 'Mongolian',
669 - 'mo' => 'Moldavian',
670 - 'mr' => 'Marathi',
671 - 'ms' => 'Malay',
672 - 'mt' => 'Maltese',
673 - 'my' => 'Burmese',
674 - 'na' => 'Nauru',
675 - 'ne' => 'Nepali',
676 - 'nl' => 'Dutch',
677 - 'no' => 'Norwegian',
678 - 'oc' => 'Occitan',
679 - 'om' => '(Afan)/Oromoor/Oriya',
680 - 'pa' => 'Punjabi',
681 - 'pl' => 'Polish',
682 - 'ps' => 'Pashto/Pushto',
683 - 'pt' => 'Portuguese',
684 - 'qu' => 'Quechua',
685 - 'rm' => 'Rhaeto-Romance',
686 - 'rn' => 'Kirundi',
687 - 'ro' => 'Romanian',
688 - 'ru' => 'Russian',
689 - 'rw' => 'Kinyarwanda',
690 - 'sa' => 'Sanskrit',
691 - 'sd' => 'Sindhi',
692 - 'sg' => 'Sangro',
693 - 'sh' => 'Serbo-Croatian',
694 - 'si' => 'Singhalese',
695 - 'sk' => 'Slovak',
696 - 'sl' => 'Slovenian',
697 - 'sm' => 'Samoan',
698 - 'sn' => 'Shona',
699 - 'so' => 'Somali',
700 - 'sq' => 'Albanian',
701 - 'sr' => 'Serbian',
702 - 'ss' => 'Siswati',
703 - 'st' => 'Sesotho',
704 - 'su' => 'Sundanese',
705 - 'sv' => 'Swedish',
706 - 'sw' => 'Swahili',
707 - 'ta' => 'Tamil',
708 - 'te' => 'Tegulu',
709 - 'tg' => 'Tajik',
710 - 'th' => 'Thai',
711 - 'ti' => 'Tigrinya',
712 - 'tk' => 'Turkmen',
713 - 'tl' => 'Tagalog',
714 - 'tn' => 'Setswana',
715 - 'to' => 'Tonga',
716 - 'tr' => 'Turkish',
717 - 'ts' => 'Tsonga',
718 - 'tt' => 'Tatar',
719 - 'tw' => 'Twi',
720 - 'uk' => 'Ukrainian',
721 - 'ur' => 'Urdu',
722 - 'uz' => 'Uzbek',
723 - 'vi' => 'Vietnamese',
724 - 'vo' => 'Volapuk',
725 - 'wo' => 'Wolof',
726 - 'xh' => 'Xhosa',
727 - 'yo' => 'Yoruba',
728 - 'zh' => 'Chinese',
729 - 'zu' => 'Zulu',
730 - );
518 + public function get_course_count_by_instructor( $instructor_id ) {
519 + global $wpdb;
731 520
732 - return apply_filters( 'tutor/utils/languages', $language_codes );
521 + $course_post_type = tutor()->course_post_type;
522 +
523 + $count = $wpdb->get_var( $wpdb->prepare(
524 + "SELECT COUNT(ID)
525 + FROM {$wpdb->posts}
526 + INNER JOIN {$wpdb->usermeta}
527 + ON user_id = %d
528 + AND meta_key = %s
529 + AND meta_value = ID
530 + WHERE post_status = %s
531 + AND post_type = %s;
532 + ",
533 + $instructor_id,
534 + '_tutor_instructor_course_id',
535 + 'publish',
536 + $course_post_type
537 + ) );
538 +
539 + return $count;
733 540 }
734 541
735 542 /**
736 - * Check raw data.
543 + * @param $instructor_id
737 544 *
738 - * @since 1.0.0
545 + * @return array|null|object
739 546 *
740 - * @param string $value value.
547 + * Get courses by a instructor
741 548 *
742 - * @return void
549 + * @since v.1.0.0
743 550 */
744 - public function print_view( $value = '' ) {
745 - echo '<pre>';
746 - print_r( $value );
747 - echo '</pre>';
551 + public function get_courses_by_instructor( $instructor_id = 0, $post_status = array( 'publish' ) ) {
552 + global $wpdb;
553 +
554 + $instructor_id = $this->get_user_id($instructor_id);
555 + $course_post_type = tutor()->course_post_type;
556 +
557 + if ( $post_status === 'any' ) {
558 + $where_post_status = "";
559 + } else {
560 + $post_status = (array) $post_status;
561 + $statuses = "'" . implode( "','", $post_status ) . "'";
562 + $where_post_status = "AND $wpdb->posts.post_status IN({$statuses}) ";
563 + }
564 +
565 + $pageposts = $wpdb->get_results( $wpdb->prepare(
566 + "SELECT $wpdb->posts.*
567 + FROM $wpdb->posts
568 + INNER JOIN {$wpdb->usermeta}
569 + ON $wpdb->usermeta.user_id = %d
570 + AND $wpdb->usermeta.meta_key = %s
571 + AND $wpdb->usermeta.meta_value = $wpdb->posts.ID
572 + WHERE 1 = 1 {$where_post_status}
573 + AND $wpdb->posts.post_type = %s
574 + ORDER BY $wpdb->posts.post_date DESC;
575 + ",
576 + $instructor_id,
577 + '_tutor_instructor_course_id',
578 + $course_post_type
579 + ), OBJECT);
580 +
581 + return $pageposts;
748 582 }
749 583
750 584 /**
751 - * Get completed lesson total number by a course
585 + * @return mixed
752 586 *
753 - * @since 1.0.0
587 + * Get archive page course count
754 588 *
755 - * @param int $course_id course ID.
756 - * @param int $user_id user ID.
589 + * @since v.1.0.0
590 + */
591 + public function get_archive_page_course_count() {
592 + global $wp_query;
593 + return $wp_query->post_count;
594 + }
595 +
596 + /**
597 + * @return null|string
757 598 *
758 - * @return int
599 + * Get course count
600 + *
601 + * @since v.1.0.0
759 602 */
760 - public function get_completed_lesson_count_by_course( $course_id = 0, $user_id = 0 ) {
761 - $course_id = $this->get_post_id( $course_id );
762 - $user_id = $this->get_user_id( $user_id );
603 + public function get_course_count() {
604 + global $wpdb;
763 605
764 - $lesson_ids = $this->get_course_content_ids_by( tutor()->lesson_post_type, tutor()->course_post_type, $course_id );
765 - if ( empty( $lesson_ids ) ) {
766 - return 0;
767 - }
606 + $course_post_type = tutor()->course_post_type;
768 607
769 - $cache_key = 'tutor_get_completed_lesson_count_by_' . $user_id . '_' . implode( '_', $lesson_ids );
770 - $cached = TutorCache::get( $cache_key );
608 + $count = $wpdb->get_var( $wpdb->prepare(
609 + "SELECT COUNT(ID)
610 + FROM {$wpdb->posts}
611 + WHERE post_status = %s
612 + AND post_type = %s;
613 + ",
614 + 'publish',
615 + $course_post_type
616 + ) );
617 +
618 + return $count;
619 + }
771 620
772 - if ( false !== $cached ) {
773 - return (int) $cached;
774 - }
621 + /**
622 + * @return null|string
623 + *
624 + * Get lesson count
625 + *
626 + * @since v.1.0.0
627 + */
628 + public function get_lesson_count() {
629 + global $wpdb;
775 630
776 - $meta_keys = array_map(
777 - fn( $id ) => '_tutor_completed_lesson_id_' . $id,
778 - $lesson_ids
779 - );
631 + $lesson_post_type = tutor()->lesson_post_type;
780 632
781 - $count = QueryHelper::get_count(
782 - 'usermeta',
783 - array(
784 - 'user_id' => $user_id,
785 - 'meta_key' => array( 'IN', $meta_keys ),
633 + $count = $wpdb->get_var( $wpdb->prepare(
634 + "SELECT COUNT(ID)
635 + FROM {$wpdb->posts}
636 + WHERE post_status = %s
637 + AND post_type = %s;
638 + ",
639 + 'publish',
640 + $lesson_post_type
641 + ) );
642 +
643 + return $count;
644 + }
645 +
646 + /**
647 + * @param int $course_id
648 + * @param int $limit
649 + *
650 + * @return \WP_Query
651 + *
652 + * Get lesson
653 + *
654 + * @since v.1.0.0
655 + */
656 + public function get_lesson( $course_id = 0, $limit = 10 ) {
657 + $course_id = $this->get_post_id( $course_id );
658 + $lesson_post_type = tutor()->lesson_post_type;
659 +
660 + $args = array(
661 + 'post_status' => 'publish',
662 + 'post_type' => $lesson_post_type,
663 + 'posts_per_page' => $limit,
664 + 'meta_query' => array(
665 + array(
666 + 'key' => '_tutor_course_id_for_lesson',
667 + 'value' => $course_id,
668 + 'compare' => '=',
669 + ),
786 670 ),
787 - array(),
788 - 'umeta_id'
789 671 );
790 672
791 - TutorCache::set( $cache_key, $count );
673 + $query = new \WP_Query( $args );
792 674
793 - return $count;
675 + return $query;
794 676 }
795 677
796 678 /**
797 - * Get course completed percentage.
679 + * @param int $course_id
798 680 *
799 - * @since 1.0.0
800 - * @since 1.6.1 get status param added.
681 + * @return int
801 682 *
802 - * @param int $course_id course ID.
803 - * @param int $user_id user ID.
804 - * @param bool $get_stats get status.
683 + * Get total lesson count by a course
805 684 *
806 - * @return mixed
685 + * @since v.1.0.0
807 686 */
808 - public function get_course_completed_percent( $course_id = 0, $user_id = 0, $get_stats = false ) {
809 - $course_id = $this->get_post_id( $course_id );
810 - $user_id = $this->get_user_id( $user_id );
687 + public function get_lesson_count_by_course( $course_id = 0 ) {
688 + global $wpdb;
811 689
812 - $post_type = get_post_type( $course_id );
813 - $result = 0;
690 + $course_id = $this->get_post_id($course_id);
691 + $lesson_post_type = tutor()->lesson_post_type;
814 692
815 - if ( tutor()->course_post_type === $post_type ) {
816 - $completed_lesson = $this->get_completed_lesson_count_by_course( $course_id, $user_id );
817 - $course_contents = $this->get_course_contents_by_id( $course_id );
818 - $total_contents = $this->count( $course_contents );
819 - $total_contents = $total_contents ? $total_contents : 0;
820 - $completed_count = $completed_lesson;
693 + $topicIDS = $wpdb->get_col( $wpdb->prepare(
694 + "SELECT ID
695 + FROM {$wpdb->posts}
696 + WHERE post_type = %s
697 + AND post_parent = %d;
698 + ",
699 + 'topics',
700 + $course_id
701 + ) );
821 702
822 - $quiz_ids = array();
823 - $assignment_ids = array();
703 + $lesson_count = 0;
704 + if ( $this->count( $topicIDS ) ) {
705 + $inIDS = implode( ",", $topicIDS );
706 + $lesson_count = $wpdb->get_var( $wpdb->prepare(
707 + "SELECT COUNT(ID)
708 + FROM {$wpdb->posts}
709 + WHERE post_parent IN({$inIDS})
710 + AND post_type = %s;
711 + ",
712 + $lesson_post_type
713 + ) );
714 + }
824 715
825 - foreach ( $course_contents as $content ) {
826 - if ( 'tutor_quiz' === $content->post_type ) {
827 - $quiz_ids[] = (int) $content->ID;
828 - }
829 - if ( 'tutor_assignments' === $content->post_type ) {
830 - $assignment_ids[] = (int) $content->ID;
831 - }
832 - }
716 + return (int) $lesson_count;
717 + }
833 718
834 - global $wpdb;
719 + /**
720 + * @param int $course_id
721 + * @param int $user_id
722 + *
723 + * @return int
724 + *
725 + * Get completed lesson total number by a course
726 + *
727 + * @since v.1.0.0
728 + */
729 + public function get_completed_lesson_count_by_course( $course_id = 0, $user_id = 0 ) {
730 + global $wpdb;
835 731
836 - if ( count( $quiz_ids ) ) {
837 - $quiz_ids_str = QueryHelper::prepare_in_clause( $quiz_ids );
732 + $course_id = $this->get_post_id( $course_id );
733 + $user_id = $this->get_user_id( $user_id );
838 734
839 - // Get data from cache.
840 - $prepare_quiz_ids_str = str_replace( ',', '_', $quiz_ids_str );
841 - $quiz_completed_cache_key = "tutor_quiz_completed_{$user_id}_{$prepare_quiz_ids_str}";
842 - $quiz_completed = TutorCache::get( $quiz_completed_cache_key );
735 + $completed_lesson_ids = $wpdb->get_col( $wpdb->prepare(
736 + "SELECT post_id
737 + FROM {$wpdb->postmeta}
738 + WHERE meta_key = %s
739 + AND meta_value = %d;
740 + ",
741 + '_tutor_course_id_for_lesson',
742 + $course_id
743 + ) );
843 744
844 - if ( false === $quiz_completed ) {
845 - //phpcs:disable
846 - $quiz_completed = (int) $wpdb->get_var(
847 - $wpdb->prepare(
848 - "SELECT count(quiz_id) completed
849 - FROM (
850 - SELECT DISTINCT quiz_id
851 - FROM {$wpdb->tutor_quiz_attempts}
852 - WHERE quiz_id IN ({$quiz_ids_str})
853 - AND user_id = % d
854 - AND attempt_status != %s
855 - ) a",
856 - $user_id,
857 - QuizModel::ATTEMPT_STARTED
858 - )
859 - );
860 - //phpcs:enable
861 - TutorCache::set( $quiz_completed_cache_key, $quiz_completed );
862 - }
863 - $completed_count += $quiz_completed;
745 + $count = 0;
746 + if ( is_array( $completed_lesson_ids ) && count( $completed_lesson_ids) ) {
747 + $completed_lesson_meta_ids = array();
748 + foreach ( $completed_lesson_ids as $lesson_id ) {
749 + $completed_lesson_meta_ids[] = '_tutor_completed_lesson_id_' . $lesson_id;
864 750 }
751 + $in_ids = implode( "','", $completed_lesson_meta_ids );
865 752
866 - if ( count( $assignment_ids ) ) {
753 + $count = (int) $wpdb->get_var( $wpdb->prepare(
754 + "SELECT count(umeta_id)
755 + FROM {$wpdb->usermeta}
756 + WHERE user_id = %d
757 + AND meta_key IN ('{$in_ids}')
758 + ",
759 + $user_id
760 + ) );
761 + }
867 762
868 - foreach ( $assignment_ids as $assignment_id ) {
869 - $submitted_assignment = $this->is_assignment_submitted( $assignment_id, $user_id );
763 + return $count;
764 + }
870 765
871 - if ( $submitted_assignment ) {
872 - ++$completed_count;
873 - }
874 - }
875 - }
766 + /**
767 + * @param int $course_id
768 + * @param int $user_id
769 + *
770 + * @return float|int
771 + *
772 + * @since v.1.0.0
773 + * @updated v.1.6.1
774 + */
775 + public function get_course_completed_percent( $course_id = 0, $user_id = 0 ) {
776 + $course_id = $this->get_post_id($course_id);
777 + $user_id = $this->get_user_id($user_id);
778 + $completed_lesson = $this->get_completed_lesson_count_by_course($course_id, $user_id);
779 + $course_contents = tutils()->get_course_contents_by_id($course_id);
780 + $totalContents = $this->count($course_contents);
781 + $totalContents = $totalContents ? $totalContents : 0;
782 + $completedCount = $completed_lesson;
876 783
877 - if ( $this->count( $course_contents ) ) {
878 - foreach ( $course_contents as $content ) {
879 - if ( 'tutor_zoom_meeting' === $content->post_type ) {
880 - /**
881 - * Count zoom lesson completion for course progress
882 - *
883 - * @since 2.0.0
884 - */
885 - $is_completed = apply_filters( 'tutor_is_zoom_lesson_done', false, $content->ID, $user_id );
886 - if ( $is_completed ) {
887 - ++$completed_count;
888 - }
889 - } elseif ( 'tutor-google-meet' === $content->post_type ) {
890 - /**
891 - * Count zoom lesson completion for course progress
892 - *
893 - * @since 2.0.0
894 - */
895 - $is_completed = apply_filters( 'tutor_google_meet_lesson_done', false, $content->ID, $user_id );
896 - if ( $is_completed ) {
897 - ++$completed_count;
898 - }
899 - }
900 - }
901 - }
784 + if ( tutils()->count( $course_contents ) ) {
785 + foreach ( $course_contents as $content ) {
786 + if ( $content->post_type === 'tutor_quiz' ) {
787 + $attempt = $this->get_quiz_attempt( $content->ID, $user_id );
788 + if ( $attempt) {
789 + $completedCount++;
790 + }
791 + } elseif ( $content->post_type === 'tutor_assignments' ) {
792 + $isSubmitted = $this->is_assignment_submitted( $content->ID, $user_id );
793 + if ( $isSubmitted ) {
794 + $completedCount++;
795 + }
796 + }
797 + }
798 + }
902 799
903 - if ( $total_contents > 0 && $completed_count > 0 ) {
904 - $result = number_format( ( $completed_count * 100 ) / $total_contents );
905 - }
906 -
907 - if ( $get_stats ) {
908 - $result = array(
909 - 'completed_percent' => $result,
910 - 'completed_count' => $completed_count,
911 - 'total_count' => $total_contents,
912 - );
913 - }
800 + if ( $totalContents > 0 && $completedCount > 0 ) {
801 + return number_format( ( $completedCount * 100 ) / $totalContents );
914 802 }
915 803
916 - if ( ! $result && $get_stats ) {
917 - $result = array(
918 - 'completed_percent' => 0,
919 - 'completed_count' => 0,
920 - 'total_count' => 0,
921 - );
922 - }
923 -
924 - return apply_filters( 'tutor_course_completed_percent', $result, $course_id, $user_id, $get_stats );
804 + return 0;
925 805 }
926 806
927 807 /**
928 - * Get all topics by given course ID
808 + * @param int $course_id
929 809 *
930 - * @since 1.0.0
810 + * @return \WP_Query
931 811 *
932 - * @since 3.6.0 $custom_args param added
812 + * Get all topics by given course ID
933 813 *
934 - * @param int $course_id course ID.
935 - * @param array $custom_args Add custom args.
936 - *
937 - * @return \WP_Query
814 + * @since v.1.0.0
938 815 */
939 - public function get_topics( $course_id = 0, $custom_args = array() ) {
816 + public function get_topics( $course_id = 0 ) {
940 817 $course_id = $this->get_post_id( $course_id );
941 818
942 - $default_args = array(
819 + $args = array(
943 820 'post_type' => 'topics',
944 821 'post_parent' => $course_id,
945 822 'orderby' => 'menu_order',
946 823 'order' => 'ASC',
@@ -946,10 +823,8 @@
946 823 'order' => 'ASC',
947 824 'posts_per_page' => -1,
948 825 );
949 826
950 - $args = wp_parse_args( $custom_args, $default_args );
951 -
952 827 $query = new \WP_Query( $args );
953 828
954 829 return $query;
955 830 }
@@ -954,95 +829,71 @@
954 829 return $query;
955 830 }
956 831
957 832 /**
958 - * Get next topic order id
833 + * @param $course_ID
959 834 *
960 - * @since 1.0.0
835 + * @return int
961 836 *
962 - * @param int $course_id course ID.
963 - * @param mixed $content_id content ID.
837 + * Get next topic order id
964 838 *
965 - * @return int
839 + * @since v.1.0.0
966 840 */
967 - public function get_next_topic_order_id( $course_id, $content_id = null ) {
841 + public function get_next_topic_order_id( $course_ID ) {
968 842 global $wpdb;
969 843
970 - if ( $content_id ) {
971 - $existing_order = get_post_field( 'menu_order', $content_id );
972 -
973 - if ( $existing_order >= 0 ) {
974 - return $existing_order;
975 - }
976 - }
977 -
978 - $last_order = (int) $wpdb->get_var(
979 - $wpdb->prepare(
980 - "SELECT MAX(menu_order)
844 + $last_order = (int) $wpdb->get_var( $wpdb->prepare(
845 + "SELECT MAX(menu_order)
981 846 FROM {$wpdb->posts}
982 847 WHERE post_parent = %d
983 848 AND post_type = %s;
984 849 ",
985 - $course_id,
986 - 'topics'
987 - )
988 - );
989 -
850 + $course_ID,
851 + 'topics'
852 + ) );
853 +
990 854 return $last_order + 1;
991 855 }
992 856
993 857 /**
994 - * Get next course content order id
858 + * @param $topic_ID
995 859 *
996 - * @since 1.0.0
860 + * @return int
997 861 *
998 - * @param int $topic_id topic ID.
999 - * @param mixed $content_id content ID.
862 + * Get next course content order id
1000 863 *
1001 - * @return int
864 + * @since v.1.0.0
1002 865 */
1003 - public function get_next_course_content_order_id( $topic_id, $content_id = null ) {
866 + public function get_next_course_content_order_id( $topic_ID ) {
1004 867 global $wpdb;
1005 868
1006 - if ( $content_id ) {
1007 - $existing_order = get_post_field( 'menu_order', $content_id );
1008 -
1009 - if ( $existing_order >= 0 ) {
1010 - return $existing_order;
1011 - }
1012 - }
1013 -
1014 - $last_order = (int) $wpdb->get_var(
1015 - $wpdb->prepare(
1016 - "SELECT MAX(menu_order)
869 + $last_order = (int) $wpdb->get_var( $wpdb->prepare(
870 + "SELECT MAX(menu_order)
1017 871 FROM {$wpdb->posts}
1018 872 WHERE post_parent = %d;
1019 873 ",
1020 - $topic_id
1021 - )
1022 - );
874 + $topic_ID
875 + ) );
1023 876
1024 - return is_numeric( $last_order ) ? $last_order + 1 : 0;
877 + return is_numeric( $last_order ) ? $last_order+1 : 0;
1025 878 }
1026 879
1027 880 /**
1028 - * Get course content by topic
881 + * @param int $topics_id
882 + * @param int $limit
1029 883 *
1030 - * @since 1.0.0
884 + * @return \WP_Query
1031 885 *
1032 - * @param int $topics_id topics ID.
1033 - * @param int $limit limit.
1034 - * @param array $custom_args Custom args.
886 + * Get lesson by topic
1035 887 *
1036 - * @return \WP_Query
888 + * @since v.1.0.0
1037 889 */
1038 - public function get_course_contents_by_topic( $topics_id = 0, $limit = 10, $custom_args = array() ) {
890 + public function get_lessons_by_topic( $topics_id = 0, $limit = 10 ) {
1039 891 $topics_id = $this->get_post_id( $topics_id );
1040 892 $lesson_post_type = tutor()->lesson_post_type;
1041 - $post_type = array_unique( apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) ) );
1042 -
1043 - $default_args = array(
1044 - 'post_type' => $post_type,
893 +
894 + $args = array(
895 + 'post_type' => $lesson_post_type,
1045 896 'post_parent' => $topics_id,
1046 897 'posts_per_page' => $limit,
1047 898 'orderby' => 'menu_order',
1048 899 'order' => 'ASC',
@@ -1047,153 +898,119 @@
1047 898 'orderby' => 'menu_order',
1048 899 'order' => 'ASC',
1049 900 );
1050 901
1051 - $args = apply_filters( 'tutor_course_topic_contents_args', wp_parse_args( $custom_args, $default_args ) );
902 + $query = new \WP_Query( $args );
1052 903
1053 - return new \WP_Query( $args );
904 + return $query;
1054 905 }
1055 906
1056 907 /**
1057 - * Check tutor nonce is verified.
908 + * @param int $topics_id
909 + * @param int $limit
1058 910 *
1059 - * @since 3.0.0
911 + * @return \WP_Query
1060 912 *
1061 - * @param string $request_method request method.
913 + * Get course content by topic
1062 914 *
1063 - * @return bool.
915 + * @since v.1.0.0
1064 916 */
1065 - public function is_nonce_verified( $request_method = null ) {
1066 - ! $request_method ? $request_method = sanitize_text_field( $_SERVER['REQUEST_METHOD'] ) : 0; //phpcs:ignore
917 + public function get_course_contents_by_topic( $topics_id = 0, $limit = 10 ) {
918 + $topics_id = $this->get_post_id($topics_id);
919 + $lesson_post_type = tutor()->lesson_post_type;
920 + $post_type = apply_filters( 'tutor_course_contents_post_types', array( $lesson_post_type, 'tutor_quiz' ) );
1067 921
1068 - $data = strtolower( $request_method ) === 'post' ? $_POST : $_GET; //phpcs:ignore
1069 - $nonce_value = sanitize_text_field( $this->array_get( tutor()->nonce, $data, null ) );
1070 - $is_matched = $nonce_value && wp_verify_nonce( $nonce_value, tutor()->nonce_action );
922 + $args = array(
923 + 'post_type' => $post_type,
924 + 'post_parent' => $topics_id,
925 + 'posts_per_page' => $limit,
926 + 'orderby' => 'menu_order',
927 + 'order' => 'ASC',
928 + );
1071 929
1072 - return $is_matched;
1073 - }
930 + $query = new \WP_Query( $args );
1074 931
1075 - /**
1076 - * Check actions nonce.
1077 - *
1078 - * @since 1.0.0
1079 - *
1080 - * @param string $request_method request method.
1081 - *
1082 - * @return void.
1083 - */
1084 - public function checking_nonce( $request_method = null ) {
1085 - if ( ! $this->is_nonce_verified( $request_method ) ) {
1086 - wp_send_json_error( array( 'message' => $this->error_message( 'nonce' ) ) );
1087 - exit;
1088 - }
932 + return $query;
1089 933 }
1090 934
1091 935 /**
1092 - * Check nonce
936 + * @param string $request_method
1093 937 *
1094 - * @since 3.0.0
938 + * Check actions nonce
1095 939 *
1096 - * @return void JSON response.
940 + * @since v.1.0.0
1097 941 */
1098 - public function check_nonce() {
1099 - if ( ! $this->is_nonce_verified() ) {
1100 - $this->json_response( $this->error_message( 'nonce' ), null, HttpHelper::STATUS_BAD_REQUEST );
1101 - }
1102 - }
942 + public function checking_nonce( $request_method = 'post' ) {
1103 943
944 + $data = $request_method === 'post' ? $_POST : $_GET;
945 + $nonce_value = sanitize_text_field(tutils()->array_get(tutor()->nonce, $data, null));
946 + $matched = $nonce_value && wp_verify_nonce( $nonce_value, tutor()->nonce_action );
1104 947
1105 - /**
1106 - * Check current user capability and send json response
1107 - *
1108 - * @since 3.0.0
1109 - *
1110 - * @param string $capability User capability, default manage_options.
1111 - * @param int $object_id post id to check with capability.
1112 - *
1113 - * @return void JSON response.
1114 - */
1115 - public function check_current_user_capability( string $capability = 'manage_options', int $object_id = 0 ) {
1116 - $can = $object_id ? current_user_can( $capability, $object_id ) : current_user_can( $capability );
1117 - if ( ! $can ) {
1118 - $this->json_response( $this->error_message(), null, HttpHelper::STATUS_UNAUTHORIZED );
1119 - }
948 + ! $matched ? exit( __('Nonce not matched', 'tutor') ) : 0;
1120 949 }
1121 950
1122 951 /**
1123 - * Check is course purchaseable.
952 + * @param int $course_id
1124 953 *
1125 - * @since 1.0.0
954 + * @return bool
1126 955 *
1127 - * @param int $course_id course ID.
1128 - *
1129 - * @return bool
956 + * @since v.1.0.0
1130 957 */
1131 958 public function is_course_purchasable( $course_id = 0 ) {
1132 -
1133 - $is_purchaseable = false;
1134 -
1135 959 $course_id = $this->get_post_id( $course_id );
1136 960 $price_type = $this->price_type( $course_id );
1137 961
1138 - if ( Course::PRICE_TYPE_PAID === $price_type ) {
1139 - $is_purchaseable = true;
1140 - } elseif ( Course::PRICE_TYPE_FREE === $price_type ) {
1141 - $is_purchaseable = apply_filters( 'is_course_paid', $is_purchaseable, $course_id );
962 + if ( $price_type === 'free' ) {
963 + $is_paid = apply_filters( 'is_course_paid', false, $course_id );
964 + if ( ! $is_paid ) {
965 + return false;
966 + }
1142 967 }
1143 968
1144 - return apply_filters( 'is_course_purchasable', $is_purchaseable, $course_id );
969 + return apply_filters( 'is_course_purchasable', false, $course_id );
1145 970 }
1146 971
1147 972 /**
1148 - * Get course price in digits format if any.
973 + * @param int $course_id
1149 974 *
1150 - * @since 1.0.0
975 + * @return null|string
1151 976 *
1152 - * @since 3.0.0
977 + * get course price in digits format if any
1153 978 *
1154 - * If monetize by is Tutor then it will return course
1155 - * formatted price
1156 - *
1157 - * @see tutor_get_course_formatted_price
1158 - *
1159 - * @param int $course_id course ID.
1160 - *
1161 - * @return null|string
979 + * @since v.1.0.0
1162 980 */
1163 981 public function get_course_price( $course_id = 0 ) {
1164 - $price = null;
1165 - $course_id = $this->get_post_id( $course_id );
1166 - $product_id = $this->get_course_product_id( $course_id );
1167 - if ( $this->is_course_purchasable( $course_id ) ) {
1168 - $monetize_by = $this->get_option( 'monetize_by' );
1169 - if ( $this->has_wc() && 'wc' === $monetize_by ) {
1170 - $product = wc_get_product( $product_id );
982 + $price = null;
983 + $course_id = $this->get_post_id( $course_id );
984 +
985 + if ( $this->is_course_purchasable() ) {
986 + $monetize_by = $this->get_option('monetize_by');
987 +
988 + if ( $this->has_wc() && $monetize_by === 'wc' ) {
989 + $product_id = tutor_utils()->get_course_product_id( $course_id );
990 + $product = wc_get_product( $product_id );
991 +
1171 992 if ( $product ) {
1172 993 $price = $product->get_price();
1173 994 }
1174 - } elseif ( 'edd' === $monetize_by && function_exists( 'edd_price' ) ) {
1175 - $download = new \EDD_Download( $product_id );
1176 - $price = \edd_price( $download->ID, false );
1177 - } elseif ( $this->is_monetize_by_tutor() ) {
1178 - $price = \tutor_get_course_formatted_price_html( $course_id, false );
995 + } else {
996 + $price = apply_filters( 'get_tutor_course_price', null, $course_id );
1179 997 }
1180 998 }
1181 999
1182 - return apply_filters( 'get_tutor_course_price', $price, $course_id );
1000 + return $price;
1183 1001 }
1184 1002
1185 1003 /**
1004 + * @param int $course_id
1005 + *
1006 + * @return object
1007 + *
1186 1008 * Get raw course price and sale price of a course
1187 1009 * It could help you to calculate something
1188 1010 * Such as Calculate discount by regular price and sale price
1189 1011 *
1190 - * @since 1.3.1
1191 - * @since 3.0.0 tax support added for monetized by tutor.
1192 - *
1193 - * @param int $course_id courrse ID.
1194 - *
1195 - * @return object
1012 + * @since v.1.3.1
1196 1013 */
1197 1014 public function get_raw_course_price( $course_id = 0 ) {
1198 1015 $course_id = $this->get_post_id( $course_id );
1199 1016
@@ -1201,29 +1018,18 @@
1201 1018 'regular_price' => 0,
1202 1019 'sale_price' => 0,
1203 1020 );
1204 1021
1205 - $monetize_by = $this->get_option( 'monetize_by' );
1022 + $monetize_by = $this->get_option('monetize_by');
1206 1023
1207 - if ( $this->is_monetize_by_tutor() ) {
1208 - $regular_price = (float) get_post_meta( $course_id, Course::COURSE_PRICE_META, true );
1209 - $sale_price = (float) get_post_meta( $course_id, Course::COURSE_SALE_PRICE_META, true );
1210 - $tax_collection = CourseModel::is_tax_enabled_for_single_purchase( $course_id );
1211 -
1212 - $prices = $this->get_prices_with_tax_info( $regular_price, $sale_price, $tax_collection );
1213 - } else {
1214 - $product_id = $this->get_course_product_id( $course_id );
1215 - if ( $product_id ) {
1216 - if ( 'wc' === $monetize_by && $this->has_wc() ) {
1217 - $product = wc_get_product( $product_id );
1218 - if ( $product ) {
1219 - $prices['regular_price'] = $product->get_regular_price();
1220 - $prices['sale_price'] = $product->get_sale_price();
1221 - }
1222 - } elseif ( 'edd' === $monetize_by && $this->has_edd() ) {
1223 - $prices['regular_price'] = get_post_meta( $product_id, 'edd_price', true );
1224 - $prices['sale_price'] = get_post_meta( $product_id, 'edd_price', true );
1225 - }
1024 + $product_id = $this->get_course_product_id( $course_id );
1025 + if ( $product_id ) {
1026 + if ( $monetize_by === 'wc' && $this->has_wc() ) {
1027 + $prices['regular_price'] = get_post_meta( $product_id, '_regular_price', true );
1028 + $prices['sale_price'] = get_post_meta( $product_id, '_sale_price', true );
1029 + } elseif ( $monetize_by === 'edd' && $this->has_edd() ) {
1030 + $prices['regular_price'] = get_post_meta( $product_id, 'edd_price', true );
1031 + $prices['sale_price'] = get_post_meta( $product_id, 'edd_price', true );
1226 1032 }
1227 1033 }
1228 1034
1229 1035 return (object) $prices;
@@ -1229,128 +1035,75 @@
1229 1035 return (object) $prices;
1230 1036 }
1231 1037
1232 1038 /**
1233 - * Get prices with tax info
1039 + * @param int $course_id
1234 1040 *
1235 - * @since 3.0.0
1236 - * @since 3.7.0 param tax collection is added.
1041 + * @return mixed
1237 1042 *
1238 - * @param int|float $regular_price regular price.
1239 - * @param int|float $sale_price sale price.
1240 - * @param bool $tax_collection tax collection.
1241 - *
1242 - * @return object
1243 - */
1244 - public function get_prices_with_tax_info( $regular_price, $sale_price = null, $tax_collection = true ) {
1245 -
1246 - $display_price = $sale_price ? $sale_price : $regular_price;
1247 - $user_logged_in = is_user_logged_in();
1248 - $should_calculate_tax = Tax::should_calculate_tax();
1249 - $show_price_with_tax = Tax::show_price_with_tax() && $user_logged_in;
1250 -
1251 - $tax_amount = 0;
1252 - $tax_rate = 0;
1253 -
1254 - if ( $should_calculate_tax
1255 - && $show_price_with_tax
1256 - && $tax_collection
1257 - && is_numeric( $display_price )
1258 - && ! Tax::is_tax_included_in_price()
1259 - ) {
1260 -
1261 - $tax_rate = $user_logged_in ? Tax::get_user_tax_rate() : 0;
1262 - $tax_amount = Tax::calculate_tax( $display_price, $tax_rate );
1263 - $display_price += $tax_amount;
1264 -
1265 - }
1266 -
1267 - $price_info = array();
1268 -
1269 - $price_info['regular_price'] = $regular_price;
1270 - $price_info['sale_price'] = $sale_price;
1271 - $price_info['display_price'] = $display_price;
1272 - $price_info['tax_rate'] = $tax_rate;
1273 - $price_info['tax_amount'] = $tax_amount;
1274 - $price_info['show_incl_tax_label'] = $should_calculate_tax && $tax_collection && $show_price_with_tax;
1275 -
1276 - return (object) $price_info;
1277 - }
1278 -
1279 - /**
1280 1043 * Get the course price type
1281 1044 *
1282 - * @since 1.3.5
1283 - *
1284 - * @param int $course_id course ID.
1285 - *
1286 - * @return mixed
1045 + * @since v.1.3.5
1287 1046 */
1288 1047 public function price_type( $course_id = 0 ) {
1289 - $course_id = $this->get_post_id( $course_id );
1290 -
1291 - $price_type = get_post_meta( $course_id, Course::COURSE_PRICE_TYPE_META, true );
1048 + $course_id = $this->get_post_id( $course_id );
1049 + $price_type = get_post_meta( $course_id, '_tutor_course_price_type', true );
1292 1050 return $price_type;
1293 1051 }
1294 1052
1295 1053 /**
1296 - * Delete course progress
1054 + * @param int $course_id
1297 1055 *
1298 - * @since 1.9.5
1056 + * @return array|bool|null|object
1299 1057 *
1300 - * @param int $course_id course ID.
1301 - * @param int $user_id user id.
1058 + * Check if current user has been enrolled or not
1302 1059 *
1303 - * @return void
1060 + * @since v.1.0.0
1304 1061 */
1305 - public function delete_course_progress( $course_id = 0, $user_id = 0 ) {
1306 - global $wpdb;
1062 + public function is_enrolled( $course_id = 0, $user_id = 0 ) {
1307 1063 $course_id = $this->get_post_id( $course_id );
1308 1064 $user_id = $this->get_user_id( $user_id );
1309 1065
1310 - // Delete Quiz submissions.
1311 - $attempts = \Tutor\Models\QuizModel::get_quiz_attempts_by_course_ids( $start = 0, $limit = 99999999, $course_ids = array( $course_id ), $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $user_id = $user_id, false, true );
1066 + if ( is_user_logged_in() ) {
1067 + global $wpdb;
1312 1068
1313 - if ( is_array( $attempts ) ) {
1314 - $attempt_ids = array_map(
1315 - function ( $attempt ) {
1316 - return is_object( $attempt ) ? $attempt->attempt_id : 0;
1317 - },
1318 - $attempts
1319 - );
1069 + do_action( 'tutor_is_enrolled_before', $course_id, $user_id );
1320 1070
1321 - $this->delete_quiz_attempt( $attempt_ids );
1322 - }
1071 + $getEnrolledInfo = $wpdb->get_row( $wpdb->prepare(
1072 + "SELECT ID,
1073 + post_author,
1074 + post_date,
1075 + post_date_gmt,
1076 + post_title
1077 + FROM {$wpdb->posts}
1078 + WHERE post_type = %s
1079 + AND post_parent = %d
1080 + AND post_author = %d
1081 + AND post_status = %s;
1082 + ",
1083 + 'tutor_enrolled',
1084 + $course_id,
1085 + $user_id,
1086 + 'completed'
1087 + ) );
1323 1088
1324 - // Delete Course completion row.
1325 - $del_where = array(
1326 - 'user_id' => $user_id,
1327 - 'comment_post_ID' => $course_id,
1328 - 'comment_type' => 'course_completed',
1329 - 'comment_agent' => 'TutorLMSPlugin',
1330 - );
1331 - $wpdb->delete( $wpdb->comments, $del_where );
1332 -
1333 - // Delete Completed lesson count.
1334 - $lesson_ids = $this->get_course_content_ids_by( tutor()->lesson_post_type, tutor()->course_post_type, $course_id );
1335 - foreach ( $lesson_ids as $id ) {
1336 - delete_user_meta( $user_id, '_tutor_completed_lesson_id_' . $id );
1337 - delete_user_meta( $user_id, '_lesson_reading_info' );
1089 + if ( $getEnrolledInfo ) {
1090 + return apply_filters( 'tutor_is_enrolled', $getEnrolledInfo, $course_id, $user_id );
1091 + }
1338 1092 }
1339 1093
1340 - // Delete other addon-wise stuffs by hook, specially assignment.
1341 - do_action( 'delete_tutor_course_progress', $course_id, $user_id );
1094 + return false;
1342 1095 }
1343 1096
1344 1097 /**
1345 - * Has any enrolled for a user in a course
1098 + * @param int $course_id
1099 + * @param int $user_id
1346 1100 *
1347 - * @since 1.0.0
1101 + * @return array|bool|null|object|void
1348 1102 *
1349 - * @param int $course_id course ID.
1350 - * @param int $user_id user ID.
1103 + * Has any enrolled for a user in a course
1351 1104 *
1352 - * @return array|bool|null|object|void
1105 + * @since v.1.0.0
1353 1106 */
1354 1107 public function has_any_enrolled( $course_id = 0, $user_id = 0 ) {
1355 1108 $course_id = $this->get_post_id( $course_id );
1356 1109 $user_id = $this->get_user_id( $user_id );
@@ -1357,28 +1110,26 @@
1357 1110
1358 1111 if ( is_user_logged_in() ) {
1359 1112 global $wpdb;
1360 1113
1361 - $enrolled_info = $wpdb->get_row(
1362 - $wpdb->prepare(
1363 - "SELECT ID,
1114 + $getEnrolledInfo = $wpdb->get_row( $wpdb->prepare(
1115 + "SELECT ID,
1364 1116 post_author,
1365 1117 post_date,
1366 1118 post_date_gmt,
1367 1119 post_title
1368 1120 FROM {$wpdb->posts}
1369 - WHERE post_type = %s
1121 + WHERE post_type = %s
1370 1122 AND post_parent = %d
1371 1123 AND post_author = %d;
1372 1124 ",
1373 - 'tutor_enrolled',
1374 - $course_id,
1375 - $user_id
1376 - )
1377 - );
1125 + 'tutor_enrolled',
1126 + $course_id,
1127 + $user_id
1128 + ) );
1378 1129
1379 - if ( $enrolled_info ) {
1380 - return $enrolled_info;
1130 + if ( $getEnrolledInfo ) {
1131 + return $getEnrolledInfo;
1381 1132 }
1382 1133 }
1383 1134
1384 1135 return false;
@@ -1384,74 +1135,73 @@
1384 1135 return false;
1385 1136 }
1386 1137
1387 1138
1388 - /**
1389 - * Get course by enrol id
1390 - *
1391 - * @since 1.6.1
1392 - *
1393 - * @param int $enrol_id enrol ID.
1394 - *
1395 - * @return array|bool|\WP_Post|null
1396 - */
1139 + /**
1140 + * @param int $enrol_id
1141 + * @return array|bool|\WP_Post|null
1142 + *
1143 + * Get course by enrol id
1144 + *
1145 + * @since v.1.6.1
1146 + */
1397 1147 public function get_course_by_enrol_id( $enrol_id = 0 ) {
1398 - if ( ! $enrol_id ) {
1399 - return false;
1400 - }
1148 + if ( ! $enrol_id ) {
1149 + return false;
1150 + }
1401 1151
1402 - global $wpdb;
1152 + global $wpdb;
1403 1153
1404 - $course_id = (int) $wpdb->get_var(
1405 - $wpdb->prepare(
1406 - "SELECT post_parent
1154 + $course_id = (int) $wpdb->get_var( $wpdb->prepare(
1155 + "SELECT post_parent
1407 1156 FROM {$wpdb->posts}
1408 1157 WHERE post_type = %s
1409 1158 AND ID = %d
1410 1159 ",
1411 - 'tutor_enrolled',
1412 - $enrol_id
1413 - )
1414 - );
1160 + 'tutor_enrolled',
1161 + $enrol_id
1162 + ) );
1415 1163
1416 - if ( $course_id ) {
1417 - return get_post( $course_id );
1418 - }
1164 + if ( $course_id ) {
1165 + return get_post( $course_id );
1166 + }
1419 1167
1420 - return null;
1421 - }
1168 + return null;
1169 + }
1422 1170
1423 1171 /**
1424 - * Get the course Enrolled confirmation by lesson ID
1172 + * @param int $lesson_id
1173 + * @param int $user_id
1425 1174 *
1426 - * @since 1.0.0
1175 + * @return array|bool|null|object
1427 1176 *
1428 - * @param int $lesson_id lesson ID.
1429 - * @param int $user_id user ID.
1177 + * Get the course Enrolled confirmation by lesson ID
1430 1178 *
1431 - * @return array|bool|null|object
1179 + * @since v.1.0.0
1432 1180 */
1433 1181 public function is_course_enrolled_by_lesson( $lesson_id = 0, $user_id = 0 ) {
1434 1182 $lesson_id = $this->get_post_id( $lesson_id );
1435 1183 $user_id = $this->get_user_id( $user_id );
1436 - $course_id = $this->get_course_id_by( 'lesson', $lesson_id );
1184 + $course_id = $this->get_course_id_by_lesson( $lesson_id );
1437 1185
1438 - return EnrollmentModel::is_enrolled( $course_id );
1186 + return $this->is_enrolled( $course_id );
1439 1187 }
1440 1188
1441 1189 /**
1190 + * @param int $lesson_id
1191 + *
1192 + * @return bool|mixed
1193 + *
1442 1194 * Get the course ID by Lesson
1443 1195 *
1444 - * @since 1.0.0
1445 - * @since 1.4.8 Legacy Supports Added.
1196 + * @since v.1.0.0
1446 1197 *
1447 - * @param int $lesson_id lesson id.
1448 - *
1449 - * @return bool|mixed
1198 + * @updated v.1.4.8
1199 + * Added Legacy Supports
1450 1200 */
1451 1201 public function get_course_id_by_lesson( $lesson_id = 0 ) {
1452 1202 $lesson_id = $this->get_post_id( $lesson_id );
1453 - $course_id = $this->get_course_id_by( 'lesson', $lesson_id );
1203 + $course_id = get_post_meta( $lesson_id, '_tutor_course_id_for_lesson', true );
1454 1204
1455 1205 if ( ! $course_id ) {
1456 1206 $course_id = $this->get_course_id_by_content( $lesson_id );
1457 1207 }
@@ -1462,56 +1212,52 @@
1462 1212 return $course_id;
1463 1213 }
1464 1214
1465 1215 /**
1466 - * Get first lesson of a course
1216 + * @param int $course_id
1467 1217 *
1468 - * @since 1.0.0
1218 + * @return bool|false|string
1469 1219 *
1470 - * @param int $course_id course ID.
1471 - * @param mixed $post_type post type.
1220 + * Get first lesson of a course
1472 1221 *
1473 - * @return bool|false|string
1222 + * @since v.1.0.0
1474 1223 */
1475 - public function get_course_first_lesson( $course_id = 0, $post_type = null ) {
1224 + public function get_course_first_lesson( $course_id = 0 ) {
1476 1225 global $wpdb;
1477 1226
1478 1227 $course_id = $this->get_post_id( $course_id );
1479 1228 $user_id = get_current_user_id();
1480 1229
1481 - $lessons = $wpdb->get_results(
1482 - $wpdb->prepare(
1483 - "SELECT items.ID
1230 + $lessons = $wpdb->get_results( $wpdb->prepare(
1231 + "SELECT items.ID
1484 1232 FROM {$wpdb->posts} topic
1485 1233 INNER JOIN {$wpdb->posts} items
1486 1234 ON topic.ID = items.post_parent
1487 1235 WHERE topic.post_parent = %d
1488 1236 AND items.post_status = %s
1489 - " . ( $post_type ? " AND items.post_type='{$post_type}' " : '' ) . '
1490 1237 ORDER BY topic.menu_order ASC,
1491 1238 items.menu_order ASC;
1492 - ',
1493 - $course_id,
1494 - 'publish'
1495 - )
1496 - );
1239 + ",
1240 + $course_id,
1241 + 'publish'
1242 + ) );
1497 1243
1498 1244 $first_lesson = false;
1499 1245
1500 - if ( $this->count( $lessons ) ) {
1501 - if ( ! empty( $lessons[0] ) ) {
1502 - $first_lesson = $lessons[0];
1503 - }
1246 + if ( tutils()->count( $lessons ) ) {
1247 + if ( ! empty( $lessons[0] ) ) {
1248 + $first_lesson = $lessons[0];
1249 + }
1504 1250
1505 1251 foreach ( $lessons as $lesson ) {
1506 1252 $is_complete = get_user_meta( $user_id, "_tutor_completed_lesson_id_{$lesson->ID}", true );
1507 - if ( ! $is_complete && ! $this->has_attempted_quiz( $user_id, $lesson->ID ) ) {
1253 + if ( ! $is_complete ) {
1508 1254 $first_lesson = $lesson;
1509 1255 break;
1510 1256 }
1511 1257 }
1512 1258
1513 - if ( ! empty( $first_lesson->ID ) ) {
1259 + if ( ! empty($first_lesson->ID) ) {
1514 1260 return get_permalink( $first_lesson->ID );
1515 1261 }
1516 1262 }
1517 1263
@@ -1518,15 +1264,28 @@
1518 1264 return false;
1519 1265 }
1520 1266
1521 1267 /**
1522 - * Get post video.
1523 1268 *
1524 - * @since 1.0.0
1269 + * Get course sub pages in course dashboard
1525 1270 *
1526 - * @param int $post_id post ID.
1271 + * @since v.1.0.0
1272 + */
1273 + public function course_sub_pages() {
1274 + $nav_items = array(
1275 + 'questions' => __('Q&A', 'tutor'),
1276 + 'announcements' => __('Announcements', 'tutor'),
1277 + );
1278 +
1279 + return apply_filters( 'tutor_course/single/enrolled/nav_items', $nav_items );
1280 + }
1281 +
1282 + /**
1283 + * @param int $post_id
1527 1284 *
1528 1285 * @return bool|array
1286 + *
1287 + * @since v.1.0.0
1529 1288 */
1530 1289 public function get_video( $post_id = 0 ) {
1531 1290 $post_id = $this->get_post_id( $post_id );
1532 1291 $attachments = get_post_meta( $post_id, '_video', true );
@@ -1536,137 +1295,77 @@
1536 1295 return $attachments;
1537 1296 }
1538 1297
1539 1298 /**
1540 - * Update the video Info
1299 + * @param int $post_id
1300 + * @param array $video_data
1541 1301 *
1542 - * @since 1.0.0
1302 + * @return bool
1543 1303 *
1544 - * @param int $post_id post ID.
1545 - * @param array $video_data video data.
1546 - *
1547 - * @return void
1304 + * Update the video Info
1548 1305 */
1549 1306 public function update_video( $post_id = 0, $video_data = array() ) {
1550 1307 $post_id = $this->get_post_id( $post_id );
1551 1308
1552 1309 if ( is_array( $video_data ) && count( $video_data ) ) {
1553 - update_post_meta( $post_id, '_video', $this->filter_video_meta( $video_data ) );
1310 + update_post_meta( $post_id, '_video', $video_data );
1554 1311 }
1555 1312 }
1556 1313
1557 1314 /**
1558 - * Whether a scalar looks like an absolute local filesystem path.
1315 + * @param int $post_id
1559 1316 *
1560 - * Used when filtering video meta so paths cannot be smuggled under another key.
1561 - * Does not call file_exists() — that would allow path probing on save.
1317 + * @return bool|mixed
1562 1318 *
1563 - * @since 4.0.6
1564 - *
1565 - * @param mixed $value value to inspect.
1566 - *
1567 - * @return bool
1319 + * @since v.1.0.0
1568 1320 */
1569 - private function is_local_filesystem_path_value( $value ) {
1570 - if ( ! is_string( $value ) || '' === $value ) {
1571 - return false;
1572 - }
1321 + public function get_attachments( $post_id = 0 ) {
1322 + $post_id = $this->get_post_id( $post_id );
1323 + $attachments = maybe_unserialize( get_post_meta( $post_id, '_tutor_attachments', true ) );
1324 + $attachments_arr = array();
1573 1325
1574 - if ( preg_match( '#^https?://#i', $value ) ) {
1575 - return false;
1576 - }
1326 + $font_icons = apply_filters( 'tutor_file_types_icon', array(
1327 + 'archive',
1328 + 'audio',
1329 + 'code',
1330 + 'default',
1331 + 'document',
1332 + 'interactive',
1333 + 'spreadsheet',
1334 + 'text',
1335 + 'video',
1336 + 'image',
1337 + ));
1577 1338
1578 - if ( '/' === $value[0] ) {
1579 - return true;
1580 - }
1339 + if ( is_array( $attachments ) && count( $attachments ) ) {
1340 + foreach ( $attachments as $attachment ) {
1341 + $url = wp_get_attachment_url( $attachment );
1342 + $file_type = wp_check_filetype( $url );
1343 + $ext = $file_type['ext'];
1344 + $title = get_the_title($attachment);
1581 1345
1582 - if ( preg_match( '/^[a-zA-Z]:[\\\\\\/]/', $value ) ) {
1583 - return true;
1584 - }
1346 + $file_path = get_attached_file( $attachment );
1347 + $size_bytes = file_exists($file_path) ? filesize( $file_path ) : 0;
1348 + $size = size_format( $size_bytes, 2 );
1349 + $type = wp_ext2type( $ext );
1585 1350
1586 - return false;
1587 - }
1351 + $icon = 'default';
1352 + if ( $type && in_array( $type, $font_icons ) ) {
1353 + $icon = $type;
1354 + }
1588 1355
1589 - /**
1590 - * Copy only trusted keys from video meta.
1591 - *
1592 - * @since 4.0.2
1593 - *
1594 - * @param array $video video meta.
1595 - *
1596 - * @return array
1597 - */
1598 - public function filter_video_meta( $video ) {
1599 - if ( ! is_array( $video ) ) {
1600 - return array();
1601 - }
1356 + $data = array(
1357 + 'post_id' => $post_id,
1358 + 'id' => $attachment,
1359 + 'url' => $url,
1360 + 'name' => $title . '.' . $ext,
1361 + 'title' => $title,
1362 + 'ext' => $ext,
1363 + 'size' => $size,
1364 + 'size_bytes' => $size_bytes,
1365 + 'icon' => $icon,
1366 + );
1602 1367
1603 - $allowed_keys = apply_filters(
1604 - 'tutor_allowed_video_meta_keys',
1605 - array(
1606 - 'source',
1607 - 'source_video_id',
1608 - 'source_html5',
1609 - 'source_external_url',
1610 - 'source_youtube',
1611 - 'source_vimeo',
1612 - 'source_embedded',
1613 - 'source_shortcode',
1614 - 'source_type',
1615 - 'poster',
1616 - 'poster_url',
1617 - 'runtime',
1618 - 'duration_sec',
1619 - 'playtime',
1620 - )
1621 - );
1622 -
1623 - $filtered = array();
1624 - foreach ( $video as $key => $value ) {
1625 - if ( 'path' === $key ) {
1626 - continue;
1627 - }
1628 -
1629 - if ( $this->is_local_filesystem_path_value( $value ) ) {
1630 - continue;
1631 - }
1632 -
1633 - $is_source_key = is_string( $key ) && 1 === preg_match( '/^source_[a-z0-9_]+$/', $key );
1634 - if ( in_array( $key, $allowed_keys, true ) || $is_source_key ) {
1635 - $filtered[ $key ] = $value;
1636 - }
1637 - }
1638 -
1639 - return $filtered;
1640 - }
1641 -
1642 - /**
1643 - * Get tutor attachment
1644 - *
1645 - * @since 1.0.0
1646 - *
1647 - * @since 2.2.0
1648 - * count param added to count attachment.
1649 - *
1650 - * @param int $post_id post id.
1651 - * @param string $meta_key meta key.
1652 - * @param bool $count set true to get only count.
1653 - *
1654 - * @return array
1655 - */
1656 - public function get_attachments( $post_id = 0, $meta_key = '_tutor_attachments', $count = false ) {
1657 - $post_id = $this->get_post_id( $post_id );
1658 - $attachments = maybe_unserialize( get_post_meta( $post_id, $meta_key, true ) );
1659 - $attachments_arr = array();
1660 -
1661 - // Since 2.2.0 get only count if required.
1662 - if ( $count ) {
1663 - return is_array( $attachments ) ? count( $attachments ) : 0;
1664 - }
1665 -
1666 - if ( is_array( $attachments ) && count( $attachments ) ) {
1667 - foreach ( $attachments as $attachment ) {
1668 - $data = (array) $this->get_attachment_data( $attachment );
1669 1368 $attachments_arr[] = (object) apply_filters( 'tutor/posts/attachments', $data );
1670 1369 }
1671 1370 }
1672 1371
@@ -1672,90 +1371,35 @@
1672 1371
1673 1372 return $attachments_arr;
1674 1373 }
1675 1374
1676 - /**
1677 - * Get attachment data.
1678 - *
1679 - * @since 1.0.0
1680 - *
1681 - * @param mixed $attachment_id attachment id.
1682 - *
1683 - * @return object
1684 - */
1685 - public function get_attachment_data( $attachment_id ) {
1686 - $url = wp_get_attachment_url( $attachment_id );
1687 - $file_type = wp_check_filetype( $url );
1688 - $ext = $file_type['ext'];
1689 - $title = get_the_title( $attachment_id );
1690 1375
1691 - $file_path = get_attached_file( $attachment_id );
1692 - $size_bytes = file_exists( $file_path ) ? filesize( $file_path ) : 0;
1693 - $size = size_format( $size_bytes, 2 );
1694 - $type = wp_ext2type( $ext );
1695 -
1696 - $icon = 'default';
1697 - $font_icons = apply_filters(
1698 - 'tutor_file_types_icon',
1699 - array(
1700 - 'archive',
1701 - 'audio',
1702 - 'code',
1703 - 'default',
1704 - 'document',
1705 - 'interactive',
1706 - 'spreadsheet',
1707 - 'text',
1708 - 'video',
1709 - 'image',
1710 - )
1711 - );
1712 -
1713 - if ( $type && in_array( $type, $font_icons ) ) {
1714 - $icon = $type;
1715 - }
1716 -
1717 - $data = array(
1718 - 'post_id' => $attachment_id,
1719 - 'id' => $attachment_id,
1720 - 'url' => $url,
1721 - 'name' => $title . '.' . $ext,
1722 - 'title' => $title,
1723 - 'ext' => $ext,
1724 - 'size' => $size,
1725 - 'size_bytes' => $size_bytes,
1726 - 'icon' => $icon,
1727 - );
1728 -
1729 - return (object) $data;
1730 - }
1731 -
1732 1376 /**
1733 - * Return seconds to formatted playtime.
1377 + * @param $seconds
1734 1378 *
1735 - * @since 1.0.0
1379 + * @return string
1736 1380 *
1737 - * @param int $seconds seconds.
1381 + * return seconds to formatted playtime
1738 1382 *
1739 - * @return string
1383 + * @since v.1.0.0
1740 1384 */
1741 1385 public function playtime_string( $seconds ) {
1742 - $sign = ( ( $seconds < 0 ) ? '-' : '' );
1386 + $sign = ( ( $seconds < 0 ) ? '-' : '' );
1743 1387 $seconds = round( abs( $seconds ) );
1744 - $h = (int) floor( $seconds / 3600 );
1745 - $m = (int) floor( ( $seconds - ( 3600 * $h ) ) / 60 );
1746 - $s = (int) round( $seconds - ( 3600 * $h ) - ( 60 * $m ) );
1747 - return $sign . ( $h ? $h . ':' : '' ) . ( $h ? str_pad( $m, 2, '0', STR_PAD_LEFT ) : intval( $m ) ) . ':' . str_pad( $s, 2, 0, STR_PAD_LEFT );
1388 + $H = (int) floor( $seconds / 3600);
1389 + $M = (int) floor( ($seconds - (3600 * $H) ) / 60 );
1390 + $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
1391 + return $sign.($H ? $H.':' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).':'.str_pad($S, 2, 0, STR_PAD_LEFT);
1748 1392 }
1749 1393
1750 1394 /**
1751 - * Get the playtime in array
1395 + * @param $seconds
1752 1396 *
1753 - * @since 1.0.0
1397 + * @return array
1754 1398 *
1755 - * @param int $seconds seconds.
1399 + * Get the playtime in array
1756 1400 *
1757 - * @return array
1401 + * @since v.1.0.0
1758 1402 */
1759 1403 public function playtime_array( $seconds ) {
1760 1404 $run_time_format = array(
1761 1405 'hours' => '00',
@@ -1762,23 +1406,23 @@
1762 1406 'minutes' => '00',
1763 1407 'seconds' => '00',
1764 1408 );
1765 1409
1766 - if ( $seconds <= 0 ) {
1410 + if ($seconds <= 0 ) {
1767 1411 return $run_time_format;
1768 1412 }
1769 1413
1770 - $play_time_string = $this->playtime_string( $seconds );
1771 - $time_in_array = explode( ':', $play_time_string );
1414 + $playTimeString = $this->playtime_string( $seconds );
1415 + $timeInArray = explode( ':', $playTimeString );
1772 1416
1773 - $run_time_size = count( $time_in_array );
1774 - if ( 3 === $run_time_size ) {
1775 - $run_time_format['hours'] = $time_in_array[0];
1776 - $run_time_format['minutes'] = $time_in_array[1];
1777 - $run_time_format['seconds'] = $time_in_array[2];
1778 - } elseif ( 2 === $run_time_size ) {
1779 - $run_time_format['minutes'] = $time_in_array[0];
1780 - $run_time_format['seconds'] = $time_in_array[1];
1417 + $run_time_size = count($timeInArray);
1418 + if ( $run_time_size === 3 ) {
1419 + $run_time_format[ 'hours' ] = $timeInArray[0];
1420 + $run_time_format[ 'minutes' ] = $timeInArray[1];
1421 + $run_time_format[ 'seconds' ] = $timeInArray[2];
1422 + } elseif ( $run_time_size === 2 ) {
1423 + $run_time_format[ 'minutes' ] = $timeInArray[0];
1424 + $run_time_format[ 'seconds' ] = $timeInArray[1];
1781 1425 }
1782 1426
1783 1427 return $run_time_format;
1784 1428 }
@@ -1783,66 +1427,33 @@
1783 1427 return $run_time_format;
1784 1428 }
1785 1429
1786 1430 /**
1787 - * Convert seconds to human readable time
1431 + * @param $seconds
1788 1432 *
1789 - * @since 1.0.0
1433 + * @return string
1790 1434 *
1791 - * @param int $seconds seconds.
1435 + * Convert seconds to human readable time
1792 1436 *
1793 - * @return string
1437 + * @since v.1.0.0
1794 1438 */
1795 1439 public function seconds_to_time_context( $seconds ) {
1796 - $sign = ( ( $seconds < 0 ) ? '-' : '' );
1440 + $sign = ( ($seconds < 0) ? '-' : '');
1797 1441 $seconds = round( abs( $seconds ) );
1798 - $h = (int) floor( $seconds / 3600 );
1799 - $m = (int) floor( ( $seconds - ( 3600 * $h ) ) / 60 );
1800 - $s = (int) round( $seconds - ( 3600 * $h ) - ( 60 * $m ) );
1442 + $H = (int) floor( $seconds / 3600);
1443 + $M = (int) floor( ($seconds - (3600 * $H) ) / 60 );
1444 + $S = (int) round( $seconds - (3600 * $H) - (60 * $M) );
1801 1445
1802 - return $sign . ( $h ? $h . 'h ' : '' ) . ( $h ? str_pad( $m, 2, '0', STR_PAD_LEFT ) : intval( $m ) ) . 'm ' . str_pad( $s, 2, 0, STR_PAD_LEFT ) . 's';
1446 + return $sign.($H ? $H.'h ' : '').($H ? str_pad($M, 2, '0', STR_PAD_LEFT) : intval($M)).'m '.str_pad($S, 2, 0, STR_PAD_LEFT).'s';
1803 1447 }
1804 1448
1805 1449 /**
1806 - * Get human readable time
1450 + * @param int $lesson_id
1807 1451 *
1808 - * @since 2.0.7
1452 + * @return bool|object
1809 1453 *
1810 - * @param string $from date time string value. Example: 2022-06-24 22:00:00.
1811 - * @param string $to (optional) date time string value. Default value is current.
1812 - * @param string $format format you want to print. Default: '%ad %hh %im %ss' Help: https://www.php.net/manual/en/dateinterval.format.php.
1813 - * @param bool $show_postfix_text show postfix text like 'ago', 'left'.
1814 - *
1815 - * @return string
1454 + * @since v.1.0.0
1816 1455 */
1817 - public function get_human_readable_time( $from, $to = null, $format = null, $show_postfix_text = true ) {
1818 - $postfix_text = '';
1819 - $wp_tz = new \DateTimeZone( wp_timezone_string() );
1820 - $from_date_time = new \DateTime( $from, $wp_tz );
1821 - $to_date_time = null === $to ? new \DateTime( 'now', $wp_tz ) : new \DateTime( $to, $wp_tz );
1822 - $format = null === $format ? '%ad %hh %im %ss' : $format;
1823 -
1824 - if ( $to_date_time > $from_date_time ) {
1825 - $postfix_text = __( ' ago', 'tutor' );
1826 - } else {
1827 - $postfix_text = __( ' left', 'tutor' );
1828 - }
1829 -
1830 - $time_span = $to_date_time->diff( $from_date_time );
1831 - $postfix_text = true === $show_postfix_text ? $postfix_text : '';
1832 -
1833 - return $time_span->format( $format ) . $postfix_text;
1834 - }
1835 -
1836 - /**
1837 - * Get video info
1838 - *
1839 - * @since 1.0.0
1840 - *
1841 - * @param int $lesson_id lesson id.
1842 - *
1843 - * @return mixed bool return if video does not exits otherwise object return.
1844 - */
1845 1456 public function get_video_info( $lesson_id = 0 ) {
1846 1457 $lesson_id = $this->get_post_id( $lesson_id );
1847 1458 $video = $this->get_video( $lesson_id );
1848 1459
@@ -1853,79 +1464,61 @@
1853 1464 $info = array(
1854 1465 'playtime' => '00:00',
1855 1466 );
1856 1467
1857 - $types = apply_filters(
1858 - 'tutor_video_types',
1859 - array(
1860 - 'mp4' => 'video/mp4',
1861 - 'webm' => 'video/webm',
1862 - 'ogg' => 'video/ogg',
1863 - )
1864 - );
1468 + $types = apply_filters( 'tutor_video_types', array( "mp4" => "video/mp4", "webm" => "video/webm", "ogg" => "video/ogg" ) );
1865 1469
1866 - $video_source = $this->avalue_dot( 'source', $video );
1470 + $videoSource = $this->avalue_dot('source', $video);
1867 1471
1868 - if ( 'html5' === $video_source ) {
1869 - $source_video_id = $this->avalue_dot( 'source_video_id', $video );
1870 - $video_info = get_post_meta( $source_video_id, '_wp_attachment_metadata', true );
1472 + if ( $videoSource === 'html5' ) {
1473 + $sourceVideoID = $this->avalue_dot( 'source_video_id', $video );
1474 + $video_info = get_post_meta( $sourceVideoID, '_wp_attachment_metadata', true );
1871 1475
1872 - if ( $video_info && in_array( $this->array_get( 'mime_type', $video_info ), $types ) ) {
1873 - $path = get_attached_file( $source_video_id );
1476 + if ( $video_info && in_array( $this->array_get('mime_type', $video_info), $types ) ) {
1477 + $path = get_attached_file( $sourceVideoID );
1874 1478 $info['playtime'] = $video_info['length_formatted'];
1875 1479 $info['path'] = $path;
1876 - $info['url'] = wp_get_attachment_url( $source_video_id );
1480 + $info['url'] = wp_get_attachment_url( $sourceVideoID );
1877 1481 $info['ext'] = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
1878 1482 $info['type'] = $types[ $info['ext'] ];
1879 1483 }
1880 1484 }
1881 1485
1882 - if ( 'html5' !== $video_source ) {
1883 - $video = maybe_unserialize( get_post_meta( $lesson_id, '_video', true ) );
1884 - $runtime_hours = $this->avalue_dot( 'runtime.hours', $video );
1885 - $runtime_minutes = $this->avalue_dot( 'runtime.minutes', $video );
1886 - $runtime_seconds = $this->avalue_dot( 'runtime.seconds', $video );
1486 + if ( $videoSource !== 'html5' ) {
1487 + $video = maybe_unserialize( get_post_meta( $lesson_id, '_video', true ) );
1488 + $runtimeHours = tutor_utils()->avalue_dot( 'runtime.hours', $video );
1489 + $runtimeMinutes = tutor_utils()->avalue_dot( 'runtime.minutes', $video );
1490 + $runtimeSeconds = tutor_utils()->avalue_dot( 'runtime.seconds', $video );
1887 1491
1888 - $runtime_hours = $runtime_hours ? $runtime_hours : '00';
1889 - $runtime_minutes = $runtime_minutes ? $runtime_minutes : '00';
1890 - $runtime_seconds = $runtime_seconds ? $runtime_seconds : '00';
1492 + $runtimeHours = $runtimeHours ? $runtimeHours : '00';
1493 + $runtimeMinutes = $runtimeMinutes ? $runtimeMinutes : '00';
1494 + $runtimeSeconds = $runtimeSeconds ? $runtimeSeconds : '00';
1891 1495
1892 - $info['playtime'] = "$runtime_hours:$runtime_minutes:$runtime_seconds";
1496 + $info['playtime'] = "$runtimeHours:$runtimeMinutes:$runtimeSeconds";
1893 1497 }
1894 1498
1895 - $resolved_path = isset( $info['path'] ) ? $info['path'] : null;
1896 - $info = array_merge( $info, $this->filter_video_meta( (array) $video ) );
1499 + $info = array_merge( $info, $video );
1897 1500
1898 - if ( $resolved_path ) {
1899 - $info['path'] = $resolved_path;
1900 - } else {
1901 - unset( $info['path'] );
1902 - }
1903 -
1904 1501 return (object) $info;
1905 1502 }
1906 1503
1907 - /**
1908 - * Get optimized duration.
1909 - *
1910 - * @since 1.0.0
1911 - *
1912 - * @param mixed $duration duration.
1913 - *
1914 - * @return mixed
1915 - */
1916 1504 public function get_optimized_duration( $duration ) {
1917 - return $this->course_content_time_format( $duration );
1505 + /* if(is_string($duration)){
1506 + strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove Empty hour
1507 + strpos($duration, '00:')===0 ? $duration=substr($duration, 3) : 0; // Remove empty minute
1508 + } */
1509 +
1510 + return $duration;
1918 1511 }
1919 1512
1920 1513 /**
1921 - * Ensure if attached video is self hosted or not.
1514 + * @param int $post_id
1922 1515 *
1923 - * @since 1.0.0
1516 + * @return bool
1924 1517 *
1925 - * @param int $post_id post ID.
1518 + * Ensure if attached video is self hosted or not
1926 1519 *
1927 - * @return bool
1520 + * @since v.1.0.0
1928 1521 */
1929 1522 public function is_html5_video( $post_id = 0 ) {
1930 1523 $post_id = $this->get_post_id( $post_id );
1931 1524 $video = $this->get_video( $post_id );
@@ -1933,25 +1526,59 @@
1933 1526 if ( ! $video ) {
1934 1527 return false;
1935 1528 }
1936 1529
1937 - return 'html5' === $this->avalue_dot( 'source', $video );
1530 + $videoSource = $this->avalue_dot( 'source', $video );
1531 +
1532 + return $videoSource === 'html5';
1938 1533 }
1939 1534
1940 1535 /**
1941 - * Check lesson is completed.
1942 1536 *
1943 - * @since 1.0.0
1537 + * return lesson type icon
1944 1538 *
1945 - * @param int $lesson_id lesson id.
1946 - * @param int $user_id user id.
1539 + * @param int $lesson_id
1540 + * @param bool $html
1541 + * @param bool $echo
1947 1542 *
1543 + * @return string
1544 + *
1545 + * @since v.1.0.0
1546 + */
1547 + public function get_lesson_type_icon( $lesson_id = 0, $html = false, $echo = false ) {
1548 + $post_id = $this->get_post_id( $lesson_id );
1549 + $video = tutor_utils()->get_video_info( $post_id );
1550 +
1551 + $play_time = false;
1552 + if ( $video ) {
1553 + $play_time = $video->playtime;
1554 + }
1555 +
1556 + $tutor_lesson_type_icon = $play_time ? 'youtube' : 'document';
1557 +
1558 + if ( $html ) {
1559 + $tutor_lesson_type_icon = "<i class='tutor-icon-$tutor_lesson_type_icon'></i> ";
1560 + }
1561 +
1562 + if ( $echo ) {
1563 + echo $tutor_lesson_type_icon;
1564 + }
1565 +
1566 + return $tutor_lesson_type_icon;
1567 + }
1568 +
1569 + /**
1570 + * @param int $lesson_id
1571 + * @param int $user_id
1572 + *
1948 1573 * @return bool|mixed
1574 + *
1575 + * @since v.1.0.0
1949 1576 */
1950 1577 public function is_completed_lesson( $lesson_id = 0, $user_id = 0 ) {
1951 1578 $lesson_id = $this->get_post_id( $lesson_id );
1952 1579 $user_id = $this->get_user_id( $user_id );
1953 - $is_completed = get_user_meta( $user_id, '_tutor_completed_lesson_id_' . $lesson_id, true );
1580 + $is_completed = get_user_meta( $user_id, '_tutor_completed_lesson_id_'.$lesson_id, true );
1954 1581
1955 1582 if ( $is_completed ) {
1956 1583 return $is_completed;
1957 1584 }
@@ -1959,51 +1586,46 @@
1959 1586 return false;
1960 1587 }
1961 1588
1962 1589 /**
1590 + * @param int $course_id
1591 + * @param int $user_id
1592 + *
1593 + * @return array|bool|null|object
1594 + *
1963 1595 * Determine if a course completed
1964 1596 *
1965 - * @since 1.0.0
1966 - * @since 2.2.3 $enable_cache param added.
1597 + * @since v.1.0.0
1967 1598 *
1968 - * @param int $course_id course id.
1969 - * @param int $user_id user id.
1970 - * @param bool $enable_cache enable or disable cache for particular function call.
1971 - *
1972 - * @return array|bool|null|object
1599 + * @updated v.1.4.9
1973 1600 */
1974 - public function is_completed_course( $course_id = 0, $user_id = 0, $enable_cache = true ) {
1601 + public function is_completed_course( $course_id = 0, $user_id = 0 ) {
1602 + if ( ! is_user_logged_in() ) {
1603 + return apply_filters( 'is_completed_course', false, $course_id, $user_id );
1604 + }
1975 1605
1976 1606 global $wpdb;
1977 - $course_id = $this->get_post_id( $course_id );
1978 - $user_id = $this->get_user_id( $user_id );
1607 + $course_id = $this->get_post_id($course_id);
1608 + $user_id = $this->get_user_id($user_id);
1979 1609
1980 - $cache_key = "tutor_is_completed_course_{$course_id}_{$user_id}";
1981 - $is_completed = TutorCache::get( $cache_key );
1610 + $is_completed = $wpdb->get_row( $wpdb->prepare(
1611 + "SELECT comment_ID,
1612 + comment_post_ID AS course_id,
1613 + comment_author AS completed_user_id,
1614 + comment_date AS completion_date,
1615 + comment_content AS completed_hash
1616 + FROM {$wpdb->comments}
1617 + WHERE comment_agent = %s
1618 + AND comment_type = %s
1619 + AND comment_post_ID = %d
1620 + AND user_id = %d;
1621 + ",
1622 + 'TutorLMSPlugin',
1623 + 'course_completed',
1624 + $course_id,
1625 + $user_id
1626 + ) );
1982 1627
1983 - if ( false === $is_completed || false === $enable_cache ) {
1984 - $is_completed = $wpdb->get_row(
1985 - $wpdb->prepare(
1986 - "SELECT comment_ID,
1987 - comment_post_ID AS course_id,
1988 - comment_author AS completed_user_id,
1989 - comment_date AS completion_date,
1990 - comment_content AS completed_hash
1991 - FROM {$wpdb->comments}
1992 - WHERE comment_agent = %s
1993 - AND comment_type = %s
1994 - AND comment_post_ID = %d
1995 - AND user_id = %d;
1996 - ",
1997 - 'TutorLMSPlugin',
1998 - 'course_completed',
1999 - $course_id,
2000 - $user_id
2001 - )
2002 - );
2003 - TutorCache::set( $cache_key, $is_completed );
2004 - }
2005 -
2006 1628 if ( $is_completed ) {
2007 1629 return apply_filters( 'is_completed_course', $is_completed, $course_id, $user_id );
2008 1630 }
2009 1631
@@ -2010,15 +1632,15 @@
2010 1632 return apply_filters( 'is_completed_course', false, $course_id, $user_id );
2011 1633 }
2012 1634
2013 1635 /**
2014 - * Sanitize input array
1636 + * @param array $input
2015 1637 *
2016 - * @since 1.0.0
1638 + * @return array
2017 1639 *
2018 - * @param array $input input.
1640 + * Sanitize input array
2019 1641 *
2020 - * @return array
1642 + * @since v.1.0.0
2021 1643 */
2022 1644 public function sanitize_array( $input = array() ) {
2023 1645 $array = array();
2024 1646
@@ -2023,14 +1645,14 @@
2023 1645 $array = array();
2024 1646
2025 1647 if ( is_array( $input ) && count( $input ) ) {
2026 1648 foreach ( $input as $key => $value ) {
2027 - if ( is_array( $value ) ) {
2028 - $array[ $key ] = $this->sanitize_array( $value );
1649 + if ( is_array( $value )) {
1650 + $array[$key] = $this->sanitize_array( $value );
2029 1651 } else {
2030 - $key = sanitize_text_field( $key );
2031 - $value = sanitize_text_field( $value );
2032 - $array[ $key ] = $value;
1652 + $key = sanitize_text_field( $key );
1653 + $value = sanitize_text_field( $value );
1654 + $array[$key] = $value;
2033 1655 }
2034 1656 }
2035 1657 }
2036 1658
@@ -2037,31 +1659,29 @@
2037 1659 return $array;
2038 1660 }
2039 1661
2040 1662 /**
2041 - * Determine if has any video in single
1663 + * @param int $post_id
2042 1664 *
2043 - * @since 1.0.0
1665 + * @return array|bool
2044 1666 *
2045 - * @param int $post_id post id.
1667 + * Determine if has any video in single
2046 1668 *
2047 - * @return array|bool
1669 + * @since v.1.0.0
2048 1670 */
2049 1671 public function has_video_in_single( $post_id = 0 ) {
2050 1672 if ( is_single() ) {
2051 1673 $post_id = $this->get_post_id( $post_id );
2052 -
1674 +
2053 1675 $video = $this->get_video( $post_id );
2054 1676 if ( $video && $this->array_get( 'source', $video ) !== '-1' ) {
2055 -
2056 - $not_empty = ! empty( $video['source_video_id'] ) ||
2057 - ! empty( $video['source_external_url'] ) ||
2058 - ! empty( $video['source_youtube'] ) ||
2059 - ! empty( $video['source_vimeo'] ) ||
2060 - ! empty( $video['source_embedded'] ) ||
2061 - ! empty( $video['source_shortcode'] ) ||
2062 - ( isset( $video['source_bunnynet'] ) && ! empty( $video['source_bunnynet'] ) );
2063 -
1677 +
1678 + $not_empty =!empty( $video[ 'source_video_id' ] ) ||
1679 + !empty( $video[ 'source_external_url' ] ) ||
1680 + !empty( $video[ 'source_youtube' ] ) ||
1681 + !empty( $video[ 'source_vimeo' ] ) ||
1682 + !empty( $video[ 'source_embedded' ] );
1683 +
2064 1684 return $not_empty ? $video : false;
2065 1685 }
2066 1686 }
2067 1687 return false;
@@ -2067,303 +1687,260 @@
2067 1687 return false;
2068 1688 }
2069 1689
2070 1690 /**
1691 + * @param int $start
1692 + * @param int $limit
1693 + * @param string $search_term
1694 + * @param int $course_id
1695 + *
1696 + * @return array|null|object
1697 + *
1698 + *
2071 1699 * Get the enrolled students for all courses.
1700 + *
2072 1701 * Pass course id in 4th parameter to get students course wise.
2073 1702 *
2074 1703 * @since v.1.0.0
2075 - *
2076 - * @param int $start start.
2077 - * @param int $limit limit.
2078 - * @param string $search_term search term.
2079 - * @param int $course_id course id.
2080 - * @param string $date data.
2081 - * @param string $order order.
2082 - *
2083 - * @return array|null|object
2084 1704 */
2085 - public function get_students( $start = 0, $limit = 10, $search_term = '', $course_id = '', $date = '', $order = 'DESC' ) {
1705 + public function get_students( $start = 0, $limit = 10, $search_term = '' ) {
2086 1706 global $wpdb;
2087 1707
2088 - $start = sanitize_text_field( $start );
2089 - $limit = sanitize_text_field( $limit );
2090 - $search_term = sanitize_text_field( $search_term );
2091 - $course_id = sanitize_text_field( $course_id );
2092 - $date = sanitize_text_field( $date );
1708 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
2093 1709
2094 - $course_query = '';
2095 - if ( '' !== $course_id ) {
2096 - $course_id = (int) $course_id;
2097 - $course_query = "AND posts.post_parent = {$course_id}";
2098 - }
2099 -
2100 - $date_query = '';
2101 - if ( '' !== $date ) {
2102 - $date_query = "AND DATE(user.user_registered) = CAST('$date' AS DATE)";
2103 - }
2104 -
2105 - $order_query = '';
2106 - if ( '' !== $order ) {
2107 - $is_valid_sql = sanitize_sql_orderby( $order );
2108 - if ( $is_valid_sql ) {
2109 - $order_query = "ORDER BY posts.post_date {$order}";
2110 - }
2111 - }
2112 - $search_term_raw = $search_term;
2113 - $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
2114 -
2115 - $students = $wpdb->get_results(
2116 - $wpdb->prepare(
2117 - "SELECT user.* FROM {$wpdb->posts} AS posts
2118 - INNER JOIN {$wpdb->users} AS user
2119 - ON user.ID = posts.post_author
2120 - WHERE posts.post_type = %s
2121 - AND posts.post_status = %s
2122 - {$course_query}
2123 - {$date_query}
2124 - AND (user.display_name LIKE %s OR user.user_email = %s OR user.user_login LIKE %s)
2125 - GROUP BY post_author
2126 - {$order_query}
2127 - LIMIT %d, %d
1710 + $students = $wpdb->get_results( $wpdb->prepare(
1711 + "SELECT SQL_CALC_FOUND_ROWS {$wpdb->users}.*
1712 + FROM {$wpdb->users}
1713 + INNER JOIN {$wpdb->usermeta}
1714 + ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
1715 + WHERE {$wpdb->usermeta}.meta_key = %s
1716 + AND ( {$wpdb->users}.display_name LIKE %s OR {$wpdb->users}.user_email LIKE %s )
1717 + ORDER BY {$wpdb->usermeta}.meta_value DESC
1718 + LIMIT {$start}, {$limit};
2128 1719 ",
2129 - 'tutor_enrolled',
2130 - 'completed',
2131 - $search_term,
2132 - $search_term_raw,
2133 - $search_term,
2134 - $start,
2135 - $limit
2136 - )
2137 - );
1720 + '_is_tutor_student',
1721 + $search_term,
1722 + $search_term
1723 + ) );
2138 1724
2139 1725 return $students;
2140 1726 }
2141 1727
2142 1728 /**
2143 - * Get the total students
2144 - * pass course id to get course wise total students
1729 + * @return int
2145 1730 *
2146 - * @since 1.0.0
1731 + * @since v.1.0.0
2147 1732 *
2148 - * @param string $search_term search term.
2149 - * @param string $course_id course id.
2150 - * @param string $date date.
1733 + * get the total students
1734 + * pass course id to get course wise total students
2151 1735 *
2152 - * @return int
1736 + * @since v.1.0.0
2153 1737 */
2154 - public function get_total_students( $search_term = '', $course_id = '', $date = '' ): int {
1738 + public function get_total_students( $search_term = '' ) {
2155 1739 global $wpdb;
2156 1740
2157 - $search_term = sanitize_text_field( $search_term );
2158 - $course_id = sanitize_text_field( $course_id );
2159 - $date = sanitize_text_field( $date );
1741 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
2160 1742
2161 - $course_query = '';
2162 - if ( '' !== $course_id ) {
2163 - $course_id = (int) $course_id;
2164 - $course_query = "AND posts.post_parent = {$course_id}";
2165 - }
2166 -
2167 - $date_query = '';
2168 - if ( '' !== $date ) {
2169 - $date_query = "AND DATE(user.user_registered) = CAST('$date' AS DATE)";
2170 - }
2171 - $search_term_raw = $search_term;
2172 - $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
2173 -
2174 - $students = $wpdb->get_results(
2175 - $wpdb->prepare(
2176 - "SELECT user.ID FROM {$wpdb->posts} AS posts
2177 - INNER JOIN {$wpdb->users} AS user
2178 - ON user.ID = posts.post_author
2179 - WHERE posts.post_type = %s
2180 - AND posts.post_status = %s
2181 - {$course_query}
2182 - {$date_query}
2183 - AND (user.display_name LIKE %s OR user.user_email = %s OR user.user_login LIKE %s)
2184 - GROUP BY user.ID
1743 + $count = $wpdb->get_var( $wpdb->prepare(
1744 + "SELECT COUNT({$wpdb->users}.ID)
1745 + FROM {$wpdb->users}
1746 + INNER JOIN {$wpdb->usermeta}
1747 + ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
1748 + WHERE {$wpdb->usermeta}.meta_key = %s
1749 + AND ( {$wpdb->users}.display_name LIKE %s OR {$wpdb->users}.user_email LIKE %s );
2185 1750 ",
2186 - 'tutor_enrolled',
2187 - 'completed',
2188 - $search_term,
2189 - $search_term_raw,
2190 - $search_term
2191 - )
2192 - );
1751 + '_is_tutor_student',
1752 + $search_term,
1753 + $search_term
1754 + ) );
2193 1755
2194 - return is_array( $students ) ? count( $students ) : 0;
1756 + return (int) $count;
2195 1757 }
2196 1758
2197 1759 /**
2198 - * Get complete courses ids by user
1760 + * @param int $user_id
2199 1761 *
2200 - * @since 1.0.0
1762 + * @return array
2201 1763 *
2202 - * @param int $user_id user id.
1764 + * Get complete courses ids by user
2203 1765 *
2204 - * @return array
1766 + * @since v.1.0.0
2205 1767 */
2206 - public function get_completed_courses_ids_by_user( $user_id = 0, $with_bundle_enrolled_courses = true ) {
1768 + public function get_completed_courses_ids_by_user( $user_id = 0 ) {
2207 1769 global $wpdb;
2208 1770
2209 1771 $user_id = $this->get_user_id( $user_id );
2210 1772
2211 - $with_bundle_enrolled_courses_clause = '';
2212 - if ( ! $with_bundle_enrolled_courses ) {
2213 - $with_bundle_enrolled_courses_clause = $wpdb->prepare(
2214 - "AND NOT EXISTS (
2215 - SELECT 1
2216 - FROM {$wpdb->postmeta} pm
2217 - WHERE pm.post_id = e.ID
2218 - AND pm.meta_key = %s
2219 - )",
2220 - '_tutor_bundle_id'
2221 - );
2222 - }
2223 -
2224 - $course_ids = (array) $wpdb->get_col(
2225 - $wpdb->prepare(
2226 - "SELECT comment_post_ID AS course_id
2227 - FROM {$wpdb->comments}
2228 - WHERE comment_agent = %s
1773 + $course_ids = (array) $wpdb->get_col( $wpdb->prepare(
1774 + "SELECT comment_post_ID AS course_id
1775 + FROM {$wpdb->comments}
1776 + WHERE comment_agent = %s
2229 1777 AND comment_type = %s
2230 1778 AND user_id = %d
2231 - AND comment_post_ID IN (
2232 - SELECT e.post_parent
2233 - FROM {$wpdb->posts} e
2234 - WHERE e.post_type = %s
2235 - AND e.post_author = %d
2236 - {$with_bundle_enrolled_courses_clause}
2237 - )",
2238 - 'TutorLMSPlugin',
2239 - 'course_completed',
2240 - $user_id,
2241 - 'tutor_enrolled',
2242 - $user_id
2243 - )
2244 - );
1779 + ",
1780 + 'TutorLMSPlugin',
1781 + 'course_completed',
1782 + $user_id
1783 + ) );
2245 1784
2246 1785 return $course_ids;
2247 1786 }
2248 1787
2249 1788 /**
2250 - * Get enrolled course ids by a user
1789 + * @param int $user_id
2251 1790 *
2252 - * @since 1.0.0
1791 + * @return bool|\WP_Query
2253 1792 *
2254 - * @param int $user_id user id.
1793 + * Return courses by user_id
2255 1794 *
2256 - * @param boolean $with_bundle_enrolled_courses including bundle courses.
1795 + * @since v.1.0.0
1796 + */
1797 + public function get_courses_by_user( $user_id = 0 ) {
1798 + $user_id = $this->get_user_id( $user_id );
1799 + $course_ids = $this->get_completed_courses_ids_by_user( $user_id );
1800 +
1801 + if ( count($course_ids) ) {
1802 + $course_post_type = tutor()->course_post_type;
1803 + $course_args = array(
1804 + 'post_type' => $course_post_type,
1805 + 'post_status' => 'publish',
1806 + 'post__in' => $course_ids,
1807 + 'posts_per_page' => -1
1808 + );
1809 +
1810 + return new \WP_Query( $course_args );
1811 + }
1812 +
1813 + return false;
1814 + }
1815 +
1816 + /**
1817 + * @param int $user_id
2257 1818 *
2258 - * @return array
1819 + * @return bool|\WP_Query
1820 + *
1821 + * Get the active course by user
1822 + *
1823 + * @since v.1.0.0
2259 1824 */
2260 - public function get_enrolled_courses_ids_by_user( $user_id = 0, $with_bundle_enrolled_courses = true ) {
2261 - global $wpdb;
2262 - $user_id = $this->get_user_id( $user_id );
1825 + public function get_active_courses_by_user( $user_id = 0 ) {
1826 + $user_id = $this->get_user_id( $user_id );
1827 + $course_ids = $this->get_completed_courses_ids_by_user( $user_id );
1828 + $enrolled_course_ids = $this->get_enrolled_courses_ids_by_user( $user_id );
1829 + $active_courses = array_diff( $enrolled_course_ids, $course_ids );
2263 1830
2264 - $with_bundle_enrolled_courses_clause = '';
2265 - if ( ! $with_bundle_enrolled_courses ) {
2266 - $with_bundle_enrolled_courses_clause = $wpdb->prepare(
2267 - "AND NOT EXISTS (
2268 - SELECT 1
2269 - FROM {$wpdb->postmeta} pm
2270 - WHERE pm.post_id = e.ID
2271 - AND pm.meta_key = %s
2272 - )",
2273 - '_tutor_bundle_id'
1831 + if ( count( $active_courses ) ) {
1832 + $course_post_type = tutor()->course_post_type;
1833 + $course_args = array(
1834 + 'post_type' => $course_post_type,
1835 + 'post_status' => 'publish',
1836 + 'post__in' => $active_courses,
1837 + 'posts_per_page' => -1,
2274 1838 );
1839 +
1840 + return new \WP_Query( $course_args );
2275 1841 }
2276 1842
2277 - $course_ids = $wpdb->get_col(
2278 - $wpdb->prepare(
2279 - "SELECT DISTINCT e.post_parent, e.post_date
2280 - FROM {$wpdb->posts} e
2281 - WHERE e.post_type = %s
2282 - AND e.post_status = %s
2283 - AND e.post_author = %d
2284 - {$with_bundle_enrolled_courses_clause}
2285 - ORDER BY e.post_date DESC;
1843 + return false;
1844 + }
1845 +
1846 + /**
1847 + * @param int $user_id
1848 + *
1849 + * @return array
1850 + *
1851 + * Get enrolled course ids by a user
1852 + *
1853 + * @since v.1.0.0
1854 + */
1855 + public function get_enrolled_courses_ids_by_user( $user_id = 0 ) {
1856 + global $wpdb;
1857 + $user_id = $this->get_user_id( $user_id );
1858 + $course_ids = $wpdb->get_col( $wpdb->prepare(
1859 + "SELECT post_parent
1860 + FROM {$wpdb->posts}
1861 + WHERE post_type = %s
1862 + AND post_status = %s
1863 + AND post_author = %d;
2286 1864 ",
2287 - 'tutor_enrolled',
2288 - 'completed',
2289 - $user_id
2290 - )
2291 - );
1865 + 'tutor_enrolled',
1866 + 'completed',
1867 + $user_id
1868 + ) );
2292 1869
2293 1870 return $course_ids;
2294 1871 }
2295 1872
2296 1873 /**
2297 - * Get total enrolled students by course id.
1874 + * @param int $course_id
2298 1875 *
2299 - * @since 1.0.0
2300 - * @since 1.9.9 $period param added.
1876 + * @return int
2301 1877 *
2302 - * @param int $course_id course id.
2303 - * @param string $period period ( optional ).
2304 - *
2305 - * @return int
1878 + * Get the total enrolled users at course
2306 1879 */
2307 - public function count_enrolled_users_by_course( $course_id = 0, $period = '' ) {
1880 + public function count_enrolled_users_by_course( $course_id = 0 ) {
1881 + global $wpdb;
2308 1882
2309 1883 $course_id = $this->get_post_id( $course_id );
2310 - // Set period wise query.
2311 - $period_filter = '';
2312 - if ( 'today' === $period ) {
2313 - $period_filter = 'AND DATE(post_date) = CURDATE()';
2314 - }
2315 - if ( 'monthly' === $period ) {
2316 - $period_filter = 'AND MONTH(post_date) = MONTH(CURDATE()) ';
2317 - }
2318 - if ( 'yearly' === $period ) {
2319 - $period_filter = 'AND YEAR(post_date) = YEAR(CURDATE()) ';
2320 - }
2321 1884
2322 - $cache_key = "tutor_enroll_count_for_course_{$course_id}_{$period}";
2323 - $course_ids = TutorCache::get( $cache_key );
1885 + $course_ids = $wpdb->get_var($wpdb->prepare(
1886 + "SELECT COUNT(ID)
1887 + FROM {$wpdb->posts}
1888 + WHERE post_type = %s
1889 + AND post_status = %s
1890 + AND post_parent = %d;
1891 + ",
1892 + 'tutor_enrolled',
1893 + 'completed',
1894 + $course_id
1895 + ) );
2324 1896
2325 - if ( false === $course_ids ) {
2326 - global $wpdb;
2327 - $course_ids = $wpdb->get_var(
2328 - $wpdb->prepare(
2329 - "SELECT COUNT(ID)
2330 - FROM {$wpdb->posts}
2331 - WHERE post_type = %s
2332 - AND post_status = %s
2333 - AND post_parent = %d;
2334 - {$period_filter}
2335 - ",
2336 - 'tutor_enrolled',
2337 - 'completed',
2338 - $course_id
2339 - )
1897 + return (int) $course_ids;
1898 + }
1899 +
1900 + /**
1901 + * @param int $user_id
1902 + *
1903 + * @return bool|\WP_Query
1904 + *
1905 + * Get the enrolled courses by user
1906 + */
1907 + public function get_enrolled_courses_by_user( $user_id = 0, $post_status='publish' ) {
1908 + global $wpdb;
1909 +
1910 + $user_id = $this->get_user_id( $user_id );
1911 + $course_ids = $this->get_enrolled_courses_ids_by_user( $user_id );
1912 +
1913 + if ( count( $course_ids ) ) {
1914 + $course_post_type = tutor()->course_post_type;
1915 + $course_args = array(
1916 + 'post_type' => $course_post_type,
1917 + 'post_status' => $post_status,
1918 + 'post__in' => $course_ids,
1919 + 'posts_per_page' => -1
2340 1920 );
2341 -
2342 - TutorCache::set( $cache_key, (int) $course_ids );
1921 + return new \WP_Query( $course_args );
2343 1922 }
2344 1923
2345 - return (int) $course_ids;
1924 + return false;
2346 1925 }
2347 1926
2348 1927 /**
2349 - * Get the video streaming URL by post/lesson/course ID
1928 + * @param int $post_id
2350 1929 *
2351 - * @since 1.0.0
1930 + * @return string
2352 1931 *
2353 - * @param int $post_id post id.
2354 - *
2355 - * @return string
1932 + * Get the video streaming URL by post/lesson/course ID
2356 1933 */
2357 1934 public function get_video_stream_url( $post_id = 0 ) {
2358 1935 $post_id = $this->get_post_id( $post_id );
2359 1936 $post = get_post( $post_id );
2360 1937
2361 - if ( tutor()->lesson_post_type === $post->post_type ) {
1938 + if ( $post->post_type === tutor()->lesson_post_type ) {
2362 1939 $video_url = trailingslashit( home_url() ) . 'video-url/' . $post->post_name;
2363 1940 } else {
2364 - $video_info = $this->get_video_info( $post_id );
2365 - $video_url = $video_info->url;
1941 + $video_info = tutor_utils()->get_video_info( $post_id );
1942 + $video_url = $video_info->url;
2366 1943 }
2367 1944
2368 1945 return $video_url;
2369 1946 }
@@ -2368,17 +1945,35 @@
2368 1945 return $video_url;
2369 1946 }
2370 1947
2371 1948 /**
2372 - * Get current post id or given post id
1949 + * @param int $lesson_id
1950 + * @param int $user_id
2373 1951 *
2374 - * @since 1.0.0
1952 + * @return array|bool|mixed
2375 1953 *
2376 - * @param int $post_id post id.
1954 + * Get student lesson reading current info
2377 1955 *
1956 + * @since v.1.0.0
1957 + */
1958 + public function get_lesson_reading_info_full( $lesson_id = 0, $user_id = 0 ) {
1959 + $lesson_id = $this->get_post_id( $lesson_id );
1960 + $user_id = $this->get_user_id( $user_id );
1961 +
1962 + $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
1963 + return $this->avalue_dot( $lesson_id, $lesson_info );
1964 + }
1965 +
1966 + /**
1967 + * @param int $post_id
1968 + *
2378 1969 * @return bool|false|int
1970 + *
1971 + * Get current post id or given post id
1972 + *
1973 + * @since v.1.0.0
2379 1974 */
2380 - public function get_post_id( $post_id = 0 ) {
1975 + public function get_post_id( $post_id = 0) {
2381 1976 if ( ! $post_id ) {
2382 1977 $post_id = get_the_ID();
2383 1978 if ( ! $post_id ) {
2384 1979 return false;
@@ -2388,20 +1983,22 @@
2388 1983 return $post_id;
2389 1984 }
2390 1985
2391 1986 /**
2392 - * Get current user ID or given user ID
1987 + * @param int $user_id
2393 1988 *
2394 - * @since 1.0.0
1989 + * @return bool|int
2395 1990 *
2396 - * @param mixed $user_id user ID.
1991 + * Get current user or given user ID
2397 1992 *
2398 - * @return int when $user_id = 0, return 0 or current user ID
2399 - * otherwise return given ID
1993 + * @since v.1.0.0
2400 1994 */
2401 1995 public function get_user_id( $user_id = 0 ) {
2402 - if ( ! $user_id ) {
2403 - return get_current_user_id();
1996 + if ( ! $user_id) {
1997 + $user_id = get_current_user_id();
1998 + if ( ! $user_id ) {
1999 + return false;
2000 + }
2404 2001 }
2405 2002
2406 2003 return $user_id;
2407 2004 }
@@ -2406,44 +2003,58 @@
2406 2003 return $user_id;
2407 2004 }
2408 2005
2409 2006 /**
2410 - * Get user name for e-mail salutation.
2007 + * @param int $lesson_id
2008 + * @param int $user_id
2009 + * @param string $key
2411 2010 *
2412 - * @since 2.0.9
2011 + * @return array|bool|mixed
2413 2012 *
2414 - * @param mixed $user user object.
2013 + * Get lesson reading info by key
2415 2014 *
2416 - * @return string
2015 + * @since v.1.0.0
2417 2016 */
2418 - public function get_user_name( $user ) {
2419 - if ( ! is_a( $user, 'WP_User' ) ) {
2420 - return '';
2421 - }
2422 - $name = '';
2017 + public function get_lesson_reading_info( $lesson_id = 0, $user_id = 0, $key = '' ) {
2018 + $lesson_id = $this->get_post_id( $lesson_id );
2019 + $user_id = $this->get_user_id( $user_id );
2020 + $lesson_info = $this->get_lesson_reading_info_full( $lesson_id, $user_id );
2423 2021
2424 - if ( empty( trim( $user->first_name ) ) ) {
2425 - $name = $user->user_login;
2426 - } else {
2427 - $name = $user->first_name;
2428 - if ( ! empty( trim( $user->last_name ) ) ) {
2429 - $name .= " {$user->last_name}";
2430 - }
2022 + return $this->avalue_dot($key, $lesson_info);
2023 + }
2024 +
2025 + /**
2026 + * @param int $lesson_id
2027 + * @param int $user_id
2028 + * @param array $data
2029 + *
2030 + * @return bool
2031 + *
2032 + * Update student lesson reading info
2033 + *
2034 + * @since v.1.0.0
2035 + */
2036 + public function update_lesson_reading_info( $lesson_id = 0, $user_id = 0, $key = '', $value = '' ) {
2037 + $lesson_id = $this->get_post_id($lesson_id);
2038 + $user_id = $this->get_user_id($user_id);
2039 +
2040 + if ( $key && $value ) {
2041 + $lesson_info = (array) maybe_unserialize( get_user_meta( $user_id, '_lesson_reading_info', true ) );
2042 + $lesson_info[ $lesson_id ][ $key ] = $value;
2043 + update_user_meta( $user_id, '_lesson_reading_info', $lesson_info );
2431 2044 }
2432 -
2433 - return $name;
2434 2045 }
2435 2046
2436 2047 /**
2437 - * Get the Youtube Video ID from URL
2048 + * @param string $url
2438 2049 *
2439 - * @since 1.0.0
2050 + * @return bool
2440 2051 *
2441 - * @param string $url URL.
2052 + * Get the Youtube Video ID from URL
2442 2053 *
2443 - * @return bool
2054 + * @since v.1.0.0
2444 2055 */
2445 - public function get_youtube_video_id( $url = '' ) {
2056 + public function get_youtube_video_id( $url = '') {
2446 2057 if ( ! $url ) {
2447 2058 return false;
2448 2059 }
2449 2060
@@ -2457,104 +2068,193 @@
2457 2068 return false;
2458 2069 }
2459 2070
2460 2071 /**
2461 - * Enrol Status change
2072 + * @param string $url
2462 2073 *
2463 - * @since 1.6.1
2074 + * @return bool
2464 2075 *
2465 - * @param bool $enrol_id enrol id.
2466 - * @param string $new_status new status.
2076 + * Get the vimeo video id from URL
2467 2077 *
2468 - * @return mixed
2078 + * @since v.1.0.0
2469 2079 */
2470 - public function course_enrol_status_change( $enrol_id = false, $new_status = '' ) {
2471 - if ( ! $enrol_id ) {
2472 - return;
2080 + public function get_vimeo_video_id( $url = '' ) {
2081 + if ( preg_match('%^https?:\/\/(?:www\.|player\.)?vimeo.com\/(?:channels\/(?:\w+\/)?|groups\/([^\/]*)\/videos\/|album\/(\d+)\/video\/|video\/|)(\d+)(?:$|\/|\?)(?:[?]?.*)$%im', $url, $match ) ) {
2082 + if ( isset( $match[3] ) ) {
2083 + return $match[3];
2084 + }
2473 2085 }
2086 + return false;
2087 + }
2474 2088
2475 - global $wpdb;
2089 + /**
2090 + * @param int $post_id
2091 + *
2092 + * Mark lesson complete
2093 + *
2094 + * @since v.1.0.0
2095 + */
2096 + public function mark_lesson_complete( $post_id = 0, $user_id = 0 ) {
2097 + $post_id = $this->get_post_id( $post_id );
2098 + $user_id = $this->get_user_id( $user_id );
2476 2099
2477 - do_action( 'tutor/course/enrol_status_change/before', $enrol_id, $new_status );
2478 - $wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $enrol_id ) );
2479 - do_action( 'tutor/course/enrol_status_change/after', $enrol_id, $new_status );
2100 + do_action( 'tutor_mark_lesson_complete_before', $post_id, $user_id );
2101 + update_user_meta( $user_id, '_tutor_completed_lesson_id_'.$post_id, tutor_time() );
2102 + do_action( 'tutor_mark_lesson_complete_after', $post_id, $user_id );
2480 2103 }
2481 2104
2482 2105 /**
2483 - * Cancel course enrol
2484 2106 *
2485 - * @since 1.0.0
2107 + * @param int $course_id
2108 + * @param int $order_id
2109 + * @param int $user_id
2486 2110 *
2487 - * @param int $course_id course id.
2488 - * @param int $user_id user id.
2489 - * @param string $cancel_status cancel status.
2111 + * Saving enroll information to posts table
2112 + * post_author = enrolled_student_id (wp_users id)
2113 + * post_parent = enrolled course id
2490 2114 *
2491 - * @return void
2115 + * @type: call when need
2116 + * @return bool;
2117 + *
2118 + * @since v.1.0.0
2119 + * @updated v.1.4.3
2120 + *
2121 + * @return bool
2492 2122 */
2123 + public function do_enroll( $course_id = 0, $order_id = 0, $user_id = 0 ) {
2124 + if ( ! $course_id ) {
2125 + return false;
2126 + }
2127 +
2128 + do_action( 'tutor_before_enroll', $course_id );
2129 + $user_id = $this->get_user_id( $user_id );
2130 + $title = __( 'Course Enrolled', 'tutor')." &ndash; ".date( get_option('date_format') ) .' @ '.date(get_option('time_format') ) ;
2131 +
2132 + $enrolment_status = 'completed';
2133 +
2134 + if ( $this->is_course_purchasable( $course_id ) ) {
2135 + /**
2136 + * We need to verify this enrollment, we will change the status later after payment confirmation
2137 + */
2138 + $enrolment_status = 'pending';
2139 + }
2140 +
2141 + $enroll_data = apply_filters( 'tutor_enroll_data',
2142 + array(
2143 + 'post_type' => 'tutor_enrolled',
2144 + 'post_title' => $title,
2145 + 'post_status' => $enrolment_status,
2146 + 'post_author' => $user_id,
2147 + 'post_parent' => $course_id,
2148 + )
2149 + );
2150 +
2151 + // Insert the post into the database
2152 + $isEnrolled = wp_insert_post( $enroll_data );
2153 + if ( $isEnrolled ) {
2154 +
2155 + // Run this hook for both of pending and completed enrollment
2156 + do_action( 'tutor_after_enroll', $course_id, $isEnrolled );
2157 +
2158 + // Run this hook for completed enrollment regardless of payment provider and free/paid mode
2159 + if( $enroll_data['post_status'] == 'completed' ) {
2160 + do_action('tutor_after_enrolled', $course_id, $user_id, $isEnrolled);
2161 + }
2162 +
2163 + //Mark Current User as Students with user meta data
2164 + update_user_meta( $user_id, '_is_tutor_student', tutor_time() );
2165 +
2166 + if ( $order_id ) {
2167 + //Mark order for course and user
2168 + $product_id = $this->get_course_product_id( $course_id );
2169 + update_post_meta( $isEnrolled, '_tutor_enrolled_by_order_id', $order_id );
2170 + update_post_meta( $isEnrolled, '_tutor_enrolled_by_product_id', $product_id );
2171 + update_post_meta( $order_id, '_is_tutor_order_for_course', tutor_time() );
2172 + update_post_meta( $order_id, '_tutor_order_for_course_id_'.$course_id, $isEnrolled );
2173 + }
2174 + return true;
2175 + }
2176 +
2177 + return false;
2178 + }
2179 +
2180 + /**
2181 + * @param bool $enrol_id
2182 + * @param string $new_status
2183 + *
2184 + * Enrol Status change
2185 + *
2186 + * @since v.1.6.1
2187 + */
2188 + public function course_enrol_status_change( $enrol_id = false, $new_status = '' ) {
2189 + if ( ! $enrol_id ) {
2190 + return;
2191 + }
2192 +
2193 + global $wpdb;
2194 +
2195 + do_action( 'tutor/course/enrol_status_change/before',$enrol_id, $new_status );
2196 + $wpdb->update( $wpdb->posts, array( 'post_status' => $new_status ), array( 'ID' => $enrol_id ) );
2197 + do_action( 'tutor/course/enrol_status_change/after',$enrol_id, $new_status );
2198 + }
2199 +
2200 + /**
2201 + * @param int $course_id
2202 + * @param int $user_id
2203 + * @param string $cancel_status
2204 + */
2493 2205 public function cancel_course_enrol( $course_id = 0, $user_id = 0, $cancel_status = 'canceled' ) {
2494 - $course_id = $this->get_post_id( $course_id );
2495 - $user_id = $this->get_user_id( $user_id );
2496 - $enrolled = EnrollmentModel::is_enrolled( $course_id, $user_id );
2206 + $course_id = $this->get_post_id( $course_id );
2207 + $user_id = $this->get_user_id( $user_id );
2208 + $enrolled = $this->is_enrolled($course_id, $user_id);
2497 2209
2498 - if ( $enrolled ) {
2499 - global $wpdb;
2210 + if ( $enrolled ) {
2211 + global $wpdb;
2500 2212
2501 - if ( 'delete' === $cancel_status ) {
2502 - $wpdb->delete(
2503 - $wpdb->posts,
2504 - array(
2505 - 'post_type' => 'tutor_enrolled',
2506 - 'post_author' => $user_id,
2507 - 'post_parent' => $course_id,
2508 - )
2509 - );
2213 + if ( $cancel_status === 'delete') {
2214 + $wpdb->delete( $wpdb->posts, array( 'post_type' => 'tutor_enrolled', 'post_author' => $user_id, 'post_parent' => $course_id ) );
2510 2215
2511 - // Delete Related Meta Data.
2512 - delete_post_meta( $enrolled->ID, EnrollmentModel::ENROLLMENT_PRODUCT_ID_META );
2513 - $order_id = get_post_meta( $enrolled->ID, EnrollmentModel::ENROLLMENT_ORDER_ID_META, true );
2514 - if ( $order_id ) {
2515 - delete_post_meta( $enrolled->ID, EnrollmentModel::ENROLLMENT_ORDER_ID_META );
2516 -
2517 - $monetize_by = $this->get_option( 'monetize_by' );
2518 - if ( 'wc' === $monetize_by ) {
2519 - // Delete WC order meta.
2520 - $order = wc_get_order( $order_id );
2521 - $order->delete_meta_data( Course::IS_TUTOR_ORDER_FOR_COURSE_META );
2522 - $order->delete_meta_data( Course::TUTOR_ORDER_FOR_COURSE_ID_META . $course_id );
2523 - $order->save();
2524 - } else {
2525 - delete_post_meta( $order_id, Course::IS_TUTOR_ORDER_FOR_COURSE_META );
2526 - delete_post_meta( $order_id, Course::TUTOR_ORDER_FOR_COURSE_ID_META . $course_id );
2527 - }
2216 + //Delete Related Meta Data
2217 + delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_product_id' );
2218 + $order_id = get_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id', true );
2219 + if ( $order_id ) {
2220 + delete_post_meta( $enrolled->ID, '_tutor_enrolled_by_order_id' );
2221 + delete_post_meta( $order_id, '_is_tutor_order_for_course' );
2222 + delete_post_meta( $order_id, '_tutor_order_for_course_id_'.$course_id );
2223 +
2224 + do_action( 'tutor_enrollment/after/delete', $enrolled->ID );
2225 + }
2226 + } else {
2227 + $wpdb->update( $wpdb->posts, array( 'post_status' => $cancel_status), array('post_type' => 'tutor_enrolled', 'post_author' => $user_id, 'post_parent' => $course_id ) );
2228 +
2229 + if ( $cancel_status === 'cancel' ) {
2230 + do_action( 'tutor_enrollment/after/cancel', $enrolled->ID );
2528 2231 }
2232 + }
2233 + }
2234 + }
2529 2235
2530 - /**
2531 - * Added for third-party
2532 - *
2533 - * @since 2.2.3
2534 - */
2535 - do_action( 'tutor_after_enrollment_deleted', $course_id, $user_id );
2236 + /**
2237 + * @param $order_id
2238 + *
2239 + * Complete course enrollment and do some task
2240 + *
2241 + * @since v.1.0.0
2242 + */
2243 + public function complete_course_enroll( $order_id ) {
2244 + if ( ! tutor_utils()->is_tutor_order( $order_id ) ) {
2245 + return;
2246 + }
2536 2247
2537 - } else {
2538 - $wpdb->update(
2539 - $wpdb->posts,
2540 - array( 'post_status' => $cancel_status ),
2541 - array(
2542 - 'post_type' => 'tutor_enrolled',
2543 - 'post_author' => $user_id,
2544 - 'post_parent' => $course_id,
2545 - )
2546 - );
2248 + global $wpdb;
2547 2249
2548 - /**
2549 - * Added for third-party
2550 - *
2551 - * @since 2.2.3
2552 - */
2553 - do_action( 'tutor_after_enrollment_cancelled', $course_id, $user_id );
2250 + $enrolled_ids_with_course = $this->get_course_enrolled_ids_by_order_id( $order_id );
2251 + if ( $enrolled_ids_with_course ) {
2252 + $enrolled_ids = wp_list_pluck( $enrolled_ids_with_course, 'enrolled_id' );
2554 2253
2555 - if ( 'cancel' === $cancel_status ) {
2556 - die( esc_html( $cancel_status ) );
2254 + if ( is_array( $enrolled_ids ) && count( $enrolled_ids ) ) {
2255 + foreach ( $enrolled_ids as $enrolled_id ) {
2256 + $wpdb->update( $wpdb->posts, array( 'post_status' => 'completed' ), array( 'ID' => $enrolled_id ) );
2557 2257 }
2558 2258 }
2559 2259 }
2560 2260 }
@@ -2559,52 +2259,35 @@
2559 2259 }
2560 2260 }
2561 2261
2562 2262 /**
2563 - * Get enrol ids by order id.
2263 + * @param $order_id
2564 2264 *
2565 - * @since 1.0.0
2265 + * @return array|bool
2566 2266 *
2567 - * @param int $order_id order id.
2568 - *
2569 - * @return array|bool
2267 + * @since v.1.0.0
2570 2268 */
2571 2269 public function get_course_enrolled_ids_by_order_id( $order_id ) {
2572 2270 global $wpdb;
2573 2271
2574 - if ( 'wc' === $this->get_option( 'monetize_by' ) && WooCommerce::hpos_enabled() ) {
2575 - // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery
2576 - $courses_ids = $wpdb->get_results(
2577 - $wpdb->prepare(
2578 - "SELECT *
2579 - FROM {$wpdb->prefix}wc_orders_meta
2580 - WHERE order_id = %d
2581 - AND meta_key LIKE '_tutor_order_for_course_id_%'",
2582 - $order_id
2583 - )
2584 - );
2585 - } else {
2586 - $courses_ids = $wpdb->get_results(
2587 - $wpdb->prepare(
2588 - "SELECT *
2589 - FROM {$wpdb->postmeta}
2590 - WHERE post_id = %d
2591 - AND meta_key LIKE '_tutor_order_for_course_id_%'
2592 - ",
2593 - $order_id
2594 - )
2595 - );
2596 - }
2597 - // phpcs:enable WordPress.DB.PreparedSQLPlaceholders.LikeWildcardsInQuery
2272 + //Getting all of courses ids within this order
2273 + $courses_ids = $wpdb->get_results( $wpdb->prepare(
2274 + "SELECT *
2275 + FROM {$wpdb->postmeta}
2276 + WHERE post_id = %d
2277 + AND meta_key LIKE '_tutor_order_for_course_id_%'
2278 + ",
2279 + $order_id
2280 + ) );
2598 2281
2599 2282 if ( is_array( $courses_ids ) && count( $courses_ids ) ) {
2600 2283 $course_enrolled_by_order = array();
2601 2284 foreach ( $courses_ids as $courses_id ) {
2602 - $course_id = str_replace( '_tutor_order_for_course_id_', '', $courses_id->meta_key );
2285 + $course_id = str_replace( '_tutor_order_for_course_id_', '',$courses_id->meta_key );
2603 2286 $course_enrolled_by_order[] = array(
2604 2287 'course_id' => $course_id,
2605 2288 'enrolled_id' => $courses_id->meta_value,
2606 - 'order_id' => $courses_id->post_id ?? $courses_id->order_id,
2289 + 'order_id' => $courses_id->post_id
2607 2290 );
2608 2291 }
2609 2292 return $course_enrolled_by_order;
2610 2293 }
@@ -2613,147 +2296,104 @@
2613 2296
2614 2297 /**
2615 2298 * Get wc product in efficient query
2616 2299 *
2617 - * @since 1.0.0
2618 - * @since 3.0.0 $exclude param added.
2300 + * @since v.1.0.0
2301 + */
2302 +
2303 + /**
2304 + * @return array|null|object
2619 2305 *
2620 - * @param array $exclude exclude ids.
2621 - *
2622 - * @return array|null|object
2306 + * WooCommerce specific utils
2623 2307 */
2624 - public function get_wc_products_db( $exclude = array() ) {
2308 + public function get_wc_products_db() {
2625 2309 global $wpdb;
2626 -
2627 - $exclude = array_filter( $exclude, 'is_numeric' );
2628 -
2629 - $where_clause = 'post_status = %s';
2630 - if ( count( $exclude ) ) {
2631 - $ids = QueryHelper::prepare_in_clause( $exclude );
2632 - $where_clause .= " AND ID NOT IN ({$ids})";
2633 - }
2634 -
2635 - $where_clause .= ' AND post_type = %s';
2636 -
2637 - $query = $wpdb->get_results(
2638 - $wpdb->prepare(
2639 - "SELECT ID,
2310 + $query = $wpdb->get_results( $wpdb->prepare(
2311 + "SELECT ID,
2640 2312 post_title
2641 2313 FROM {$wpdb->posts}
2642 - WHERE {$where_clause}", //phpcs:ignore
2643 - 'publish',
2644 - 'product'
2645 - )
2646 - );
2314 + WHERE post_status = %s
2315 + AND post_type = %s;
2316 + ",
2317 + 'publish',
2318 + 'product'
2319 + ) );
2647 2320
2648 2321 return $query;
2649 2322 }
2650 2323
2651 2324 /**
2325 + * @return array|null|object
2326 + *
2652 2327 * Get EDD Products
2653 - *
2654 - * @since 1.0.0
2655 - *
2656 - * @return array|null|object
2657 2328 */
2658 2329 public function get_edd_products() {
2659 2330 global $wpdb;
2660 - $query = $wpdb->get_results(
2661 - $wpdb->prepare(
2662 - "SELECT ID,
2331 + $query = $wpdb->get_results( $wpdb->prepare(
2332 + "SELECT ID,
2663 2333 post_title
2664 2334 FROM {$wpdb->posts}
2665 2335 WHERE post_status = %s
2666 2336 AND post_type = %s;
2667 2337 ",
2668 - 'publish',
2669 - 'download'
2670 - )
2671 - );
2338 + 'publish',
2339 + 'download'
2340 + ) );
2672 2341
2673 2342 return $query;
2674 2343 }
2675 2344
2676 2345 /**
2677 - * Get course productID
2346 + * @param int $course_id
2678 2347 *
2679 - * @since 1.0.0
2348 + * @return int
2680 2349 *
2681 - * @param int $course_id course id.
2350 + * Get course productID
2682 2351 *
2683 - * @return int
2352 + * @since v.1.0.0
2684 2353 */
2685 2354 public function get_course_product_id( $course_id = 0 ) {
2686 2355 $course_id = $this->get_post_id( $course_id );
2687 - $product_id = (int) get_post_meta( $course_id, Course::COURSE_PRODUCT_ID_META, true );
2356 + $product_id = (int) get_post_meta( $course_id, '_tutor_course_product_id', true );
2688 2357
2689 2358 return $product_id;
2690 2359 }
2691 2360
2692 2361 /**
2693 - * Get all WC product ids which are linked with course.
2362 + * @param int $product_id
2694 2363 *
2695 - * @since 3.0.0
2364 + * @return array|null|object|void
2696 2365 *
2697 - * @return array
2698 - */
2699 - public function get_linked_product_ids() {
2700 - global $wpdb;
2701 - $ids = $wpdb->get_col(
2702 - $wpdb->prepare(
2703 - "SELECT meta_value
2704 - FROM {$wpdb->postmeta}
2705 - WHERE meta_key = %s",
2706 - Course::COURSE_PRODUCT_ID_META
2707 - )
2708 - );
2709 -
2710 - return array_filter( $ids, 'is_numeric' );
2711 - }
2712 -
2713 - /**
2714 2366 * Get Product belongs with course
2715 2367 *
2716 - * @since 1.0.0
2717 - *
2718 - * @param int $product_id product id.
2719 - *
2720 - * @return array|null|object|void
2368 + * @since v.1.0.0
2721 2369 */
2722 - public function product_belongs_with_course( int $product_id ) {
2723 - if ( ! $product_id ) {
2724 - return null;
2725 - }
2726 -
2370 + public function product_belongs_with_course( $product_id = 0 ) {
2727 2371 global $wpdb;
2728 2372
2729 - $query = $wpdb->get_row(
2730 - $wpdb->prepare(
2731 - "SELECT *
2373 + $query = $wpdb->get_row( $wpdb->prepare(
2374 + "SELECT *
2732 2375 FROM {$wpdb->postmeta}
2733 - WHERE meta_key = %s
2734 - AND meta_value = %d
2376 + WHERE meta_key = %s
2377 + AND meta_value = %d
2735 2378 limit 1
2736 2379 ",
2737 - Course::COURSE_PRODUCT_ID_META,
2738 - $product_id
2739 - )
2740 - );
2741 -
2380 + '_tutor_course_product_id',
2381 + $product_id
2382 + ) );
2383 +
2742 2384 return $query;
2743 2385 }
2744 2386
2745 2387 /**
2746 - * Get enroll status
2388 + * #End WooCommerce specific utils
2747 2389 *
2748 - * @since 1.0.0
2749 - *
2750 - * @return array
2390 + * @since v.1.0.0
2751 2391 */
2752 2392 public function get_enrolled_statuses() {
2753 2393 return apply_filters(
2754 2394 'tutor_get_enrolled_statuses',
2755 - array(
2395 + array (
2756 2396 'pending',
2757 2397 'processing',
2758 2398 'on-hold',
2759 2399 'completed',
@@ -2764,236 +2404,147 @@
2764 2404 );
2765 2405 }
2766 2406
2767 2407 /**
2768 - * Determine is this a tutor order
2408 + * @param $order_id
2769 2409 *
2770 - * @since 1.0.0
2410 + * @return mixed
2771 2411 *
2772 - * @param int $order_id order id.
2412 + * determine is this a tutor order
2773 2413 *
2774 - * @return mixed
2414 + * @since v.1.0.0
2775 2415 */
2776 2416 public function is_tutor_order( $order_id ) {
2777 - $monetize_by = $this->get_option( 'monetize_by' );
2778 - if ( 'wc' === $monetize_by ) {
2779 - $order = wc_get_order( $order_id );
2780 - return $order->get_meta( Course::IS_TUTOR_ORDER_FOR_COURSE_META, true );
2781 - } elseif ( 'edd' === $monetize_by ) {
2782 - $payment = new \EDD_Payment( $order_id );
2783 - return $payment->get_meta( Course::IS_TUTOR_ORDER_FOR_COURSE_META, true );
2784 - } else {
2785 - return get_post_meta( $order_id, Course::IS_TUTOR_ORDER_FOR_COURSE_META, true );
2786 - }
2417 + return get_post_meta( $order_id, '_is_tutor_order_for_course', true );
2787 2418 }
2788 2419
2789 2420 /**
2790 - * Separation of all menu items for providing ease of usage
2421 + * @return mixed
2791 2422 *
2792 - * @since 2.0.0
2793 - *
2794 - * @since 4.0.0 Menu item updated based on student view
2795 - *
2796 - * @return array array of menu items.
2423 + * @deprecated
2797 2424 */
2798 - public function default_menus(): array {
2799 - $items = array(
2800 - 'index' => array(
2801 - 'title' => __( 'Home', 'tutor' ),
2802 - 'icon' => Icon::HOME,
2803 - 'active_icon' => Icon::HOME_FILL,
2804 - ),
2805 - 'courses' => array(
2806 - 'title' => __( 'Courses', 'tutor' ),
2807 - 'icon' => Icon::COURSES,
2808 - 'active_icon' => Icon::COURSES_FILL,
2809 - ),
2810 - 'retrieve-password' => array(
2811 - 'title' => __( 'Retrieve Password', 'tutor' ),
2812 - 'show_ui' => false,
2813 - 'login_require' => false,
2814 - ),
2815 - 'account' => array(
2816 - 'label' => __( 'Account', 'tutor' ),
2817 - 'show_ui' => false,
2818 - ),
2819 - );
2820 -
2821 - if ( $this->should_show_dicussion_menu() ) {
2822 - $items['discussions'] = array(
2823 - 'title' => __( 'Discussions', 'tutor' ),
2824 - 'icon' => Icon::QA,
2825 - 'active_icon' => Icon::QA_FILL,
2826 - );
2827 - }
2828 -
2829 - return apply_filters( 'tutor_student_dashboard_nav', $items );
2425 + public function tutor_student_dashboard_pages() {
2426 + _deprecated_function( __METHOD__, '1.1.2', 'tutor_dashboard_pages' );
2427 + return $this->tutor_dashboard_pages();
2830 2428 }
2831 2429
2832 2430 /**
2833 - * Separation of all menu items for providing ease of usage
2431 + * @return mixed
2834 2432 *
2835 - * @since 2.0.0
2433 + * Tutor Dashboard Pages, supporting for the URL rewriting
2836 2434 *
2837 - * @return array array of menu items.
2435 + * @since v.1.0.0
2838 2436 */
2839 - public function instructor_menus(): array {
2840 - $menus = array(
2841 - 'index' => array(
2842 - 'title' => __( 'Home', 'tutor' ),
2843 - 'icon' => Icon::HOME,
2844 - 'active_icon' => Icon::HOME_FILL,
2845 - ),
2846 - 'my-courses' => array(
2847 - 'title' => __( 'Courses', 'tutor' ),
2848 - 'auth_cap' => tutor()->instructor_role,
2849 - 'icon' => Icon::COURSES,
2850 - 'active_icon' => Icon::COURSES_FILL,
2851 - ),
2852 - // Hidden menu.
2853 - 'create-course' => array(
2854 - 'title' => __( 'Create Course', 'tutor' ),
2855 - 'show_ui' => false,
2856 - 'auth_cap' => tutor()->instructor_role,
2857 - ),
2858 - 'create-bundle' => array(
2859 - 'title' => __( 'Create Bundle', 'tutor' ),
2860 - 'show_ui' => false,
2861 - 'auth_cap' => tutor()->instructor_role,
2862 - ),
2863 - );
2437 + public function tutor_dashboard_pages() {
2438 + $nav_items = apply_filters( 'tutor_dashboard/nav_items', array(
2439 + 'index' => __( 'Dashboard', 'tutor' ),
2440 + 'my-profile' => __( 'My Profile', 'tutor' ),
2441 + 'enrolled-courses' => __( 'Enrolled Courses', 'tutor' ),
2442 + 'wishlist' => __( 'Wishlist', 'tutor' ),
2443 + 'reviews' => __( 'Reviews', 'tutor' ),
2444 + 'my-quiz-attempts' => __( 'My Quiz Attempts', 'tutor' ),
2445 + 'purchase_history' => __( 'Purchase History', 'tutor' ),
2446 + ));
2864 2447
2865 - $menus = apply_filters( 'tutor_after_instructor_menu_my_courses', $menus );
2448 + $instructor_nav_items = apply_filters( 'tutor_dashboard/instructor_nav_items', array(
2449 + 'separator-1' => array( 'title' => __( 'Instructor', 'tutor'), 'auth_cap' => tutor()->instructor_role, 'type' => 'separator' ),
2450 + 'create-course' => array( 'title' => __( 'Create Course', 'tutor'), 'show_ui' => false, 'auth_cap' => tutor()->instructor_role ),
2451 + 'my-courses' => array( 'title' => __( 'My Courses', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2452 + 'announcements' => array( 'title' => __( 'Announcements', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2453 + 'earning' => array( 'title' => __( 'Earnings', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2454 + 'withdraw' => array( 'title' => __( 'Withdrawals', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2455 + 'quiz-attempts' => array( 'title' => __( 'Quiz Attempts', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2456 + 'question-answer' => array( 'title' => __( 'Question & Answer', 'tutor'), 'auth_cap' => tutor()->instructor_role ),
2457 + ));
2866 2458
2867 - $other_menus = array(
2868 - 'announcements' => array(
2869 - 'title' => __( 'Announcements', 'tutor' ),
2870 - 'auth_cap' => tutor()->instructor_role,
2871 - 'icon' => Icon::ANNOUNCEMENT,
2872 - 'active_icon' => Icon::ANNOUNCEMENT_FILL,
2873 - ),
2874 - 'quiz-attempts' => array(
2875 - 'title' => __( 'Quiz Attempts', 'tutor' ),
2876 - 'auth_cap' => tutor()->instructor_role,
2877 - 'icon' => Icon::QUIZ_2,
2878 - 'active_icon' => Icon::QUIZ_2_FILL,
2879 - ),
2880 - );
2459 + $disable = get_tutor_option( 'disable_course_review' );
2460 + if ( $disable && isset( $nav_items['reviews'] ) ) {
2461 + unset( $nav_items['reviews'] );
2462 + }
2881 2463
2882 - if ( $this->should_show_dicussion_menu() ) {
2883 - $other_menus['discussions'] = array(
2884 - 'title' => __( 'Discussions', 'tutor' ),
2885 - 'auth_cap' => tutor()->instructor_role,
2886 - 'icon' => Icon::QA,
2887 - 'active_icon' => Icon::QA_FILL,
2888 - );
2889 - }
2464 + $nav_items = array_merge( $nav_items, $instructor_nav_items );
2890 2465
2891 - $all_menus = apply_filters( 'tutor_instructor_dashboard_nav', array_merge( $menus, $other_menus ) );
2466 + $new_navs = apply_filters( 'tutor_dashboard/bottom_nav_items', array(
2467 + 'separator-2' => array( 'title' => '', 'type' => 'separator' ),
2468 + 'settings' => __( 'Settings', 'tutor' ),
2469 + 'logout' => __( 'Logout', 'tutor' ),
2470 + ));
2471 + $all_nav_items = array_merge( $nav_items, $new_navs );
2892 2472
2893 - return $all_menus;
2473 + return apply_filters( 'tutor_dashboard/nav_items_all', $all_nav_items );
2894 2474 }
2895 2475
2896 - /**
2897 - * Tutor Dashboard Pages, supporting for the URL rewriting
2898 - *
2899 - * @since 1.0.0
2900 - *
2901 - * @since 4.0.0 param $context added.
2902 - *
2903 - * @param string $context context.
2904 - * `view` to get pages according to role.
2905 - * `rewrite_rules` to get all page for rewrite rules.
2906 - *
2907 - * @return array
2908 - */
2909 - public function tutor_dashboard_pages( $context = 'view' ) {
2476 + public function tutor_dashboard_permalinks() {
2477 + $dashboard_pages = $this->tutor_dashboard_pages();
2910 2478
2911 - $nav_items = apply_filters( 'tutor_dashboard/nav_items', $this->default_menus() );
2912 - $instructor_nav_items = apply_filters( 'tutor_dashboard/instructor_nav_items', $this->instructor_menus() );
2479 + $dashboard_permalinks = apply_filters( 'tutor_dashboard/permalinks', array(
2480 + 'retrieve-password' => array( 'title' => __( 'Retrieve Password', 'tutor' ), 'login_require' => false ),
2481 + ));
2913 2482
2914 - if ( 'rewrite_rules' === $context ) {
2915 - $nav_items = array_merge( $nav_items, $instructor_nav_items );
2916 - } else {
2917 - $nav_items = User::is_instructor_view() ? $instructor_nav_items : $nav_items;
2918 - }
2483 + $dashboard_pages = array_merge( $dashboard_pages, $dashboard_permalinks );
2919 2484
2920 - return apply_filters( 'tutor_dashboard/nav_items_all', $nav_items );
2485 + return $dashboard_pages;
2921 2486 }
2922 2487
2923 2488 /**
2924 - * Get tutor dashboard permalinks
2489 + * @return mixed
2925 2490 *
2926 - * @since 1.0.0
2927 - *
2928 - * @return array
2929 - */
2930 - public function tutor_dashboard_permalinks() {
2931 - $dashboard_permalinks = apply_filters( 'tutor_dashboard/permalinks', $this->tutor_dashboard_pages( 'rewrite_rules' ) );
2932 - return $dashboard_permalinks;
2933 - }
2934 -
2935 - /**
2936 2491 * Tutor Dashboard UI nav, only for using in the nav, it's handling user permission based
2937 2492 * Dashboard nav items
2938 2493 *
2939 - * @since 1.3.4
2940 - *
2941 - * @return mixed
2494 + * @since v.1.3.4
2942 2495 */
2943 2496 public function tutor_dashboard_nav_ui_items() {
2944 2497 $nav_items = $this->tutor_dashboard_pages();
2945 2498
2946 2499 foreach ( $nav_items as $key => $nav_item ) {
2947 - if ( is_array( $nav_item ) ) {
2500 + if ( is_array($nav_item) ) {
2948 2501
2949 - if ( isset( $nav_item['show_ui'] ) && ! $this->array_get( 'show_ui', $nav_item ) ) {
2502 + if ( isset( $nav_item['show_ui'] ) && ! tutor_utils()->array_get( 'show_ui', $nav_item ) ) {
2950 2503 unset( $nav_items[ $key ] );
2951 2504 }
2952 -
2953 - if ( isset( $nav_item['auth_cap'] ) && ! User::is_admin() && ! current_user_can( $nav_item['auth_cap'] ) ) {
2505 + if ( isset($nav_item['auth_cap'] ) && ! current_user_can( $nav_item['auth_cap'] ) ) {
2954 2506 unset( $nav_items[ $key ] );
2955 2507 }
2956 2508 }
2957 2509 }
2958 2510
2959 - return apply_filters( 'tutor_dashboard/nav_ui_items', $nav_items );
2511 + return apply_filters('tutor_dashboard/nav_ui_items', $nav_items);
2960 2512 }
2961 2513
2962 2514 /**
2963 - * Get tutor dashboard page single URL
2515 + * @param string $page_key
2516 + * @param int $page_id
2964 2517 *
2965 - * @since 1.0.0
2518 + * @return string
2966 2519 *
2967 - * @param string $page_key page key.
2968 - * @param int $page_id page id.
2520 + * Get tutor dashboard page single URL
2969 2521 *
2970 - * @return string
2522 + * @since v.1.0.0
2971 2523 */
2972 2524 public function get_tutor_dashboard_page_permalink( $page_key = '', $page_id = 0 ) {
2973 - if ( 'index' === $page_key ) {
2525 + if ( $page_key === 'index' ) {
2974 2526 $page_key = '';
2975 2527 }
2976 2528 if ( ! $page_id ) {
2977 - $page_id = (int) $this->get_option( 'tutor_dashboard_page_id' );
2978 - }
2529 + $page_id = (int) tutils()->get_option( 'tutor_dashboard_page_id' );
2530 + }
2979 2531 return trailingslashit( get_permalink( $page_id ) ) . $page_key;
2980 2532 }
2981 2533
2982 2534 /**
2983 - * Get old input
2535 + * @param string $input
2984 2536 *
2985 - * @since 1.0.0
2986 - * @since 1.4.2 updated.
2537 + * @return array|bool|mixed|string
2987 2538 *
2988 - * @param string $input input.
2989 - * @param mixed $old_data old data.
2539 + * Get old input
2990 2540 *
2991 - * @return array|bool|mixed|string
2541 + * @since v.1.0.0
2542 + * @updated v.1.4.2
2992 2543 */
2993 2544 public function input_old( $input = '', $old_data = null ) {
2994 2545 if ( ! $old_data ) {
2995 - $old_data = tutor_sanitize_data( $_REQUEST );
2546 + $old_data = $_REQUEST;
2996 2547 }
2997 2548 $value = $this->avalue_dot( $input, $old_data );
2998 2549 if ( $value ) {
2999 2550 return $value;
@@ -3002,191 +2553,114 @@
3002 2553 return '';
3003 2554 }
3004 2555
3005 2556 /**
3006 - * Determine if is instructor or not
2557 + * @param int $user_id
3007 2558 *
3008 - * @since 1.0.0
2559 + * @return mixed
3009 2560 *
3010 - * @param int $user_id user id.
3011 - * @param bool $is_approved is approved.
2561 + * Determine if is instructor or not
3012 2562 *
3013 - * @return mixed
2563 + * @since v.1.0.0
3014 2564 */
3015 - public function is_instructor( $user_id = 0, $is_approved = false ) {
2565 + public function is_instructor( $user_id = 0 ) {
3016 2566 $user_id = $this->get_user_id( $user_id );
3017 - if ( $is_approved ) {
3018 - $user_status = get_user_meta( $user_id, '_tutor_instructor_status', true );
3019 - $is_approved_instructor = 'approved' === $user_status ? true : false;
3020 - return $is_approved_instructor && get_user_meta( $user_id, '_is_tutor_instructor', true );
3021 - }
3022 2567 return get_user_meta( $user_id, '_is_tutor_instructor', true );
3023 2568 }
3024 2569
3025 2570 /**
3026 - * Instructor status
2571 + * @param int $user_id
2572 + * @param bool $status_name
3027 2573 *
3028 - * @since 1.0.0
2574 + * @return bool|mixed
3029 2575 *
3030 - * @param int $user_id user id.
3031 - * @param bool $status_name status name.
2576 + * Instructor status
3032 2577 *
3033 - * @return bool|mixed
2578 + * @since v.1.0.0
3034 2579 */
3035 2580 public function instructor_status( $user_id = 0, $status_name = true ) {
3036 2581 $user_id = $this->get_user_id( $user_id );
3037 2582
3038 - $instructor_status = apply_filters(
3039 - 'tutor_instructor_statuses',
3040 - array(
3041 - 'pending' => __( 'Pending', 'tutor' ),
3042 - 'approved' => __( 'Approved', 'tutor' ),
3043 - 'blocked' => __( 'Blocked', 'tutor' ),
3044 - )
3045 - );
2583 + $instructor_status = apply_filters( 'tutor_instructor_statuses', array(
2584 + 'pending' => __( 'Pending', 'tutor' ),
2585 + 'approved' => __( 'Approved', 'tutor' ),
2586 + 'blocked' => __( 'Blocked', 'tutor' ),
2587 + ));
3046 2588
3047 2589 $status = get_user_meta( $user_id, '_tutor_instructor_status', true );
3048 2590
3049 - if ( isset( $instructor_status[ $status ] ) ) {
2591 + if ( isset( $instructor_status[$status] ) ) {
3050 2592 if ( ! $status_name ) {
3051 2593 return $status;
3052 2594 }
3053 - return $instructor_status[ $status ];
2595 + return $instructor_status[$status];
3054 2596 }
3055 2597 return false;
3056 2598 }
3057 2599
3058 2600 /**
3059 - * Get Total number of instructor
2601 + * @param string $search_term
3060 2602 *
3061 - * @since 1.0.0
2603 + * @return int
3062 2604 *
3063 - * @param string $search_filter serach filter.
3064 - * @param string $status (approved | pending | blocked).
3065 - * @param string $course_id course id.
3066 - * @param string $date user_registered date.
2605 + * Get total number of instructors
3067 2606 *
3068 - * @return int
2607 + * @since v.1.0.0
3069 2608 */
3070 - public function get_total_instructors( $search_filter = '', $status = array(), $course_id = '', $date = '' ): int {
2609 + public function get_total_instructors( $search_term = '' ) {
3071 2610 global $wpdb;
3072 - $search_filter = sanitize_text_field( $search_filter );
3073 - $course_id = sanitize_text_field( $course_id );
3074 - $date = sanitize_text_field( $date );
3075 2611
3076 - $search_term_raw = $search_filter;
3077 - $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
2612 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
3078 2613
3079 - $status_query = '';
3080 - if ( is_array( $status ) && count( $status ) ) {
3081 - $status = array_map(
3082 - function ( $str ) {
3083 - return "'{$str}'";
3084 - },
3085 - $status
3086 - );
2614 + $count = $wpdb->get_var( $wpdb->prepare(
2615 + "SELECT COUNT({$wpdb->users}.ID)
2616 + FROM {$wpdb->users}
2617 + INNER JOIN {$wpdb->usermeta}
2618 + ON ( {$wpdb->users}.ID = {$wpdb->usermeta}.user_id )
2619 + WHERE {$wpdb->usermeta}.meta_key = %s
2620 + AND ( {$wpdb->users}.display_name LIKE %s OR {$wpdb->users}.user_email LIKE %s );
2621 + ",
2622 + '_is_tutor_instructor',
2623 + $search_term,
2624 + $search_term
2625 + ) );
3087 2626
3088 - $status_query = ' AND inst_status.meta_value IN (' . implode( ',', $status ) . ')';
3089 - }
3090 -
3091 - $course_query = '';
3092 - if ( '' !== $course_id ) {
3093 - $course_query = "AND umeta.meta_value = $course_id ";
3094 - }
3095 -
3096 - $date_query = '';
3097 - if ( '' !== $date ) {
3098 - $date = tutor_get_formated_date( 'Y-m-d', $date );
3099 - $date_query = "AND DATE(user.user_registered) = CAST('$date' AS DATE)";
3100 - }
3101 -
3102 - $count = $wpdb->get_var(
3103 - $wpdb->prepare(
3104 - "SELECT COUNT(DISTINCT user.ID )
3105 - FROM {$wpdb->users} user
3106 - INNER JOIN {$wpdb->usermeta} user_meta
3107 - ON ( user.ID = user_meta.user_id )
3108 - INNER JOIN {$wpdb->usermeta} inst_status
3109 - ON ( user.ID = inst_status.user_id )
3110 - LEFT JOIN {$wpdb->usermeta} AS umeta
3111 - ON umeta.user_id = user.ID AND umeta.meta_key = '_tutor_instructor_course_id'
3112 -
3113 - WHERE user_meta.meta_key = %s
3114 - AND ( user.display_name LIKE %s OR user.user_email = %s )
3115 - {$status_query}
3116 - {$course_query}
3117 - {$date_query}
3118 - ",
3119 - '_is_tutor_instructor',
3120 - $search_filter,
3121 - $search_term_raw
3122 - )
3123 - );
3124 - return $count ? $count : 0;
2627 + return (int) $count;
3125 2628 }
3126 2629
3127 2630 /**
3128 - * Get instructor with optional filters.
3129 - * Available instructor status ( approved | blocked | pending )
2631 + * @param int $start
2632 + * @param int $limit
2633 + * @param string $search_term
3130 2634 *
3131 - * @since 1.0.0
2635 + * @return array|null|object
3132 2636 *
3133 - * @param int $start start.
3134 - * @param int $limit limit.
3135 - * @param string $search_filter search term.
3136 - * @param string $course_filter course filter.
3137 - * @param string $date_filter date filter.
3138 - * @param string $order_filter order filter.
3139 - * @param mixed $status status.
3140 - * @param array $cat_ids cat ids.
3141 - * @param mixed $rating rating.
3142 - * @param bool $count_only count only or not.
2637 + * Get all instructors
3143 2638 *
3144 - * @return array|null|object
2639 + * @since v.1.0.0
3145 2640 */
3146 - public function get_instructors( $start = 0, $limit = 10, $search_filter = '', $course_filter = '', $date_filter = '', $order_filter = '', $status = null, $cat_ids = array(), $rating = '', $count_only = false ) {
2641 + public function get_instructors( $start = 0, $limit = 10, $search_term = '', $status = null, $cat_ids = array() ) {
3147 2642 global $wpdb;
3148 2643
3149 - $search_filter = sanitize_text_field( $search_filter );
3150 - $course_filter = sanitize_text_field( $course_filter );
3151 - $date_filter = sanitize_text_field( $date_filter );
3152 - $order_filter = sanitize_sql_orderby( $order_filter );
3153 - $rating = sanitize_text_field( $rating );
3154 -
3155 - $search_term_raw = $search_filter;
3156 - $search_filter = '%' . $wpdb->esc_like( $search_filter ) . '%';
3157 - $course_filter = $course_filter != '' ? " AND umeta.meta_value = $course_filter " : '';
3158 -
3159 - if ( '' != $date_filter ) {
3160 - $date_filter = tutor_get_formated_date( 'Y-m-d', $date_filter );
3161 - }
3162 -
3163 - $date_filter = $date_filter != '' ? " AND DATE(user.user_registered) = CAST('$date_filter' AS DATE) " : '';
3164 -
3165 - $category_join = '';
2644 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
2645 + $category_join = '';
3166 2646 $category_where = '';
3167 2647
3168 2648 if ( $status ) {
3169 - ! is_array( $status ) ? $status = array( $status ) : 0;
2649 + !is_array( $status ) ? $status = array( $status ) : 0;
3170 2650
3171 - $status = array_map(
3172 - function ( $str ) {
3173 - return "'{$str}'";
3174 - },
3175 - $status
3176 - );
2651 + $status = array_map( function($str) {
2652 + return "'{$str}'";
2653 + }, $status);
3177 2654
3178 - $status = ' AND inst_status.meta_value IN (' . implode( ',', $status ) . ')';
2655 + $status = " AND inst_status.meta_value IN (".implode( ',', $status ).")";
3179 2656 }
3180 2657
3181 - $cat_ids = array_filter(
3182 - $cat_ids,
3183 - function ( $id ) {
3184 - return is_numeric( $id );
3185 - }
3186 - );
2658 + $cat_ids = array_filter($cat_ids, function($id) {
2659 + return is_numeric($id);
2660 + });
3187 2661
3188 - if ( count( $cat_ids ) ) {
2662 + if(count( $cat_ids )) {
3189 2663
3190 2664 $category_join =
3191 2665 "INNER JOIN {$wpdb->posts} course
3192 2666 ON course.post_author = user.ID
@@ -3196,480 +2670,140 @@
3196 2670 ON taxonomy.term_taxonomy_id=term_rel.term_taxonomy_id
3197 2671 INNER JOIN {$wpdb->prefix}terms term
3198 2672 ON term.term_id=taxonomy.term_id";
3199 2673
3200 - $cat_ids = implode( ',', $cat_ids );
2674 + $cat_ids = implode(',', $cat_ids);
3201 2675 $category_where = " AND term.term_id IN ({$cat_ids})";
3202 2676 }
3203 2677
3204 - // Rating wise sorting @since 2.0.0.
3205 - $res_rat = array( 1, 2, 3, 4, 5 );
3206 - $rating = isset( $_POST['rating_filter'] ) && in_array( $rating, $res_rat ) ? $rating : '';
2678 + $instructors = $wpdb->get_results( $wpdb->prepare(
2679 + "SELECT DISTINCT user.*, user_meta.meta_value AS instructor_from_date
2680 + FROM {$wpdb->users} user
2681 + INNER JOIN {$wpdb->usermeta} user_meta
2682 + ON ( user.ID = user_meta.user_id )
2683 + INNER JOIN {$wpdb->usermeta} inst_status
2684 + ON ( user.ID = inst_status.user_id )
2685 + {$category_join}
2686 + WHERE user_meta.meta_key = %s
2687 + AND ( user.display_name LIKE %s OR user.user_email LIKE %s )
2688 + {$status}
2689 + {$category_where}
2690 + ORDER BY user_meta.meta_value DESC
2691 + LIMIT %d, %d;
2692 + ",
2693 + '_is_tutor_instructor',
2694 + $search_term,
2695 + $search_term,
2696 + $start,
2697 + $limit
2698 + ) );
3207 2699
3208 - $rating_having = '';
3209 - if ( '' !== $rating ) {
3210 - $max_rating = (int) $rating + 1;
3211 - if ( 5 === (int) $rating ) {
3212 - $max_rating = 5;
3213 - }
3214 - $rating_having = $wpdb->prepare( ' HAVING rating >= %d AND rating <= %d ', $rating, $max_rating );
3215 - }
3216 -
3217 - /**
3218 - * Handle Sort by Relevant | New | Popular & Order Shorting
3219 - * from instructor list backend
3220 - *
3221 - * @since 2.0.0
3222 - */
3223 - $order_query = '';
3224 - if ( 'new' === $order_filter ) {
3225 - $order_query = ' ORDER BY user_meta.meta_value DESC ';
3226 - } elseif ( 'popular' === $order_filter ) {
3227 - $order_query = ' ORDER BY rating DESC ';
3228 - } else {
3229 - $order_query = " ORDER BY user_meta.meta_value {$order_filter} ";
3230 - }
3231 -
3232 - $limit_offset = $count_only ? '' : " LIMIT {$start}, {$limit} ";
3233 - $select_col = $count_only ?
3234 - ' COUNT(DISTINCT user.ID) ' :
3235 - ' DISTINCT user.*, user_meta.meta_value AS instructor_from_date, IFNULL(Avg(cmeta.meta_value), 0) AS rating, inst_status.meta_value AS status ';
3236 -
3237 - $query = $wpdb->prepare(
3238 - "SELECT {$select_col}
3239 - FROM {$wpdb->users} user
3240 - INNER JOIN {$wpdb->usermeta} user_meta
3241 - ON ( user.ID = user_meta.user_id )
3242 - INNER JOIN {$wpdb->usermeta} inst_status
3243 - ON ( user.ID = inst_status.user_id )
3244 - {$category_join}
3245 - LEFT JOIN {$wpdb->usermeta} AS umeta
3246 - ON umeta.user_id = user.ID AND umeta.meta_key = '_tutor_instructor_course_id'
3247 - LEFT JOIN {$wpdb->comments} AS c
3248 - ON c.comment_post_ID = umeta.meta_value
3249 - LEFT JOIN {$wpdb->commentmeta} AS cmeta
3250 - ON cmeta.comment_id = c.comment_ID
3251 - AND cmeta.meta_key = 'tutor_rating'
3252 - WHERE user_meta.meta_key = '_is_tutor_instructor'
3253 - AND inst_status.meta_key = '_tutor_instructor_status'
3254 - AND ( user.display_name LIKE %s OR user.user_email = %s )
3255 - {$status}
3256 - {$category_where}
3257 - {$course_filter}
3258 - {$date_filter}
3259 - GROUP BY user.ID {$rating_having} {$order_query} {$limit_offset}",
3260 - $search_filter,
3261 - $search_term_raw
3262 - );
3263 -
3264 - $results = $wpdb->get_results( $query );
3265 - return $count_only ? count( $results ) : $results;
2700 + return $instructors;
3266 2701 }
3267 2702
3268 2703 /**
3269 - * Get all instructors by course
2704 + * @param int $course_id
3270 2705 *
3271 - * @since 1.0.0
2706 + * @return array|bool|null|object
3272 2707 *
3273 - * @param int $course_id course id.
2708 + * Get all instructors by course
3274 2709 *
3275 - * @return array|bool|null|object
2710 + * @since v.1.0.0
3276 2711 */
3277 2712 public function get_instructors_by_course( $course_id = 0 ) {
3278 2713 global $wpdb;
3279 2714 $course_id = $this->get_post_id( $course_id );
3280 2715
3281 - $instructors = $wpdb->get_results(
3282 - $wpdb->prepare(
3283 - "SELECT ID,
2716 + $instructors = $wpdb->get_results( $wpdb->prepare(
2717 + "SELECT ID,
3284 2718 display_name,
3285 - _user.user_email,
3286 2719 get_course.meta_value AS taught_course_id,
3287 2720 tutor_job_title.meta_value AS tutor_profile_job_title,
3288 2721 tutor_bio.meta_value AS tutor_profile_bio,
3289 - tutor_photo.meta_value AS tutor_profile_photo
3290 - FROM {$wpdb->users} _user
3291 - INNER JOIN {$wpdb->usermeta} get_course
3292 - ON ID = get_course.user_id
3293 - AND get_course.meta_key = %s
3294 - AND get_course.meta_value = %d
3295 - LEFT JOIN {$wpdb->usermeta} tutor_job_title
3296 - ON ID = tutor_job_title.user_id
3297 - AND tutor_job_title.meta_key = %s
3298 - LEFT JOIN {$wpdb->usermeta} tutor_bio
3299 - ON ID = tutor_bio.user_id
3300 - AND tutor_bio.meta_key = %s
3301 - LEFT JOIN {$wpdb->usermeta} tutor_photo
3302 - ON ID = tutor_photo.user_id
2722 + tutor_photo.meta_value AS tutor_profile_photo
2723 + FROM {$wpdb->users}
2724 + INNER JOIN {$wpdb->usermeta} get_course
2725 + ON ID = get_course.user_id
2726 + AND get_course.meta_key = %s
2727 + AND get_course.meta_value = %d
2728 + LEFT JOIN {$wpdb->usermeta} tutor_job_title
2729 + ON ID = tutor_job_title.user_id
2730 + AND tutor_job_title.meta_key = %s
2731 + LEFT JOIN {$wpdb->usermeta} tutor_bio
2732 + ON ID = tutor_bio.user_id
2733 + AND tutor_bio.meta_key = %s
2734 + LEFT JOIN {$wpdb->usermeta} tutor_photo
2735 + ON ID = tutor_photo.user_id
3303 2736 AND tutor_photo.meta_key = %s
3304 2737 ",
3305 - '_tutor_instructor_course_id',
3306 - $course_id,
3307 - '_tutor_profile_job_title',
3308 - '_tutor_profile_bio',
3309 - '_tutor_profile_photo'
3310 - )
3311 - );
3312 - // Get main instructor.
3313 - $main_instructor = $wpdb->get_results(
3314 - $wpdb->prepare(
3315 - "SELECT _user.ID,
3316 - display_name,
3317 - _user.user_email,
3318 - course.ID AS taught_course_id,
3319 - tutor_job_title.meta_value AS tutor_profile_job_title,
3320 - tutor_bio.meta_value AS tutor_profile_bio,
3321 - tutor_photo.meta_value AS tutor_profile_photo
3322 - FROM {$wpdb->users} _user
3323 - INNER JOIN {$wpdb->posts} course
3324 - ON _user.ID = course.post_author
3325 - AND course.ID = %d
3326 - LEFT JOIN {$wpdb->usermeta} tutor_job_title
3327 - ON _user.ID = tutor_job_title.user_id
3328 - AND tutor_job_title.meta_key = %s
3329 - LEFT JOIN {$wpdb->usermeta} tutor_bio
3330 - ON _user.ID = tutor_bio.user_id
3331 - AND tutor_bio.meta_key = %s
3332 - LEFT JOIN {$wpdb->usermeta} tutor_photo
3333 - ON _user.ID = tutor_photo.user_id
3334 - AND tutor_photo.meta_key = %s
3335 - ",
3336 - $course_id,
3337 - '_tutor_profile_job_title',
3338 - '_tutor_profile_bio',
3339 - '_tutor_profile_photo'
3340 - )
3341 - );
2738 + '_tutor_instructor_course_id',
2739 + $course_id,
2740 + '_tutor_profile_job_title',
2741 + '_tutor_profile_bio',
2742 + '_tutor_profile_photo'
2743 + ) );
2744 +
3342 2745 if ( is_array( $instructors ) && count( $instructors ) ) {
3343 - // Exclude instructor if already in main instructor.
3344 - $instructors = array_filter(
3345 - $instructors,
3346 - function ( $instructor ) use ( $main_instructor ) {
3347 - if ( $instructor->ID !== $main_instructor[0]->ID ) {
3348 - return true;
3349 - }
3350 - }
3351 - );
3352 - return array_merge( $main_instructor, $instructors );
2746 + return $instructors;
3353 2747 }
3354 - return $main_instructor;
2748 +
2749 + return false;
3355 2750 }
3356 2751
3357 2752 /**
2753 + * @param $instructor_id
2754 + *
3358 2755 * Get total Students by instructor
3359 2756 * 1 enrollment = 1 student, so total enrolled for a equivalent total students (Tricks)
3360 2757 *
3361 - * @since 1.0.0
3362 - * @since 4.0.0 $args parameter added for additional where clause in query.
3363 - *
3364 - * @param int $instructor_id instructor id.
3365 - * @param array $args Optional additional WHERE conditions.
3366 - *
3367 2758 * @return int
3368 - */
3369 - public function get_total_students_by_instructor( $instructor_id, $args = array() ) {
3370 - global $wpdb;
3371 -
3372 - $course_post_type = tutor()->course_post_type;
3373 - $enrollment_date_clause = '';
3374 -
3375 - if ( ! empty( $args['from'] ) && ! empty( $args['to'] ) ) {
3376 - $from = Input::sanitize( $args['from'] );
3377 - $to = Input::sanitize( $args['to'] );
3378 -
3379 - $where['enrollment.post_date'] = array( 'BETWEEN', array( $from, $to ) );
3380 - $enrollment_date_clause = ' AND ' . QueryHelper::prepare_where_clause( $where );
3381 - }
3382 -
3383 - $count = $wpdb->get_var(
3384 - $wpdb->prepare(
3385 - "SELECT COUNT(DISTINCT(enrollment.post_author))
3386 - FROM {$wpdb->posts} enrollment
3387 - INNER JOIN {$wpdb->posts} course
3388 - ON enrollment.post_parent=course.ID
3389 - WHERE course.post_author = %d
3390 - AND course.post_type = %s
3391 - AND course.post_status = %s
3392 - AND enrollment.post_type = %s
3393 - AND enrollment.post_status = %s
3394 - {$enrollment_date_clause}",
3395 - $instructor_id,
3396 - $course_post_type,
3397 - 'publish',
3398 - 'tutor_enrolled',
3399 - 'completed'
3400 - )
3401 - );
3402 -
3403 - return (int) $count;
3404 - }
3405 -
3406 - /**
3407 - * Get all students by instructor_id
3408 2759 *
3409 - * @since 1.9.9
3410 - *
3411 - * @param integer $instructor_id instructor id.
3412 - * @param integer $offset offset.
3413 - * @param integer $limit limit.
3414 - * @param string $search_filter search filter.
3415 - * @param string $course_id course id.
3416 - * @param string $date_filter date filter.
3417 - * @param string $order_by order by.
3418 - * @param string $order order.
3419 - *
3420 - * @since 3.4.0
3421 - * @since 4.0.0 $args parameter added for additional where clause in query.
3422 - *
3423 - * @param array $post_status the post status.
3424 - * @param array $args Optional additional WHERE conditions.
3425 - *
3426 - * @return array
2760 + * @since v.1.0.0
3427 2761 */
3428 - public function get_students_by_instructor( int $instructor_id, int $offset, int $limit, $search_filter = '', $course_id = '', $date_filter = '', $order_by = '', $order = '', $post_status = array( 'publish' ), $args = array() ): array {
2762 + public function get_total_students_by_instructor( $instructor_id ) {
3429 2763 global $wpdb;
3430 - $instructor_id = sanitize_text_field( $instructor_id );
3431 - $limit = sanitize_text_field( $limit );
3432 - $offset = sanitize_text_field( $offset );
3433 - $course_id = sanitize_text_field( $course_id );
3434 - $date_filter = sanitize_text_field( $date_filter );
3435 - $search_filter = sanitize_text_field( $search_filter );
3436 2764
3437 - $order_by = 'user.ID';
3438 - if ( 'registration_date' === $order_by ) {
3439 - $order_by = 'enrollment.post_date';
3440 - } elseif ( 'course_taken' === $order_by ) {
3441 - $order_by = 'course_taken';
3442 - } else {
3443 - $order_by = 'user.ID';
3444 - }
3445 -
3446 - $order = sanitize_sql_orderby( $order );
3447 -
3448 - if ( '' !== $date_filter ) {
3449 - $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter );
3450 - }
3451 -
3452 2765 $course_post_type = tutor()->course_post_type;
3453 2766
3454 - $search_term_raw = $search_filter;
3455 - $search_query = '%' . $wpdb->esc_like( $search_filter ) . '%';
3456 - $course_query = '';
3457 - $date_query = '';
3458 - $author_query = '';
3459 - $registratipn_date_clause = '';
3460 -
3461 - if ( $course_id ) {
3462 - $course_query = " AND course.ID = $course_id ";
3463 - }
3464 - if ( '' !== $date_filter ) {
3465 - $date_query = " AND DATE(user.user_registered) = CAST( '$date_filter' AS DATE ) ";
3466 - }
3467 - /**
3468 - * If instructor id set then by only students that belongs to instructor
3469 - * otherwise get all
3470 - *
3471 - * @since 2.0.0
3472 - */
3473 - if ( $instructor_id ) {
3474 - $author_query = "AND course.post_author = $instructor_id";
3475 - }
3476 -
3477 - if ( ! empty( $args['from'] ) && ! empty( $args['to'] ) ) {
3478 - $from = Input::sanitize( $args['from'] );
3479 - $to = Input::sanitize( $args['to'] );
3480 -
3481 - $where['user.user_registered'] = array( 'BETWEEN', array( $from, $to ) );
3482 - $registratipn_date_clause = ' AND ' . QueryHelper::prepare_where_clause( $where );
3483 - }
3484 -
3485 - $post_status = QueryHelper::prepare_in_clause( $post_status );
3486 - $students = $wpdb->get_results(
3487 - $wpdb->prepare(
3488 - "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, (SELECT post_date FROM {$wpdb->posts} WHERE post_author = user.ID LIMIT 1) AS enroll_date
3489 - FROM {$wpdb->posts} enrollment
3490 - INNER JOIN {$wpdb->posts} AS course
3491 - ON enrollment.post_parent=course.ID
3492 - INNER JOIN {$wpdb->users} AS user
3493 - ON user.ID = enrollment.post_author
3494 - WHERE course.post_type = %s
3495 - AND course.post_status IN ({$post_status})
3496 - AND enrollment.post_type = %s
3497 - AND enrollment.post_status = %s
3498 - {$registratipn_date_clause}
3499 - {$author_query}
3500 - {$course_query}
3501 - {$date_query}
3502 - AND ( user.display_name LIKE %s OR user.user_nicename LIKE %s OR user.user_email = %s OR user.user_login LIKE %s )
3503 - GROUP BY enrollment.post_author
3504 - ORDER BY {$order_by} {$order}
3505 - LIMIT %d, %d",
3506 - $course_post_type,
3507 - 'tutor_enrolled',
3508 - 'completed',
3509 - $search_query,
3510 - $search_query,
3511 - $search_term_raw,
3512 - $search_query,
3513 - $offset,
3514 - $limit
3515 - )
3516 - );
3517 - $total_students = $wpdb->get_results(
3518 - $wpdb->prepare(
3519 - "SELECT COUNT(enrollment.post_author) AS course_taken, user.*, enrollment.post_date AS enroll_date
3520 - FROM {$wpdb->posts} enrollment
3521 - INNER JOIN {$wpdb->posts} AS course
2767 + $count = $wpdb->get_var( $wpdb->prepare(
2768 + "SELECT COUNT(enrollment.ID)
2769 + FROM {$wpdb->posts} enrollment
2770 + LEFT JOIN {$wpdb->posts} course
3522 2771 ON enrollment.post_parent=course.ID
3523 - INNER JOIN {$wpdb->users} AS user
3524 - ON user.ID = enrollment.post_author
3525 - WHERE course.post_type = %s
3526 - AND course.post_status IN ({$post_status})
3527 - AND enrollment.post_type = %s
3528 - AND enrollment.post_status = %s
3529 - AND ( user.display_name LIKE %s OR user.user_nicename LIKE %s OR user.user_email = %s OR user.user_login LIKE %s )
3530 - {$author_query}
3531 - {$course_query}
3532 - {$date_query}
3533 - GROUP BY enrollment.post_author
3534 - ORDER BY {$order_by} {$order}",
3535 - $course_post_type,
3536 - 'tutor_enrolled',
3537 - 'completed',
3538 - $search_query,
3539 - $search_query,
3540 - $search_term_raw,
3541 - $search_query
3542 - )
3543 - );
3544 -
3545 - return array(
3546 - 'students' => $students,
3547 - 'total_students' => count( $total_students ),
3548 - );
3549 - }
3550 -
3551 - /**
3552 - * Get all course for a give student & instructor id
3553 - *
3554 - * @since 1.9.9
3555 - * @since 3.4.0 param $post_status added.
3556 - *
3557 - * @param int $student_id student id.
3558 - * @param int $instructor_id instructor id.
3559 - * @param array $post_status the post status.
3560 - *
3561 - * @return array
3562 - */
3563 - public function get_courses_by_student_instructor_id( int $student_id, int $instructor_id, $post_status = array( 'publish' ) ): array {
3564 - global $wpdb;
3565 - $course_post_type = tutor()->course_post_type;
3566 - $post_status = QueryHelper::prepare_in_clause( $post_status );
3567 - $students = $wpdb->get_results(
3568 - $wpdb->prepare(
3569 - "SELECT course.*
3570 - FROM {$wpdb->posts} enrollment
3571 - INNER JOIN {$wpdb->posts} AS course
3572 - ON enrollment.post_parent=course.ID
3573 - WHERE course.post_author = %d
2772 + WHERE course.post_author = %d
3574 2773 AND course.post_type = %s
3575 - AND course.post_status IN ({$post_status})
2774 + AND course.post_status = %s
3576 2775 AND enrollment.post_type = %s
3577 - AND enrollment.post_status = %s
3578 - AND enrollment.post_author = %d
3579 - ORDER BY course.post_date DESC
2776 + AND enrollment.post_status = %s;
3580 2777 ",
3581 - $instructor_id,
3582 - $course_post_type,
3583 - 'tutor_enrolled',
3584 - 'completed',
3585 - $student_id
3586 - )
3587 - );
3588 - return $students;
3589 - }
2778 + $instructor_id,
2779 + $course_post_type,
2780 + 'publish',
2781 + 'tutor_enrolled',
2782 + 'completed'
3590 2783
3591 - /**
3592 - * Get total number of completed assignment
3593 - *
3594 - * @since 1.9.9
3595 - *
3596 - * @param int $course_id course id.
3597 - * @param int $student_id student id.
3598 - *
3599 - * @return int
3600 - */
3601 - public function get_completed_assignment( int $course_id, int $student_id ): int {
3602 - global $wpdb;
3603 - $course_id = sanitize_text_field( $course_id );
3604 - $student_id = sanitize_text_field( $student_id );
3605 - $count = $wpdb->get_var(
3606 - $wpdb->prepare(
3607 - "SELECT COUNT( DISTINCT ID ) FROM {$wpdb->posts}
3608 - INNER JOIN {$wpdb->comments} c ON c.comment_post_ID = ID AND c.user_id = %d AND c.comment_approved = %s
3609 - WHERE post_parent IN (SELECT ID FROM {$wpdb->posts} WHERE post_type = %s AND post_parent = %d AND post_status = %s)
3610 - AND post_type =%s
3611 - AND post_status = %s
3612 - ",
3613 - $student_id,
3614 - 'submitted',
3615 - 'topics',
3616 - $course_id,
3617 - 'publish',
3618 - 'tutor_assignments',
3619 - 'publish'
3620 - )
3621 - );
2784 + ) );
2785 +
3622 2786 return (int) $count;
3623 2787 }
3624 2788
3625 2789 /**
3626 - * Get total number of completed quiz
2790 + * @param float $input
3627 2791 *
3628 - * @since 1.9.9
2792 + * @return float|string
3629 2793 *
3630 - * @param int $course_id course id.
3631 - * @param int $student_id student id.
3632 - *
3633 - * @return int
3634 - */
3635 - public function get_completed_quiz( int $course_id, int $student_id ): int {
3636 - global $wpdb;
3637 - $course_id = sanitize_text_field( $course_id );
3638 - $student_id = sanitize_text_field( $student_id );
3639 - $count = $wpdb->get_var(
3640 - $wpdb->prepare(
3641 - "SELECT COUNT(DISTINCT quiz_id) AS total
3642 - FROM {$wpdb->prefix}tutor_quiz_attempts
3643 - WHERE course_id = %d
3644 - AND user_id = %d
3645 - AND attempt_status = %s
3646 - ",
3647 - $course_id,
3648 - $student_id,
3649 - 'attempt_ended'
3650 - )
3651 - );
3652 - return (int) $count;
3653 - }
3654 -
3655 - /**
3656 2794 * Get rating format from value
3657 2795 *
3658 - * @since 1.0.0
3659 - *
3660 - * @param float $input input.
3661 - *
3662 - * @return float|string
2796 + * @since v.1.0.0
3663 2797 */
3664 2798 public function get_rating_value( $input = 0.00 ) {
3665 2799
3666 - if ( $input > 0 ) {
3667 - $input = number_format( $input, 2 );
2800 + if ( $input > 0) {
2801 + $input = number_format( $input, 2 );
3668 2802 $int_value = (int) $input;
3669 - $fraction = $input - $int_value;
2803 + $fraction = $input - $int_value;
3670 2804
3671 - if ( 0 == $fraction ) {
2805 + if ( $fraction == 0 ) {
3672 2806 $fraction = 0.00;
3673 2807 } elseif ( $fraction > 0.5 ) {
3674 2808 $fraction = 1;
3675 2809 } else {
@@ -3682,37 +2816,40 @@
3682 2816 return 0.00;
3683 2817 }
3684 2818
3685 2819 /**
3686 - * Generate star rating based in given rating value
2820 + * @param float $current_rating
2821 + * @param bool $echo
3687 2822 *
3688 - * @since 1.0.0
2823 + * @return string
3689 2824 *
3690 - * @param float $current_rating current rating.
3691 - * @param bool $echo print output.
2825 + * Generate star rating based in given rating value
3692 2826 *
3693 - * @return string
2827 + * @since v.1.0.0
3694 2828 */
3695 2829 public function star_rating_generator( $current_rating = 0.00, $echo = true ) {
2830 + $output = '<div class="tutor-star-rating-group">';
3696 2831
3697 - $output = '<div class="tutor-ratings-stars">';
2832 + for ( $i = 1; $i <=5 ; $i++ ) {
2833 + $intRating = (int) $current_rating;
3698 2834
3699 - for ( $i = 1; $i <= 5; $i++ ) {
3700 - if ( (int) $current_rating >= $i ) {
3701 - $output .= '<i class="tutor-icon-star-bold" data-rating-value="' . $i . '"></i>';
3702 - } elseif ( ( $current_rating - $i ) >= -0.5 ) {
3703 - $output .= '<i class="tutor-icon-star-half-bold" data-rating-value="' . $i . '"></i>';
2835 + if ( $intRating >= $i ) {
2836 + $output.= '<i class="tutor-icon-star-full" data-rating-value="'.$i.'"></i>';
3704 2837 } else {
3705 - $output .= '<i class="tutor-icon-star-line" data-rating-value="' . $i . '"></i>';
2838 + if ( ( $current_rating - $i) == -0.5 ) {
2839 + $output.= '<i class="tutor-icon-star-half" data-rating-value="'.$i.'"></i>';
2840 + } else {
2841 + $output.= '<i class="tutor-icon-star-line" data-rating-value="'.$i.'"></i>';
2842 + }
3706 2843 }
3707 2844 }
3708 2845
3709 - $output .= '</div>';
2846 + $output .= "<div class='tutor-rating-gen-input'><input type='hidden' name='tutor_rating_gen_input' value='{$current_rating}' /> </div>";
3710 2847
3711 - $output .= '<input type="hidden" name="tutor_rating_gen_input" value="' . $current_rating . '" />';
2848 + $output .= "</div>";
3712 2849
3713 2850 if ( $echo ) {
3714 - echo tutor_kses_html( $output );
2851 + echo $output;
3715 2852 }
3716 2853
3717 2854 return $output;
3718 2855 }
@@ -3717,232 +2854,81 @@
3717 2854 return $output;
3718 2855 }
3719 2856
3720 2857 /**
3721 - * Generate star rating.
2858 + * @param $string
3722 2859 *
3723 - * @since 1.0.0
2860 + * @return string
3724 2861 *
3725 - * @param mixed $current_rating current rating.
3726 - * @param mixed $total_count total count.
3727 - * @param boolean $show_avg_rate show avg rate.
3728 - * @param string $parent_class perent class.
3729 - * @param string $screen_size screen size.
3730 - *
3731 - * @return void
3732 - */
3733 - public function star_rating_generator_v2( $current_rating, $total_count = null, $show_avg_rate = false, $parent_class = '', $screen_size = '' ) {
3734 - $current_rating = number_format( $current_rating, 2, '.', '' );
3735 - $css_class = isset( $screen_size ) ? "{$parent_class} tutor-ratings-{$screen_size}" : "{$parent_class}";
3736 - ?>
3737 - <div class="tutor-ratings<?php echo esc_attr( $css_class ); ?>">
3738 - <div class="tutor-ratings-stars">
3739 - <?php
3740 - for ( $i = 1; $i <= 5; $i++ ) {
3741 - $class = 'tutor-icon-star-line';
3742 -
3743 - if ( $i <= round( $current_rating ) ) {
3744 - $class = 'tutor-icon-star-bold';
3745 - }
3746 -
3747 - // Todo: Add half start later. tutor-icon-star-half-bold.
3748 - echo '<span class="' . $class . '"></span>';
3749 - }
3750 - ?>
3751 - </div>
3752 - <?php if ( $show_avg_rate && $total_count > 0 ) : ?>
3753 - <div class="tutor-ratings-average">
3754 - <?php echo esc_html( $current_rating ); ?>
3755 - </div>
3756 - <div class="tutor-ratings-count">
3757 - (<?php echo esc_html( $total_count ) . ' ' . ( $total_count > 1 ? esc_html__( 'Ratings', 'tutor' ) : esc_html__( 'Rating', 'tutor' ) ); ?>)
3758 - </div>
3759 - <?php endif; ?>
3760 - </div>
3761 - <?php
3762 - }
3763 -
3764 - /**
3765 - * Generate course star rating.
3766 - *
3767 - * @since 1.0.0
3768 - *
3769 - * @param float $current_rating current rating.
3770 - * @param boolean $echo output print.
3771 - *
3772 - * @return mixed
3773 - */
3774 - public function star_rating_generator_course( $current_rating = 0.00, $echo = true ) {
3775 - $output = '';
3776 - for ( $i = 1; $i <= 5; $i++ ) {
3777 - if ( (int) $current_rating >= $i ) {
3778 - $output .= '<span class="tutor-icon-star-bold" data-rating-value="' . $i . '"></span>';
3779 - } elseif ( ( $current_rating - $i ) >= -0.5 ) {
3780 - $output .= '<span class="tutor-icon-star-half-bold" data-rating-value="' . $i . '"></span>';
3781 - } else {
3782 - $output .= '<span class="tutor-icon-star-line" data-rating-value="' . $i . '"></span>';
3783 - }
3784 - }
3785 -
3786 - if ( $echo ) {
3787 - echo wp_kses(
3788 - $output,
3789 - array(
3790 - 'span' => array(
3791 - 'class' => true,
3792 - 'data-rating' => true,
3793 - 'data-rating-value' => true,
3794 - ),
3795 - )
3796 - );
3797 - }
3798 -
3799 - return $output;
3800 - }
3801 -
3802 - /**
3803 2862 * Split string regardless of ASCI, Unicode
3804 2863 *
3805 - * @since 1.0.0
3806 - *
3807 - * @param string $string string.
3808 - *
3809 - * @return string
2864 + *
3810 2865 */
3811 2866 public function str_split( $string ) {
3812 2867 $strlen = mb_strlen( $string );
3813 2868 while ( $strlen ) {
3814 - $array[] = mb_substr( $string, 0, 1, 'UTF-8' );
3815 - $string = mb_substr( $string, 1, $strlen, 'UTF-8' );
3816 - $strlen = mb_strlen( $string );
2869 + $array[] = mb_substr( $string,0,1,"UTF-8" );
2870 + $string = mb_substr( $string,1,$strlen,"UTF-8" );
2871 + $strlen = mb_strlen( $string );
3817 2872 }
3818 2873 return $array;
3819 - }
2874 + }
3820 2875
3821 2876 /**
3822 - * Generate avatar for user
2877 + * @param null $name
3823 2878 *
3824 - * @since 1.0.0
3825 - * @since 2.1.7 changed param $user_id to $user for reduce query.
3826 - * @since 2.1.8 Get user data using get_userdata API
2879 + * @return string
3827 2880 *
3828 - * @param integer|object $user user id or object.
3829 - * @param string $size size of avatar like sm, md, lg.
3830 - * @param bool $echo whether to echo or return.
2881 + * Generate text to avatar
3831 2882 *
3832 - * @return string
2883 + * @since v.1.0.0
3833 2884 */
3834 - public function get_tutor_avatar( $user = null, $size = '', $echo = false ) {
2885 + public function get_tutor_avatar( $user_id = null, $size = 'thumbnail' ) {
2886 + global $wpdb;
3835 2887
3836 - if ( ! $user ) {
2888 + if ( ! $user_id ) {
3837 2889 return '';
3838 2890 }
3839 2891
3840 - if ( ! is_object( $user ) ) {
3841 - $user = get_userdata( $user );
2892 + $user = $this->get_tutor_user( $user_id );
2893 + if ( $user->tutor_profile_photo ) {
2894 + return '<img src="'.wp_get_attachment_image_url( $user->tutor_profile_photo, $size ).'" class="tutor-image-avatar" alt="" /> ';
3842 2895 }
3843 2896
3844 - if ( is_a( $user, 'WP_User' ) ) {
3845 - // Get & set user profile photo.
3846 - $profile_photo = get_user_meta( $user->ID, '_tutor_profile_photo', true );
3847 - $user->tutor_profile_photo = $profile_photo;
3848 - }
2897 + $name = $user->display_name;
2898 + $arr = explode( ' ', trim( $name ) );
3849 2899
3850 - $name = is_object( $user ) ? $user->display_name : '';
3851 - $arr = explode( ' ', trim( $name ) );
3852 - $class = $size ? ' tutor-avatar-' . $size : '';
2900 + $first_char = ! empty( $arr[0] ) ? $this->str_split( $arr[0] )[0] : '';
2901 + $second_char = ! empty( $arr[1] ) ? $this->str_split( $arr[1] )[0] : '';
2902 + $initial_avatar = strtoupper( $first_char.$second_char );
3853 2903
3854 - $output = '<div class="tutor-avatar' . $class . '">';
3855 - $output .= '<div class="tutor-ratio tutor-ratio-1x1">';
2904 + $bg_color = '#'.substr( md5( $initial_avatar ), 0, 6);
2905 + $initial_avatar = "<span class='tutor-text-avatar' style='background-color: {$bg_color}; color: #fff8e5'>{$initial_avatar}</span>";
3856 2906
3857 - if ( is_object( $user ) && $user->tutor_profile_photo && wp_get_attachment_image_url( $user->tutor_profile_photo ) ) {
3858 - $output .= '<img src="' . wp_get_attachment_image_url( $user->tutor_profile_photo, 'thumbnail' ) . '" alt="' . esc_attr( $name ) . '" /> ';
3859 - } else {
3860 - $first_char = ! empty( $arr[0] ) ? $this->str_split( $arr[0] )[0] : '';
3861 - $second_char = ! empty( $arr[1] ) ? $this->str_split( $arr[1] )[0] : '';
3862 - $initial_avatar = strtoupper( $first_char . $second_char );
3863 - $output .= '<span class="tutor-avatar-text">' . $initial_avatar . '</span>';
3864 - }
3865 -
3866 - $output .= '</div>';
3867 - $output .= '</div>';
3868 -
3869 - if ( $echo ) {
3870 - echo wp_kses( $output, $this->allowed_avatar_tags() );
3871 - } else {
3872 - return apply_filters( 'tutor_text_avatar', $output );
3873 - }
2907 + return $initial_avatar;
3874 2908 }
3875 2909
3876 2910 /**
3877 - * Get user avatar URL.
2911 + * @param $user_id
3878 2912 *
3879 - * @since 4.0.0
2913 + * @return array|null|object|void
3880 2914 *
3881 - * @param integer $user_id user id.
2915 + * Get tutor user
3882 2916 *
3883 - * @return string
2917 + * @since v.1.0.0
3884 2918 */
3885 - public function get_user_avatar_url( $user_id = 0 ) {
3886 - $user_id = $this->get_user_id( $user_id );
3887 - $cache_key = 'tutor_get_user_avatar_url_' . $user_id;
3888 - $cached_data = TutorCache::get( $cache_key );
3889 -
3890 - if ( false !== $cached_data ) {
3891 - return $cached_data;
3892 - }
3893 -
3894 - $avatar_url = '';
3895 -
3896 - $user = get_userdata( $user_id );
3897 - if ( is_a( $user, 'WP_User' ) ) {
3898 - $user->tutor_profile_photo = get_user_meta( $user->ID, '_tutor_profile_photo', true );
3899 - }
3900 -
3901 - if ( is_object( $user ) && $user->tutor_profile_photo && wp_get_attachment_image_url( $user->tutor_profile_photo ) ) {
3902 - $avatar_url = wp_get_attachment_image_url( $user->tutor_profile_photo, 'thumbnail' );
3903 - } else {
3904 - $avatar_url = get_avatar_url( $user_id );
3905 - }
3906 -
3907 - TutorCache::set( $cache_key, $avatar_url );
3908 -
3909 - return $avatar_url;
3910 - }
3911 -
3912 - /**
3913 - * Get tutor user.
3914 - *
3915 - * @since 1.0.0
3916 - * @since 3.0.0 tutor_profile_photo_url property added.
3917 - *
3918 - * @param int $user_id user id.
3919 - *
3920 - * @return array|null|object|void
3921 - */
3922 2919 public function get_tutor_user( $user_id ) {
3923 - $cache_key = 'tutor_user_' . $user_id;
3924 - $cached_data = TutorCache::get( $cache_key );
3925 -
3926 - if ( false !== $cached_data ) {
3927 - return $cached_data;
3928 - }
3929 -
3930 2920 global $wpdb;
3931 2921
3932 - $user = $wpdb->get_row(
3933 - $wpdb->prepare(
3934 - "SELECT ID,
3935 - display_name,
3936 - user_email,
3937 - user_login,
3938 - user_nicename,
3939 - tutor_job_title.meta_value AS tutor_profile_job_title,
2922 + $user = $wpdb->get_row( $wpdb->prepare(
2923 + "SELECT ID,
2924 + display_name,
2925 + tutor_job_title.meta_value AS tutor_profile_job_title,
3940 2926 tutor_bio.meta_value AS tutor_profile_bio,
3941 2927 tutor_photo.meta_value AS tutor_profile_photo
3942 2928 FROM {$wpdb->users}
3943 - LEFT JOIN {$wpdb->usermeta} tutor_job_title
3944 - ON ID = tutor_job_title.user_id
2929 + LEFT JOIN {$wpdb->usermeta} tutor_job_title
2930 + ON ID = tutor_job_title.user_id
3945 2931 AND tutor_job_title.meta_key = '_tutor_profile_job_title'
3946 2932 LEFT JOIN {$wpdb->usermeta} tutor_bio
3947 2933 ON ID = tutor_bio.user_id
3948 2934 AND tutor_bio.meta_key = '_tutor_profile_bio'
@@ -3950,96 +2936,66 @@
3950 2936 ON ID = tutor_photo.user_id
3951 2937 AND tutor_photo.meta_key = '_tutor_profile_photo'
3952 2938 WHERE ID = %d
3953 2939 ",
3954 - $user_id
3955 - )
3956 - );
2940 + $user_id
2941 + ) );
3957 2942
3958 - if ( $user ) {
3959 - $user->tutor_profile_photo_url = wp_get_attachment_image_url( $user->tutor_profile_photo );
3960 - }
3961 -
3962 - TutorCache::set( $cache_key, $user );
3963 -
3964 2943 return $user;
3965 2944 }
3966 2945
3967 2946 /**
3968 - * Get course reviews
2947 + * @param int $course_id
2948 + * @param int $offset
2949 + * @param int $limit
3969 2950 *
3970 - * @since 1.0.0
2951 + * @return array|null|object
3971 2952 *
3972 - * @since 3.6.0
2953 + * get course reviews
3973 2954 *
3974 - * Fetching data by context, either course or comment
3975 - *
3976 - * @param int $object_id Course/Comment id.
3977 - * @param int $start offset.
3978 - * @param int $limit limit.
3979 - * @param bool $count_only count only.
3980 - * @param array $status_in status list.
3981 - * @param int $include_user_id include user id.
3982 - * @param int $is_course_object Whether fetching by course or not.
3983 - *
3984 - * @return array|null|object
2955 + * @since v.1.0.0
3985 2956 */
3986 - public function get_course_reviews( $object_id = 0, $start = 0, $limit = 10, $count_only = false, $status_in = array( 'approved' ), $include_user_id = 0, $is_course_object = true ) {
2957 + public function get_course_reviews( $course_id = 0, $offset = 0, $limit = 150 ) {
2958 + $course_id = $this->get_post_id( $course_id );
3987 2959 global $wpdb;
3988 2960
3989 - $object_id = (int) $object_id;
2961 + $reviews = $wpdb->get_results( $wpdb->prepare(
2962 + "SELECT {$wpdb->comments}.comment_ID,
2963 + {$wpdb->comments}.comment_post_ID,
2964 + {$wpdb->comments}.comment_author,
2965 + {$wpdb->comments}.comment_author_email,
2966 + {$wpdb->comments}.comment_date,
2967 + {$wpdb->comments}.comment_content,
2968 + {$wpdb->comments}.user_id,
2969 + {$wpdb->commentmeta}.meta_value AS rating,
2970 + {$wpdb->users}.display_name
2971 +
2972 + FROM {$wpdb->comments}
2973 + INNER JOIN {$wpdb->commentmeta}
2974 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
2975 + LEFT JOIN {$wpdb->users}
2976 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
2977 + WHERE {$wpdb->comments}.comment_post_ID = %d
2978 + AND comment_type = 'tutor_course_rating' AND meta_key = 'tutor_rating'
2979 + ORDER BY comment_ID DESC
2980 + LIMIT %d, %d;
2981 + ",
2982 + $course_id,
2983 + $offset,
2984 + $limit
2985 + ) );
3990 2986
3991 - $where_clause = '_reviews.comment_ID = %d';
3992 -
3993 - if ( $is_course_object ) {
3994 - $object_id = $this->get_post_id( $object_id );
3995 - $where_clause = '_reviews.comment_post_ID = %d';
3996 - }
3997 -
3998 - $limit_offset = $count_only ? '' : ' LIMIT ' . (int) $limit . ' OFFSET ' . (int) $start;
3999 - $status_in = '"' . implode( '","', $status_in ) . '"';
4000 - $include_user_id = is_array( $include_user_id ) ? $include_user_id : array( $include_user_id );
4001 - $include_user_id = implode( ',', $include_user_id );
4002 -
4003 - $select_columns = $count_only ? ' COUNT(DISTINCT _reviews.comment_ID) ' :
4004 - '_reviews.comment_ID,
4005 - _reviews.comment_post_ID,
4006 - _reviews.comment_author,
4007 - _reviews.comment_author_email,
4008 - _reviews.comment_date,
4009 - _reviews.comment_date_gmt,
4010 - _reviews.comment_content,
4011 - _reviews.comment_approved AS comment_status,
4012 - _reviews.user_id,
4013 - _rev_meta.meta_value AS rating,
4014 - _reviewer.display_name';
4015 -
4016 - $query = $wpdb->prepare(
4017 - "SELECT {$select_columns}
4018 - FROM {$wpdb->comments} _reviews
4019 - INNER JOIN {$wpdb->commentmeta} _rev_meta
4020 - ON _reviews.comment_ID = _rev_meta.comment_id
4021 - LEFT JOIN {$wpdb->users} _reviewer
4022 - ON _reviews.user_id = _reviewer.ID
4023 - WHERE {$where_clause}
4024 - AND _reviews.comment_type = 'tutor_course_rating'
4025 - AND (_reviews.comment_approved IN ({$status_in}) OR _reviews.user_id IN ({$include_user_id}))
4026 - AND _rev_meta.meta_key = 'tutor_rating'
4027 - ORDER BY _reviews.comment_ID DESC {$limit_offset}",
4028 - $object_id
4029 - );
4030 -
4031 - return $count_only ? $wpdb->get_var( $query ) : $wpdb->get_results( $query );
2987 + return $reviews;
4032 2988 }
4033 2989
4034 2990 /**
4035 - * Get course rating
2991 + * @param int $course_id
4036 2992 *
4037 - * @since 1.0.0
2993 + * @return object
4038 2994 *
4039 - * @param int $course_id course ID.
2995 + * Get course rating
4040 2996 *
4041 - * @return object
2997 + * @since v.1.0.0
4042 2998 */
4043 2999 public function get_course_rating( $course_id = 0 ) {
4044 3000 global $wpdb;
4045 3001 $course_id = $this->get_post_id( $course_id );
@@ -4047,20 +3003,13 @@
4047 3003 $ratings = array(
4048 3004 'rating_count' => 0,
4049 3005 'rating_sum' => 0,
4050 3006 'rating_avg' => 0.00,
4051 - 'count_by_value' => array(
4052 - 5 => 0,
4053 - 4 => 0,
4054 - 3 => 0,
4055 - 2 => 0,
4056 - 1 => 0,
4057 - ),
3007 + 'count_by_value' => array( 5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0 )
4058 3008 );
4059 3009
4060 - $rating = $wpdb->get_row(
4061 - $wpdb->prepare(
4062 - "SELECT COUNT(meta_value) AS rating_count,
3010 + $rating = $wpdb->get_row( $wpdb->prepare(
3011 + "SELECT COUNT(meta_value) AS rating_count,
4063 3012 SUM(meta_value) AS rating_sum
4064 3013 FROM {$wpdb->comments}
4065 3014 INNER JOIN {$wpdb->commentmeta}
4066 3015 ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
@@ -4065,51 +3014,38 @@
4065 3014 INNER JOIN {$wpdb->commentmeta}
4066 3015 ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4067 3016 WHERE {$wpdb->comments}.comment_post_ID = %d
4068 3017 AND {$wpdb->comments}.comment_type = %s
4069 - AND {$wpdb->comments}.comment_approved = %s
4070 3018 AND meta_key = %s;
4071 - ",
4072 - $course_id,
4073 - 'tutor_course_rating',
4074 - 'approved',
4075 - 'tutor_rating'
4076 - )
4077 - );
3019 + ",
3020 + $course_id,
3021 + 'tutor_course_rating',
3022 + 'tutor_rating'
3023 + ) );
4078 3024
4079 3025 if ( $rating->rating_count ) {
4080 3026 $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
4081 3027
4082 - $stars = $wpdb->get_results(
4083 - $wpdb->prepare(
4084 - "SELECT CAST(commentmeta.meta_value AS SIGNED) AS rating,
4085 - COUNT(commentmeta.meta_value) as rating_count
3028 + $stars = $wpdb->get_results( $wpdb->prepare(
3029 + "SELECT commentmeta.meta_value AS rating,
3030 + COUNT(commentmeta.meta_value) as rating_count
4086 3031 FROM {$wpdb->comments} comments
4087 3032 INNER JOIN {$wpdb->commentmeta} commentmeta
4088 3033 ON comments.comment_ID = commentmeta.comment_id
4089 - WHERE comments.comment_post_ID = %d
3034 + WHERE comments.comment_post_ID = %d
4090 3035 AND comments.comment_type = %s
4091 3036 AND commentmeta.meta_key = %s
4092 - AND comments.comment_approved = %s
4093 - GROUP BY CAST(commentmeta.meta_value AS SIGNED);
4094 - ",
4095 - $course_id,
4096 - 'tutor_course_rating',
4097 - 'tutor_rating',
4098 - 'approved'
4099 - )
4100 - );
3037 + GROUP BY commentmeta.meta_value;
3038 + ",
3039 + $course_id,
3040 + 'tutor_course_rating',
3041 + 'tutor_rating'
3042 + ) );
4101 3043
4102 - $ratings = array(
4103 - 5 => 0,
4104 - 4 => 0,
4105 - 3 => 0,
4106 - 2 => 0,
4107 - 1 => 0,
4108 - );
3044 + $ratings = array( 5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0 );
4109 3045 foreach ( $stars as $star ) {
4110 3046 $index = (int) $star->rating;
4111 - array_key_exists( $index, $ratings ) ? $ratings[ $index ] = $star->rating_count : 0;
3047 + array_key_exists($index, $ratings) ? $ratings[ $index ] = $star->rating_count : 0;
4112 3048 }
4113 3049
4114 3050 $ratings = array(
4115 3051 'rating_count' => $rating->rating_count,
@@ -4114,9 +3050,9 @@
4114 3050 $ratings = array(
4115 3051 'rating_count' => $rating->rating_count,
4116 3052 'rating_sum' => $rating->rating_sum,
4117 3053 'rating_avg' => $avg_rating,
4118 - 'count_by_value' => $ratings,
3054 + 'count_by_value' => $ratings
4119 3055 );
4120 3056 }
4121 3057
4122 3058 return (object) $ratings;
@@ -4122,169 +3058,72 @@
4122 3058 return (object) $ratings;
4123 3059 }
4124 3060
4125 3061 /**
4126 - * Get reviews by a user (Given by the user)
3062 + * @param int $user_id
3063 + * @param int $offset
3064 + * @param int $limit
4127 3065 *
4128 - * @since 1.0.0
3066 + * @return array|null|object
4129 3067 *
4130 - * @param int $user_id user id.
4131 - * @param int $offset offset.
4132 - * @param int $limit limit.
4133 - * @param bool $get_object get object.
4134 - * @param mixed $course_id course id.
4135 - * @param array $status_in status.
3068 + * Get reviews by a user
4136 3069 *
4137 - * @return array|null|object
3070 + * @since v.1.0.0
4138 3071 */
4139 - public function get_reviews_by_user( $user_id = 0, $offset = 0, $limit = null, $get_object = false, $course_id = null, $status_in = array( 'approved' ) ) {
3072 + public function get_reviews_by_user( $user_id = 0, $offset = 0, $limit = 150 ) {
3073 + $user_id = $this->get_user_id( $user_id );
4140 3074 global $wpdb;
4141 3075
4142 - if ( ! $limit ) {
4143 - $limit = $this->get_option( 'pagination_per_page', 10 );
4144 - }
3076 + $reviews = $wpdb->get_results( $wpdb->prepare(
3077 + "SELECT {$wpdb->comments}.comment_ID,
3078 + {$wpdb->comments}.comment_post_ID,
3079 + {$wpdb->comments}.comment_author,
3080 + {$wpdb->comments}.comment_author_email,
3081 + {$wpdb->comments}.comment_date,
3082 + {$wpdb->comments}.comment_content,
3083 + {$wpdb->comments}.user_id,
3084 + {$wpdb->commentmeta}.meta_value as rating,
3085 + {$wpdb->users}.display_name
3086 +
3087 + FROM {$wpdb->comments}
3088 + INNER JOIN {$wpdb->commentmeta}
3089 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3090 + INNER JOIN {$wpdb->users}
3091 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3092 + WHERE {$wpdb->comments}.user_id = %d
3093 + AND comment_type = %s
3094 + AND meta_key = %s
3095 + ORDER BY comment_ID DESC
3096 + LIMIT %d, %d;
3097 + ",
3098 + $user_id,
3099 + 'tutor_course_rating',
3100 + 'tutor_rating',
3101 + $offset,
3102 + $limit
3103 + ) );
4145 3104
4146 - $course_filter = '';
4147 - if ( $course_id ) {
4148 - $course_ids = is_array( $course_id ) ? $course_id : array( $course_id );
4149 - $course_ids = implode( ',', $course_ids );
4150 - $course_filter = " AND _comment.comment_post_ID IN ($course_ids)";
4151 - }
4152 -
4153 - $user_filter = '';
4154 - if ( null !== $user_id ) {
4155 - $user_id = $this->get_user_id( $user_id );
4156 - $user_filter = ' AND _comment.user_id=' . $user_id;
4157 - }
4158 -
4159 - $status_in = '"' . implode( '","', $status_in ) . '"';
4160 - $status_filter = ' AND _comment.comment_approved IN (' . $status_in . ')';
4161 -
4162 - $reviews = $wpdb->get_results(
4163 - $wpdb->prepare(
4164 - "SELECT _comment.comment_ID,
4165 - _comment.comment_post_ID,
4166 - _comment.comment_author,
4167 - _comment.comment_author_email,
4168 - _comment.comment_date,
4169 - _comment.comment_date_gmt,
4170 - _comment.comment_content,
4171 - _comment.comment_approved AS comment_status,
4172 - _comment.user_id,
4173 - _meta.meta_value as rating,
4174 - _course.post_title AS course_title,
4175 - _student.display_name
4176 - FROM {$wpdb->comments} _comment
4177 - INNER JOIN {$wpdb->commentmeta} _meta
4178 - ON _comment.comment_ID = _meta.comment_id
4179 - INNER JOIN {$wpdb->posts} _course
4180 - ON _comment.comment_post_ID=_course.ID
4181 - INNER JOIN {$wpdb->users} _student
4182 - ON _comment.user_id = _student.ID
4183 - WHERE _comment.comment_type = %s
4184 - AND _meta.meta_key = %s
4185 - {$user_filter}
4186 - {$course_filter}
4187 - {$status_filter}
4188 - ORDER BY _comment.comment_ID DESC
4189 - LIMIT %d, %d;",
4190 - 'tutor_course_rating',
4191 - 'tutor_rating',
4192 - $offset,
4193 - $limit
4194 - )
4195 - );
4196 -
4197 - if ( $get_object ) {
4198 - // Prepare other data for multiple reviews case.
4199 - $count = (int) $wpdb->get_var(
4200 - $wpdb->prepare(
4201 - "SELECT COUNT({$wpdb->comments}.comment_ID)
4202 - FROM {$wpdb->comments}
4203 - INNER JOIN {$wpdb->commentmeta}
4204 - ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4205 - INNER JOIN {$wpdb->users}
4206 - ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
4207 - INNER JOIN {$wpdb->posts} AS course
4208 - ON course.ID = comment_post_ID
4209 - WHERE {$wpdb->comments}.user_id = %d
4210 - AND comment_type = %s
4211 - AND meta_key = %s
4212 - AND comment_approved = 'approved'
4213 - ",
4214 - $user_id,
4215 - 'tutor_course_rating',
4216 - 'tutor_rating'
4217 - )
4218 - );
4219 -
4220 - return (object) array(
4221 - 'count' => $count,
4222 - 'results' => $reviews,
4223 - );
4224 - }
4225 -
4226 - // Return single review for single course.
4227 - if ( $course_id && ! is_array( $course_id ) ) {
4228 - return count( $reviews ) ? $reviews[0] : null;
4229 - }
4230 -
4231 3105 return $reviews;
4232 3106 }
4233 3107
4234 3108 /**
4235 - * Get reviews by instructor (Received by the instructor)
3109 + * @param int $user_id
3110 + * @param int $offset
3111 + * @param int $limit
4236 3112 *
4237 - * @since 1.0.0
4238 - * @since 1.4.0 $course_id $date_filter param added.
4239 - * @since 1.9.9 Course id & date filter is sorting with specific course and date.
4240 - * @since 4.0.0 $args parameter added.
3113 + * @return array|null|object
4241 3114 *
4242 - * @param int $instructor_id user id.
4243 - * @param int $offset offset.
4244 - * @param int $limit limit.
4245 - * @param string $course_id course id.
4246 - * @param string $date_filter date filter.
4247 - * @param array $args Optional additional WHERE conditions.
3115 + * Get reviews by instructor
4248 3116 *
4249 - * @return array|null|object
3117 + * @since v.1.4.0
4250 3118 */
4251 - public function get_reviews_by_instructor( $instructor_id = 0, $offset = 0, $limit = 150, $course_id = '', $date_filter = '', $args = array() ) {
3119 + public function get_reviews_by_instructor( $instructor_id = 0, $offset = 0, $limit = 150 ) {
3120 + $instructor_id = $this->get_user_id( $instructor_id );
4252 3121 global $wpdb;
4253 - $instructor_id = sanitize_text_field( $instructor_id );
4254 - $offset = sanitize_text_field( $offset );
4255 - $limit = sanitize_text_field( $limit );
4256 - $course_id = sanitize_text_field( $course_id );
4257 - $date_filter = sanitize_text_field( $date_filter );
4258 - $instructor_id = $this->get_user_id( $instructor_id );
4259 3122
4260 - $course_query = '';
4261 - $date_query = '';
4262 - $extra_where_clause = '';
4263 -
4264 - if ( ! empty( $args['from'] ) && ! empty( $args['to'] ) ) {
4265 - $from = Input::sanitize( $args['from'] );
4266 - $to = Input::sanitize( $args['to'] );
4267 -
4268 - $where['comment_date'] = array( 'BETWEEN', array( $from, $to ) );
4269 - $extra_where_clause = ' AND ' . QueryHelper::prepare_where_clause( $where );
4270 - }
4271 -
4272 - if ( ! empty( $args['comment_approved'] ) ) {
4273 - $extra_where_clause = ' AND ' . QueryHelper::prepare_where_clause( array( 'comment_approved' => $args['comment_approved'] ) );
4274 - }
4275 -
4276 - if ( '' !== $course_id ) {
4277 - $course_query = " AND {$wpdb->comments}.comment_post_ID = {$course_id} ";
4278 - }
4279 - if ( '' !== $date_filter ) {
4280 - $date_filter = \tutor_get_formated_date( 'Y-m-d', $date_filter );
4281 - $date_query = " AND DATE({$wpdb->comments}.comment_date) = CAST( '$date_filter' AS DATE ) ";
4282 - }
4283 -
4284 3123 $results = array(
4285 - 'count' => 0,
4286 - 'results' => false,
3124 + 'count' => 0,
3125 + 'results' => false,
4287 3126 );
4288 3127
4289 3128 $cours_ids = (array) $this->get_assigned_courses_ids_by_instructors( $instructor_id );
4290 3129
@@ -4290,65 +3129,52 @@
4290 3129
4291 3130 if ( $this->count( $cours_ids ) ) {
4292 3131 $implode_ids = implode( ',', $cours_ids );
4293 3132
4294 - // Count.
4295 - $results['count'] = $wpdb->get_var(
4296 - $wpdb->prepare(
4297 - "SELECT COUNT({$wpdb->comments}.comment_ID)
3133 + //Count
3134 + $results['count'] = $wpdb->get_var( $wpdb->prepare(
3135 + "SELECT COUNT({$wpdb->comments}.comment_ID)
4298 3136 FROM {$wpdb->comments}
4299 3137 INNER JOIN {$wpdb->commentmeta}
4300 3138 ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4301 3139 INNER JOIN {$wpdb->users}
4302 3140 ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
4303 - WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3141 + WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
4304 3142 AND comment_type = %s
4305 - AND meta_key = %s
4306 - {$extra_where_clause}
4307 - {$course_query}
4308 - {$date_query}
3143 + AND meta_key = %s;
4309 3144 ",
4310 - 'tutor_course_rating',
4311 - 'tutor_rating'
4312 - )
4313 - );
3145 + 'tutor_course_rating',
3146 + 'tutor_rating'
3147 + ) );
4314 3148
4315 - $order_by = $args['order_by'] ?? 'comment_ID';
4316 - // Results.
4317 - $results['results'] = $wpdb->get_results(
4318 - $wpdb->prepare(
4319 - "SELECT {$wpdb->comments}.comment_ID,
4320 - {$wpdb->comments}.comment_post_ID,
4321 - {$wpdb->comments}.comment_author,
4322 - {$wpdb->comments}.comment_author_email,
4323 - {$wpdb->comments}.comment_date,
4324 - {$wpdb->comments}.comment_content,
4325 - {$wpdb->comments}.user_id,
3149 + //Results
3150 + $results['results'] = $wpdb->get_results( $wpdb->prepare(
3151 + "SELECT {$wpdb->comments}.comment_ID,
3152 + {$wpdb->comments}.comment_post_ID,
3153 + {$wpdb->comments}.comment_author,
3154 + {$wpdb->comments}.comment_author_email,
3155 + {$wpdb->comments}.comment_date,
3156 + {$wpdb->comments}.comment_content,
3157 + {$wpdb->comments}.user_id,
4326 3158 {$wpdb->commentmeta}.meta_value AS rating,
4327 - {$wpdb->users}.display_name,
4328 - {$wpdb->posts}.post_title as course_title
4329 -
4330 - FROM {$wpdb->comments}
4331 - INNER JOIN {$wpdb->commentmeta}
4332 - ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4333 - INNER JOIN {$wpdb->users}
4334 - ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
4335 - INNER JOIN {$wpdb->posts}
4336 - ON {$wpdb->posts}.ID = {$wpdb->comments}.comment_post_ID
4337 - WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
3159 + {$wpdb->users}.display_name
3160 +
3161 + FROM {$wpdb->comments}
3162 + INNER JOIN {$wpdb->commentmeta}
3163 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3164 + INNER JOIN {$wpdb->users}
3165 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3166 + WHERE {$wpdb->comments}.comment_post_ID IN({$implode_ids})
4338 3167 AND comment_type = %s
4339 3168 AND meta_key = %s
4340 - {$extra_where_clause}
4341 - {$course_query}
4342 - {$date_query}
4343 - ORDER BY {$order_by} DESC
4344 - LIMIT %d, %d",
4345 - 'tutor_course_rating',
4346 - 'tutor_rating',
4347 - $offset,
4348 - $limit
4349 - )
4350 - );
3169 + ORDER BY comment_ID DESC
3170 + LIMIT %d, %d;
3171 + ",
3172 + 'tutor_course_rating',
3173 + 'tutor_rating',
3174 + $offset,
3175 + $limit
3176 + ) );
4351 3177 }
4352 3178
4353 3179 return (object) $results;
4354 3180 }
@@ -4353,62 +3179,48 @@
4353 3179 return (object) $results;
4354 3180 }
4355 3181
4356 3182 /**
4357 - * Get instructors rating
3183 + * @param $instructor_id
4358 3184 *
4359 - * @since 1.0.0
4360 - * @since 4.0.0 Added $args Parameter.
3185 + * @return object
4361 3186 *
4362 - * @param int $instructor_id instructor id.
4363 - * @param array $args Optional additional WHERE conditions.
3187 + * Get instructors rating
4364 3188 *
4365 - * @return object
3189 + * @since v.1.0.0
4366 3190 */
4367 - public function get_instructor_ratings( $instructor_id, $args = array() ) {
3191 + public function get_instructor_ratings( $instructor_id ) {
4368 3192 global $wpdb;
4369 3193
4370 3194 $ratings = array(
4371 - 'rating_count' => 0,
4372 - 'rating_sum' => 0,
4373 - 'rating_avg' => 0.00,
3195 + 'rating_count' => 0,
3196 + 'rating_sum' => 0,
3197 + 'rating_avg' => 0.00,
4374 3198 );
4375 3199
4376 - $where = array(
4377 - 'courses.user_id' => (int) $instructor_id,
4378 - 'courses.meta_key' => '_tutor_instructor_course_id',
4379 - );
3200 + $rating = $wpdb->get_row( $wpdb->prepare(
3201 + "SELECT COUNT(rating.meta_value) as rating_count, SUM(rating.meta_value) as rating_sum
3202 + FROM {$wpdb->usermeta} courses
3203 + INNER JOIN {$wpdb->comments} reviews
3204 + ON courses.meta_value = reviews.comment_post_ID
3205 + AND reviews.comment_type = 'tutor_course_rating'
3206 + INNER JOIN {$wpdb->commentmeta} rating
3207 + ON reviews.comment_ID = rating.comment_id
3208 + AND rating.meta_key = 'tutor_rating'
3209 + WHERE courses.user_id = %d
3210 + AND courses.meta_key = %s
3211 + ",
3212 + $instructor_id,
3213 + '_tutor_instructor_course_id'
3214 + ) );
4380 3215
4381 - if ( ! empty( $args['from'] ) && ! empty( $args['to'] ) ) {
4382 - $from = Input::sanitize( $args['from'] );
4383 - $to = Input::sanitize( $args['to'] );
4384 -
4385 - $where['reviews.comment_date'] = array( 'BETWEEN', array( $from, $to ) );
4386 - }
4387 -
4388 - // Prepare where clause.
4389 - $where_clause = QueryHelper::prepare_where_clause( $where );
4390 -
4391 - $rating = $wpdb->get_row(
4392 - "SELECT COUNT(rating.meta_value) as rating_count, SUM(rating.meta_value) as rating_sum
4393 - FROM {$wpdb->usermeta} courses
4394 - INNER JOIN {$wpdb->comments} reviews
4395 - ON courses.meta_value = reviews.comment_post_ID
4396 - AND reviews.comment_type = 'tutor_course_rating'
4397 - AND reviews.comment_approved = 'approved'
4398 - INNER JOIN {$wpdb->commentmeta} rating
4399 - ON reviews.comment_ID = rating.comment_id
4400 - AND rating.meta_key = 'tutor_rating'
4401 - WHERE {$where_clause}"
4402 - );
4403 -
4404 3216 if ( $rating->rating_count ) {
4405 3217 $avg_rating = number_format( ( $rating->rating_sum / $rating->rating_count ), 2 );
4406 3218
4407 3219 $ratings = array(
4408 - 'rating_count' => $rating->rating_count,
4409 - 'rating_sum' => $rating->rating_sum,
4410 - 'rating_avg' => $avg_rating,
3220 + 'rating_count' => $rating->rating_count,
3221 + 'rating_sum' => $rating->rating_sum,
3222 + 'rating_avg' => $avg_rating,
4411 3223 );
4412 3224 }
4413 3225
4414 3226 return (object) $ratings;
@@ -4414,22 +3226,22 @@
4414 3226 return (object) $ratings;
4415 3227 }
4416 3228
4417 3229 /**
4418 - * Get course rating by user
3230 + * @param int $course_id
3231 + * @param int $user_id
4419 3232 *
4420 - * @since 1.0.0
3233 + * @return object
4421 3234 *
4422 - * @param int $course_id course id.
4423 - * @param int $user_id user id.
3235 + * Get course rating by user
4424 3236 *
4425 - * @return object
3237 + * @since v.1.0.0
4426 3238 */
4427 3239 public function get_course_rating_by_user( $course_id = 0, $user_id = 0 ) {
4428 3240 global $wpdb;
4429 3241
4430 3242 $course_id = $this->get_post_id( $course_id );
4431 - $user_id = $this->get_user_id( $user_id );
3243 + $user_id = $this->get_user_id( $user_id );
4432 3244
4433 3245 $ratings = array(
4434 3246 'rating' => 0,
4435 3247 'review' => '',
@@ -4434,24 +3246,22 @@
4434 3246 'rating' => 0,
4435 3247 'review' => '',
4436 3248 );
4437 3249
4438 - $rating = $wpdb->get_row(
4439 - $wpdb->prepare(
4440 - "SELECT meta_value AS rating,
3250 + $rating = $wpdb->get_row( $wpdb->prepare(
3251 + "SELECT meta_value AS rating,
4441 3252 comment_content AS review
4442 3253 FROM {$wpdb->comments}
4443 - INNER JOIN {$wpdb->commentmeta}
4444 - ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3254 + INNER JOIN {$wpdb->commentmeta}
3255 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
4445 3256 WHERE {$wpdb->comments}.comment_post_ID = %d
4446 3257 AND user_id = %d
4447 3258 AND meta_key = %s;
4448 3259 ",
4449 - $course_id,
4450 - $user_id,
4451 - 'tutor_rating'
4452 - )
4453 - );
3260 + $course_id,
3261 + $user_id,
3262 + 'tutor_rating'
3263 + ) );
4454 3264
4455 3265 if ( $rating ) {
4456 3266 $rating_format = number_format( $rating->rating, 2 );
4457 3267
@@ -4464,46 +3274,42 @@
4464 3274 return (object) $ratings;
4465 3275 }
4466 3276
4467 3277 /**
4468 - * Count reviews wrote by user
3278 + * @param int $user_id
4469 3279 *
4470 - * @since 1.0.0
3280 + * @return null|string
4471 3281 *
4472 - * @param int $user_id user id.
4473 - *
4474 - * @return null|string
3282 + * @since v.1.0.0
4475 3283 */
4476 3284 public function count_reviews_wrote_by_user( $user_id = 0 ) {
4477 3285 global $wpdb;
4478 3286
4479 - $user_id = $this->get_user_id( $user_id );
3287 + $user_id = $this->get_user_id($user_id);
4480 3288
4481 - $count_reviews = $wpdb->get_var(
4482 - $wpdb->prepare(
4483 - "SELECT COUNT(comment_ID)
3289 + $count_reviews = $wpdb->get_var( $wpdb->prepare(
3290 + "SELECT COUNT(comment_ID)
4484 3291 FROM {$wpdb->comments}
4485 3292 WHERE user_id = %d
4486 3293 AND comment_type = %s
4487 3294 ",
4488 - $user_id,
4489 - 'tutor_course_rating'
4490 - )
4491 - );
3295 + $user_id,
3296 + 'tutor_course_rating'
3297 + ) );
4492 3298
4493 3299 return $count_reviews;
4494 3300 }
4495 3301
4496 3302 /**
4497 - * This function transforms the php.ini notation for numbers (like '2M') to an integer.
3303 + * @param $size
4498 3304 *
4499 - * @since 1.0.0
3305 + * @return bool|int|string
4500 3306 *
4501 - * @param mixed $size size.
3307 + * This function transforms the php.ini notation for numbers (like '2M') to an integer.
4502 3308 *
4503 - * @return bool|int|string
3309 + * @since v.1.0.0
4504 3310 */
4505 - public function let_to_num( $size ) {
3311 + function let_to_num( $size ) {
4506 3312 $l = substr( $size, -1 );
4507 3313 $ret = substr( $size, 0, -1 );
4508 3314 $byte = 1024;
4509 3315
@@ -4509,33 +3315,33 @@
4509 3315
4510 3316 switch ( strtoupper( $l ) ) {
4511 3317 case 'P':
4512 3318 $ret *= 1024;
4513 - // No break.
3319 + // No break.
4514 3320 case 'T':
4515 3321 $ret *= 1024;
4516 - // No break.
3322 + // No break.
4517 3323 case 'G':
4518 3324 $ret *= 1024;
4519 - // No break.
3325 + // No break.
4520 3326 case 'M':
4521 3327 $ret *= 1024;
4522 - // No break.
3328 + // No break.
4523 3329 case 'K':
4524 3330 $ret *= 1024;
4525 - // No break.
3331 + // No break.
4526 3332 }
4527 3333 return $ret;
4528 3334 }
4529 3335
4530 3336 /**
3337 + * @return array
3338 + *
4531 3339 * Get Database version
4532 3340 *
4533 - * @since 1.0.0
4534 - *
4535 - * @return array
3341 + * @since v.1.0.0
4536 3342 */
4537 - public function get_db_version() {
3343 + function get_db_version() {
4538 3344 global $wpdb;
4539 3345
4540 3346 if ( empty( $wpdb->is_mysql ) ) {
4541 3347 return array(
@@ -4544,11 +3350,11 @@
4544 3350 );
4545 3351 }
4546 3352
4547 3353 if ( $wpdb->use_mysqli ) {
4548 - $server_info = mysqli_get_server_info($wpdb->dbh); // @codingStandardsIgnoreLine.
3354 + $server_info = mysqli_get_server_info( $wpdb->dbh ); // @codingStandardsIgnoreLine.
4549 3355 } else {
4550 - $server_info = mysql_get_server_info($wpdb->dbh); // @codingStandardsIgnoreLine.
3356 + $server_info = mysql_get_server_info( $wpdb->dbh ); // @codingStandardsIgnoreLine.
4551 3357 }
4552 3358
4553 3359 return array(
4554 3360 'string' => $server_info,
@@ -4555,311 +3361,326 @@
4555 3361 'number' => preg_replace( '/([^\d.]+).*/', '', $server_info ),
4556 3362 );
4557 3363 }
4558 3364
3365 + public function help_tip( $tip = '' ) {
3366 + return '<span class="tutor-help-tip" data-tip="' . $tip . '"></span>';
3367 + }
3368 +
4559 3369 /**
4560 - * Get help tip
3370 + * @param int $course_id
3371 + * @param int $user_id
3372 + * @param int $offset
3373 + * @param int $limit
4561 3374 *
4562 - * @since 1.0.0
3375 + * @return array|null|object
4563 3376 *
4564 - * @param string $tip tip name.
3377 + * Get top question
4565 3378 *
4566 - * @return string
3379 + * @since v.1.0.0
4567 3380 */
4568 - public function help_tip( $tip = '' ) {
4569 - return '<span class="tutor-help-tip" data-tip="' . $tip . '"></span>';
3381 + public function get_top_question( $course_id = 0, $user_id = 0, $offset = 0, $limit = 20, $is_author = false ) {
3382 + global $wpdb;
3383 +
3384 + $course_id = $this->get_post_id( $course_id );
3385 + $user_id = $this->get_user_id( $user_id );
3386 +
3387 + $author_sql = $is_author ? "" : "AND {$wpdb->comments}.user_id = {$user_id}";
3388 +
3389 + $questions = $wpdb->get_results( $wpdb->prepare(
3390 + "SELECT {$wpdb->comments}.comment_ID,
3391 + {$wpdb->comments}.comment_post_ID,
3392 + {$wpdb->comments}.comment_author,
3393 + {$wpdb->comments}.comment_date,
3394 + {$wpdb->comments}.comment_date_gmt,
3395 + {$wpdb->comments}.comment_content,
3396 + {$wpdb->comments}.user_id,
3397 + {$wpdb->commentmeta}.meta_value as question_title,
3398 + {$wpdb->users}.display_name
3399 + FROM {$wpdb->comments}
3400 + INNER JOIN {$wpdb->commentmeta}
3401 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3402 + INNER JOIN {$wpdb->users}
3403 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3404 + WHERE {$wpdb->comments}.comment_post_ID = {$course_id} {$author_sql}
3405 + AND {$wpdb->comments}.comment_type = %s
3406 + AND meta_key = %s
3407 + ORDER BY comment_ID DESC
3408 + LIMIT %d, %d;
3409 + ",
3410 + 'tutor_q_and_a',
3411 + 'tutor_question_title',
3412 + $offset,
3413 + $limit
3414 + ) );
3415 +
3416 + return $questions;
4570 3417 }
4571 3418
4572 3419 /**
4573 - * Get question and answer query
3420 + * @param string $search_term
4574 3421 *
4575 - * @since 1.0.0
3422 + * @return int
4576 3423 *
4577 - * @param integer $start start.
4578 - * @param integer $limit limit.
4579 - * @param string $search_term search term.
4580 - * @param mixed $question_id question id.
4581 - * @param mixed $meta_query meta query.
4582 - * @param mixed $asker_id asker id.
4583 - * @param mixed $question_status question status.
4584 - * @param boolean $count_only count only.
4585 - * @param array $args args.
3424 + * Get total number of Q&A questions
4586 3425 *
4587 - * @return array|null|object
3426 + * @since v.1.0.0
4588 3427 */
4589 - public function get_qa_questions( $start = 0, $limit = 10, $search_term = '', $question_id = null, $meta_query = null, $asker_id = null, $question_status = null, $count_only = false, $args = array() ) {
3428 + public function get_total_qa_question( $search_term = '' ) {
4590 3429 global $wpdb;
4591 3430
4592 - $user_id = get_current_user_id();
4593 - $course_type = tutor()->course_post_type;
4594 - $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4595 - $question_clause = $question_id ? ' AND _question.comment_ID=' . (int) $question_id : '';
4596 - $order_condition = ' ORDER BY _question.comment_ID DESC ';
4597 - $meta_clause = '';
4598 - $in_course_id_query = '';
4599 - $qna_types_caluse = '';
4600 - $filter_clause = '';
3431 + $user_id = get_current_user_id();
3432 + $course_type = tutor()->course_post_type;
3433 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4601 3434
4602 - // Sanitize args before process.
4603 - $args = Input::sanitize_array( $args );
4604 -
4605 - if ( ! $user_id && ! $asker_id && null === $question_id && empty( $args['course_id'] ) ) {
4606 - return $count_only ? 0 : array();
4607 - }
4608 -
3435 + $in_question_id_query = '';
4609 3436 /**
4610 - * Get only assinged courses questions if current user is not admin
4611 - * User query.
3437 + * Get only assinged courses questions if current user is a
4612 3438 */
4613 - if ( $asker_id ) {
4614 - $question_clause .= ' AND _question.user_id=' . (int) $asker_id;
4615 - }
3439 + if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
4616 3440
4617 - if ( ! $user_id ) {
4618 - $in_course_id_query .= " AND _course.post_status = 'publish' ";
4619 - }
3441 + $get_course_ids = $wpdb->get_col( $wpdb->prepare(
3442 + "SELECT ID
3443 + FROM {$wpdb->posts}
3444 + WHERE post_author = %d
3445 + AND post_type = %s
3446 + AND post_status = %s
3447 + ",
3448 + $user_id,
3449 + $course_type,
3450 + 'publish'
3451 + ) );
4620 3452
4621 - if ( isset( $args['course_id'] ) ) {
4622 - // Get qa for specific course.
4623 - $args['course_id'] = intval( $args['course_id'] );
4624 - $in_course_id_query .= ' AND _question.comment_post_ID=' . $args['course_id'] . ' ';
3453 + $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
3454 + "SELECT meta_value
3455 + FROM {$wpdb->usermeta}
3456 + WHERE meta_key = %s
3457 + AND user_id = %d
3458 + ",
3459 + '_tutor_instructor_course_id',
3460 + $user_id
3461 + ) );
4625 3462
4626 - } elseif ( ! $asker_id && null === $question_id && ! $this->has_user_role( 'administrator', $user_id ) && current_user_can( tutor()->instructor_role ) ) {
4627 - // If current user is simple instructor (non admin), then get qa from their courses only.
4628 - $my_course_ids = $this->get_course_id_by( 'instructor', $user_id );
4629 - $in_ids = count( $my_course_ids ) ? implode( ',', $my_course_ids ) : '0';
4630 - $in_course_id_query .= " AND _question.comment_post_ID IN($in_ids) ";
4631 - }
3463 + $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4632 3464
4633 - // Add more filters to the query.
4634 - if ( isset( $args['course-id'] ) && is_numeric( $args['course-id'] ) ) {
4635 - $filter_clause .= ' AND _course.ID=' . $args['course-id'];
4636 - }
4637 -
4638 - if ( isset( $args['date'] ) ) {
4639 - $date = esc_sql( $args['date'] );
4640 - $filter_clause .= ' AND DATE(_question.comment_date)=\'' . $date . '\'';
4641 - }
4642 -
4643 - if ( isset( $args['order'] ) ) {
4644 - $order = strtolower( $args['order'] );
4645 - if ( 'asc' === $order || 'desc' === $order ) {
4646 - $order_condition = ' ORDER BY _question.comment_ID ' . $order . ' ';
3465 + if ( $this->count( $my_course_ids ) ) {
3466 + $implode_ids = implode( ',', $my_course_ids );
3467 + $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4647 3468 }
4648 3469 }
4649 3470
4650 - // Meta query.
4651 - if ( $meta_query ) {
4652 - $meta_array = array();
4653 - foreach ( $meta_query as $key => $value ) {
4654 - $meta_array[] = "_meta.meta_key='{$key}' AND _meta.meta_value='{$value}'";
4655 - }
4656 - $meta_clause .= ' AND ' . implode( ' AND ', $meta_array );
4657 - }
3471 + $count = $wpdb->get_var( $wpdb->prepare(
3472 + "SELECT COUNT({$wpdb->comments}.comment_ID)
3473 + FROM {$wpdb->comments}
3474 + INNER JOIN {$wpdb->commentmeta}
3475 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3476 + WHERE comment_type = %s
3477 + AND comment_parent = 0 {$in_question_id_query}
3478 + AND {$wpdb->commentmeta}.meta_value LIKE %s;
3479 + ",
3480 + 'tutor_q_and_a',
3481 + $search_term
3482 + ) );
4658 3483
4659 - $asker_prefix = null === $asker_id ? '' : '_' . $asker_id;
4660 - $exclude_archive = ' AND NOT EXISTS (SELECT meta_key FROM ' . $wpdb->commentmeta . ' WHERE meta_key = \'tutor_qna_archived' . $asker_prefix . '\' AND meta_value=1 AND comment_id = _meta.comment_id) ';
3484 + return (int) $count;
3485 + }
4661 3486
4662 - // Assign read, unread, archived, important identifier.
4663 - switch ( $question_status ) {
4664 - case null:
4665 - case 'all':
4666 - if ( ! $question_id ) {
4667 - $qna_types_caluse = $exclude_archive;
4668 - }
4669 - break;
3487 + /**
3488 + * @param int $start
3489 + * @param int $limit
3490 + * @param string $search_term
3491 + *
3492 + * @return array|null|object
3493 + *
3494 + *
3495 + * Get question and answer query
3496 + *
3497 + * @since v.1.0.0
3498 + */
3499 + public function get_qa_questions( $start = 0, $limit = 10, $search_term = '' ) {
3500 + global $wpdb;
4670 3501
4671 - case 'read':
4672 - $qna_types_caluse = ' AND (_meta.meta_key=\'tutor_qna_read' . $asker_prefix . '\' AND _meta.meta_value=1) ' . $exclude_archive;
4673 - break;
3502 + $user_id = get_current_user_id();
3503 + $course_type = tutor()->course_post_type;
3504 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4674 3505
4675 - case 'unread':
4676 - $qna_types_caluse = ' AND (_meta.meta_key=\'tutor_qna_read' . $asker_prefix . '\' AND _meta.meta_value!=1) ' . $exclude_archive;
4677 - break;
3506 + $in_question_id_query = '';
3507 + /**
3508 + * Get only assinged courses questions if current user is a
3509 + */
3510 + if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
3511 +
3512 + $get_course_ids = $wpdb->get_col( $wpdb->prepare(
3513 + "SELECT ID
3514 + FROM {$wpdb->posts}
3515 + WHERE post_author = %d
3516 + AND post_type = %s
3517 + AND post_status = %s
3518 + ",
3519 + $user_id,
3520 + $course_type,
3521 + 'publish'
3522 + ) );
4678 3523
4679 - case 'archived':
4680 - $qna_types_caluse = ' AND (_meta.meta_key=\'tutor_qna_archived' . $asker_prefix . '\' AND _meta.meta_value=1) ';
4681 - break;
3524 + $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
3525 + "SELECT meta_value
3526 + FROM {$wpdb->usermeta}
3527 + WHERE meta_key = %s
3528 + AND user_id = %d
3529 + ",
3530 + '_tutor_instructor_course_id',
3531 + $user_id
3532 + ) );
4682 3533
4683 - case 'important':
4684 - $qna_types_caluse = ' AND (_meta.meta_key=\'tutor_qna_important' . $asker_prefix . '\' AND _meta.meta_value=1) ' . $exclude_archive;
4685 - break;
4686 - }
3534 + $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4687 3535
4688 - $columns_select = $count_only ? 'COUNT(DISTINCT _question.comment_ID)' :
4689 - "DISTINCT _question.comment_ID,
4690 - _question.comment_post_ID,
4691 - _question.comment_author,
4692 - _question.comment_date,
4693 - _question.comment_date_gmt,
4694 - _question.comment_content,
4695 - _question.user_id,
4696 - _user.user_email,
4697 - _user.display_name,
4698 - _course.ID as course_id,
4699 - _course.post_title,
4700 - ( SELECT COUNT(answers_t.comment_ID)
4701 - FROM {$wpdb->comments} answers_t
4702 - WHERE answers_t.comment_parent = _question.comment_ID
4703 - ) AS answer_count";
4704 -
4705 - $limit_offset = $count_only ? '' : ' LIMIT ' . (int) $limit . ' OFFSET ' . (int) $start;
4706 -
4707 - $query = $wpdb->prepare(
4708 - "SELECT {$columns_select}
4709 - FROM {$wpdb->comments} _question
4710 - INNER JOIN {$wpdb->posts} _course
4711 - ON _question.comment_post_ID = _course.ID
4712 - INNER JOIN {$wpdb->users} _user
4713 - ON _question.user_id = _user.ID
4714 - LEFT JOIN {$wpdb->commentmeta} _meta
4715 - ON _question.comment_ID = _meta.comment_id
4716 - LEFT JOIN {$wpdb->commentmeta} _meta_archive
4717 - ON _question.comment_ID = _meta_archive.comment_id
4718 - WHERE _question.comment_type = 'tutor_q_and_a'
4719 - AND _question.comment_parent = 0
4720 - AND _question.comment_content LIKE %s
4721 - {$in_course_id_query}
4722 - {$question_clause}
4723 - {$meta_clause}
4724 - {$qna_types_caluse}
4725 - {$filter_clause}
4726 - {$order_condition}
4727 - {$limit_offset}",
4728 - $search_term
4729 - );
4730 - if ( $count_only ) {
4731 - return $wpdb->get_var( $query );
4732 - }
4733 -
4734 - $query = $wpdb->get_results( $query );
4735 -
4736 - // Collect question IDs and create empty meta array placeholder.
4737 - $question_ids = array();
4738 - foreach ( $query as $index => $q ) {
4739 - $question_ids[] = $q->comment_ID;
4740 - $query[ $index ]->meta = array();
4741 - }
4742 -
4743 - // Assign meta data.
4744 - if ( count( $question_ids ) ) {
4745 - $q_ids = implode( ',', $question_ids );
4746 - $meta_array = $wpdb->get_results(
4747 - "SELECT comment_id, meta_key, meta_value
4748 - FROM {$wpdb->commentmeta}
4749 - WHERE comment_id IN ({$q_ids})"
4750 - );
4751 - // Loop through meta array.
4752 - foreach ( $meta_array as $meta ) {
4753 - // Loop through questions.
4754 - foreach ( $query as $index => $question ) {
4755 -
4756 - if ( $query[ $index ]->comment_ID == $meta->comment_id ) {
4757 -
4758 - $query[ $index ]->meta[ $meta->meta_key ] = $meta->meta_value;
4759 - }
4760 - }
3536 + if ( $this->count( $my_course_ids ) ) {
3537 + $implode_ids = implode( ',', $my_course_ids );
3538 + $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4761 3539 }
4762 3540 }
4763 3541
4764 - if ( $question_id ) {
4765 - return isset( $query[0] ) ? $query[0] : null;
4766 - }
3542 + $query = $wpdb->get_results( $wpdb->prepare(
3543 + "SELECT {$wpdb->comments}.comment_ID,
3544 + {$wpdb->comments}.comment_post_ID,
3545 + {$wpdb->comments}.comment_author,
3546 + {$wpdb->comments}.comment_date,
3547 + {$wpdb->comments}.comment_content,
3548 + {$wpdb->comments}.user_id,
3549 + {$wpdb->commentmeta}.meta_value as question_title,
3550 + {$wpdb->users}.display_name,
3551 + {$wpdb->posts}.post_title,
3552 + ( SELECT COUNT(answers_t.comment_ID)
3553 + FROM {$wpdb->comments} answers_t
3554 + WHERE answers_t.comment_parent = {$wpdb->comments}.comment_ID
3555 + ) AS answer_count
3556 + FROM {$wpdb->comments}
3557 + INNER JOIN {$wpdb->commentmeta}
3558 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3559 + INNER JOIN {$wpdb->posts}
3560 + ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
3561 + INNER JOIN {$wpdb->users}
3562 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3563 + WHERE {$wpdb->comments}.comment_type = %s
3564 + AND {$wpdb->comments}.comment_parent = 0
3565 + AND {$wpdb->commentmeta}.meta_value LIKE %s
3566 + {$in_question_id_query}
3567 + ORDER BY {$wpdb->comments}.comment_ID DESC
3568 + LIMIT %d, %d;
3569 + ",
3570 + 'tutor_q_and_a',
3571 + $search_term,
3572 + $start,
3573 + $limit
3574 + ) );
4767 3575
4768 3576 return $query;
4769 3577 }
4770 3578
4771 3579 /**
4772 - * Get question for Q&A
3580 + * @param $question_id
4773 3581 *
4774 - * @since 1.0.0
3582 + * @return array|null|object|void
4775 3583 *
4776 - * @param int $question_id question id.
3584 + * Get question for Q&A
4777 3585 *
4778 - * @return array|null|object|void
3586 + * @since v.1.0.0
4779 3587 */
4780 3588 public function get_qa_question( $question_id ) {
4781 - return $this->get_qa_questions( 0, 1, '', $question_id );
3589 + global $wpdb;
3590 + $query = $wpdb->get_row( $wpdb->prepare(
3591 + "SELECT {$wpdb->comments}.comment_ID,
3592 + {$wpdb->comments}.comment_post_ID,
3593 + {$wpdb->comments}.comment_author,
3594 + {$wpdb->comments}.comment_date,
3595 + {$wpdb->comments}.comment_date_gmt,
3596 + {$wpdb->comments}.comment_content,
3597 + {$wpdb->comments}.user_id,
3598 + {$wpdb->commentmeta}.meta_value as question_title,
3599 + {$wpdb->users}.display_name,
3600 + {$wpdb->posts}.post_title
3601 + FROM {$wpdb->comments}
3602 + INNER JOIN {$wpdb->commentmeta}
3603 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
3604 + INNER JOIN {$wpdb->posts}
3605 + ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
3606 + INNER JOIN {$wpdb->users}
3607 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3608 + WHERE comment_type = %s
3609 + AND {$wpdb->comments}.comment_ID = %d;
3610 + ",
3611 + 'tutor_q_and_a',
3612 + $question_id
3613 + ) );
3614 +
3615 + return $query;
4782 3616 }
4783 3617
4784 3618 /**
4785 - * Get question and asnwer by question
3619 + * @param $question_id
4786 3620 *
4787 - * @since 1.0.0
4788 - * @since 4.0.0 param $order and $context added.
3621 + * @return array|null|object
4789 3622 *
4790 - * @param int $question_id question id.
4791 - * @param string $order order ASC or DESC.
4792 - * @param string $context context frontend or dashboard.
4793 - *
4794 - * @return array|null|object
3623 + * Get question and asnwer by question
4795 3624 */
4796 - public function get_qa_answer_by_question( $question_id, $order = 'ASC', $context = '' ) {
3625 + public function get_qa_answer_by_question( $question_id ) {
4797 3626 global $wpdb;
4798 - $order = 'ASC' === strtoupper( $order ) ? 'ASC' : 'DESC';
4799 -
4800 - $condition = '(_chat.comment_ID=%d OR _chat.comment_parent = %d)';
4801 - $params = array( $question_id, $question_id );
4802 -
4803 - if ( 'frontend' === $context ) {
4804 - $condition = '_chat.comment_parent = %d';
4805 - $params = array( $question_id );
4806 - }
4807 -
4808 - $query = $wpdb->get_results(
4809 - $wpdb->prepare(
4810 - "SELECT _chat.comment_ID,
4811 - _chat.comment_post_ID,
4812 - _chat.comment_author,
4813 - _chat.comment_date,
4814 - _chat.comment_date_gmt,
4815 - _chat.comment_content,
4816 - _chat.comment_parent,
4817 - _chat.user_id,
3627 + $query = $wpdb->get_results( $wpdb->prepare(
3628 + "SELECT {$wpdb->comments}.comment_ID,
3629 + {$wpdb->comments}.comment_post_ID,
3630 + {$wpdb->comments}.comment_author,
3631 + {$wpdb->comments}.comment_date,
3632 + {$wpdb->comments}.comment_date_gmt,
3633 + {$wpdb->comments}.comment_content,
3634 + {$wpdb->comments}.comment_parent,
3635 + {$wpdb->comments}.user_id,
4818 3636 {$wpdb->users}.display_name
4819 - FROM {$wpdb->comments} _chat
4820 - INNER JOIN {$wpdb->users} ON _chat.user_id = {$wpdb->users}.ID
4821 - WHERE comment_type = 'tutor_q_and_a'
4822 - AND {$condition}
4823 - ORDER BY _chat.comment_ID {$order};",
4824 - $params
4825 - )
4826 - );
3637 + FROM {$wpdb->comments}
3638 + INNER JOIN {$wpdb->users}
3639 + ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
3640 + WHERE comment_type = %s
3641 + AND {$wpdb->comments}.comment_parent = %d
3642 + ORDER BY {$wpdb->comments}.comment_ID ASC;
3643 + ",
3644 + 'tutor_q_and_a',
3645 + $question_id
3646 + ) );
4827 3647
4828 3648 return $query;
4829 3649 }
4830 3650
4831 3651 /**
4832 - * Get question and asnwer by answer_id
3652 + * @param $answer_id
4833 3653 *
4834 - * @since 1.6.9
3654 + * @return array|null|object
3655 + *
3656 + * @since v1.6.9
4835 3657 *
4836 - * @param int $answer_id answer id.
4837 - *
4838 - * @return array|null|object
3658 + * Get question and asnwer by answer_id
4839 3659 */
4840 3660 public function get_qa_answer_by_answer_id( $answer_id ) {
4841 3661 global $wpdb;
4842 - $answer = $wpdb->get_row(
4843 - $wpdb->prepare(
4844 - "SELECT answer.comment_post_ID,
4845 - answer.comment_content,
3662 + $answer = $wpdb->get_row( $wpdb->prepare(
3663 + "SELECT answer.comment_post_ID,
3664 + answer.comment_content,
4846 3665 users.display_name,
4847 3666 question.user_id AS question_by,
4848 3667 question.comment_content AS question,
4849 - question.comment_ID AS question_id
3668 + question_meta.meta_value AS question_title
4850 3669 FROM {$wpdb->comments} answer
4851 3670 INNER JOIN {$wpdb->users} users
4852 - ON answer.user_id = users.id
4853 - INNER JOIN {$wpdb->comments} question
4854 - ON answer.comment_parent = question.comment_ID
4855 - WHERE answer.comment_ID = %d
3671 + ON answer.user_id = users.id
3672 + INNER JOIN {$wpdb->comments} question
3673 + ON answer.comment_parent = question.comment_ID
3674 + INNER JOIN {$wpdb->commentmeta} question_meta
3675 + ON answer.comment_parent = question_meta.comment_id
3676 + AND question_meta.meta_key = 'tutor_question_title'
3677 + WHERE answer.comment_ID = %d
4856 3678 AND answer.comment_type = %s;
4857 - ",
4858 - $answer_id,
4859 - 'tutor_q_and_a'
4860 - )
4861 - );
3679 + ",
3680 + $answer_id,
3681 + 'tutor_q_and_a'
3682 + ) );
4862 3683
4863 3684 if ( $answer ) {
4864 3685 return $answer;
4865 3686 }
@@ -4866,107 +3687,12 @@
4866 3687
4867 3688 return false;
4868 3689 }
4869 3690
4870 - /**
4871 - * Funcion to check if a user can delete qa by id
4872 - *
4873 - * @since 1.6.9
4874 - *
4875 - * @param int $user_id user id.
4876 - * @param int $question_id question id.
4877 - *
4878 - * @return boolean
4879 - */
4880 - public function can_delete_qa( $user_id, $question_id ) {
4881 - global $wpdb;
4882 -
4883 - $is_admin = $this->has_user_role( 'administrator', $user_id );
4884 -
4885 - if ( $is_admin ) {
4886 - return true;
4887 - }
4888 -
4889 - $result = $wpdb->get_row(
4890 - $wpdb->prepare(
4891 - "SELECT *
4892 - FROM {$wpdb->comments} qa
4893 - WHERE qa.comment_ID = %d
4894 - ",
4895 - $question_id
4896 - )
4897 - );
4898 -
4899 - if ( $result && (int) $result->user_id === $user_id ) {
4900 - return true;
4901 - }
4902 -
4903 - return false;
4904 - }
4905 -
4906 - /**
4907 - * Get total number of un-answered question.
4908 - *
4909 - * @since 1.0.0
4910 - *
4911 - * @return int
4912 - */
4913 3691 public function unanswered_question_count() {
4914 3692 global $wpdb;
4915 - /**
4916 - * Q & A unanswered showing wrong number when login as
4917 - * instructor as it was count unanswered question from all courses
4918 - * from now on it will check if tutor instructor and count
4919 - * from instructor's course
4920 - *
4921 - * @since 1.9.0
4922 - */
4923 - $user_id = get_current_user_id();
4924 - $course_type = tutor()->course_post_type;
4925 -
4926 - $in_question_id_query = '';
4927 - /**
4928 - * Get only assinged courses questions if current user is a
4929 - */
4930 - if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
4931 -
4932 - $get_course_ids = $wpdb->get_col(
4933 - $wpdb->prepare(
4934 - "SELECT ID
4935 - FROM {$wpdb->posts}
4936 - WHERE post_author = %d
4937 - AND post_type = %s
4938 - AND post_status = %s
4939 - ",
4940 - $user_id,
4941 - $course_type,
4942 - 'publish'
4943 - )
4944 - );
4945 -
4946 - $get_assigned_courses_ids = $wpdb->get_col(
4947 - $wpdb->prepare(
4948 - "SELECT meta_value
4949 - FROM {$wpdb->usermeta}
4950 - WHERE meta_key = %s
4951 - AND user_id = %d
4952 - ",
4953 - '_tutor_instructor_course_id',
4954 - $user_id
4955 - )
4956 - );
4957 -
4958 - $my_course_ids = array_unique( array_merge( $get_course_ids, $get_assigned_courses_ids ) );
4959 -
4960 - if ( $this->count( $my_course_ids ) ) {
4961 - $implode_ids = implode( ',', $my_course_ids );
4962 - $in_question_id_query = " AND {$wpdb->comments}.comment_post_ID IN($implode_ids) ";
4963 - }
4964 - }
4965 -
4966 - $count = $wpdb->get_var(
4967 - $wpdb->prepare(
4968 - "SELECT COUNT({$wpdb->comments}.comment_ID)
3693 + $count = $wpdb->get_var( $wpdb->prepare(
3694 + "SELECT COUNT({$wpdb->comments}.comment_ID)
4969 3695 FROM {$wpdb->comments}
4970 3696 INNER JOIN {$wpdb->posts}
4971 3697 ON {$wpdb->comments}.comment_post_ID = {$wpdb->posts}.ID
4972 3698 INNER JOIN {$wpdb->users}
@@ -4972,60 +3698,57 @@
4972 3698 INNER JOIN {$wpdb->users}
4973 3699 ON {$wpdb->comments}.user_id = {$wpdb->users}.ID
4974 3700 WHERE {$wpdb->comments}.comment_type = %s
4975 3701 AND {$wpdb->comments}.comment_approved = %s
4976 - AND {$wpdb->comments}.comment_parent = 0 {$in_question_id_query};
3702 + AND {$wpdb->comments}.comment_parent = %d;
4977 3703 ",
4978 - 'tutor_q_and_a',
4979 - 'waiting_for_answer'
4980 - )
4981 - );
3704 + 'tutor_q_and_a',
3705 + 'waiting_for_answer',
3706 + 0
3707 + ) );
4982 3708 return (int) $count;
4983 3709 }
4984 3710
4985 3711 /**
4986 - * Return all of announcements for a course
3712 + * @param int $course_id
4987 3713 *
4988 - * @since 1.0.0
3714 + * @return array|null|object
4989 3715 *
4990 - * @param int $course_id course id.
3716 + * Return all of announcements for a course
4991 3717 *
4992 - * @return array|null|object
3718 + * @since v.1.0.0
4993 3719 */
4994 3720 public function get_announcements( $course_id = 0 ) {
4995 3721 $course_id = $this->get_post_id( $course_id );
4996 3722 global $wpdb;
4997 - $query = $wpdb->get_results(
4998 - $wpdb->prepare(
4999 - "SELECT {$wpdb->posts}.ID,
5000 - post_author,
5001 - post_date,
5002 - post_date_gmt,
5003 - post_content,
5004 - post_title,
5005 - display_name
5006 - FROM {$wpdb->posts}
5007 - INNER JOIN {$wpdb->users}
5008 - ON post_author = {$wpdb->users}.ID
5009 - WHERE post_type = %s
3723 + $query = $wpdb->get_results( $wpdb->prepare(
3724 + "SELECT {$wpdb->posts}.ID,
3725 + post_author,
3726 + post_date,
3727 + post_content,
3728 + post_title,
3729 + display_name
3730 + FROM {$wpdb->posts}
3731 + INNER JOIN {$wpdb->users}
3732 + ON post_author = {$wpdb->users}.ID
3733 + WHERE post_type = %s
5010 3734 AND post_parent = %d
5011 3735 ORDER BY {$wpdb->posts}.ID DESC;
5012 3736 ",
5013 - 'tutor_announcements',
5014 - $course_id
5015 - )
5016 - );
3737 + 'tutor_announcements',
3738 + $course_id
3739 + ) );
5017 3740 return $query;
5018 3741 }
5019 3742
5020 3743 /**
5021 - * Announcement content
3744 + * @param string $content
5022 3745 *
5023 - * @since 1.0.0
3746 + * @return mixed
5024 3747 *
5025 - * @param string $content content.
3748 + * Announcement content
5026 3749 *
5027 - * @return mixed
3750 + * @since v.1.0.0
5028 3751 */
5029 3752 public function announcement_content( $content = '' ) {
5030 3753 $search = array( '{user_display_name}' );
5031 3754
@@ -5030,9 +3753,9 @@
5030 3753 $search = array( '{user_display_name}' );
5031 3754
5032 3755 $user_display_name = 'User';
5033 3756 if ( is_user_logged_in() ) {
5034 - $user = wp_get_current_user();
3757 + $user = wp_get_current_user();
5035 3758 $user_display_name = $user->display_name;
5036 3759 }
5037 3760
5038 3761 $replace = array( $user_display_name );
@@ -5040,32 +3763,26 @@
5040 3763 return str_replace( $search, $replace, $content );
5041 3764 }
5042 3765
5043 3766 /**
5044 - * Get the quiz option from meta
3767 + * @param int $post_id
3768 + * @param string $option_key
3769 + * @param bool $default
5045 3770 *
5046 - * @since 1.0.0
3771 + * @return array|bool|mixed
5047 3772 *
5048 - * @param int $post_id post id.
5049 - * @param string $option_key option key.
5050 - * @param bool $default default.
5051 - *
5052 - * @return array|bool|mixed
3773 + * Get the quiz option from meta
5053 3774 */
5054 3775 public function get_quiz_option( $post_id = 0, $option_key = '', $default = false ) {
5055 - $post_id = $this->get_post_id( $post_id );
5056 - $get_option_meta = maybe_unserialize( get_post_meta( $post_id, 'tutor_quiz_option', true ) );
3776 + $post_id = $this->get_post_id( $post_id );
3777 + $get_option_meta = maybe_unserialize(get_post_meta( $post_id, 'tutor_quiz_option', true ) );
5057 3778
5058 - if ( is_array( $get_option_meta ) ) {
5059 - $get_option_meta = Quiz::normalize_quiz_settings( $get_option_meta );
5060 - }
5061 -
5062 3779 if ( ! $option_key && ! empty( $get_option_meta ) ) {
5063 3780 return $get_option_meta;
5064 3781 }
5065 3782
5066 3783 $value = $this->avalue_dot( $option_key, $get_option_meta );
5067 - if ( $value > 0 || false !== $value ) {
3784 + if ( $value > 0 || $value !== false ) {
5068 3785 return $value;
5069 3786 }
5070 3787
5071 3788 return $default;
@@ -5071,62 +3788,168 @@
5071 3788 return $default;
5072 3789 }
5073 3790
5074 3791 /**
5075 - * Get the questions by quiz ID
3792 + * @param int $quiz_id
5076 3793 *
5077 - * @since 1.0.0
3794 + * @return array|bool|null|object
5078 3795 *
5079 - * @param int $quiz_id quiz id.
5080 - *
5081 - * @return array|bool|null|object
3796 + * Get the questions by quiz ID
5082 3797 */
5083 3798 public function get_questions_by_quiz( $quiz_id = 0 ) {
5084 3799 $quiz_id = $this->get_post_id( $quiz_id );
3800 + global $wpdb;
5085 3801
5086 - $where = array(
5087 - 'quiz_id' => $quiz_id,
5088 - );
3802 + $questions = $wpdb->get_results( $wpdb->prepare(
3803 + "SELECT *
3804 + FROM {$wpdb->prefix}tutor_quiz_questions
3805 + WHERE quiz_id = %d
3806 + ORDER BY question_order ASC
3807 + ",
3808 + $quiz_id
3809 + ) );
5089 3810
5090 - /**
5091 - * Filter to exclude quiz question types
5092 - *
5093 - * @since 4.0.0
5094 - */
5095 - $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() );
3811 + if ( is_array( $questions ) && count( $questions ) ) {
3812 + return $questions;
3813 + }
5096 3814
5097 - if ( tutor_utils()->count( $exclude_types ) ) {
5098 - $exclude_types = array_unique( $exclude_types );
5099 - $where['question_type'] = array( 'NOT IN', $exclude_types );
3815 + return false;
3816 + }
3817 +
3818 + /**
3819 + * @param int $question_id
3820 + *
3821 + * @return array|bool|object|void|null
3822 + *
3823 + * Get Quiz question by question id
3824 + */
3825 + public function get_quiz_question_by_id( $question_id = 0 ) {
3826 + global $wpdb;
3827 +
3828 + if ( $question_id ) {
3829 + $question = $wpdb->get_row( $wpdb->prepare(
3830 + "SELECT *
3831 + FROM {$wpdb->prefix}tutor_quiz_questions
3832 + WHERE question_id = %d
3833 + LIMIT 0, 1;
3834 + ",
3835 + $question_id
3836 + ) );
3837 +
3838 + return $question;
5100 3839 }
5101 3840
5102 - $questions = QueryHelper::get_all(
5103 - 'tutor_quiz_questions',
5104 - $where,
5105 - 'question_order',
5106 - -1,
5107 - 'ASC'
3841 + return false;
3842 + }
3843 +
3844 + /**
3845 + * @param null $type
3846 + *
3847 + * @return array|mixed
3848 + *
3849 + * Get all question types
3850 + *
3851 + * @since v.1.0.0
3852 + */
3853 + public function get_question_types( $type = null ) {
3854 + $types = array(
3855 + 'true_false' => array( 'name' => __('True/False', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="True/False"><i class="tutor-icon-block tutor-icon-yes-no"></i></span>', 'is_pro' => false ),
3856 + 'single_choice' => array( 'name' => __('Single Choice', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Single Choice"><i class="tutor-icon-block tutor-icon-mark"></i></span>', 'is_pro' => false ),
3857 + 'multiple_choice' => array( 'name' => __('Multiple Choice', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Multiple Choicee"><i class="tutor-icon-block tutor-icon-multiple-choice"></i></span>', 'is_pro' => false ),
3858 + 'open_ended' => array( 'name' => __('Open Ended/Essay', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Open/Essay"><i class="tutor-icon-block tutor-icon-open-ended"></i></span>', 'is_pro' => false ),
3859 + 'fill_in_the_blank' => array( 'name' => __('Fill In The Blanks', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Fill In The Blanks"><i class="tutor-icon-block tutor-icon-fill-gaps"></i></span>', 'is_pro' => false ),
3860 + 'short_answer' => array( 'name' => __('Short Answer', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Short Answer"><i class="tutor-icon-block tutor-icon-short-ans"></i></span>', 'is_pro' => true ),
3861 + 'matching' => array( 'name' => __('Matching', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Matching"><i class="tutor-icon-block tutor-icon-matching"></i></span>', 'is_pro' => true ),
3862 + 'image_matching' => array( 'name' => __('Image Matching', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Image Matching"><i class="tutor-icon-block tutor-icon-image-matching"></i></span>', 'is_pro' => true ),
3863 + 'image_answering' => array( 'name' => __('Image Answering', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Image Answering"><i class="tutor-icon-block tutor-icon-image-ans"></i></span>', 'is_pro' => true ),
3864 + 'ordering' => array( 'name' => __('Ordering', 'tutor'), 'icon' => '<span class="tooltip-btn" data-tooltip="Ordering"><i class="tutor-icon-block tutor-icon-ordering"></i></span>', 'is_pro' => true ),
5108 3865 );
5109 3866
5110 - $questions = apply_filters( 'tutor_get_questions_by_quiz', $questions, $quiz_id );
3867 + if ( isset( $types[ $type ] ) ) {
3868 + return $types[ $type ];
3869 + }
3870 +
3871 + return $types;
3872 + }
5111 3873
5112 - foreach ( $questions as $question ) {
5113 - $question->question_title = stripslashes( $question->question_title );
5114 - $question->question_description = stripslashes( $question->question_description );
5115 - $question->answer_explanation = stripslashes( $question->answer_explanation ?? '' );
3874 + public function get_quiz_answer_options_by_question( $question_id ) {
3875 + global $wpdb;
3876 +
3877 + $answer_options = $wpdb->get_results( $wpdb->prepare(
3878 + "SELECT {$wpdb->comments}.comment_ID,
3879 + {$wpdb->comments}.comment_post_ID,
3880 + {$wpdb->comments}.comment_content
3881 + FROM {$wpdb->comments}
3882 + WHERE {$wpdb->comments}.comment_post_ID = %d
3883 + AND {$wpdb->comments}.comment_type = %s
3884 + ORDER BY {$wpdb->comments}.comment_karma ASC;
3885 + ",
3886 + $question_id,
3887 + 'quiz_answer_option'
3888 + ) );
3889 +
3890 + if ( is_array( $answer_options ) && count( $answer_options ) ) {
3891 + return $answer_options;
5116 3892 }
3893 + return false;
3894 + }
5117 3895
5118 - return ( is_array( $questions ) && count( $questions ) ) ? $questions : false;
3896 + /**
3897 + * @param $quiz_id
3898 + *
3899 + * @return int
3900 + *
3901 + * Get the next question order ID
3902 + *
3903 + * @since v.1.0.0
3904 + */
3905 + public function quiz_next_question_order_id( $quiz_id ) {
3906 + global $wpdb;
3907 +
3908 + $last_order = (int) $wpdb->get_var( $wpdb->prepare(
3909 + "SELECT MAX(question_order)
3910 + FROM {$wpdb->prefix}tutor_quiz_questions
3911 + WHERE quiz_id = %d ;
3912 + ",
3913 + $quiz_id
3914 + ) );
3915 +
3916 + return $last_order + 1;
5119 3917 }
5120 3918
5121 3919 /**
5122 - * Get attached quiz.
3920 + * @param $quiz_id
5123 3921 *
5124 - * @since 1.0.0
3922 + * @return int
5125 3923 *
5126 - * @param int $post_id post id.
3924 + * new design quiz question
3925 + * @since v.1.0.0
3926 + */
3927 + public function quiz_next_question_id() {
3928 + global $wpdb;
3929 +
3930 + $last_order = (int) $wpdb->get_var( "SELECT MAX(question_id) FROM {$wpdb->prefix}tutor_quiz_questions;" );
3931 + return $last_order + 1;
3932 + }
3933 +
3934 + public function get_quiz_id_by_question( $question_id ) {
3935 + global $wpdb;
3936 + $quiz_id = $wpdb->get_var( $wpdb->prepare(
3937 + "SELECT quiz_id
3938 + FROM {$wpdb->tutor_quiz_questions}
3939 + WHERE question_id = %d;
3940 + ",
3941 + $question_id
3942 + ) );
3943 + return $quiz_id;
3944 + }
3945 +
3946 + /**
3947 + * @param int $post_id
5127 3948 *
5128 3949 * @return array|bool|null|object
3950 + *
3951 + * @since v.1.0.0
5129 3952 */
5130 3953 public function get_attached_quiz( $post_id = 0 ) {
5131 3954 global $wpdb;
5132 3955
@@ -5131,11 +3954,10 @@
5131 3954 global $wpdb;
5132 3955
5133 3956 $post_id = $this->get_post_id( $post_id );
5134 3957
5135 - $questions = $wpdb->get_results(
5136 - $wpdb->prepare(
5137 - "SELECT ID,
3958 + $questions = $wpdb->get_results( $wpdb->prepare(
3959 + "SELECT ID,
5138 3960 post_content,
5139 3961 post_title,
5140 3962 post_parent
5141 3963 FROM {$wpdb->posts}
@@ -5142,13 +3964,12 @@
5142 3964 WHERE post_type = %s
5143 3965 AND post_status = %s
5144 3966 AND post_parent = %d;
5145 3967 ",
5146 - 'tutor_quiz',
5147 - 'publish',
5148 - $post_id
5149 - )
5150 - );
3968 + 'tutor_quiz',
3969 + 'publish',
3970 + $post_id
3971 + ) );
5151 3972
5152 3973 if ( is_array( $questions ) && count( $questions ) ) {
5153 3974 return $questions;
5154 3975 }
@@ -5156,42 +3977,69 @@
5156 3977 return false;
5157 3978 }
5158 3979
5159 3980 /**
5160 - * Total questions for student by quiz.
3981 + * @param $quiz_id
5161 3982 *
5162 - * @since 1.0.0
3983 + * @return array|bool|null|object|void
5163 3984 *
5164 - * @param int $quiz_id quiz id.
3985 + * Get course by quiz
5165 3986 *
3987 + * @since v.1.0.0
3988 + */
3989 + public function get_course_by_quiz( $quiz_id ) {
3990 + global $wpdb;
3991 +
3992 + $quiz_id = $this->get_post_id( $quiz_id );
3993 + $post = get_post( $quiz_id );
3994 +
3995 + if ( $post ) {
3996 + $course_post_type = tutor()->course_post_type;
3997 + $query_string = "SELECT ID, post_author, post_name, post_type, post_parent FROM {$wpdb->posts} where ID = %d";
3998 + $course = $wpdb->get_row( $wpdb->prepare( $query_string, $post->post_parent ) );
3999 +
4000 + if ( $course ) {
4001 + if ( $course->post_type !== $course_post_type ) {
4002 + $course = $wpdb->get_row( $wpdb->prepare( $query_string, $course->post_parent ) );
4003 + }
4004 + return $course;
4005 + }
4006 + }
4007 +
4008 + return false;
4009 + }
4010 +
4011 + /**
4012 + * @param $quiz_id
4013 + *
5166 4014 * @return int
4015 + *
4016 + * @since v.1.0.0
5167 4017 */
5168 4018 public function total_questions_for_student_by_quiz( $quiz_id ) {
5169 4019 $quiz_id = $this->get_post_id( $quiz_id );
5170 4020 global $wpdb;
5171 4021
5172 - $max_questions_count = (int) $this->get_quiz_option( $quiz_id, 'max_questions_for_answer' );
5173 - $total_question = (int) $wpdb->get_var(
5174 - $wpdb->prepare(
5175 - "SELECT count(question_id)
4022 + $max_questions_count = (int) tutor_utils()->get_quiz_option( get_the_ID(), 'max_questions_for_answer' );
4023 + $total_question = (int) $wpdb->get_var( $wpdb->prepare(
4024 + "SELECT count(question_id)
5176 4025 FROM {$wpdb->tutor_quiz_questions}
5177 4026 WHERE quiz_id = %d;
5178 4027 ",
5179 - $quiz_id
5180 - )
5181 - );
4028 + $quiz_id
4029 + ) );
5182 4030
5183 - return min( $max_questions_count, $total_question ) <= 0 ? $total_question : min( $max_questions_count, $total_question );
4031 + return min($max_questions_count, $total_question);
5184 4032 }
5185 4033
5186 4034 /**
5187 - * Determine if there is any started quiz exists.
4035 + * @param int $quiz_id
5188 4036 *
5189 - * @since 1.0.0
4037 + * @return array|null|object|void
5190 4038 *
5191 - * @param int $quiz_id quiz id.
4039 + * Determine if there is any started quiz exists
5192 4040 *
5193 - * @return array|null|object|void
4041 + * @since v.1.0.0
5194 4042 */
5195 4043 public function is_started_quiz( $quiz_id = 0 ) {
5196 4044 global $wpdb;
5197 4045
@@ -5197,62 +4045,48 @@
5197 4045
5198 4046 $quiz_id = $this->get_post_id( $quiz_id );
5199 4047 $user_id = get_current_user_id();
5200 4048
5201 - $cache_key = "tutor_is_started_quiz_{$user_id}_{$quiz_id}";
5202 - $is_started = TutorCache::get( $cache_key );
4049 + $is_started = $wpdb->get_row( $wpdb->prepare(
4050 + "SELECT *
4051 + FROM {$wpdb->prefix}tutor_quiz_attempts
4052 + WHERE user_id = %d
4053 + AND quiz_id = %d
4054 + AND attempt_status = %s;
4055 + ",
4056 + $user_id,
4057 + $quiz_id,
4058 + 'attempt_started'
4059 + ) );
5203 4060
5204 - if ( false === $is_started ) {
5205 - $is_started = $wpdb->get_row(
5206 - $wpdb->prepare(
5207 - "SELECT *
5208 - FROM {$wpdb->prefix}tutor_quiz_attempts
5209 - WHERE user_id = %d
5210 - AND quiz_id = %d
5211 - AND attempt_status = %s;
5212 - ",
5213 - $user_id,
5214 - $quiz_id,
5215 - 'attempt_started'
5216 - )
5217 - );
5218 - TutorCache::set( $cache_key, $is_started );
5219 - }
5220 -
5221 4061 return $is_started;
5222 4062 }
5223 4063
5224 4064 /**
4065 + * @param $quiz_id
4066 + *
5225 4067 * Method for get the total amount of question for a quiz
5226 4068 * Student will answer this amount of question, one quiz have many question
5227 4069 * but student will answer a specific amount of questions
5228 4070 *
5229 - * @since 1.0.0
4071 + * @return int
5230 4072 *
5231 - * @param int $quiz_id quiz id.
5232 - *
5233 - * @return int
4073 + * @since v.1.0.0
5234 4074 */
5235 4075 public function max_questions_for_take_quiz( $quiz_id ) {
5236 4076 $quiz_id = $this->get_post_id( $quiz_id );
5237 4077 global $wpdb;
5238 4078
5239 - $max_questions = (int) $wpdb->get_var(
5240 - $wpdb->prepare(
5241 - "SELECT count(question_id)
4079 + $max_questions = (int) $wpdb->get_var( $wpdb->prepare(
4080 + "SELECT count(question_id)
5242 4081 FROM {$wpdb->prefix}tutor_quiz_questions
5243 4082 WHERE quiz_id = %d;
5244 4083 ",
5245 - $quiz_id
5246 - )
5247 - );
4084 + $quiz_id
4085 + ) );
5248 4086
5249 4087 $max_mentioned = (int) $this->get_quiz_option( $quiz_id, 'max_questions_for_answer', 10 );
5250 4088
5251 - if ( $max_mentioned <= 0 ) {
5252 - return $max_questions;
5253 - }
5254 -
5255 4089 if ( $max_mentioned < $max_questions ) {
5256 4090 return $max_mentioned;
5257 4091 }
5258 4092
@@ -5259,15 +4093,15 @@
5259 4093 return $max_questions;
5260 4094 }
5261 4095
5262 4096 /**
5263 - * Get single quiz attempt
4097 + * @param int $attempt_id
5264 4098 *
5265 - * @since 1.0.0
4099 + * @return array|bool|null|object|void
5266 4100 *
5267 - * @param int $attempt_id attempt id.
4101 + * Get single quiz attempt
5268 4102 *
5269 - * @return array|bool|null|object|void
4103 + * @since v.1.0.0
5270 4104 */
5271 4105 public function get_attempt( $attempt_id = 0 ) {
5272 4106 global $wpdb;
5273 4107 if ( ! $attempt_id ) {
@@ -5273,29 +4107,27 @@
5273 4107 if ( ! $attempt_id ) {
5274 4108 return false;
5275 4109 }
5276 4110
5277 - $attempt = $wpdb->get_row(
5278 - $wpdb->prepare(
5279 - "SELECT *
4111 + $attempt = $wpdb->get_row( $wpdb->prepare(
4112 + "SELECT *
5280 4113 FROM {$wpdb->prefix}tutor_quiz_attempts
5281 4114 WHERE attempt_id = %d;
5282 4115 ",
5283 - $attempt_id
5284 - )
5285 - );
4116 + $attempt_id
4117 + ) );
5286 4118
5287 4119 return $attempt;
5288 4120 }
5289 4121
5290 4122 /**
5291 - * Get unserialize attempt info
4123 + * @param $attempt_info
5292 4124 *
5293 - * @since 1.0.0
4125 + * @return mixed
5294 4126 *
5295 - * @param mixed $attempt_info attempt info.
4127 + * Get unserialize attempt info
5296 4128 *
5297 - * @return mixed
4129 + * @since v.1.0.0
5298 4130 */
5299 4131 public function quiz_attempt_info( $attempt_info ) {
5300 4132 return maybe_unserialize( $attempt_info );
5301 4133 }
@@ -5300,67 +4132,63 @@
5300 4132 return maybe_unserialize( $attempt_info );
5301 4133 }
5302 4134
5303 4135 /**
5304 - * Update attempt for various action
4136 + * @param $quiz_attempt_id
4137 + * @param array $attempt_info
5305 4138 *
5306 - * @since 1.0.0
4139 + * @return bool|int
5307 4140 *
5308 - * @param int $quiz_attempt_id quiz attempt id.
5309 - * @param array $attempt_info attempt info.
4141 + * Update attempt for various action
5310 4142 *
5311 - * @return bool|int
4143 + * @since v.1.0.0
5312 4144 */
5313 4145 public function quiz_update_attempt_info( $quiz_attempt_id, $attempt_info = array() ) {
5314 - $answers = $this->avalue_dot( 'answers', $attempt_info );
5315 - $total_marks = array_sum( wp_list_pluck( $answers, 'question_mark' ) );
5316 - $earned_marks = $this->avalue_dot( 'marks_earned', $attempt_info );
5317 - $earned_mark_percent = $earned_marks > 0 ? ( number_format( ( $earned_marks * 100 ) / $total_marks ) ) : 0;
4146 + $answers = tutor_utils()->avalue_dot( 'answers', $attempt_info );
4147 + $total_marks = array_sum( wp_list_pluck( $answers, 'question_mark' ) );
4148 + $earned_marks = tutor_utils()->avalue_dot( 'marks_earned', $attempt_info );
4149 + $earned_mark_percent = $earned_marks > 0 ? ( number_format( ($earned_marks * 100) / $total_marks) ) : 0;
5318 4150 update_comment_meta( $quiz_attempt_id, 'earned_mark_percent', $earned_mark_percent );
5319 4151
5320 - return update_comment_meta( $quiz_attempt_id, 'quiz_attempt_info', $attempt_info );
4152 + return update_comment_meta( $quiz_attempt_id,'quiz_attempt_info', $attempt_info );
5321 4153 }
5322 4154
5323 4155 /**
5324 - * Get random question by quiz id
4156 + * @param int $quiz_id
5325 4157 *
5326 - * @since 1.0.0
4158 + * @return array|null|object
5327 4159 *
5328 - * @param int $quiz_id quiz id.
4160 + * Get random question by quiz id
5329 4161 *
5330 - * @return array|null|object
4162 + * @since v.1.0.0
5331 4163 */
5332 4164 public function get_random_question_by_quiz( $quiz_id = 0 ) {
5333 4165 global $wpdb;
5334 4166
5335 - $quiz_id = $this->get_post_id( $quiz_id );
4167 + $quiz_id = $this->get_post_id( $quiz_id );
5336 4168 $is_attempt = $this->is_started_quiz( $quiz_id );
5337 4169
5338 - $temp_sql = " AND question_type = 'matching' ";
5339 - $questions = $wpdb->get_results(
5340 - $wpdb->prepare(
5341 - "SELECT *
4170 + $tempSql = " AND question_type = 'matching' ";
4171 + $questions = $wpdb->get_results( $wpdb->prepare(
4172 + "SELECT *
5342 4173 FROM {$wpdb->prefix}tutor_quiz_questions
5343 4174 WHERE quiz_id = %d
5344 - {$temp_sql}
4175 + {$tempSql}
5345 4176 ORDER BY RAND()
5346 4177 LIMIT 0, 1
5347 4178 ",
5348 - $quiz_id
5349 - )
5350 - );
4179 + $quiz_id
4180 + ) );
5351 4181
5352 4182 return $questions;
5353 4183 }
5354 4184
5355 4185 /**
5356 - * Get random questions by quiz
4186 + * @param int $quiz_id
5357 4187 *
5358 - * @since 1.0.0
4188 + * @return array|null|object
5359 4189 *
5360 - * @param int $quiz_id quiz id.
5361 - *
5362 - * @return array|null|object
4190 + * Get random questions by quiz
5363 4191 */
5364 4192 public function get_random_questions_by_quiz( $quiz_id = 0 ) {
5365 4193 global $wpdb;
5366 4194
@@ -5365,76 +4193,118 @@
5365 4193 global $wpdb;
5366 4194
5367 4195 $quiz_id = $this->get_post_id( $quiz_id );
5368 4196 $attempt = $this->is_started_quiz( $quiz_id );
4197 + $total_questions = (int) $attempt->total_questions;
5369 4198 if ( ! $attempt ) {
5370 4199 return false;
5371 4200 }
5372 4201
5373 - $total_questions = (int) $attempt->total_questions;
5374 - $questions_order = $this->get_quiz_option( $quiz_id, 'questions_order', 'rand' );
4202 + $questions_order = tutor_utils()->get_quiz_option( get_the_ID(), 'questions_order', 'rand' );
5375 4203
5376 - $order_by = 'RAND()';
5377 - $order = '';
4204 + $order_by = "";
4205 + if ( $questions_order === 'rand' ) {
4206 + $order_by = "ORDER BY RAND()";
4207 + } elseif ( $questions_order === 'asc' ) {
4208 + $order_by = "ORDER BY question_id ASC";
4209 + } elseif ( $questions_order === 'desc' ) {
4210 + $order_by = "ORDER BY question_id DESC";
4211 + } elseif ( $questions_order === 'sorting' ) {
4212 + $order_by = "ORDER BY question_order ASC";
4213 + }
5378 4214
5379 - if ( 'asc' === $questions_order ) {
5380 - $order_by = 'question_id';
5381 - $order = 'ASC';
5382 - } elseif ( 'desc' === $questions_order ) {
5383 - $order_by = 'question_id';
5384 - $order = 'DESC';
5385 - } elseif ( 'sorting' === $questions_order ) {
5386 - $order_by = 'question_order';
5387 - $order = 'ASC';
4215 + $limit = '';
4216 + if ( $total_questions ) {
4217 + $limit = "LIMIT {$total_questions} ";
5388 4218 }
5389 4219
5390 - $where = array(
5391 - 'quiz_id' => $quiz_id,
5392 - );
4220 + $questions = $wpdb->get_results( $wpdb->prepare(
4221 + "SELECT *
4222 + FROM {$wpdb->prefix}tutor_quiz_questions
4223 + WHERE quiz_id = %d
4224 + {$order_by}
4225 + {$limit}
4226 + ",
4227 + $quiz_id
4228 + ) );
5393 4229
5394 - $exclude_types = apply_filters( 'tutor_filter_unsupported_quiz_question_types', array() );
4230 + return $questions;
4231 + }
5395 4232
5396 - if ( tutor_utils()->count( $exclude_types ) ) {
5397 - $exclude_types = array_unique( $exclude_types );
5398 - $where['question_type'] = array( 'NOT IN', $exclude_types );
4233 + /**
4234 + * @param $question_id
4235 + * @param bool $rand
4236 + *
4237 + * @return array|bool|null|object
4238 + *
4239 + * Get answers list by quiz question
4240 + *
4241 + * @since v.1.0.0
4242 + */
4243 + public function get_answers_by_quiz_question( $question_id, $rand = false ) {
4244 + global $wpdb;
4245 +
4246 + $question = $wpdb->get_row( $wpdb->prepare(
4247 + "SELECT *
4248 + FROM {$wpdb->prefix}tutor_quiz_questions
4249 + WHERE question_id = %d;
4250 + ",
4251 + $question_id
4252 + ) );
4253 +
4254 + if ( ! $question ) {
4255 + return false;
5399 4256 }
5400 4257
5401 - $limit = $total_questions ? $total_questions : -1;
4258 + $order = " answer_order ASC ";
4259 + if ( $question->question_type === 'ordering' ) {
4260 + $order = " RAND() ";
4261 + }
5402 4262
5403 - $questions = QueryHelper::get_all(
5404 - 'tutor_quiz_questions',
5405 - $where,
5406 - $order_by,
5407 - $limit,
5408 - $order
5409 - );
4263 + if ($rand){
4264 + $order = " RAND() ";
4265 + }
5410 4266
5411 - return $questions;
4267 + $answers = $wpdb->get_results( $wpdb->prepare(
4268 + "SELECT *
4269 + FROM {$wpdb->prefix}tutor_quiz_question_answers
4270 + WHERE belongs_question_id = %d
4271 + AND belongs_question_type = %s
4272 + ORDER BY {$order}
4273 + ",
4274 + $question_id,
4275 + $question->question_type
4276 + ) );
4277 +
4278 + return $answers;
5412 4279 }
5413 4280
5414 4281 /**
5415 - * Get attempts by an user
4282 + * @param int $quiz_id
4283 + * @param int $user_id
5416 4284 *
5417 - * @since 1.0.0
4285 + * @return array|bool|null|object
5418 4286 *
5419 - * @param int $user_id user id.
4287 + * Get all of the attempts by an user of a quiz
5420 4288 *
5421 - * @return array|bool|null|object
4289 + * @since v.1.0.0
5422 4290 */
5423 - public function get_all_quiz_attempts_by_user( $user_id = 0 ) {
4291 +
4292 + public function quiz_attempts( $quiz_id = 0, $user_id = 0 ) {
5424 4293 global $wpdb;
5425 4294
5426 - $user_id = $this->get_user_id( $user_id );
5427 - $attempts = $wpdb->get_results(
5428 - $wpdb->prepare(
5429 - "SELECT *
5430 - FROM {$wpdb->prefix}tutor_quiz_attempts
5431 - WHERE user_id = %d
5432 - ORDER BY attempt_id DESC
4295 + $quiz_id = $this->get_post_id( $quiz_id );
4296 + $user_id = $this->get_user_id( $user_id );
4297 +
4298 + $attempts = $wpdb->get_results( $wpdb->prepare(
4299 + "SELECT *
4300 + FROM {$wpdb->prefix}tutor_quiz_attempts
4301 + WHERE quiz_id = %d
4302 + AND user_id = %d;
5433 4303 ",
5434 - $user_id
5435 - )
5436 - );
4304 + $quiz_id,
4305 + $user_id
4306 + ) );
5437 4307
5438 4308 if ( is_array( $attempts ) && count( $attempts ) ) {
5439 4309 return $attempts;
5440 4310 }
@@ -5442,357 +4312,577 @@
5442 4312 return false;
5443 4313 }
5444 4314
5445 4315 /**
5446 - * Get the users / students / course levels
4316 + * @param int $quiz_id
4317 + * @param int $user_id
5447 4318 *
5448 - * @since 1.0.0
4319 + * @return array|bool|null|object
5449 4320 *
5450 - * @param mixed $level level.
4321 + * Get all ended attempts by an user of a quiz
5451 4322 *
5452 - * @return mixed
4323 + * @since v.1.4.1
5453 4324 */
5454 - public function course_levels( $level = null ) {
5455 - $levels = apply_filters(
5456 - 'tutor_course_level',
5457 - array(
5458 - 'all_levels' => __( 'All Levels', 'tutor' ),
5459 - 'beginner' => __( 'Beginner', 'tutor' ),
5460 - 'intermediate' => __( 'Intermediate', 'tutor' ),
5461 - 'expert' => __( 'Expert', 'tutor' ),
5462 - )
5463 - );
4325 + public function quiz_ended_attempts( $quiz_id = 0, $user_id = 0 ) {
4326 + global $wpdb;
5464 4327
5465 - if ( $level ) {
5466 - if ( isset( $levels[ $level ] ) ) {
5467 - return $levels[ $level ];
5468 - } else {
5469 - return '';
5470 - }
4328 + $quiz_id = $this->get_post_id( $quiz_id );
4329 + $user_id = $this->get_user_id( $user_id );
4330 +
4331 + $attempts = $wpdb->get_results( $wpdb->prepare(
4332 + "SELECT *
4333 + FROM {$wpdb->prefix}tutor_quiz_attempts
4334 + WHERE quiz_id = %d
4335 + AND user_id = %d
4336 + AND attempt_status != %s
4337 + ",
4338 + $quiz_id,
4339 + $user_id,
4340 + 'attempt_started'
4341 + ) );
4342 +
4343 + if ( is_array( $attempts ) && count( $attempts ) ) {
4344 + return $attempts;
5471 4345 }
5472 4346
5473 - return $levels;
4347 + return false;
5474 4348 }
5475 4349
4350 +
5476 4351 /**
5477 - * Generate cache busting URL
4352 + * @param int $user_id
5478 4353 *
5479 - * @since 2.8.0
4354 + * @return array|bool|null|object
5480 4355 *
5481 - * @param string $url url.
4356 + * Get attempts by an user
5482 4357 *
5483 - * @return string
4358 + * @since v.1.0.0
5484 4359 */
5485 - public function get_nocache_url( $url ) {
5486 - return add_query_arg( 'nocache', time(), $url );
4360 + public function get_all_quiz_attempts_by_user( $user_id = 0 ) {
4361 + global $wpdb;
4362 +
4363 + $user_id = $this->get_user_id( $user_id );
4364 + $attempts = $wpdb->get_results( $wpdb->prepare(
4365 + "SELECT *
4366 + FROM {$wpdb->prefix}tutor_quiz_attempts
4367 + WHERE user_id = %d
4368 + ORDER BY attempt_id DESC
4369 + ",
4370 + $user_id
4371 + ) );
4372 +
4373 + if ( is_array( $attempts ) && count( $attempts ) ) {
4374 + return $attempts;
4375 + }
4376 +
4377 + return false;
5487 4378 }
5488 4379
5489 4380 /**
5490 - * Student registration form
4381 + * @param string $search_term
5491 4382 *
5492 - * @since 1.0.0
4383 + * @return int
5493 4384 *
5494 - * @return bool|false|string
4385 + * Total number of quiz attempts
4386 + *
4387 + * @since v.1.0.0
5495 4388 */
5496 - public function student_register_url() {
5497 - $student_register_page = (int) $this->get_option( 'student_register_page' );
4389 + public function get_total_quiz_attempts( $search_term = '' ) {
4390 + global $wpdb;
5498 4391
5499 - if ( $student_register_page ) {
5500 - return apply_filters( 'tutor_student_register_url', get_the_permalink( $student_register_page ) );
5501 - }
4392 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5502 4393
5503 - return false;
4394 + $count = $wpdb->get_var( $wpdb->prepare(
4395 + "SELECT COUNT(attempt_id)
4396 + FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4397 + INNER JOIN {$wpdb->posts} quiz
4398 + ON quiz_attempts.quiz_id = quiz.ID
4399 + INNER JOIN {$wpdb->users}
4400 + ON quiz_attempts.user_id = {$wpdb->users}.ID
4401 + WHERE attempt_status != %s
4402 + AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4403 + ",
4404 + 'attempt_started',
4405 + $search_term,
4406 + $search_term,
4407 + $search_term
4408 + ) );
4409 +
4410 + return (int) $count;
5504 4411 }
5505 4412
5506 4413 /**
5507 - * Instructor registration form
4414 + * @param int $start
4415 + * @param int $limit
4416 + * @param string $search_term
5508 4417 *
5509 - * @since v.1.2.13
4418 + * @return array|null|object
5510 4419 *
5511 - * @return bool|false|string
4420 + *
4421 + * Get the all quiz attempts
4422 + *
4423 + * @since v.1.0.0
5512 4424 */
5513 - public function instructor_register_url() {
5514 - $instructor_register_page = (int) $this->get_option( 'instructor_register_page' );
4425 + public function get_quiz_attempts( $start = 0, $limit = 10, $search_term = '' ) {
4426 + global $wpdb;
5515 4427
5516 - if ( $instructor_register_page ) {
5517 - return apply_filters( 'tutor_instructor_register_url', get_the_permalink( $instructor_register_page ) );
5518 - }
4428 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5519 4429
5520 - return false;
4430 + $query = $wpdb->get_results( $wpdb->prepare(
4431 + "SELECT *
4432 + FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4433 + INNER JOIN {$wpdb->posts} quiz
4434 + ON quiz_attempts.quiz_id = quiz.ID
4435 + INNER JOIN {$wpdb->users}
4436 + ON quiz_attempts.user_id = {$wpdb->users}.ID
4437 + WHERE attempt_status != %s
4438 + AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4439 + ORDER BY quiz_attempts.attempt_id DESC
4440 + LIMIT %d, %d;
4441 + ",
4442 + 'attempt_started',
4443 + $search_term,
4444 + $search_term,
4445 + $search_term,
4446 + $start,
4447 + $limit
4448 + ) );
4449 +
4450 + return $query;
5521 4451 }
5522 4452
4453 + public function get_quiz_attempts_by_course_ids( $start = 0, $limit = 10, $course_ids = array(), $search_term = '' ) {
4454 + global $wpdb;
4455 +
4456 + $course_ids = array_map( function( $id ) {
4457 + return "'" . esc_sql( $id ) . "'";
4458 + }, $course_ids );
4459 +
4460 + $course_ids_in = implode( ', ', $course_ids );
4461 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4462 +
4463 + $query = $wpdb->get_results( $wpdb->prepare(
4464 + "SELECT *
4465 + FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4466 + INNER JOIN {$wpdb->posts} quiz
4467 + ON quiz_attempts.quiz_id = quiz.ID
4468 + INNER JOIN {$wpdb->users}
4469 + ON quiz_attempts.user_id = {$wpdb->users}.ID
4470 + WHERE quiz_attempts.course_id IN (" . $course_ids_in . ")
4471 + AND attempt_status != %s
4472 + AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4473 + ORDER BY quiz_attempts.attempt_id DESC
4474 + LIMIT %d, %d;
4475 + ",
4476 + 'attempt_started',
4477 + $search_term,
4478 + $search_term,
4479 + $search_term,
4480 + $start,
4481 + $limit
4482 + ) );
4483 +
4484 + return $query;
4485 + }
4486 +
4487 + public function get_total_quiz_attempts_by_course_ids( $course_ids = array(), $search_term = '' ) {
4488 + global $wpdb;
4489 +
4490 + $course_ids = array_map( function( $id ) {
4491 + return "'" . esc_sql( $id ) . "'";
4492 + }, $course_ids );
4493 +
4494 + $course_ids_in = implode( ', ', $course_ids );
4495 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
4496 +
4497 + $count = $wpdb->get_var( $wpdb->prepare(
4498 + "SELECT COUNT(attempt_id)
4499 + FROM {$wpdb->prefix}tutor_quiz_attempts quiz_attempts
4500 + INNER JOIN {$wpdb->posts} quiz
4501 + ON quiz_attempts.quiz_id = quiz.ID
4502 + INNER JOIN {$wpdb->users}
4503 + ON quiz_attempts.user_id = {$wpdb->users}.ID
4504 + WHERE quiz_attempts.course_id IN (" . $course_ids_in . ")
4505 + AND attempt_status != %s
4506 + AND ( user_email LIKE %s OR display_name LIKE %s OR post_title LIKE %s )
4507 + ",
4508 + 'attempt_started',
4509 + $search_term,
4510 + $search_term,
4511 + $search_term
4512 + ) );
4513 +
4514 + return (int) $count;
4515 + }
4516 +
5523 4517 /**
5524 - * Get frontend dashboard URL
4518 + * @param $attempt_id
5525 4519 *
5526 - * @since 1.0.0
4520 + * @return array|null|object
5527 4521 *
5528 - * @param string $sub_url sub url.
4522 + * Get quiz answers by attempt id
5529 4523 *
5530 - * @return false|string
4524 + * @since v.1.0.0
5531 4525 */
5532 - public function tutor_dashboard_url( $sub_url = '' ) {
5533 - $page_id = (int) $this->get_option( 'tutor_dashboard_page_id' );
5534 - $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
5535 - return apply_filters( 'tutor_dashboard_url', trailingslashit( get_the_permalink( $page_id ) ) . $sub_url, $sub_url );
4526 + public function get_quiz_answers_by_attempt_id( $attempt_id ) {
4527 + global $wpdb;
4528 +
4529 + $results = $wpdb->get_results( $wpdb->prepare(
4530 + "SELECT answers.*,
4531 + question.question_title,
4532 + question.question_type
4533 + FROM {$wpdb->prefix}tutor_quiz_attempt_answers answers
4534 + LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
4535 + ON answers.question_id = question.question_id
4536 + WHERE answers.quiz_attempt_id = %d
4537 + ORDER BY attempt_answer_id ASC;
4538 + ",
4539 + $attempt_id
4540 + ) );
4541 +
4542 + return $results;
5536 4543 }
5537 4544
5538 4545 /**
5539 - * Get the tutor dashboard page ID
4546 + * @param $answer_id array|init
5540 4547 *
5541 - * @since 1.0.0
4548 + * @return array|null|object
5542 4549 *
5543 - * @return int
4550 + * Get single answer by answer_id
4551 + *
4552 + * @since v.1.0.0
5544 4553 */
5545 - public function dashboard_page_id() {
5546 - $page_id = (int) $this->get_option( 'tutor_dashboard_page_id' );
5547 - $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
5548 - return $page_id;
4554 + public function get_answer_by_id( $answer_id ) {
4555 + global $wpdb;
4556 +
4557 + ! is_array( $answer_id ) ? $answer_id = array( $answer_id ) : 0;
4558 +
4559 + $answer_id = array_map( function( $id ) {
4560 + return "'" . esc_sql( $id ) . "'";
4561 + }, $answer_id );
4562 +
4563 + $in_ids_string = implode( ', ', $answer_id );
4564 +
4565 + $answer = $wpdb->get_results( $wpdb->prepare(
4566 + "SELECT answer.*,
4567 + question.question_title,
4568 + question.question_type
4569 + FROM {$wpdb->prefix}tutor_quiz_question_answers answer
4570 + LEFT JOIN {$wpdb->prefix}tutor_quiz_questions question
4571 + ON answer.belongs_question_id = question.question_id
4572 + WHERE answer.answer_id IN (" . $in_ids_string . ")
4573 + AND 1 = %d;
4574 + ",
4575 + 1
4576 + ) );
4577 +
4578 + return $answer;
5549 4579 }
5550 4580
5551 4581 /**
5552 - * Check if the current page is frontend dashboard or the subpage
5553 - * is the part of dashboard
4582 + * @param $ids
5554 4583 *
5555 - * @since 4.0.0
4584 + * @return array|bool|null|object
5556 4585 *
5557 - * @param string $subpage check is dashboard subpage or not.
4586 + * Get quiz answers by ids
5558 4587 *
5559 - * @return bool
4588 + * @since v.1.0.0
5560 4589 */
5561 - public function is_dashboard_page( $subpage = null ): bool {
5562 - if ( $subpage ) {
5563 - return $this->is_tutor_frontend_dashboard( $subpage );
4590 + public function get_quiz_answers_by_ids( $ids ) {
4591 + $ids = (array) $ids;
4592 +
4593 + if ( ! count( $ids ) ) {
4594 + return false;
5564 4595 }
5565 4596
5566 - $has_shortcode = has_shortcode( get_the_content(), 'tutor_dashboard' );
5567 - if ( $has_shortcode ) {
5568 - return true;
4597 + $in_ids = implode(",", $ids);
4598 +
4599 + global $wpdb;
4600 +
4601 + $query = $wpdb->get_results( $wpdb->prepare(
4602 + "SELECT comment_ID,
4603 + comment_content
4604 + FROM {$wpdb->comments}
4605 + WHERE comment_type = %s
4606 + AND comment_ID IN({$in_ids})
4607 + ",
4608 + 'quiz_answer_option'
4609 + ) );
4610 +
4611 + if ( is_array( $query ) && count( $query ) ) {
4612 + return $query;
5569 4613 }
5570 4614
5571 - $current_id = get_the_ID();
5572 - $dashboard_page_id = $this->dashboard_page_id();
5573 -
5574 - return apply_filters(
5575 - 'tutor_is_dashboard_page',
5576 - ( $current_id && $dashboard_page_id ) && $current_id === $dashboard_page_id,
5577 - $current_id,
5578 - $dashboard_page_id
5579 - );
4615 + return false;
5580 4616 }
5581 4617
5582 4618 /**
5583 - * Check if the current page is the part of learning area
4619 + * @param null $level
5584 4620 *
5585 - * @since 4.0.0
4621 + * @return mixed
5586 4622 *
5587 - * @return bool
4623 + * Get the users / students / course levels
4624 + *
4625 + * @since v.1.0.0
5588 4626 */
5589 - public function is_learning_area(): bool {
5590 - $post_types = array(
5591 - tutor()->lesson_post_type,
5592 - tutor()->quiz_post_type,
5593 - tutor()->assignment_post_type,
5594 - tutor()->zoom_post_type,
5595 - tutor()->meet_post_type,
5596 - );
4627 + public function course_levels( $level = null ) {
4628 + $levels = apply_filters( 'tutor_course_level', array(
4629 + 'all_levels' => __( 'All Levels', 'tutor' ),
4630 + 'beginner' => __( 'Beginner', 'tutor' ),
4631 + 'intermediate' => __( 'Intermediate', 'tutor' ),
4632 + 'expert' => __( 'Expert', 'tutor' ),
4633 + ));
5597 4634
5598 - $current_post_type = get_post_type();
5599 -
5600 - if ( is_single() && ! empty( $current_post_type ) ) {
5601 - if ( in_array( $current_post_type, $post_types, true ) ) {
5602 - return true;
5603 - } elseif ( tutor()->course_post_type === $current_post_type && Input::has( 'subpage' ) ) {
5604 - return true;
4635 + if ( $level ) {
4636 + if ( isset( $levels[ $level ] ) ) {
4637 + return $levels[ $level ];
4638 + } else {
4639 + return '';
5605 4640 }
5606 4641 }
5607 4642
5608 - return false;
4643 + return $levels;
5609 4644 }
5610 4645
5611 4646 /**
5612 - * Check if the current page is course list page
4647 + * @return mixed|void
5613 4648 *
5614 - * @since 4.0.0
4649 + * Get user permalink for dashboard
5615 4650 *
5616 - * @return boolean
4651 + * @since v.1.0.0
5617 4652 */
5618 - public function is_course_list_page(): bool {
5619 - $is_course_list_page = false;
4653 + public function user_profile_permalinks() {
4654 + $permalinks = array(
4655 + 'courses_taken' => __( 'Courses Taken', 'tutor' ),
4656 + );
5620 4657
5621 - $post_type = get_query_var( 'post_type' );
5622 - if ( ! is_array( $post_type ) ) {
5623 - $post_type = array( $post_type );
4658 + $show_enrolled_course = tutor_utils()->get_option( 'show_courses_completed_by_student' );
4659 + $enable_show_reviews_wrote = tutor_utils()->get_option( 'students_own_review_show_at_profile' );
4660 +
4661 + if ( $show_enrolled_course ) {
4662 + $permalinks['enrolled_course'] = __( 'Enrolled Course', 'tutor' );
5624 4663 }
5625 4664
5626 - $course_category = get_query_var( 'course-category' );
4665 + if ( $enable_show_reviews_wrote ) {
4666 + $permalinks['reviews_wrote'] = __( 'Reviews Written', 'tutor' );
4667 + }
5627 4668
5628 - if ( ( in_array( tutor()->course_post_type, $post_type, true ) || ! empty( $course_category ) ) && is_archive() ) {
5629 - $is_course_list_page = true;
4669 + return apply_filters( 'tutor_public_profile/permalinks', $permalinks );
4670 + }
4671 +
4672 + /**
4673 + * @return bool|false|string
4674 + *
4675 + * Student registration form
4676 + *
4677 + * @since v.1.0.0
4678 + */
4679 + public function student_register_url() {
4680 + $student_register_page = (int) $this->get_option( 'student_register_page' );
4681 +
4682 + if ( $student_register_page ) {
4683 + return get_the_permalink( $student_register_page );
5630 4684 }
5631 4685
5632 - return $is_course_list_page;
4686 + return false;
5633 4687 }
5634 4688
5635 4689 /**
5636 - * Check if the current page is course details page
4690 + * @return bool|false|string
5637 4691 *
5638 - * @since 4.0.0
4692 + * Instructor registration form
5639 4693 *
5640 - * @return boolean
4694 + * @since v.1.2.13
5641 4695 */
5642 - public function is_course_details_page() {
5643 - if ( Input::has( 'subpage' ) ) {
5644 - return false;
4696 + public function instructor_register_url() {
4697 + $instructor_register_page = (int) $this->get_option( 'instructor_register_page' );
4698 +
4699 + if ( $instructor_register_page ) {
4700 + return get_the_permalink( $instructor_register_page );
5645 4701 }
5646 4702
5647 - return (bool) is_single() && tutor()->course_post_type === get_post_type();
4703 + return false;
5648 4704 }
5649 4705
5650 4706 /**
5651 - * Check is wishlisted.
4707 + * @return false|string
5652 4708 *
5653 - * @since 1.0.0
4709 + * Get frontend dashboard URL
4710 + */
4711 + public function tutor_dashboard_url($sub_url = '') {
4712 + $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
4713 + $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
4714 + return trailingslashit( get_the_permalink( $page_id ) ) . $sub_url;
4715 + }
4716 +
4717 + /**
4718 + * Get the tutor dashboard page ID
5654 4719 *
5655 - * @param int $course_id course id.
5656 - * @param int $user_id user id.
4720 + * @return int
5657 4721 *
4722 + */
4723 + public function dashboard_page_id() {
4724 + $page_id = (int) tutor_utils()->get_option( 'tutor_dashboard_page_id' );
4725 + $page_id = apply_filters( 'tutor_dashboard_page_id', $page_id );
4726 + return $page_id;
4727 + }
4728 +
4729 + /**
4730 + * @param int $course_id
4731 + * @param int $user_id
4732 + *
5658 4733 * @return bool
4734 + *
4735 + * is_wishlisted();
4736 + *
4737 + * @since v.1.0.0
5659 4738 */
5660 4739 public function is_wishlisted( $course_id = 0, $user_id = 0 ) {
5661 4740 $course_id = $this->get_post_id( $course_id );
5662 - $user_id = $this->get_user_id( $user_id );
4741 + $user_id = $this->get_user_id( $user_id );
5663 4742 if ( ! $user_id ) {
5664 4743 return false;
5665 4744 }
5666 4745
5667 4746 global $wpdb;
5668 - $if_added_to_list = (bool) $wpdb->get_row(
5669 - $wpdb->prepare(
5670 - "SELECT *
5671 - FROM {$wpdb->usermeta}
4747 + $if_added_to_list = (bool) $wpdb->get_row( $wpdb->prepare(
4748 + "SELECT *
4749 + FROM {$wpdb->usermeta}
5672 4750 WHERE user_id = %d
5673 4751 AND meta_key = '_tutor_course_wishlist'
5674 4752 AND meta_value = %d;
5675 4753 ",
5676 - $user_id,
5677 - $course_id
5678 - )
5679 - );
4754 + $user_id,
4755 + $course_id
4756 + ) );
5680 4757
5681 4758 return $if_added_to_list;
5682 4759 }
5683 4760
5684 4761 /**
5685 - * Get the wish lists by an user
4762 + * @param int $user_id
5686 4763 *
5687 - * @since 1.0.0
4764 + * @return array|null|object
5688 4765 *
5689 - * @param int $user_id user id.
5690 - * @param int $offset offset.
5691 - * @param int $limit limit.
4766 + * Get the wish lists by an user
5692 4767 *
5693 - * @return array|null|object
4768 + * @since v.1.0.0
5694 4769 */
5695 - public function get_wishlist( $user_id = 0, int $offset = 0, int $limit = PHP_INT_MAX ) {
4770 + public function get_wishlist( $user_id = 0 ) {
5696 4771 global $wpdb;
5697 4772
5698 4773 $user_id = $this->get_user_id( $user_id );
5699 - $post_types = apply_filters( 'tutor_wishlist_post_types', array( tutor()->course_post_type ) );
5700 - $post_type_clause = QueryHelper::prepare_in_clause( $post_types );
4774 + $course_post_type = tutor()->course_post_type;
5701 4775
5702 - $pageposts = $wpdb->get_results(
5703 - $wpdb->prepare(
5704 - "SELECT $wpdb->posts.*
4776 + $pageposts = $wpdb->get_results( $wpdb->prepare(
4777 + "SELECT $wpdb->posts.*
5705 4778 FROM $wpdb->posts
5706 4779 LEFT JOIN $wpdb->usermeta
5707 4780 ON ($wpdb->posts.ID = $wpdb->usermeta.meta_value)
5708 - WHERE post_type IN ({$post_type_clause})
4781 + WHERE post_type = %s
5709 4782 AND post_status = %s
5710 4783 AND $wpdb->usermeta.meta_key = %s
5711 4784 AND $wpdb->usermeta.user_id = %d
5712 - ORDER BY $wpdb->usermeta.umeta_id DESC LIMIT %d, %d;
4785 + ORDER BY $wpdb->usermeta.umeta_id DESC;
5713 4786 ",
5714 - 'publish',
5715 - '_tutor_course_wishlist',
5716 - $user_id,
5717 - $offset,
5718 - $limit
5719 - ),
5720 - OBJECT
5721 - );
4787 + $course_post_type,
4788 + 'publish',
4789 + '_tutor_course_wishlist',
4790 + $user_id
4791 + ), OBJECT );
5722 4792
5723 4793 return $pageposts;
5724 4794 }
5725 4795
5726 4796 /**
5727 - * Getting popular courses
4797 + * @param int $limit
5728 4798 *
5729 - * @since 1.0.0
4799 + * @return array|null|object
5730 4800 *
5731 - * @param int $limit limit.
5732 - * @param mixed $user_id user id.
4801 + * Getting popular courses
5733 4802 *
5734 - * @return array|null|object
4803 + * @since v.1.0.0
5735 4804 */
5736 - public function most_popular_courses( $limit = 10, $user_id = '' ) {
4805 + public function most_popular_courses( $limit = 10 ) {
5737 4806 global $wpdb;
5738 - $limit = sanitize_text_field( $limit );
5739 - $user_id = sanitize_text_field( $user_id );
5740 4807
5741 - $author_query = '';
5742 - if ( '' !== $user_id ) {
5743 - $author_query = "AND course.post_author = $user_id";
5744 - }
5745 -
5746 - $courses = $wpdb->get_results(
5747 - $wpdb->prepare(
5748 - "SELECT COUNT(enrolled.ID) AS total_enrolled,
4808 + $courses = $wpdb->get_results( $wpdb->prepare(
4809 + "SELECT COUNT(enrolled.ID) AS total_enrolled,
5749 4810 enrolled.post_parent as course_id,
5750 4811 course.*
5751 4812 FROM {$wpdb->posts} enrolled
5752 4813 INNER JOIN {$wpdb->posts} course
5753 - ON enrolled.post_parent = course.ID
4814 + ON enrolled.post_parent = course.ID
5754 4815 WHERE enrolled.post_type = %s
5755 4816 AND enrolled.post_status = %s
5756 - AND course.post_type = %s
5757 - {$author_query}
5758 4817 GROUP BY course_id
5759 4818 ORDER BY total_enrolled DESC
5760 4819 LIMIT 0, %d;
5761 4820 ",
5762 - 'tutor_enrolled',
5763 - 'completed',
5764 - tutor()->course_post_type,
5765 - $limit
5766 - )
5767 - );
4821 + 'tutor_enrolled',
4822 + 'completed',
4823 + $limit
4824 + ) );
5768 4825
5769 4826 return $courses;
5770 4827 }
5771 4828
5772 4829 /**
5773 - * Get Addon config
4830 + * @param int $limit
5774 4831 *
5775 - * @since 1.0.0
5776 - * @since 3.0.0 make addon_field value based on param.
4832 + * @return array|bool|null|object
5777 4833 *
5778 - * @param mixed $addon_field addon field.
4834 + * Get most rated courses lists
5779 4835 *
5780 - * @return mixed
4836 + * @since v.1.0.0
5781 4837 */
4838 + public function most_rated_courses( $limit = 10 ) {
4839 + global $wpdb;
4840 +
4841 + $result = $wpdb->get_results( $wpdb->prepare(
4842 + "SELECT COUNT(comment_ID) AS total_rating,
4843 + comment_ID,
4844 + comment_post_ID,
4845 + course.*
4846 + FROM {$wpdb->comments}
4847 + INNER JOIN {$wpdb->posts} course
4848 + ON comment_post_ID = course.ID
4849 + WHERE {$wpdb->comments}.comment_type = %s
4850 + AND {$wpdb->comments}.comment_approved = %s
4851 + GROUP BY comment_post_ID
4852 + ORDER BY total_rating DESC
4853 + LIMIT 0, %d
4854 + ;",
4855 + 'tutor_course_rating',
4856 + 'approved',
4857 + $limit
4858 + ) );
4859 +
4860 + if ( is_array( $result ) && count( $result ) ) {
4861 + return $result;
4862 + }
4863 +
4864 + return false;
4865 + }
4866 +
4867 + /**
4868 + * @param null $addon_field
4869 + *
4870 + * @return bool
4871 + *
4872 + * Get Addon config
4873 + *
4874 + * @since v.1.0.0
4875 + */
5782 4876 public function get_addon_config( $addon_field = null ) {
5783 4877 if ( ! $addon_field ) {
5784 4878 return false;
5785 4879 }
5786 4880
5787 - $addon_field = ( strpos( $addon_field, 'tutor-pro/addons/' ) === 0 )
5788 - ? $addon_field
5789 - : "tutor-pro/addons/{$addon_field}/{$addon_field}.php";
4881 + $addonsConfig = maybe_unserialize( get_option( 'tutor_addons_config' ) );
5790 4882
5791 - $addons_config = maybe_unserialize( get_option( 'tutor_addons_config' ) );
5792 -
5793 - if ( isset( $addons_config[ $addon_field ] ) ) {
5794 - return $addons_config[ $addon_field ];
4883 + if ( isset( $addonsConfig[ $addon_field ] ) ) {
4884 + return $addonsConfig[ $addon_field ];
5795 4885 }
5796 4886
5797 4887 return false;
5798 4888 }
@@ -5797,61 +4887,46 @@
5797 4887 return false;
5798 4888 }
5799 4889
5800 4890 /**
4891 + * @return array|false|string
4892 + *
5801 4893 * Get the IP from visitor
5802 4894 *
5803 - * @since 1.0.0
5804 - *
5805 - * @return array|false|string
4895 + * @since v.1.0.0
5806 4896 */
5807 - public function get_ip() {
4897 + function get_ip() {
5808 4898 $ipaddress = '';
5809 - if ( getenv( 'HTTP_CLIENT_IP' ) ) {
4899 + if ( getenv( 'HTTP_CLIENT_IP') )
5810 4900 $ipaddress = getenv( 'HTTP_CLIENT_IP' );
5811 - } elseif ( getenv( 'HTTP_X_FORWARDED_FOR' ) ) {
4901 + else if( getenv( 'HTTP_X_FORWARDED_FOR' ) )
5812 4902 $ipaddress = getenv( 'HTTP_X_FORWARDED_FOR' );
5813 - } elseif ( getenv( 'HTTP_X_FORWARDED' ) ) {
4903 + else if( getenv( 'HTTP_X_FORWARDED' ) )
5814 4904 $ipaddress = getenv( 'HTTP_X_FORWARDED' );
5815 - } elseif ( getenv( 'HTTP_FORWARDED_FOR' ) ) {
4905 + else if( getenv( 'HTTP_FORWARDED_FOR' ) )
5816 4906 $ipaddress = getenv( 'HTTP_FORWARDED_FOR' );
5817 - } elseif ( getenv( 'HTTP_FORWARDED' ) ) {
4907 + else if( getenv( 'HTTP_FORWARDED' ) )
5818 4908 $ipaddress = getenv( 'HTTP_FORWARDED' );
5819 - } elseif ( getenv( 'REMOTE_ADDR' ) ) {
4909 + else if( getenv( 'REMOTE_ADDR' ) )
5820 4910 $ipaddress = getenv( 'REMOTE_ADDR' );
5821 - } else {
4911 + else
5822 4912 $ipaddress = 'UNKNOWN';
5823 - }
5824 4913 return $ipaddress;
5825 4914 }
5826 4915
5827 4916 /**
4917 + * @return array $array
4918 + *
5828 4919 * Get the social icons
5829 4920 *
5830 - * @since 1.0.4
5831 - *
5832 - * @return array $array
4921 + * @since v.1.0.4
5833 4922 */
5834 4923 public function tutor_social_share_icons() {
5835 4924 $icons = array(
5836 - 'facebook' => array(
5837 - 'share_class' => 's_facebook',
5838 - 'icon_html' => '<i class="tutor-valign-middle tutor-icon-brand-facebook"></i>',
5839 - 'text' => '',
5840 - 'color' => '#3877EA',
5841 - ),
5842 - 'twitter' => array(
5843 - 'share_class' => 's_twitter',
5844 - 'icon_html' => '<i class="tutor-valign-middle tutor-icon-brand-x-twitter"></i>',
5845 - 'text' => '',
5846 - 'color' => '#000000',
5847 - ),
5848 - 'linkedin' => array(
5849 - 'share_class' => 's_linkedin',
5850 - 'icon_html' => '<i class="tutor-valign-middle tutor-icon-brand-linkedin"></i>',
5851 - 'text' => '',
5852 - 'color' => '#3967B6',
5853 - ),
4925 + 'facebook' => array( 'share_class' => 's_facebook', 'icon_html' => '<i class="tutor-icon-facebook"></i>' ),
4926 + 'twitter' => array( 'share_class' => 's_twitter', 'icon_html' => '<i class="tutor-icon-twitter"></i>' ),
4927 + 'linkedin' => array( 'share_class' => 's_linkedin', 'icon_html' => '<i class="tutor-icon-linkedin"></i>' ),
4928 + 'tumblr' => array( 'share_class' => 's_tumblr', 'icon_html' => '<i class="tutor-icon-tumblr"></i>' ),
5854 4929 );
5855 4930
5856 4931 return apply_filters( 'tutor_social_share_icons', $icons );
5857 4932 }
@@ -5856,52 +4931,41 @@
5856 4931 return apply_filters( 'tutor_social_share_icons', $icons );
5857 4932 }
5858 4933
5859 4934 /**
4935 + * @return array $array
4936 + *
5860 4937 * Get the user social icons
5861 4938 *
5862 - * @since 1.3.7
5863 - * @since 4.0.0 added svg_icon and pattern
5864 - *
5865 - * @return array $array
4939 + * @since v.1.3.7
5866 4940 */
5867 4941 public function tutor_user_social_icons() {
5868 4942 $icons = array(
5869 - '_tutor_profile_facebook' => array(
5870 - 'label' => __( 'Facebook', 'tutor' ),
4943 + '_tutor_profile_website' => array(
4944 + 'label' => __('Website URL', 'tutor'),
4945 + 'placeholder' => 'https://example.com/',
4946 + 'icon_classes' => 'tutor-icon-earth'
4947 + ),
4948 + '_tutor_profile_github' => array(
4949 + 'label' => __('Github URL', 'tutor'),
4950 + 'placeholder' => 'https://github.com/username',
4951 + 'icon_classes' => 'tutor-icon-github-logo'
4952 + ),
4953 + '_tutor_profile_facebook' => array(
4954 + 'label' => __('Facebook URL', 'tutor'),
5871 4955 'placeholder' => 'https://facebook.com/username',
5872 - 'icon_classes' => 'tutor-icon-brand-facebook',
5873 - 'svg_icon' => Icon::FACEBOOK,
5874 - 'pattern' => '^https?:\/\/(www\.|m\.|web\.|mobile\.)?facebook\.com\/([A-Za-z0-9._-]+)\/?$',
4956 + 'icon_classes' => 'tutor-icon-facebook'
5875 4957 ),
5876 4958 '_tutor_profile_twitter' => array(
5877 - 'label' => __( 'X', 'tutor' ),
5878 - 'placeholder' => 'https://x.com/username',
5879 - 'icon_classes' => 'tutor-icon-brand-x-twitter',
5880 - 'svg_icon' => Icon::X,
5881 - 'pattern' => '^https?:\/\/(www\.)?(x\.com|twitter\.com)\/([A-Za-z0-9_]+)\/?$',
4959 + 'label' => __('Twitter URL', 'tutor'),
4960 + 'placeholder' => 'https://twitter.com/username',
4961 + 'icon_classes' => 'tutor-icon-twitter'
5882 4962 ),
5883 - '_tutor_profile_linkedin' => array(
5884 - 'label' => __( 'Linkedin', 'tutor' ),
4963 + '_tutor_profile_linkedin' => array(
4964 + 'label' => __('Linkedin URL', 'tutor'),
5885 4965 'placeholder' => 'https://linkedin.com/username',
5886 - 'icon_classes' => 'tutor-icon-brand-linkedin',
5887 - 'svg_icon' => Icon::LINKEDIN,
5888 - 'pattern' => '^https?:\/\/(www\.)?linkedin\.com\/(in|company|school)\/([A-Za-z0-9_-]+)\/?$',
4966 + 'icon_classes' => 'tutor-icon-linkedin'
5889 4967 ),
5890 - '_tutor_profile_github' => array(
5891 - 'label' => __( 'Github', 'tutor' ),
5892 - 'placeholder' => 'https://github.com/username',
5893 - 'icon_classes' => 'tutor-icon-brand-github',
5894 - 'svg_icon' => Icon::GITHUB,
5895 - 'pattern' => '^https?:\/\/(www\.)?github\.com\/([A-Za-z0-9_-]+)\/?$',
5896 - ),
5897 - '_tutor_profile_website' => array(
5898 - 'label' => __( 'Website', 'tutor' ),
5899 - 'placeholder' => 'https://example.com/',
5900 - 'icon_classes' => 'tutor-icon-earth',
5901 - 'svg_icon' => Icon::GLOBE,
5902 - 'pattern' => '^https?:\/\/(www\.)?[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?(\.[A-Za-z0-9]([A-Za-z0-9-]{0,61}[A-Za-z0-9])?)*\.[A-Za-z]{2,}(\/.*)?$',
5903 - ),
5904 4968 );
5905 4969
5906 4970 return apply_filters( 'tutor_user_social_icons', $icons );
5907 4971 }
@@ -5906,15 +4970,15 @@
5906 4970 return apply_filters( 'tutor_user_social_icons', $icons );
5907 4971 }
5908 4972
5909 4973 /**
5910 - * Count method with check is_array
4974 + * @param array $array
5911 4975 *
5912 - * @since 1.0.4
4976 + * @return bool
5913 4977 *
5914 - * @param array $array array.
4978 + * count method with check is_array
5915 4979 *
5916 - * @return bool
4980 + * @since v.1.0.4
5917 4981 */
5918 4982 public function count( $array = array() ) {
5919 4983 if ( is_array( $array ) && count( $array ) ) {
5920 4984 return count( $array );
@@ -5923,29 +4987,29 @@
5923 4987 return false;
5924 4988 }
5925 4989
5926 4990 /**
5927 - * Get all screen ids
4991 + * @return array
5928 4992 *
5929 - * @since 1.1.2
4993 + * get all screen ids
5930 4994 *
5931 - * @return array
4995 + * @since v.1.1.2
5932 4996 */
5933 4997 public function tutor_get_screen_ids() {
5934 4998 $screen_ids = array(
5935 - 'edit-course',
5936 - 'course',
5937 - 'edit-course-category',
5938 - 'edit-course-tag',
5939 - 'tutor-lms_page_tutor-students',
5940 - 'tutor-lms_page_tutor-instructors',
5941 - 'tutor-lms_page_question_answer',
5942 - 'tutor-lms_page_tutor_quiz_attempts',
5943 - 'tutor-lms_page_tutor-addons',
5944 - 'tutor-lms_page_tutor-status',
5945 - 'tutor-lms_page_tutor_report',
5946 - 'tutor-lms_page_tutor_settings',
5947 - 'tutor-lms_page_tutor_emails',
4999 + "edit-course",
5000 + "course",
5001 + "edit-course-category",
5002 + "edit-course-tag",
5003 + "tutor-lms_page_tutor-students",
5004 + "tutor-lms_page_tutor-instructors",
5005 + "tutor-lms_page_question_answer",
5006 + "tutor-lms_page_tutor_quiz_attempts",
5007 + "tutor-lms_page_tutor-addons",
5008 + "tutor-lms_page_tutor-status",
5009 + "tutor-lms_page_tutor_report",
5010 + "tutor-lms_page_tutor_settings",
5011 + "tutor-lms_page_tutor_emails",
5948 5012 );
5949 5013
5950 5014 return apply_filters( 'tutor_get_screen_ids', $screen_ids );
5951 5015 }
@@ -5950,18 +5014,18 @@
5950 5014 return apply_filters( 'tutor_get_screen_ids', $screen_ids );
5951 5015 }
5952 5016
5953 5017 /**
5954 - * Get earning transaction completed status
5018 + * @return mixed
5955 5019 *
5956 - * @since 1.1.2
5020 + * get earning transaction completed status
5957 5021 *
5958 - * @return mixed
5022 + * @since v.1.1.2
5959 5023 */
5960 5024 public function get_earnings_completed_statuses() {
5961 5025 return apply_filters(
5962 5026 'tutor_get_earnings_completed_statuses',
5963 - array(
5027 + array (
5964 5028 'wc-completed',
5965 5029 'completed',
5966 5030 'complete',
5967 5031 )
@@ -5968,58 +5032,21 @@
5968 5032 );
5969 5033 }
5970 5034
5971 5035 /**
5972 - * Change earning status.
5036 + * @param int $user_id
5037 + * @param array $date_filter
5973 5038 *
5974 - * @since 2.2.0
5039 + * @return array|null|object
5975 5040 *
5976 - * @param int $order_id order id.
5977 - * @param string $status status.
5978 - *
5979 - * @return bool
5980 - */
5981 - public static function change_earning_status( $order_id, $status ) {
5982 - $is_updated = false;
5983 -
5984 - global $wpdb;
5985 - $is_earning_data = (int) $wpdb->get_var(
5986 - $wpdb->prepare(
5987 - "SELECT COUNT(earning_id)
5988 - FROM {$wpdb->prefix}tutor_earnings
5989 - WHERE order_id = %d ",
5990 - $order_id
5991 - )
5992 - );
5993 -
5994 - if ( $is_earning_data ) {
5995 - $update_earning_status = $wpdb->update(
5996 - $wpdb->prefix . 'tutor_earnings',
5997 - array( 'order_status' => $status ),
5998 - array( 'order_id' => $order_id )
5999 - );
6000 -
6001 - $is_updated = true;
6002 - do_action( 'tutor_after_earning_status_change', $update_earning_status );
6003 - }
6004 -
6005 - return $is_updated;
6006 - }
6007 -
6008 - /**
6009 5041 * Get all time earning sum for an instructor with all commission
6010 5042 *
6011 - * @since 1.1.2
6012 - *
6013 - * @param int $user_id user id.
6014 - * @param array $date_filter date filter.
6015 - *
6016 - * @return array|null|object
5043 + * @since v.1.1.2
6017 5044 */
6018 5045 public function get_earning_sum( $user_id = 0, $date_filter = array() ) {
6019 5046 global $wpdb;
6020 5047
6021 - $user_id = $this->get_user_id( $user_id );
5048 + $user_id = $this->get_user_id( $user_id );
6022 5049 $date_query = '';
6023 5050
6024 5051 if ( $this->count( $date_filter ) ) {
6025 5052 extract( $date_filter );
@@ -6035,43 +5062,44 @@
6035 5062 $date_query = " AND (created_at BETWEEN '{$start_date}' AND '{$end_date}') ";
6036 5063 }
6037 5064 }
6038 5065
6039 - $complete_status = $this->get_earnings_completed_statuses();
5066 + $complete_status = tutor_utils()->get_earnings_completed_statuses();
6040 5067 $complete_status = "'" . implode( "','", $complete_status ) . "'";
6041 5068
6042 - $earning_sum = $wpdb->get_row(
6043 - $wpdb->prepare(
6044 - "SELECT SUM(course_price_total) AS course_price_total,
6045 - SUM(course_price_grand_total) AS course_price_grand_total,
6046 - SUM(instructor_amount) AS instructor_amount,
5069 + $earning_sum = $wpdb->get_row( $wpdb->prepare(
5070 + "SELECT SUM(course_price_total) AS course_price_total,
5071 + SUM(course_price_grand_total) AS course_price_grand_total,
5072 + SUM(instructor_amount) AS instructor_amount,
6047 5073 (SELECT SUM(amount)
6048 5074 FROM {$wpdb->prefix}tutor_withdraws
6049 5075 WHERE user_id = {$user_id}
6050 5076 AND status != 'rejected'
6051 5077 ) AS withdraws_amount,
6052 - SUM(admin_amount) AS admin_amount,
5078 + SUM(admin_amount) AS admin_amount,
6053 5079 SUM(deduct_fees_amount) AS deduct_fees_amount
6054 - FROM {$wpdb->prefix}tutor_earnings
5080 + FROM {$wpdb->prefix}tutor_earnings
6055 5081 WHERE user_id = %d
6056 5082 AND order_status IN({$complete_status})
6057 5083 {$date_query}
6058 5084 ",
6059 - $user_id
6060 - )
6061 - );
5085 + $user_id
5086 + ) );
6062 5087
5088 + //TODO: need to check
5089 + // (SUM(instructor_amount) - (SELECT withdraws_amount) ) as balance,
5090 +
6063 5091 if ( $earning_sum->course_price_total ) {
6064 5092 $earning_sum->balance = $earning_sum->instructor_amount - $earning_sum->withdraws_amount;
6065 5093 } else {
6066 5094 $earning_sum = (object) array(
6067 - 'course_price_total' => 0,
6068 - 'course_price_grand_total' => 0,
6069 - 'instructor_amount' => 0,
6070 - 'withdraws_amount' => 0,
6071 - 'balance' => 0,
6072 - 'admin_amount' => 0,
6073 - 'deduct_fees_amount' => 0,
5095 + 'course_price_total' => 0,
5096 + 'course_price_grand_total' => 0,
5097 + 'instructor_amount' => 0,
5098 + 'withdraws_amount' => 0,
5099 + 'balance' => 0,
5100 + 'admin_amount' => 0,
5101 + 'deduct_fees_amount' => 0,
6074 5102 );
6075 5103 }
6076 5104
6077 5105 return $earning_sum;
@@ -6077,44 +5105,124 @@
6077 5105 return $earning_sum;
6078 5106 }
6079 5107
6080 5108 /**
6081 - * Get the price format
5109 + * @param int $user_id
5110 + * @param array $date_filter
6082 5111 *
6083 - * @since 1.1.2
6084 - * @since 4.0.0 Condition added for different monetizations.
5112 + * @return array|null|object
6085 5113 *
6086 - * @param int $price price.
5114 + * Get earning statements
6087 5115 *
5116 + * @since v.1.1.2
5117 + */
5118 + public function get_earning_statements( $user_id = 0, $filter_data = array() ) {
5119 + global $wpdb;
5120 +
5121 + $user_sql = "";
5122 + if ($user_id){
5123 + $user_sql = " AND user_id='{$user_id}' ";
5124 + }
5125 +
5126 + $date_query = '';
5127 + $query_by_status = '';
5128 + $pagination_query = '';
5129 +
5130 + /**
5131 + * Query by Date Filter
5132 + */
5133 + if ( $this->count( $filter_data ) ) {
5134 + extract( $filter_data );
5135 +
5136 + if ( ! empty( $dataFor ) ) {
5137 + if ( $dataFor === 'yearly' ) {
5138 + if ( empty( $year ) ) {
5139 + $year = date( 'Y' );
5140 + }
5141 + $date_query = "AND YEAR(created_at) = {$year} ";
5142 + }
5143 + } else {
5144 + $date_query = " AND (created_at BETWEEN '{$start_date}' AND '{$end_date}') ";
5145 + }
5146 +
5147 + /**
5148 + * Query by order status related to this earning transaction
5149 + */
5150 + if ( ! empty( $statuses ) ) {
5151 + if ( $this->count( $statuses ) ) {
5152 + $status = "'" . implode( "','", $statuses ) . "'";
5153 + $query_by_status = "AND order_status IN({$status})";
5154 + } elseif ( $statuses === 'completed' ) {
5155 + $get_earnings_completed_statuses = $this->get_earnings_completed_statuses();
5156 + if ( $this->count( $get_earnings_completed_statuses ) ) {
5157 + $status = "'" . implode( "','", $get_earnings_completed_statuses ) . "'";
5158 + $query_by_status = "AND order_status IN({$status})";
5159 + }
5160 + }
5161 + }
5162 +
5163 + if ( ! empty( $per_page ) ) {
5164 + $offset = (int) ! empty($offset) ? $offset : 0;
5165 + $pagination_query = " LIMIT {$offset}, {$per_page} ";
5166 + }
5167 + }
5168 +
5169 + $query = $wpdb->get_results( $wpdb->prepare(
5170 + "SELECT earning_tbl.*,
5171 + course.post_title AS course_title
5172 + FROM {$wpdb->prefix}tutor_earnings earning_tbl
5173 + LEFT JOIN {$wpdb->posts} course
5174 + ON earning_tbl.course_id = course.ID
5175 + WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
5176 + ORDER BY created_at DESC {$pagination_query}
5177 + ",
5178 + 1
5179 + ) );
5180 +
5181 + $query_count = (int) $wpdb->get_var( $wpdb->prepare(
5182 + "SELECT COUNT(earning_tbl.earning_id)
5183 + FROM {$wpdb->prefix}tutor_earnings earning_tbl
5184 + WHERE 1 = %d {$user_sql} {$date_query} {$query_by_status}
5185 + ORDER BY created_at DESC
5186 + ",
5187 + 1
5188 + ) );
5189 +
5190 + return (object) array(
5191 + 'count' => $query_count,
5192 + 'results' => $query,
5193 + );
5194 + }
5195 +
5196 + /**
5197 + * @param int $price
5198 + *
6088 5199 * @return int|string
5200 + *
5201 + * Get the price format
5202 + *
5203 + * @since v.1.1.2
6089 5204 */
6090 5205 public function tutor_price( $price = 0 ) {
6091 -
6092 - $monetize_by = $this->get_option( 'monetize_by' );
6093 -
6094 - if ( Ecommerce::MONETIZE_BY === $monetize_by ) {
6095 - return tutor_get_formatted_price( $price );
6096 - } elseif ( function_exists( 'wc_price' ) && 'wc' === $monetize_by ) {
5206 + if ( function_exists( 'wc_price') ) {
6097 5207 return wc_price( $price );
6098 - } elseif ( function_exists( 'edd_currency_filter' ) && 'edd' === $monetize_by ) {
5208 + } elseif ( function_exists( 'edd_currency_filter' ) ) {
6099 5209 return edd_currency_filter( edd_format_amount( $price ) );
6100 - } elseif ( function_exists( 'pmpro_formatPrice' ) && 'pmpro' === $monetize_by ) {
6101 - return pmpro_formatPrice( floatval( $price ) );
6102 - } else {
6103 - return number_format_i18n( floatval( $price ) );
5210 + }else{
5211 + return number_format_i18n( $price );
6104 5212 }
6105 5213 }
6106 5214
6107 5215 /**
5216 + * @return mixed
5217 + *
6108 5218 * Get currency symbol from activated plugin, WC,EDD
6109 5219 *
6110 - * @since 1.3.4
6111 - *
6112 - * @return mixed
5220 + * @since v.1.3.4
6113 5221 */
6114 5222 public function currency_symbol() {
6115 - $enable_tutor_edd = $this->get_option( 'enable_tutor_edd' );
6116 - $monetize_by = $this->get_option( 'monetize_by' );
5223 + $enable_tutor_edd = tutor_utils()->get_option( 'enable_tutor_edd' );
5224 + $monetize_by = $this->get_option('monetize_by');
6117 5225
6118 5226 $symbol = '&#36;';
6119 5227 if ( $enable_tutor_edd && function_exists( 'edd_currency_symbol' ) ) {
6120 5228 $symbol = edd_currency_symbol();
@@ -6119,9 +5227,9 @@
6119 5227 if ( $enable_tutor_edd && function_exists( 'edd_currency_symbol' ) ) {
6120 5228 $symbol = edd_currency_symbol();
6121 5229 }
6122 5230
6123 - if ( 'wc' === $monetize_by && function_exists( 'get_woocommerce_currency_symbol' ) ) {
5231 + if ( $monetize_by === 'wc' && function_exists( 'get_woocommerce_currency_symbol' ) ) {
6124 5232 $symbol = get_woocommerce_currency_symbol();
6125 5233 }
6126 5234
6127 5235 return apply_filters( 'get_tutor_currency_symbol', $symbol );
@@ -6127,16 +5235,109 @@
6127 5235 return apply_filters( 'get_tutor_currency_symbol', $symbol );
6128 5236 }
6129 5237
6130 5238 /**
6131 - * Add Instructor role to any user by user ID
5239 + * @param int $user_id
6132 5240 *
6133 - * @since 1.0.0
5241 + * @return bool|mixed
6134 5242 *
6135 - * @param int $instructor_id instructor id.
5243 + * Get withdraw method for a specific
5244 + */
5245 + public function get_user_withdraw_method( $user_id = 0 ) {
5246 + $user_id = $this->get_user_id( $user_id );
5247 + $account = get_user_meta( $user_id, '_tutor_withdraw_method_data', true );
5248 +
5249 + if ( $account ) {
5250 + return maybe_unserialize( $account );
5251 + }
5252 +
5253 + return false;
5254 + }
5255 +
5256 + /**
5257 + * @param int $user_id
5258 + * @param array $filter
6136 5259 *
6137 - * @return void
5260 + * get withdrawal history
5261 + *
5262 + * @return object
6138 5263 */
5264 + public function get_withdrawals_history( $user_id = 0, $filter = array() ) {
5265 + global $wpdb;
5266 +
5267 + $filter = (array) $filter;
5268 + extract($filter);
5269 +
5270 + $query_by_status_sql = "";
5271 + $query_by_user_sql = "";
5272 + $query_by_pagination = "";
5273 +
5274 + if ( ! empty( $status ) ) {
5275 + $status = (array) $status;
5276 + $status = "'" . implode( "','", $status ) . "'";
5277 +
5278 + $query_by_status_sql = " AND status IN({$status}) ";
5279 + }
5280 +
5281 + if ( ! empty( $per_page ) ) {
5282 + if ( empty( $start ) )
5283 + $start = 0;
5284 +
5285 + $query_by_pagination = " LIMIT {$start}, {$per_page} ";
5286 + }
5287 +
5288 + if ( $user_id ) {
5289 + $query_by_user_sql = " AND user_id = {$user_id} ";
5290 + }
5291 +
5292 + $count = (int) $wpdb->get_var( $wpdb->prepare(
5293 + "SELECT COUNT(withdraw_id)
5294 + FROM {$wpdb->prefix}tutor_withdraws
5295 + WHERE 1 = %d
5296 + {$query_by_user_sql}
5297 + {$query_by_status_sql}
5298 + ",
5299 + 1
5300 + ) );
5301 +
5302 + $results = $wpdb->get_results( $wpdb->prepare(
5303 + "SELECT withdraw_tbl.*,
5304 + user_tbl.display_name AS user_name,
5305 + user_tbl.user_email
5306 + FROM {$wpdb->prefix}tutor_withdraws withdraw_tbl
5307 + INNER JOIN {$wpdb->users} user_tbl
5308 + ON withdraw_tbl.user_id = user_tbl.ID
5309 + WHERE 1 = %d
5310 + {$query_by_user_sql}
5311 + {$query_by_status_sql}
5312 + ORDER BY created_at DESC
5313 + {$query_by_pagination}
5314 + ",
5315 + 1
5316 + ) );
5317 +
5318 + $withdraw_history = array(
5319 + 'count' => 0,
5320 + 'results' => null,
5321 + );
5322 +
5323 + if ( $count ) {
5324 + $withdraw_history['count'] = $count;
5325 + }
5326 +
5327 + if ( tutor_utils()->count( $results ) ) {
5328 + $withdraw_history['results'] = $results;
5329 + }
5330 +
5331 + return (object) $withdraw_history;
5332 +
5333 + }
5334 +
5335 + /**
5336 + * @param int $instructor_id
5337 + *
5338 + * Add Instructor role to any user by user iD
5339 + */
6139 5340 public function add_instructor_role( $instructor_id = 0 ) {
6140 5341 if ( ! $instructor_id ) {
6141 5342 return;
6142 5343 }
@@ -6152,15 +5353,11 @@
6152 5353 do_action( 'tutor_after_approved_instructor', $instructor_id );
6153 5354 }
6154 5355
6155 5356 /**
5357 + * @param int $instructor_id
5358 + *
6156 5359 * Remove instructor role by instructor id
6157 - *
6158 - * @since 1.0.0
6159 - *
6160 - * @param int $instructor_id instructor id.
6161 - *
6162 - * @return void
6163 5360 */
6164 5361 public function remove_instructor_role( $instructor_id = 0 ) {
6165 5362 if ( ! $instructor_id ) {
6166 5363 return;
@@ -6175,57 +5372,137 @@
6175 5372 do_action( 'tutor_after_blocked_instructor', $instructor_id );
6176 5373 }
6177 5374
6178 5375 /**
6179 - * Get purchase history by customer id
5376 + * @param string $msg
5377 + * @param string $name
6180 5378 *
6181 - * @since 1.0.0
6182 - * @since 4.0.0 Added $args parameter.
5379 + * Set Flash Message to view in next action / route
5380 + */
5381 + public function set_flash_msg( $msg = '', $name = 'success' ) {
5382 + global $wp_filesystem;
5383 + if ( ! $wp_filesystem ) {
5384 + require_once( ABSPATH . 'wp-admin/includes/file.php' );
5385 + }
5386 +
5387 + $filename = "tutor_flash_msg_{$name}.txt";
5388 + $upload_dir = wp_upload_dir();
5389 + $dir = trailingslashit( $upload_dir['basedir'] ) . 'tutor/';
5390 +
5391 + WP_Filesystem( false, $upload_dir['basedir'], true );
5392 +
5393 + if ( ! $wp_filesystem->is_dir( $dir ) ) {
5394 + $wp_filesystem->mkdir( $dir );
5395 + }
5396 +
5397 + $wp_filesystem->put_contents( $dir . $filename, $msg );
5398 + }
5399 +
5400 + /**
5401 + * @param null $name
6183 5402 *
6184 - * @param integer $user_id user id.
6185 - * @param array $args array of arguments.
5403 + * @return mixed|string|void
6186 5404 *
6187 - * @return object {results: array, total_count: int}
5405 + * Get Flash Message
6188 5406 */
6189 - public function get_orders_by_user_id( $user_id = 0, $args = array() ) {
6190 - $data = (object) array(
6191 - 'results' => array(),
6192 - 'total_count' => 0,
6193 - );
5407 + public function get_flash_msg( $name = null ) {
5408 + if ( ! $name ) {
5409 + return '';
5410 + }
6194 5411
6195 - return apply_filters( 'tutor_get_orders_by_user_id', $data, $user_id, $args );
5412 + $upload_dir = wp_get_upload_dir();
5413 + $upload_dir = trailingslashit( $upload_dir['basedir'] );
5414 + $msg_name = 'tutor_flash_msg_'.$name;
5415 +
5416 + $msg = '';
5417 + $flash_msg_file_name = $upload_dir."tutor/{$msg_name}.txt";
5418 + if ( file_exists( $flash_msg_file_name ) ) {
5419 + $msg = file_get_contents( $flash_msg_file_name );
5420 + unlink( $flash_msg_file_name );
5421 + }
5422 +
5423 + return apply_filters( 'tutor_get_flash_msg', $msg, $name );
6196 5424 }
6197 5425
6198 5426 /**
6199 - * Get status contact formatted for order
5427 + * @param int $user_id
6200 5428 *
6201 - * @since 1.3.1
5429 + * @return array|null|object
6202 5430 *
6203 - * @param mixed $status status.
5431 + * Get purchase history by customer id
5432 + */
5433 + public function get_orders_by_user_id( $user_id = 0 ) {
5434 + global $wpdb;
5435 +
5436 + $user_id = $this->get_user_id();
5437 + $monetize_by = tutils()->get_option( 'monetize_by' );
5438 +
5439 + $post_type = "";
5440 + $user_meta = "";
5441 +
5442 + if ( $monetize_by === 'wc' ) {
5443 + $post_type = "shop_order";
5444 + $user_meta = "_customer_user";
5445 + } else if ( $monetize_by === 'edd' ) {
5446 + $post_type = "edd_payment";
5447 + $user_meta = "_edd_payment_user_id";
5448 + }
5449 +
5450 + $orders = $wpdb->get_results( $wpdb->prepare(
5451 + "SELECT {$wpdb->posts}.*
5452 + FROM {$wpdb->posts}
5453 + INNER JOIN {$wpdb->postmeta} customer
5454 + ON id = customer.post_id
5455 + AND customer.meta_key = '{$user_meta}'
5456 + INNER JOIN {$wpdb->postmeta} tutor_order
5457 + ON id = tutor_order.post_id
5458 + AND tutor_order.meta_key = '_is_tutor_order_for_course'
5459 + WHERE post_type = %s
5460 + AND customer.meta_value = %d
5461 + ORDER BY {$wpdb->posts}.id DESC
5462 + ",
5463 + $post_type,
5464 + $user_id
5465 + ) );
5466 +
5467 + return $orders;
5468 + }
5469 +
5470 + /**
5471 + * @param null $status
6204 5472 *
6205 5473 * @return string
5474 + *
5475 + * Get status contact formatted for order
5476 + *
5477 + * @since v.1.3.1
6206 5478 */
6207 5479 public function order_status_context( $status = null ) {
6208 5480 $status = str_replace( 'wc-', '', $status );
6209 5481 $status_name = ucwords( str_replace( '-', ' ', $status ) );
6210 5482
6211 - return '<span class="label-order-status label-status-' . $status . '">' . $status_name . '</span>';
5483 + return "<span class='label-order-status label-status-{$status}'>$status_name</span>";
6212 5484 }
6213 5485
5486 + public function get_course_id_by_assignment( $assignment_id = 0 ) {
5487 + $assignment_id = $this->get_post_id( $assignment_id );
5488 + return get_post_meta( $assignment_id, '_tutor_course_id_for_assignments', true );
5489 + }
5490 +
6214 5491 /**
6215 - * Get assignment options
5492 + * @param int $assignment_id
5493 + * @param string $option_key
5494 + * @param bool $default
6216 5495 *
6217 - * @since 1.3.3
5496 + * @return array|bool|mixed
6218 5497 *
6219 - * @param int $assignment_id assignment id.
6220 - * @param string $option_key option key.
6221 - * @param bool $default default.
5498 + * Get assignment options
6222 5499 *
6223 - * @return array|bool|mixed
5500 + * @since v.1.3.3
6224 5501 */
6225 5502 public function get_assignment_option( $assignment_id = 0, $option_key = '', $default = false ) {
6226 5503 $assignment_id = $this->get_post_id( $assignment_id );
6227 - $get_option_meta = maybe_unserialize( get_post_meta( $assignment_id, 'assignment_option', true ) );
5504 + $get_option_meta = maybe_unserialize( get_post_meta($assignment_id, 'assignment_option', true ) );
6228 5505
6229 5506 if ( ! $option_key && ! empty( $get_option_meta ) ) {
6230 5507 return $get_option_meta;
6231 5508 }
@@ -6231,9 +5508,9 @@
6231 5508 }
6232 5509
6233 5510 $value = $this->avalue_dot( $option_key, $get_option_meta );
6234 5511
6235 - if ( false !== $value ) {
5512 + if ( $value ) {
6236 5513 return $value;
6237 5514 }
6238 5515
6239 5516 return $default;
@@ -6239,284 +5516,174 @@
6239 5516 return $default;
6240 5517 }
6241 5518
6242 5519 /**
6243 - * Is running any assignment submitting
5520 + * @param int $assignment_id
5521 + * @param int $user_id
6244 5522 *
6245 - * @since 1.3.3
5523 + * @return int
6246 5524 *
6247 - * @param int $assignment_id assignment id.
6248 - * @param int $user_id user id.
5525 + * Is running any assignment submitting
6249 5526 *
6250 - * @return int
5527 + * @since v.1.3.3
6251 5528 */
6252 5529 public function is_assignment_submitting( $assignment_id = 0, $user_id = 0 ) {
6253 5530 global $wpdb;
6254 5531
6255 5532 $assignment_id = $this->get_post_id( $assignment_id );
6256 - $user_id = $this->get_user_id( $user_id );
5533 + $user_id = $this->get_user_id( $user_id );
6257 5534
6258 - $is_running_submit = (int) $wpdb->get_var(
6259 - $wpdb->prepare(
6260 - "SELECT comment_ID
5535 + $is_running_submit = (int) $wpdb->get_var( $wpdb->prepare(
5536 + "SELECT comment_ID
6261 5537 FROM {$wpdb->comments}
6262 - WHERE comment_type = %s
6263 - AND comment_approved = %s
5538 + WHERE comment_type = %s
5539 + AND comment_approved = %s
6264 5540 AND user_id = %d
6265 5541 AND comment_post_ID = %d;
6266 5542 ",
6267 - 'tutor_assignment',
6268 - 'submitting',
6269 - $user_id,
6270 - $assignment_id
6271 - )
6272 - );
5543 + 'tutor_assignment',
5544 + 'submitting',
5545 + $user_id,
5546 + $assignment_id
5547 + ) );
6273 5548
6274 5549 return $is_running_submit;
6275 5550 }
6276 5551
6277 5552 /**
6278 - * Determine if any assignment submitted by user to a assignment.
5553 + * @param int $assignment_id
5554 + * @param int $user_id
6279 5555 *
6280 - * @since 1.3.3
6281 - * @since 3.8.2 param $attempt_id added.
5556 + * @return array|null|object
6282 5557 *
6283 - * @param int $assignment_id assignment id.
6284 - * @param int $user_id user id.
6285 - * @param int $attempt_id the attempt id.
5558 + * Determine if any assignment submitted by user to a assignment
6286 5559 *
6287 - * @return array|null|object
5560 + * @since v.1.3.3
6288 5561 */
6289 - public function is_assignment_submitted( $assignment_id = 0, $user_id = 0, $attempt_id = 0 ) {
5562 + public function is_assignment_submitted( $assignment_id = 0, $user_id = 0 ) {
5563 + global $wpdb;
6290 5564
6291 5565 $assignment_id = $this->get_post_id( $assignment_id );
6292 5566 $user_id = $this->get_user_id( $user_id );
6293 5567
6294 - $cache_key = "tutor_is_assignment_submitted_{$user_id}_{$assignment_id}_{$attempt_id}";
6295 - $has_submitted = TutorCache::get( $cache_key );
5568 + $has_submitted = $wpdb->get_row( $wpdb->prepare(
5569 + "SELECT *
5570 + FROM {$wpdb->comments}
5571 + WHERE comment_type = %s
5572 + AND comment_approved = %s
5573 + AND user_id = %d
5574 + AND comment_post_ID = %d;
5575 + ",
5576 + 'tutor_assignment',
5577 + 'submitted',
5578 + $user_id,
5579 + $assignment_id
5580 + ) );
6296 5581
6297 - if ( false === $has_submitted ) {
6298 -
6299 - $has_submitted = QueryHelper::get_all(
6300 - 'comments',
6301 - array(
6302 - 'comment_type' => 'tutor_assignment',
6303 - 'comment_approved' => 'submitted',
6304 - 'user_id' => $user_id,
6305 - 'comment_post_ID' => $assignment_id,
6306 - ),
6307 - 'comment_ID'
6308 - );
6309 - TutorCache::set( $cache_key, $has_submitted );
6310 - }
6311 -
6312 - if ( $attempt_id ) {
6313 - $has_submitted = QueryHelper::get_row(
6314 - 'comments',
6315 - array(
6316 - 'comment_ID' => $attempt_id,
6317 - 'comment_type' => 'tutor_assignment',
6318 - 'comment_approved' => 'submitted',
6319 - 'user_id' => $user_id,
6320 - 'comment_post_ID' => $assignment_id,
6321 - ),
6322 - 'comment_ID'
6323 - );
6324 - TutorCache::set( $cache_key, $has_submitted );
6325 - }
6326 -
6327 5582 return $has_submitted;
6328 5583 }
6329 5584
6330 - /**
6331 - * Get assignment submitted info
6332 - *
6333 - * @since 1.0.0
6334 - *
6335 - * @param integer $assignment_submitted_id assignment submitted id.
6336 - *
6337 - * @return mixed
6338 - */
6339 5585 public function get_assignment_submit_info( $assignment_submitted_id = 0 ) {
6340 5586 global $wpdb;
6341 5587
6342 5588 $assignment_submitted_id = $this->get_post_id( $assignment_submitted_id );
6343 5589
6344 - $submitted_info = $wpdb->get_row(
6345 - $wpdb->prepare(
6346 - "SELECT *
5590 + $submitted_info = $wpdb->get_row( $wpdb->prepare(
5591 + "SELECT *
6347 5592 FROM {$wpdb->comments}
6348 5593 WHERE comment_ID = %d
6349 5594 AND comment_type = %s
6350 5595 AND comment_approved = %s;
6351 5596 ",
6352 - $assignment_submitted_id,
6353 - 'tutor_assignment',
6354 - 'submitted'
6355 - )
6356 - );
5597 + $assignment_submitted_id,
5598 + 'tutor_assignment',
5599 + 'submitted'
5600 + ) );
6357 5601
6358 5602 return $submitted_info;
6359 5603 }
6360 5604
6361 - /**
6362 - * It is redundant and will be removed later
6363 - *
6364 - * @since 1.0.0
6365 - * @deprecated 1.9.8
6366 - *
6367 - * @return int
6368 - */
6369 5605 public function get_total_assignments() {
6370 5606 global $wpdb;
6371 5607
6372 - $count = $wpdb->get_var(
6373 - $wpdb->prepare(
6374 - "SELECT COUNT(comment_ID)
5608 + $count = $wpdb->get_var( $wpdb->prepare(
5609 + "SELECT COUNT(comment_ID)
6375 5610 FROM {$wpdb->comments}
6376 5611 WHERE comment_type = %s
6377 5612 AND comment_approved = %s;
6378 5613 ",
6379 - 'tutor_assignment',
6380 - 'submitted'
6381 - )
6382 - );
5614 + 'tutor_assignment',
5615 + 'submitted'
5616 + ) );
6383 5617
6384 5618 return (int) $count;
6385 5619 }
6386 5620
6387 - /**
6388 - * It is redundant and will be removed later
6389 - *
6390 - * @since 1.0.0
6391 - * @deprecated 1.9.8
6392 - *
6393 - * @return mixed
6394 - */
6395 5621 public function get_assignments() {
6396 5622 global $wpdb;
6397 5623
6398 - $results = $wpdb->get_results(
6399 - $wpdb->prepare(
6400 - "SELECT *
5624 + $results = $wpdb->get_results( $wpdb->prepare(
5625 + "SELECT *
6401 5626 FROM {$wpdb->comments}
6402 5627 WHERE comment_type = %s
6403 5628 AND comment_approved = %s;
6404 5629 ",
6405 - 'tutor_assignment',
6406 - 'submitted'
6407 - )
6408 - );
5630 + 'tutor_assignment',
5631 + 'submitted'
5632 + ) );
6409 5633
6410 5634 return $results;
6411 5635 }
6412 5636
6413 5637 /**
6414 - * Get all courses id assigned or owned by an instructors
5638 + * @param int $user_id
6415 5639 *
6416 - * @since 1.3.3
6417 - * @since 4.0.5 $status param added to filter by instructor status.
5640 + * @return array
6418 5641 *
6419 - * @param int $user_id user id.
6420 - * @param string $status Optional instructor status to filter by, e.g. 'approved'. Empty to skip the filter.
5642 + * Get all courses id assigned or owned by an instructors
6421 5643 *
6422 - * @return array
5644 + * @since v.1.3.3
6423 5645 */
6424 - public function get_assigned_courses_ids_by_instructors( $user_id = 0, $status = '' ) {
5646 + public function get_assigned_courses_ids_by_instructors( $user_id = 0 ) {
6425 5647 global $wpdb;
6426 - $user_id = $this->get_user_id( $user_id );
5648 + $user_id = $this->get_user_id( $user_id );
5649 + $course_post_type = tutor()->course_post_type;
6427 5650
6428 - $where_clause = "meta.meta_key = '_tutor_instructor_course_id' AND meta.user_id = %d";
6429 - $args = array( $user_id );
5651 + $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare(
5652 + "SELECT meta_value
5653 + FROM {$wpdb->usermeta}
5654 + WHERE meta_key = %s
5655 + AND user_id = %d
5656 + GROUP BY meta_value;
5657 + ",
5658 + '_tutor_instructor_course_id',
5659 + $user_id
5660 + ) );
6430 5661
6431 - if ( ! empty( $status ) ) {
6432 - $where_clause .= " AND EXISTS(
6433 - SELECT 1
6434 - FROM {$wpdb->usermeta} meta_status
6435 - WHERE meta_status.user_id = meta.user_id
6436 - AND meta_status.meta_key = '_tutor_instructor_status'
6437 - AND meta_status.meta_value = %s
6438 - )";
6439 - $args[] = $status;
6440 - }
6441 -
6442 - $course_ids = $wpdb->get_col(
6443 - $wpdb->prepare(
6444 - "SELECT meta.meta_value
6445 - FROM {$wpdb->usermeta} meta
6446 - INNER JOIN {$wpdb->posts} course ON meta.meta_value = course.ID
6447 - WHERE {$where_clause} GROUP BY meta.meta_value", //phpcs:ignore
6448 - ...$args
6449 - )
6450 - );
6451 -
6452 - return array_map( 'intval', $course_ids );
5662 + return $get_assigned_courses_ids;
6453 5663 }
6454 5664
6455 5665 /**
6456 - * Get course categories in array with child
5666 + * @param int $parent
6457 5667 *
6458 - * @since 1.3.4
5668 + * @return array
6459 5669 *
6460 - * @param int $parent parent.
6461 - * @param array $custom_args Custom args.
6462 - * @param bool $top_level_children top level children.
5670 + * Get course categories in array with child
6463 5671 *
6464 - * @return array
5672 + * @since v.1.3.4
6465 5673 */
6466 - public function get_course_categories( $parent = 0, $custom_args = array(), $top_level_children = false ) {
6467 - $default_args = array(
6468 - 'taxonomy' => CourseModel::COURSE_CATEGORY,
5674 + public function get_course_categories( $parent = 0 ) {
5675 + $args = apply_filters( 'tutor_get_course_categories_args', array(
5676 + 'taxonomy' => 'course-category',
6469 5677 'hide_empty' => false,
6470 - );
5678 + 'parent' => $parent,
5679 + ));
6471 5680
6472 - if ( $parent > 0 ) {
6473 - $default_args['parent'] = $parent;
6474 - }
6475 -
6476 - $default = apply_filters(
6477 - 'tutor_get_course_categories_args',
6478 - $default_args
6479 - );
6480 -
6481 - $args = wp_parse_args( $custom_args, $default );
6482 -
6483 5681 $terms = get_terms( $args );
6484 5682
6485 - if ( $top_level_children ) {
6486 - return $terms;
6487 - }
6488 -
6489 - return $this->build_term_tree( $terms, $parent );
6490 - }
6491 -
6492 - /**
6493 - * Get course tags in array with child
6494 - *
6495 - * @since 1.9.3
6496 - *
6497 - * @since 3.6.0 Custom args param added
6498 - *
6499 - * @param array $custom_args Custom args.
6500 - *
6501 - * @return array
6502 - */
6503 - public function get_course_tags( $custom_args = array() ) {
6504 - $default_args = apply_filters(
6505 - 'tutor_get_course_tags_args',
6506 - array(
6507 - 'taxonomy' => CourseModel::COURSE_TAG,
6508 - 'hide_empty' => false,
6509 - )
6510 - );
6511 -
6512 - $args = wp_parse_args( $custom_args, $default_args );
6513 -
6514 - $terms = get_terms( $args );
6515 -
6516 5683 $children = array();
6517 5684 foreach ( $terms as $term ) {
6518 - $term->children = array();
5685 + $term->children = $this->get_course_categories( $term->term_id );
6519 5686 $children[ $term->term_id ] = $term;
6520 5687 }
6521 5688
6522 5689 return $children;
@@ -6522,25 +5689,22 @@
6522 5689 return $children;
6523 5690 }
6524 5691
6525 5692 /**
6526 - * Get course categories terms in raw array
5693 + * @param int $parent_id
6527 5694 *
6528 - * @since 1.3.5
5695 + * @return array|int|\WP_Error
6529 5696 *
6530 - * @param int $parent_id parent id.
5697 + * Get course categories terms in raw array
6531 5698 *
6532 - * @return array|int|\WP_Error
5699 + * @since v.1.3.5
6533 5700 */
6534 5701 public function get_course_categories_term( $parent_id = 0 ) {
6535 - $args = apply_filters(
6536 - 'tutor_get_course_categories_terms_args',
6537 - array(
6538 - 'taxonomy' => CourseModel::COURSE_CATEGORY,
6539 - 'parent' => $parent_id,
6540 - 'hide_empty' => false,
6541 - )
6542 - );
5702 + $args = apply_filters( 'tutor_get_course_categories_terms_args', array(
5703 + 'taxonomy' => 'course-category',
5704 + 'parent' => $parent_id,
5705 + 'hide_empty' => false,
5706 + ));
6543 5707
6544 5708 $terms = get_terms( $args );
6545 5709
6546 5710 return $terms;
@@ -6546,13 +5710,12 @@
6546 5710 return $terms;
6547 5711 }
6548 5712
6549 5713 /**
5714 + * @return mixed
5715 + *
6550 5716 * Get back url from the request
6551 - *
6552 - * @since 1.3.4
6553 - *
6554 - * @return mixed
5717 + * @since v.1.3.4
6555 5718 */
6556 5719 public function referer() {
6557 5720 $url = $this->array_get( '_wp_http_referer', $_REQUEST );
6558 5721 return apply_filters( 'tutor_referer_url', $url );
@@ -6558,100 +5721,49 @@
6558 5721 return apply_filters( 'tutor_referer_url', $url );
6559 5722 }
6560 5723
6561 5724 /**
6562 - * Get HTTP referer field
5725 + * @param int $course_id
6563 5726 *
6564 - * @since 2.5.0
5727 + * @return false|string
6565 5728 *
6566 - * @param boolean $url_decode URL decode for unicode support.
6567 - *
6568 - * @return void|string
6569 - */
6570 - public function referer_field( $url_decode = true ) {
6571 - $url = remove_query_arg( '_wp_http_referer' );
6572 - if ( $url_decode ) {
6573 - $url = urldecode( $url );
6574 - }
6575 -
6576 - echo '<input type="hidden" name="_wp_http_referer" value="' . esc_url( $url ) . '">';
6577 - }
6578 -
6579 - /**
6580 5729 * Get the frontend dashboard course edit page
6581 5730 *
6582 - * @since 1.3.4
6583 - * @since 3.0.0 hide admin bar support and location param added.
6584 - *
6585 - * @param int $course_id course id.
6586 - * @param mixed $location possible values `null|backend|frontend`.
6587 - *
6588 - * @return false|string
5731 + * @since v.1.3.4
6589 5732 */
6590 - public function course_edit_link( $course_id = 0, $location = null ) {
6591 - $course_id = $this->get_post_id( $course_id );
6592 - $frontend_url = $this->tutor_dashboard_url( 'create-course?course_id=' . $course_id );
6593 - $backend_url = admin_url( "admin.php?page=create-course&course_id={$course_id}" );
5733 + public function course_edit_link( $course_id = 0 ) {
5734 + $course_id = $this->get_post_id( $course_id );
6594 5735
6595 - $url = $frontend_url;
6596 - if ( is_null( $location ) ) {
6597 - if ( User::is_admin() || ! (bool) get_tutor_option( 'hide_admin_bar_for_users' ) ) {
6598 - $url = $backend_url;
6599 - }
6600 - } elseif ( 'backend' === $location ) {
6601 - $url = $backend_url;
5736 + $url = admin_url("post.php?post={$course_id}&action=edit");
5737 + if ( tutor()->has_pro ) {
5738 + $url = $this->tutor_dashboard_url( "create-course/?course_ID=" . $course_id );
6602 5739 }
6603 5740
6604 5741 return $url;
6605 5742 }
6606 5743
6607 - /**
6608 - * Get assignments by instructor
6609 - *
6610 - * @since 1.0.0
6611 - *
6612 - * @param integer $instructor_id instructor id.
6613 - * @param array $filter_data filter data.
6614 - *
6615 - * @return mixed
6616 - */
6617 5744 public function get_assignments_by_instructor( $instructor_id = 0, $filter_data = array() ) {
6618 5745 global $wpdb;
6619 5746
6620 5747 $instructor_id = $this->get_user_id( $instructor_id );
6621 - $course_ids = $this->get_assigned_courses_ids_by_instructors( $instructor_id );
5748 + $course_ids = tutor_utils()->get_assigned_courses_ids_by_instructors( $instructor_id );
6622 5749 $assignment_post_type = 'tutor_assignments';
6623 5750
6624 - $in_course_ids = QueryHelper::prepare_in_clause( $course_ids );
5751 + $in_course_ids = implode( "','", $course_ids );
6625 5752
6626 - $pagination_query = '';
6627 - $date_query = '';
6628 - $search_query = '';
6629 - $sort_query = 'ORDER BY ID DESC';
6630 -
5753 + $pagination_query = $date_query = '';
5754 + $sort_query = 'ORDER BY ID DESC';
6631 5755 if ( $this->count( $filter_data ) ) {
6632 - extract( $filter_data );//phpcs:ignore
5756 + extract( $filter_data );
6633 5757
6634 - if ( ! empty( $search_filter ) ) {
6635 - $like = '%' . $wpdb->esc_like( $search_filter ) . '%';
6636 - $search_query = $wpdb->prepare(
6637 - ' AND assignment.post_title LIKE %s ',
6638 - $like
6639 - );
6640 - }
6641 -
6642 5758 if ( ! empty( $course_id ) ) {
6643 5759 $in_course_ids = $course_id;
6644 5760 }
6645 - if ( ! empty( $start_date ) && ! empty( $end_date ) ) {
6646 - $start_date = tutor_get_formated_date( 'Y-m-d', $start_date );
6647 - $end_date = tutor_get_formated_date( 'Y-m-d', $end_date );
6648 -
6649 - $date_query = $wpdb->prepare( 'AND DATE(post_date) BETWEEN %s AND %s', $start_date, $end_date );
5761 + if ( ! empty( $date_filter ) ) {
5762 + $date_query = " AND DATE(post_date) = '{$date_filter}'";
6650 5763 }
6651 5764 if ( ! empty( $order_filter ) ) {
6652 - $order_filter = QueryHelper::get_valid_sort_order( $order_filter );
6653 - $sort_query = " ORDER BY ID {$order_filter} ";
5765 + $sort_query = " ORDER BY ID {$order_filter} ";
6654 5766 }
6655 5767 if ( ! empty( $per_page ) ) {
6656 5768 $offset = (int) ! empty( $offset ) ? $offset : 0;
6657 5769 $pagination_query = " LIMIT {$offset}, {$per_page} ";
@@ -6657,58 +5769,45 @@
6657 5769 $pagination_query = " LIMIT {$offset}, {$per_page} ";
6658 5770 }
6659 5771 }
6660 5772
6661 - $count = (int) $wpdb->get_var(
6662 - $wpdb->prepare(
6663 - "SELECT COUNT(ID)
5773 + $count = (int) $wpdb->get_var( $wpdb->prepare(
5774 + "SELECT COUNT(ID)
6664 5775 FROM {$wpdb->postmeta} post_meta
6665 5776 INNER JOIN {$wpdb->posts} assignment
6666 5777 ON post_meta.post_id = assignment.ID
6667 5778 AND post_meta.meta_key = '_tutor_course_id_for_assignments'
6668 5779 WHERE post_type = %s
6669 - AND assignment.post_parent>0
6670 - AND post_meta.meta_value IN({$in_course_ids})
5780 + AND post_meta.meta_value IN('$in_course_ids')
6671 5781 {$date_query}
6672 - {$search_query}
6673 5782 ",
6674 - $assignment_post_type
6675 - )
6676 - );
5783 + $assignment_post_type
5784 + ) );
6677 5785
6678 - $query = $wpdb->get_results(
6679 - $wpdb->prepare(
6680 - "SELECT *
5786 + $query = $wpdb->get_results( $wpdb->prepare(
5787 + "SELECT *
6681 5788 FROM {$wpdb->postmeta} post_meta
6682 5789 INNER JOIN {$wpdb->posts} assignment
6683 5790 ON post_meta.post_id = assignment.ID
6684 5791 AND post_meta.meta_key = '_tutor_course_id_for_assignments'
6685 5792 WHERE post_type = %s
6686 - AND assignment.post_parent>0
6687 - AND post_meta.meta_value IN({$in_course_ids})
5793 + AND post_meta.meta_value IN('$in_course_ids')
6688 5794 {$date_query}
6689 - {$search_query}
6690 5795 {$sort_query}
6691 5796 {$pagination_query}
6692 5797 ",
6693 - $assignment_post_type
6694 - )
6695 - );
5798 + $assignment_post_type
5799 + ) );
6696 5800
6697 - return (object) array(
6698 - 'count' => $count,
6699 - 'results' => $query,
6700 - );
5801 + return (object) array( 'count' => $count, 'results' => $query );
6701 5802 }
6702 5803
6703 5804 /**
6704 - * Get assignments by course id
5805 + * @param int $course_id
6705 5806 *
6706 - * @since 1.0.0
5807 + * @return bool|object
6707 5808 *
6708 - * @param int $course_id course id.
6709 - *
6710 - * @return bool|object
5809 + * Get assignments by course id
6711 5810 */
6712 5811 public function get_assignments_by_course( $course_id = 0 ) {
6713 5812 if ( ! $course_id ) {
6714 5813 return false;
@@ -6716,11 +5815,10 @@
6716 5815 global $wpdb;
6717 5816
6718 5817 $assignment_post_type = 'tutor_assignments';
6719 5818
6720 - $count = (int) $wpdb->get_var(
6721 - $wpdb->prepare(
6722 - "SELECT COUNT(ID)
5819 + $count = (int) $wpdb->get_var( $wpdb->prepare(
5820 + "SELECT COUNT(ID)
6723 5821 FROM {$wpdb->postmeta} post_meta
6724 5822 INNER JOIN {$wpdb->posts} assignment
6725 5823 ON post_meta.post_id = assignment.ID
6726 5824 AND post_meta.meta_key = '_tutor_course_id_for_assignments'
@@ -6727,16 +5825,14 @@
6727 5825 WHERE post_type = %s
6728 5826 AND post_meta.meta_value = %d
6729 5827 ORDER BY ID DESC;
6730 5828 ",
6731 - $assignment_post_type,
6732 - $course_id
6733 - )
6734 - );
5829 + $assignment_post_type,
5830 + $course_id
5831 + ) );
6735 5832
6736 - $query = $wpdb->get_results(
6737 - $wpdb->prepare(
6738 - "SELECT *
5833 + $query = $wpdb->get_results( $wpdb->prepare(
5834 + "SELECT *
6739 5835 FROM {$wpdb->postmeta} post_meta
6740 5836 INNER JOIN {$wpdb->posts} assignment
6741 5837 ON post_meta.post_id = assignment.ID
6742 5838 AND post_meta.meta_key = '_tutor_course_id_for_assignments'
@@ -6743,25 +5839,21 @@
6743 5839 WHERE post_type = %s
6744 5840 AND post_meta.meta_value = %d
6745 5841 ORDER BY ID DESC;
6746 5842 ",
6747 - $assignment_post_type,
6748 - $course_id
6749 - )
6750 - );
5843 + $assignment_post_type,
5844 + $course_id
5845 + ) );
6751 5846
6752 - return (object) array(
6753 - 'count' => $count,
6754 - 'results' => $query,
6755 - );
5847 + return (object) array( 'count' => $count, 'results' => $query );
6756 5848 }
6757 5849
6758 5850 /**
5851 + * @return bool
5852 + *
6759 5853 * Determine if script debug
6760 5854 *
6761 - * @since 1.3.4
6762 - *
6763 - * @return bool
5855 + * @since v.1.3.4
6764 5856 */
6765 5857 public function is_script_debug() {
6766 5858 return ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG );
6767 5859 }
@@ -6768,14 +5860,9 @@
6768 5860
6769 5861 /**
6770 5862 * Check lesson edit access by instructor
6771 5863 *
6772 - * @since 1.4.0
6773 - *
6774 - * @param int $lesson_id lesson id.
6775 - * @param int $instructor_id instructor id.
6776 - *
6777 - * @return bool
5864 + * @since v.1.4.0
6778 5865 */
6779 5866 public function has_lesson_edit_access( $lesson_id = 0, $instructor_id = 0 ) {
6780 5867 $lesson_id = $this->get_post_id( $lesson_id );
6781 5868 $instructor_id = $this->get_user_id( $instructor_id );
@@ -6780,10 +5867,10 @@
6780 5867 $lesson_id = $this->get_post_id( $lesson_id );
6781 5868 $instructor_id = $this->get_user_id( $instructor_id );
6782 5869
6783 5870 if ( user_can( $instructor_id, tutor()->instructor_role ) ) {
6784 - $permitted_course_ids = $this->get_assigned_courses_ids_by_instructors();
6785 - $course_id = $this->get_course_id_by( 'lesson', $lesson_id );
5871 + $permitted_course_ids = tutils()->get_assigned_courses_ids_by_instructors();
5872 + $course_id = tutils()->get_course_id_by_lesson( $lesson_id );
6786 5873
6787 5874 if ( in_array( $course_id, $permitted_course_ids ) ) {
6788 5875 return true;
6789 5876 }
@@ -6793,15 +5880,80 @@
6793 5880 }
6794 5881
6795 5882
6796 5883 /**
6797 - * Get current URL
5884 + * Get total Enrolments
5885 + * @since v.1.4.0
5886 + */
5887 + public function get_total_enrolments( $search_term = '' ) {
5888 + global $wpdb;
5889 +
5890 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5891 +
5892 + $count = $wpdb->get_var( $wpdb->prepare(
5893 + "SELECT COUNT(enrol.ID)
5894 + FROM {$wpdb->posts} enrol
5895 + INNER JOIN {$wpdb->posts} course
5896 + ON enrol.post_parent = course.ID
5897 + INNER JOIN {$wpdb->users} student
5898 + ON enrol.post_author = student.ID
5899 + WHERE enrol.post_type = %s
5900 + AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s );
5901 + ",
5902 + 'tutor_enrolled',
5903 + $search_term,
5904 + $search_term,
5905 + $search_term,
5906 + $search_term
5907 + ) );
5908 +
5909 + return (int) $count;
5910 + }
5911 +
5912 + public function get_enrolments( $start = 0, $limit = 10, $search_term = '' ) {
5913 + global $wpdb;
5914 +
5915 + $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
5916 +
5917 + $enrolments = $wpdb->get_results( $wpdb->prepare(
5918 + "SELECT enrol.ID AS enrol_id,
5919 + enrol.post_author AS student_id,
5920 + enrol.post_date AS enrol_date,
5921 + enrol.post_title AS enrol_title,
5922 + enrol.post_status AS status,
5923 + enrol.post_parent AS course_id,
5924 + course.post_title AS course_title,
5925 + student.user_nicename,
5926 + student.user_email,
5927 + student.display_name
5928 + FROM {$wpdb->posts} enrol
5929 + INNER JOIN {$wpdb->posts} course
5930 + ON enrol.post_parent = course.ID
5931 + INNER JOIN {$wpdb->users} student
5932 + ON enrol.post_author = student.ID
5933 + WHERE enrol.post_type = %s
5934 + AND ( enrol.ID LIKE %s OR student.display_name LIKE %s OR student.user_email LIKE %s OR course.post_title LIKE %s )
5935 + ORDER BY enrol_id DESC
5936 + LIMIT %d, %d;
5937 + ",
5938 + 'tutor_enrolled',
5939 + $search_term,
5940 + $search_term,
5941 + $search_term,
5942 + $search_term,
5943 + $start,
5944 + $limit
5945 + ) );
5946 +
5947 + return $enrolments;
5948 + }
5949 +
5950 + /**
5951 + * @param int $post_id
6798 5952 *
6799 - * @since 1.4.0
5953 + * @return false|string
6800 5954 *
6801 - * @param int $post_id post ID.
6802 - *
6803 - * @return false|string
5955 + * @since v.1.4.0
6804 5956 */
6805 5957 public function get_current_url( $post_id = 0 ) {
6806 5958 $page_id = $this->get_post_id( $post_id );
6807 5959
@@ -6808,9 +5960,8 @@
6808 5960 if ( $page_id ) {
6809 5961 return get_the_permalink( $page_id );
6810 5962 } else {
6811 5963 global $wp;
6812 - $wp->parse_request();
6813 5964 $current_url = home_url( $wp->request );
6814 5965 return $current_url;
6815 5966 }
6816 5967 }
@@ -6815,16 +5966,17 @@
6815 5966 }
6816 5967 }
6817 5968
6818 5969 /**
6819 - * Get rating by rating id|comment_ID
5970 + * @param int $rating_id
6820 5971 *
6821 - * @since 1.4.0
5972 + * @return object
6822 5973 *
6823 - * @param int $rating_id rating id.
5974 + * Get rating by rating id|comment_ID
6824 5975 *
6825 - * @return object
5976 + * @since v.1.4.0
6826 5977 */
5978 +
6827 5979 public function get_rating_by_id( $rating_id = 0 ) {
6828 5980 global $wpdb;
6829 5981
6830 5982 $ratings = array(
@@ -6831,27 +5983,25 @@
6831 5983 'rating' => 0,
6832 5984 'review' => '',
6833 5985 );
6834 5986
6835 - $rating = $wpdb->get_row(
6836 - $wpdb->prepare(
6837 - "SELECT meta_value AS rating,
5987 + $rating = $wpdb->get_row( $wpdb->prepare(
5988 + "SELECT meta_value AS rating,
6838 5989 comment_content AS review
6839 5990 FROM {$wpdb->comments}
6840 - INNER JOIN {$wpdb->commentmeta}
6841 - ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
5991 + INNER JOIN {$wpdb->commentmeta}
5992 + ON {$wpdb->comments}.comment_ID = {$wpdb->commentmeta}.comment_id
6842 5993 WHERE {$wpdb->comments}.comment_ID = %d;
6843 - ",
6844 - $rating_id
6845 - )
6846 - );
5994 + ",
5995 + $rating_id
5996 + ) );
6847 5997
6848 5998 if ( $rating ) {
6849 5999 $rating_format = number_format( $rating->rating, 2 );
6850 6000
6851 6001 $ratings = array(
6852 - 'rating' => $rating_format,
6853 - 'review' => $rating->review,
6002 + 'rating' => $rating_format,
6003 + 'review' => $rating->review,
6854 6004 );
6855 6005 }
6856 6006 return (object) $ratings;
6857 6007 }
@@ -6856,17 +6006,15 @@
6856 6006 return (object) $ratings;
6857 6007 }
6858 6008
6859 6009 /**
6860 - * Get course settings by course ID
6010 + * @param int $course_id
6011 + * @param null $key
6012 + * @param bool $default
6861 6013 *
6862 - * @since 1.4.0
6014 + * @return array|bool|mixed
6863 6015 *
6864 - * @param int $course_id course id.
6865 - * @param null $key key.
6866 - * @param bool $default default value.
6867 - *
6868 - * @return array|bool|mixed
6016 + * Get course settings by course ID
6869 6017 */
6870 6018 public function get_course_settings( $course_id = 0, $key = null, $default = false ) {
6871 6019 $course_id = $this->get_post_id( $course_id );
6872 6020 $settings_meta = get_post_meta( $course_id, '_tutor_course_settings', true );
@@ -6875,17 +6023,17 @@
6875 6023 return $this->array_get( $key, $settings, $default );
6876 6024 }
6877 6025
6878 6026 /**
6879 - * Get Lesson content drip settings
6027 + * @param int $lesson_id
6028 + * @param null $key
6029 + * @param bool $default
6880 6030 *
6881 - * @since 1.4.0
6031 + * @return array|bool|mixed
6882 6032 *
6883 - * @param int $lesson_id lesson id.
6884 - * @param null $key key.
6885 - * @param bool $default default value.
6033 + * Get Lesson content drip settings
6886 6034 *
6887 - * @return array|bool|mixed
6035 + * @since v.1.4.0
6888 6036 */
6889 6037 public function get_item_content_drip_settings( $lesson_id = 0, $key = null, $default = false ) {
6890 6038 $lesson_id = $this->get_post_id( $lesson_id );
6891 6039 $settings_meta = get_post_meta( $lesson_id, '_content_drip_settings', true );
@@ -6894,37 +6042,42 @@
6894 6042 return $this->array_get( $key, $settings, $default );
6895 6043 }
6896 6044
6897 6045 /**
6898 - * Get course previous content ID
6046 + * @param null $post
6899 6047 *
6900 - * @since 1.4.0
6048 + * @return bool
6901 6049 *
6902 - * @param int $current_id current id.
6903 - * @param array $exclude_type types.
6904 - *
6905 - * @return mixed
6050 + * Get previous ID
6906 6051 */
6907 - public function get_course_previous_content_id( $current_id, $exclude_type = array() ) {
6908 - $course_id = $this->get_course_id_by_content( $current_id );
6909 - $topics = $this->get_topics( $course_id );
6052 + public function get_course_previous_content_id( $post = null ) {
6053 + $current_item = get_post( $post );
6054 + $course_id = $this->get_course_id_by_content( $current_item );
6055 + $topics = tutor_utils()->get_topics( $course_id );
6910 6056
6911 - $content_ids = array();
6057 + $contents = array();
6058 + if ( $topics->have_posts() ) {
6059 + while ( $topics->have_posts() ) {
6060 + $topics->the_post();
6061 + $topic_id = get_the_ID();
6062 + $lessons = tutor_utils()->get_course_contents_by_topic( $topic_id, -1 );
6063 + if ( $lessons->have_posts() ) {
6064 + while ( $lessons->have_posts() ) {
6065 + $lessons->the_post();
6066 + global $post;
6067 + $contents[] = $post;
6068 + }
6069 + }
6912 6070
6913 - foreach ( $topics->posts as $topic ) {
6914 - $contents = $this->get_course_contents_by_topic( $topic->ID, -1 );
6915 -
6916 - foreach ( $contents->posts as $content ) {
6917 - if ( ! in_array( $content->post_type, $exclude_type ) ) {
6918 - $content_ids[] = $content->ID;
6919 - }
6920 6071 }
6921 6072 }
6922 6073
6923 - foreach ( $content_ids as $key => $content_id ) {
6924 - if ( $current_id == $content_id ) {
6925 - if ( ! empty( $content_ids[ $key - 1 ] ) ) {
6926 - return $content_ids[ $key - 1 ];
6074 + if ( tutils()->count( $contents) ) {
6075 + foreach ( $contents as $key => $content ) {
6076 + if ( $current_item->ID == $content->ID ) {
6077 + if ( ! empty( $contents[ $key-1 ]->ID ) ) {
6078 + return $contents[ $key-1 ]->ID;
6079 + }
6927 6080 }
6928 6081 }
6929 6082 }
6930 6083
@@ -6931,29 +6084,39 @@
6931 6084 return false;
6932 6085 }
6933 6086
6934 6087 /**
6935 - * Get Course ID by any course content
6088 + * @param null $post
6936 6089 *
6937 - * @since 1.0.0
6090 + * @return int
6938 6091 *
6939 - * @param object $post post object.
6940 - *
6941 - * @return int
6092 + * Get Course iD by any course content
6942 6093 */
6943 - public function get_course_id_by_content( $post ) {
6944 - return $this->get_course_id_by_subcontent( is_numeric( $post ) ? $post : $post->ID );
6094 + public function get_course_id_by_content( $post = null ) {
6095 + global $wpdb;
6096 + $post = get_post( $post );
6097 +
6098 + $course_id = $wpdb->get_var( $wpdb->prepare(
6099 + "SELECT post_parent
6100 + FROM {$wpdb->posts}
6101 + WHERE ID = %d
6102 + AND post_type = %s
6103 + ",
6104 + $post->post_parent,
6105 + 'topics'
6106 + ) );
6107 +
6108 + return (int) $course_id;
6945 6109 }
6946 6110
6947 6111 /**
6948 - * Get Course contents by Course ID
6112 + * @param int $course_id
6949 6113 *
6950 - * @since 1.4.1
6951 - * @since 3.0.0 filterable `post_type` and where clause support added.
6114 + * @return array|null|object
6952 6115 *
6953 - * @param int $course_id course id.
6116 + * Get Course contents by Course ID
6954 6117 *
6955 - * @return array|null|object
6118 + * @since v.1.4.1
6956 6119 */
6957 6120 public function get_course_contents_by_id( $course_id = 0 ) {
6958 6121 global $wpdb;
6959 6122
@@ -6958,80 +6121,114 @@
6958 6121 global $wpdb;
6959 6122
6960 6123 $course_id = $this->get_post_id( $course_id );
6961 6124
6962 - $cache_key = "tutor_get_course_contents_by_{$course_id}";
6125 + $contents = $wpdb->get_results( $wpdb->prepare(
6126 + "SELECT items.*
6127 + FROM {$wpdb->posts} topic
6128 + INNER JOIN {$wpdb->posts} items
6129 + ON topic.ID = items.post_parent
6130 + WHERE topic.post_parent = %d
6131 + AND items.post_status = %s
6132 + ORDER BY topic.menu_order ASC,
6133 + items.menu_order ASC;
6134 + ",
6135 + $course_id,
6136 + 'publish'
6137 + ) );
6963 6138
6964 - $contents = TutorCache::get( $cache_key );
6965 - if ( false === $contents ) {
6966 - $conditions = array(
6967 - $wpdb->prepare( 'topic.post_parent = %d', $course_id ),
6968 - $wpdb->prepare( 'items.post_status = %s', CourseModel::STATUS_PUBLISH ),
6969 - );
6970 -
6971 - $default_post_types = array( tutor()->lesson_post_type, tutor()->quiz_post_type );
6972 - $content_post_types = array_unique( apply_filters( 'tutor_course_contents_post_types', $default_post_types ) );
6973 -
6974 - if ( $this->count( $content_post_types ) ) {
6975 - $placeholders = implode( ', ', array_fill( 0, count( $content_post_types ), '%s' ) );
6976 - $conditions[] = $wpdb->prepare( "items.post_type IN ($placeholders)", ...$content_post_types );
6977 - }
6978 -
6979 - $conditions = apply_filters( 'tutor_course_contents_where_clause', $conditions, $course_id );
6980 - $where_clause = 'WHERE ' . implode( ' AND ', $conditions );
6981 -
6982 - $contents = $wpdb->get_results(
6983 - "SELECT items.*
6984 - FROM {$wpdb->posts} topic
6985 - INNER JOIN {$wpdb->posts} items
6986 - ON topic.ID = items.post_parent
6987 - {$where_clause}
6988 - ORDER BY topic.menu_order ASC,
6989 - items.menu_order ASC;
6990 - "
6991 - );
6992 -
6993 - TutorCache::set( $cache_key, $contents );
6994 - }
6995 -
6996 6139 return $contents;
6997 6140 }
6998 6141
6999 6142 /**
6143 + * @param string $grade_for
6144 + *
6145 + * @return array|null|object
6146 + *
7000 6147 * Get Gradebooks lists by type
7001 6148 *
7002 - * @since 1.4.2
7003 - *
7004 - * @return array|null|object
6149 + * @since v.1.4.2
7005 6150 */
7006 6151 public function get_gradebooks() {
7007 6152 global $wpdb;
7008 - $results = $wpdb->get_results( "SELECT * FROM {$wpdb->tutor_gradebooks} ORDER BY grade_point DESC " );
6153 + $results = $wpdb->get_results("SELECT * FROM {$wpdb->tutor_gradebooks} ORDER BY grade_point DESC ");
7009 6154 return $results;
7010 6155 }
7011 6156
6157 +
7012 6158 /**
7013 - * Print Course Status Context
6159 + * @param int $quiz_id
6160 + * @param int $user_id
7014 6161 *
7015 - * @param int $course_id course id.
7016 - * @param int $user_id user id.
6162 + * @return array|bool|null|object
7017 6163 *
6164 + * Get Attempt row by grade method settings
6165 + *
6166 + * @since v.1.4.2
6167 + */
6168 + public function get_quiz_attempt( $quiz_id = 0, $user_id = 0 ) {
6169 + global $wpdb;
6170 +
6171 + $quiz_id = $this->get_post_id( $quiz_id );
6172 + $user_id = $this->get_user_id( $user_id );
6173 +
6174 + $attempt = false;
6175 +
6176 + $quiz_grade_method = get_tutor_option( 'quiz_grade_method', 'highest_grade' );
6177 + $from_string = "FROM {$wpdb->tutor_quiz_attempts} WHERE quiz_id = %d AND user_id = %d AND attempt_status != 'attempt_started' ";
6178 +
6179 + if ( $quiz_grade_method === 'highest_grade') {
6180 +
6181 + $attempt = $wpdb->get_row( $wpdb->prepare( "SELECT * {$from_string} ORDER BY earned_marks DESC LIMIT 1; ", $quiz_id, $user_id ) );
6182 +
6183 + } elseif ($quiz_grade_method === 'average_grade' ) {
6184 +
6185 + $attempt = $wpdb->get_row( $wpdb->prepare(
6186 + "SELECT {$wpdb->tutor_quiz_attempts}.*,
6187 + COUNT(attempt_id) AS attempt_count,
6188 + AVG(total_marks) AS total_marks,
6189 + AVG(earned_marks) AS earned_marks {$from_string}
6190 + ",
6191 + $quiz_id,
6192 + $user_id
6193 + ) );
6194 +
6195 + } elseif ( $quiz_grade_method === 'first_attempt' ) {
6196 +
6197 + $attempt = $wpdb->get_row( $wpdb->prepare( "SELECT * {$from_string} ORDER BY attempt_id ASC LIMIT 1; ", $quiz_id, $user_id ) );
6198 +
6199 + } elseif ( $quiz_grade_method === 'last_attempt' ) {
6200 +
6201 + $attempt = $wpdb->get_row( $wpdb->prepare( "SELECT * {$from_string} ORDER BY attempt_id DESC LIMIT 1; ", $quiz_id, $user_id ) );
6202 + }
6203 +
6204 + return $attempt;
6205 + }
6206 +
6207 + /**
6208 + * @param int $course_id
6209 + * @param int $user_id
6210 + *
7018 6211 * @return string
6212 + *
6213 + * Print Course Status Context
6214 + *
6215 + * @since v.1.4.2
7019 6216 */
7020 6217 public function course_progress_status_context( $course_id = 0, $user_id = 0 ) {
7021 6218 $course_id = $this->get_post_id( $course_id );
7022 6219 $user_id = $this->get_user_id( $user_id );
7023 - $is_completed = $this->is_completed_course( $course_id, $user_id );
6220 + $is_completed = tutils()->is_completed_course( $course_id, $user_id );
7024 6221
7025 6222 $html = '';
7026 6223 if ( $is_completed ) {
7027 - $html = '<span class="course-completion-status course-completed"><i class="tutor-icon-mark"></i> ' . __( 'Completed', 'tutor' ) . ' </span>';
6224 + $html = '<span class="course-completion-status course-completed"><i class="tutor-icon-mark"></i> '.__('Completed', 'tutor').' </span>';
7028 6225 } else {
7029 - $is_in_progress = $this->get_completed_lesson_count_by_course( $course_id, $user_id );
6226 + $is_in_progress = tutor_utils()->get_completed_lesson_count_by_course( $course_id, $user_id );
7030 6227 if ( $is_in_progress ) {
7031 - $html = '<span class="course-completion-status course-inprogress"><i class="tutor-icon-refresh-o"></i> ' . __( 'In Progress', 'tutor' ) . ' </span>';
6228 + $html = '<span class="course-completion-status course-inprogress"><i class="tutor-icon-refresh-button-1"></i> '.__('In Progress', 'tutor').' </span>';
7032 6229 } else {
7033 - $html = '<span class="course-completion-status course-not-taken"><i class="tutor-icon-spinner"></i> ' . __( 'Not Taken', 'tutor' ) . ' </span>';
6230 + $html = '<span class="course-completion-status course-not-taken"><i class="tutor-icon-spinner"></i> '.__('Not Taken', 'tutor').' </span>';
7034 6231 }
7035 6232 }
7036 6233 return $html;
7037 6234 }
@@ -7036,16 +6233,14 @@
7036 6233 return $html;
7037 6234 }
7038 6235
7039 6236 /**
6237 + * @param $user
6238 + * @param $new_pass
6239 + *
7040 6240 * Reset Password
7041 6241 *
7042 - * @since 1.4.3
7043 - *
7044 - * @param object $user user object.
7045 - * @param string $new_pass new password.
7046 - *
7047 - * @return void
6242 + * @since v.1.4.3
7048 6243 */
7049 6244 public function reset_password( $user, $new_pass ) {
7050 6245 do_action( 'password_reset', $user, $new_pass );
7051 6246
@@ -7058,25 +6253,20 @@
7058 6253 wp_password_change_notification( $user );
7059 6254 }
7060 6255
7061 6256 /**
6257 + * @return array
6258 + *
7062 6259 * Get tutor pages, required to show dashboard, and others forms
7063 6260 *
7064 - * @since 1.4.3
7065 - *
7066 - * @return array
6261 + * @since v.1.4.3
7067 6262 */
7068 6263 public function tutor_pages() {
7069 - $pages = apply_filters(
7070 - 'tutor_pages',
7071 - array(
7072 - 'tutor_dashboard_page_id' => __( 'Dashboard Page', 'tutor' ),
7073 - 'instructor_register_page' => __( 'Instructor Registration Page', 'tutor' ),
7074 - 'student_register_page' => __( 'Student Registration Page', 'tutor' ),
7075 - 'tutor_cart_page_id' => __( 'Cart', 'tutor' ),
7076 - 'tutor_checkout_page_id' => __( 'Checkout', 'tutor' ),
7077 - )
7078 - );
6264 + $pages = apply_filters( 'tutor_pages', array(
6265 + 'tutor_dashboard_page_id' => __( 'Dashboard Page', 'tutor' ),
6266 + 'instructor_register_page' => __( 'Instructor Registration Page', 'tutor' ),
6267 + 'student_register_page' => __( 'Student Registration Page', 'tutor' ),
6268 + ));
7079 6269
7080 6270 $new_pages = array();
7081 6271 foreach ( $pages as $key => $page ) {
7082 6272 $page_id = (int) get_tutor_option( $key );
@@ -7087,20 +6277,18 @@
7087 6277 $page_visible = false;
7088 6278
7089 6279 if ( $wp_page ) {
7090 6280 $wp_page_name = $wp_page->post_title;
7091 - $page_visible = 'publish' === $wp_page->post_status;
7092 - } else {
7093 - $page_id = 0;
6281 + $page_visible = $wp_page->post_status === 'publish';
7094 6282 }
7095 6283
7096 6284 $new_pages[] = array(
7097 - 'option_key' => $key,
7098 - 'page_name' => $page,
7099 - 'wp_page_name' => $wp_page_name,
7100 - 'page_id' => $page_id,
7101 - 'page_exists' => $page_exists,
7102 - 'page_visible' => $page_visible,
6285 + 'option_key' => $key,
6286 + 'page_name' => $page,
6287 + 'wp_page_name' => $wp_page_name,
6288 + 'page_id' => $page_id,
6289 + 'page_exists' => $page_exists,
6290 + 'page_visible' => $page_visible,
7103 6291 );
7104 6292 }
7105 6293
7106 6294 return $new_pages;
@@ -7106,44 +6294,27 @@
7106 6294 return $new_pages;
7107 6295 }
7108 6296
7109 6297 /**
7110 - * Get Course prev next lession contents by content ID
6298 + * @param int $course_id
7111 6299 *
7112 - * @since 1.4.9
6300 + * @return array|null|object
7113 6301 *
7114 - * @param int $content_id content id.
6302 + * Get Course prev next lession contents by content ID
7115 6303 *
7116 - * @return array|null|object
6304 + * @since v.1.4.9
7117 6305 */
7118 6306 public function get_course_prev_next_contents_by_id( $content_id = 0 ) {
7119 6307
7120 - $course_id = $this->get_course_id_by_content( $content_id );
7121 - $course_contents = array();
7122 - $topics = $this->get_topics( $course_id, array( 'fields' => 'ids' ) );
7123 - $topic_ids = $topics->posts ?? array();
6308 + $course_id = $this->get_course_id_by_content($content_id);
6309 + $course_contents = $this->get_course_contents_by_id($course_id);
6310 + $previous_id = 0;
6311 + $next_id = 0;
7124 6312
7125 - /*
7126 - * Get course content based on topic ordering
7127 - * instead of ordering all the content through query.
7128 - */
7129 - if ( $this->count( $topic_ids ) ) {
7130 - foreach ( $topic_ids as $topic_id ) {
7131 - $course_content = $this->get_course_contents_by_topic( $topic_id, -1 );
7132 - if ( ! $this->count( $course_content->posts ) ) {
7133 - continue;
7134 - }
7135 - array_push( $course_contents, ...$course_content->posts );
7136 - }
7137 - }
7138 -
7139 - $previous_id = 0;
7140 - $next_id = 0;
7141 -
7142 6313 if ( $this->count( $course_contents ) ) {
7143 6314 $ids = wp_list_pluck( $course_contents, 'ID' );
7144 6315
7145 - $i = 0;
6316 + $i=0;
7146 6317 foreach ( $ids as $key => $id ) {
7147 6318 $previous_i = $key - 1;
7148 6319 $next_i = $key + 1;
7149 6320
@@ -7154,27 +6325,24 @@
7154 6325 if ( isset( $ids[ $next_i ] ) ) {
7155 6326 $next_id = $ids[ $next_i ];
7156 6327 }
7157 6328 }
7158 - ++$i;
6329 + $i++;
7159 6330 }
7160 6331 }
7161 6332
7162 - return (object) array(
7163 - 'previous_id' => $previous_id,
7164 - 'next_id' => $next_id,
7165 - );
6333 + return (object) [ 'previous_id' => $previous_id, 'next_id' => $next_id ];
7166 6334 }
7167 6335
7168 6336 /**
7169 6337 * Get a subset of the items from the given array.
7170 6338 *
7171 - * @since 1.5.2
6339 + * @param array $array
6340 + * @param array|string $keys
7172 6341 *
7173 - * @param array $array array.
7174 - * @param array|string $keys keys.
6342 + * @return array|bool
7175 6343 *
7176 - * @return array|bool
6344 + * @since v.1.5.2
7177 6345 */
7178 6346 public function array_only( $array = array(), $keys = null ) {
7179 6347 if ( ! $this->count( $array ) || ! $keys ) {
7180 6348 return false;
@@ -7183,261 +6351,203 @@
7183 6351 return array_intersect_key( $array, array_flip( (array) $keys ) );
7184 6352 }
7185 6353
7186 6354 /**
7187 - * Is instructor of this course
6355 + * @param int $instructor_id
6356 + * @param int $course_id
7188 6357 *
7189 - * @since 1.6.4
7190 - * @since 3.4.0 param $is_approved added.
6358 + * @return bool|int
7191 6359 *
7192 - * @param int $instructor_id instructor id.
7193 - * @param int $course_id course id.
7194 - * @param bool $is_approved is approved.
6360 + * Is instructor of this course
7195 6361 *
7196 - * @return bool
6362 + * @since v.1.6.4
7197 6363 */
7198 - public function is_instructor_of_this_course( $instructor_id = 0, $course_id = 0, $is_approved = true ) {
7199 - $instructor_id = $this->get_user_id( $instructor_id );
7200 - $course_id = $this->get_post_id( $course_id );
6364 + public function is_instructor_of_this_course( $instructor_id=0, $course_id=0 ) {
6365 + global $wpdb;
7201 6366
6367 + $instructor_id = $this->get_user_id( $instructor_id );
6368 + $course_id = $this->get_post_id( $course_id );
6369 +
7202 6370 if ( ! $instructor_id || ! $course_id ) {
7203 6371 return false;
7204 6372 }
7205 6373
7206 - $cache_key = "tutor_is_instructor_of_the_course_{$instructor_id}_{$course_id}_{$is_approved}";
7207 - $instructor = TutorCache::get( $cache_key );
7208 -
7209 - if ( false === $instructor ) {
7210 - $meta_query_args = array(
7211 - array(
7212 - 'key' => '_tutor_instructor_course_id',
7213 - 'value' => $course_id,
7214 - 'compare' => '=',
7215 - 'type' => 'NUMERIC',
7216 - ),
7217 - );
7218 -
7219 - if ( $is_approved ) {
7220 - $meta_query_args[] = array(
7221 - 'key' => '_tutor_instructor_status',
7222 - 'value' => 'approved',
7223 - 'compare' => '=',
7224 - );
7225 - }
7226 -
7227 - $meta_query_args['relation'] = 'AND';
7228 - $meta_query = new \WP_Meta_Query( $meta_query_args );
7229 - $instructor_query = new \WP_User_Query(
7230 - array(
7231 - 'include' => array( $instructor_id ),
7232 - 'number' => 1,
7233 - 'fields' => 'ID',
7234 - 'count_total' => false,
7235 - 'meta_query' => $meta_query->queries,
7236 - )
7237 - );
7238 -
7239 - $instructor = $instructor_query->get_results();
7240 -
7241 - TutorCache::set( $cache_key, $instructor );
6374 + $instructor = $wpdb->get_col( $wpdb->prepare(
6375 + "SELECT umeta_id
6376 + FROM {$wpdb->usermeta}
6377 + WHERE user_id = %d
6378 + AND meta_key = '_tutor_instructor_course_id'
6379 + AND meta_value = %d
6380 + ",
6381 + $instructor_id,
6382 + $course_id
6383 + ) );
6384 +
6385 + if (is_array($instructor) && count($instructor)) {
6386 + return $instructor;
7242 6387 }
7243 6388
7244 - if ( $this->count( $instructor ) ) {
7245 - return true;
7246 - }
7247 -
7248 6389 return false;
7249 6390 }
7250 6391
7251 6392 /**
7252 - * User profile completion
6393 + * @param int $user_id
7253 6394 *
7254 - * @since 1.6.6
6395 + * @return array|object
7255 6396 *
7256 - * @param int $user_id user id.
6397 + * User profile completion
7257 6398 *
7258 - * @return array|object
6399 + * @since v.1.6.6
7259 6400 */
7260 6401 public function user_profile_completion( $user_id = 0 ) {
7261 - $user_id = $this->get_user_id( $user_id );
7262 - $instructor_status = get_user_meta( $user_id, '_tutor_instructor_status', true );
6402 + $user_id = $this->get_user_id( $user_id );
6403 + $instructor = $this->is_instructor( $user_id );
7263 6404
7264 - $settings_url = Dashboard::get_account_page_url( 'settings' );
7265 - $social_settings_url = Dashboard::get_account_page_url( 'settings?tab=social-accounts' );
7266 - $withdraw_settings_url = Dashboard::get_account_page_url( 'settings?tab=withdraw' );
6405 + $required_fields = apply_filters( 'tutor_profile_required_fields', array(
6406 + 'first_name' => __( 'First Name', 'tutor' ),
6407 + 'last_name' => __( 'Last Name', 'tutor' ),
6408 + '_tutor_profile_photo' => __( 'Profile Photo', 'tutor' ),
6409 + '_tutor_withdraw_method_data' => __( 'Withdraw Method', 'tutor' ),
6410 + ));
7267 6411
7268 - $required_fields = array(
7269 - '_tutor_profile_photo' => __( 'Set Your Profile Photo', 'tutor' ),
7270 - '_tutor_social_links' => __( 'Add Your Social Links', 'tutor' ),
7271 - '_tutor_profile_bio' => __( 'Set Your Bio', 'tutor' ),
7272 - );
6412 + if ( ! $instructor && array_key_exists( "_tutor_withdraw_method_data", $required_fields ) ) {
6413 + unset( $required_fields[ '_tutor_withdraw_method_data' ] );
6414 + }
7273 6415
7274 - // Add payment method as a required on if current user is an approved instructor.
7275 - if ( 'approved' === $instructor_status ) {
7276 - $required_fields['_tutor_withdraw_method_data'] = __( 'Set Withdraw Method', 'tutor' );
6416 + $empty_fields = array();
6417 + foreach ( $required_fields as $key => $field ) {
6418 + $value = get_user_meta( $user_id, $key, true );
6419 + if ( !$value ) {
6420 + array_push( $empty_fields, $field );
6421 + }
7277 6422 }
6423 +
6424 + $total_empty_fields = count( $empty_fields );
6425 + $total_required_fields = count( $required_fields );
6426 + $signup_point = apply_filters( 'tutor_profile_completion_signup_point', 50 );
7278 6427
7279 - // Check if any individual social link meta is set.
7280 - $social_meta_keys = array_keys( $this->tutor_user_social_icons() );
7281 - $has_social_link = false;
7282 - foreach ( $social_meta_keys as $social_key ) {
7283 - if ( get_user_meta( $user_id, $social_key, true ) ) {
7284 - $has_social_link = true;
7285 - break;
7286 - }
6428 + if ( $total_empty_fields == 0 ) {
6429 + $progress = 100;
6430 + } else {
6431 + $completed_field = $total_required_fields-$total_empty_fields;
6432 + $per_field_point = $signup_point / $total_required_fields;
6433 + $progress = $signup_point + ceil($per_field_point * $completed_field);
7287 6434 }
7288 6435
7289 - // url where user should redirect for profile completion.
7290 - $profile_completion_urls = array(
7291 - '_tutor_profile_photo' => $settings_url,
7292 - '_tutor_profile_bio' => $settings_url,
7293 - '_tutor_social_links' => $social_settings_url,
7294 - '_tutor_withdraw_method_data' => $withdraw_settings_url,
6436 + $return = array(
6437 + 'empty_fields' => $empty_fields,
6438 + 'progress' => $progress,
7295 6439 );
7296 - foreach ( $required_fields as $key => $field ) {
7297 - $is_set = '_tutor_social_links' === $key
7298 - ? $has_social_link
7299 - : (bool) get_user_meta( $user_id, $key, true );
7300 6440
7301 - $required_fields[ $key ] = array(
7302 - 'text' => $field,
7303 - 'is_set' => $is_set,
7304 - 'url' => $profile_completion_urls[ $key ],
7305 - );
7306 - }
7307 -
7308 - // Apply fitlers on the list.
7309 - return apply_filters( 'tutor/user/profile/completion', $required_fields );
6441 + return (object) $return;
7310 6442 }
7311 6443
7312 6444 /**
7313 - * Get students list based on course id
6445 + * @param int $enrol_id
7314 6446 *
7315 - * @since 1.6.6
6447 + * @return array|object
7316 6448 *
7317 - * @param integer $course_id course id.
7318 - * @param string $field_name field name.
7319 - * @param boolean $all if all is false it will return only $field_name column.
6449 + * Get enrolment by enrol_id
7320 6450 *
7321 - * @return array of objects for student list or array
6451 + * @since v1.6.9
7322 6452 */
7323 - public function get_students_data_by_course_id( $course_id = 0, $field_name = 'ID', $all = false ) {
7324 -
6453 + public function get_enrolment_by_enrol_id( $enrol_id = 0 ) {
7325 6454 global $wpdb;
7326 - $course_id = $this->get_post_id( $course_id );
7327 6455
7328 - $student_data = $wpdb->get_results(
7329 - $wpdb->prepare(
7330 - "SELECT student.{$field_name}, student.display_name as display_name, student.user_login as username, student.user_email
7331 - FROM {$wpdb->posts} enrol
6456 + $enrolment = $wpdb->get_row( $wpdb->prepare(
6457 + "SELECT enrol.id AS enrol_id,
6458 + enrol.post_author AS student_id,
6459 + enrol.post_date AS enrol_date,
6460 + enrol.post_title AS enrol_title,
6461 + enrol.post_status AS status,
6462 + enrol.post_parent AS course_id,
6463 + course.post_title AS course_title,
6464 + student.user_nicename,
6465 + student.user_email,
6466 + student.display_name
6467 + FROM {$wpdb->posts} enrol
6468 + INNER JOIN {$wpdb->posts} course
6469 + ON enrol.post_parent = course.id
7332 6470 INNER JOIN {$wpdb->users} student
7333 - ON enrol.post_author = student.id
7334 - WHERE enrol.post_type = %s
7335 - AND enrol.post_parent = %d
7336 - AND enrol.post_status = %s;
7337 - ",
7338 - 'tutor_enrolled',
7339 - $course_id,
7340 - 'completed'
7341 - )
7342 - );
7343 - if ( $all ) {
7344 - return $student_data;
6471 + ON enrol.post_author = student.id
6472 + WHERE enrol.id = %d;
6473 + ", $enrol_id));
6474 +
6475 + if ( $enrolment ) {
6476 + return $enrolment;
7345 6477 }
7346 - return array_column( $student_data, $field_name );
6478 +
6479 + return false;
7347 6480 }
7348 6481
7349 6482 /**
7350 - * Get student data by course id.
6483 + * @param int $course_id
7351 6484 *
7352 - * @since 1.0.0
6485 + * @return array
6486 + *
6487 + * @since v1.6.9
7353 6488 *
7354 - * @param integer $course_id course id.
7355 - *
7356 - * @return array
6489 + * Get students email by course id
7357 6490 */
7358 - public function get_students_all_data_by_course_id( $course_id = 0 ) {
7359 -
6491 + public function get_student_emails_by_course_id( $course_id = 0 ) {
7360 6492 global $wpdb;
7361 6493 $course_id = $this->get_post_id( $course_id );
7362 6494
7363 - $student_data = $wpdb->get_results(
7364 - $wpdb->prepare(
7365 - "SELECT *
6495 + $student_emails = $wpdb->get_results( $wpdb->prepare(
6496 + "SELECT student.user_email
7366 6497 FROM {$wpdb->posts} enrol
7367 6498 INNER JOIN {$wpdb->users} student
7368 6499 ON enrol.post_author = student.id
7369 6500 WHERE enrol.post_type = %s
7370 6501 AND enrol.post_parent = %d
7371 - AND enrol.post_status = %s;
6502 + AND enrol.post_status = %s;
7372 6503 ",
7373 - 'tutor_enrolled',
7374 - $course_id,
7375 - 'completed'
7376 - )
7377 - );
6504 + 'tutor_enrolled',
6505 + $course_id,
6506 + 'completed'
6507 + ) );
7378 6508
7379 - return $student_data;
7380 - }
6509 + $email_array = array_column( $student_emails, 'user_email' );
7381 6510
7382 - /**
7383 - * Get students email by course id
7384 - *
7385 - * @since 1.6.9
7386 - *
7387 - * @param int $course_id course id.
7388 - *
7389 - * @return array
7390 - */
7391 - public function get_student_emails_by_course_id( $course_id = 0 ) {
7392 - return $this->get_students_data_by_course_id( $course_id, 'user_email' );
6511 + return $email_array;
7393 6512 }
7394 6513
7395 - /**
7396 - * Get single comment user post id.
7397 - *
7398 - * @since 1.0.0
7399 - *
7400 - * @param int $post_id post id.
7401 - * @param int $user_id user id.
7402 - *
7403 - * @return mixed
7404 - */
7405 - public function get_single_comment_user_post_id( $post_id, $user_id ) {
6514 + /*
6515 + *requie post id & user id
6516 + *return single comment post
6517 + */
6518 + public function get_single_comment_user_post_id( $post_id,$user_id ) {
7406 6519 global $wpdb;
7407 - $table = $wpdb->prefix . 'comments';
7408 - $query = $wpdb->get_row(
7409 - $wpdb->prepare(
7410 - "SELECT *
6520 + $table = $wpdb->prefix . "comments";
6521 + $query = $wpdb->get_row( $wpdb->prepare(
6522 + "SELECT *
7411 6523 FROM $table
7412 6524 WHERE comment_post_ID = %d
7413 6525 AND user_id = %d
7414 6526 LIMIT 1
7415 6527 ",
7416 - $post_id,
7417 - $user_id
7418 - )
7419 - );
6528 + $post_id,
6529 + $user_id
6530 + ) );
7420 6531 return $query ? $query : false;
7421 6532 }
7422 -
6533 +
7423 6534 /**
7424 - * Check if course is in wc cart
6535 + * @param int $course_id
7425 6536 *
7426 - * @since 1.7.5
6537 + * @return bool
6538 + *
6539 + * @since v1.7.5
7427 6540 *
7428 - * @param int $course_or_product_id course or product id.
7429 - * @param bool $is_product_id is product id or not.
7430 - *
7431 - * @return bool
6541 + * Check if course is in wc cart
7432 6542 */
7433 - public function is_course_added_to_cart( $course_or_product_id = 0, $is_product_id = false ) {
7434 -
7435 - switch ( $this->get_option( 'monetize_by' ) ) {
6543 + public function is_course_added_to_cart( $course_or_product_id = 0, $is_product_id=false ) {
6544 +
6545 + switch( $this->get_option( 'monetize_by' ) ) {
7436 6546 case 'wc':
7437 6547 global $woocommerce;
7438 6548 $product_id = $is_product_id ? $course_or_product_id : $this->get_course_product_id( $course_or_product_id );
7439 -
6549 +
7440 6550 if ( $woocommerce->cart ) {
7441 6551 foreach ( $woocommerce->cart->get_cart() as $key => $val ) {
7442 6552 if ( $product_id == $val['product_id'] ) {
7443 6553 return true;
@@ -7448,21 +6558,21 @@
7448 6558 }
7449 6559 }
7450 6560
7451 6561 /**
7452 - * Get profile pic url
6562 + * @param int $user_id
7453 6563 *
7454 - * @since 1.7.5
6564 + * @return bool
6565 + *
6566 + * @since v1.7.5
7455 6567 *
7456 - * @param int $user_id user id.
7457 - *
7458 - * @return string
6568 + * Get profile pic url
7459 6569 */
7460 6570 public function get_cover_photo_url( $user_id ) {
7461 - $cover_photo_src = tutor()->url . 'assets/images/cover-photo.webp';
6571 + $cover_photo_src = tutor()->url . 'assets/images/cover-photo.jpg';
7462 6572 $cover_photo_id = get_user_meta( $user_id, '_tutor_cover_photo', true );
7463 6573 if ( $cover_photo_id ) {
7464 - $url = wp_get_attachment_image_url( $cover_photo_id, 'full' );
6574 + $url = wp_get_attachment_image_url( $cover_photo_id, 'full' );
7465 6575 ! empty( $url ) ? $cover_photo_src = $url : 0;
7466 6576 }
7467 6577
7468 6578 return $cover_photo_src;
@@ -7468,3036 +6578,368 @@
7468 6578 return $cover_photo_src;
7469 6579 }
7470 6580
7471 6581 /**
7472 - * Return the course ID by lesson, quiz, answer etc.
6582 + * @return int
6583 + *
6584 + * @since v1.7.9
7473 6585 *
7474 - * @since 1.7.9
7475 - *
7476 - * @param string $content content like lesson, quiz, answer etc.
7477 - * @param int $object_id object id.
7478 - *
7479 - * @return int
6586 + * Return the course ID by lession, quiz, answer etc.
7480 6587 */
7481 6588 public function get_course_id_by( $content, $object_id ) {
7482 - $cache_key = "tutor_get_course_id_by_{$content}_{$object_id}";
7483 - $course_id = TutorCache::get( $cache_key );
6589 + global $wpdb;
6590 + $course_id = null;
7484 6591
7485 - if ( false === $course_id ) {
7486 - global $wpdb;
7487 - switch ( $content ) {
7488 - case 'course':
7489 - $course_id = $object_id;
7490 - break;
6592 + switch ( $content ) {
6593 + case 'course' :
6594 + $course_id = $object_id;
6595 + break;
7491 6596
7492 - case 'zoom_meeting':
7493 - case 'tutor_gm_course':
7494 - case 'topic':
7495 - case 'announcement':
7496 - $course_id = wp_get_post_parent_id( $object_id );
7497 - break;
6597 + case 'topic' :
6598 + case 'announcement' :
6599 + $course_id = $wpdb->get_var( $wpdb->prepare(
6600 + "SELECT post_parent
6601 + FROM {$wpdb->posts}
6602 + WHERE ID=%d
6603 + LIMIT 1",
6604 + $object_id ) );
6605 + break;
6606 +
6607 + case 'lesson' :
6608 + case 'quiz' :
6609 + case 'assignment' :
6610 + $course_id = $wpdb->get_var( $wpdb->prepare(
6611 + "SELECT post_parent
6612 + FROM {$wpdb->posts}
6613 + WHERE ID = (SELECT post_parent FROM {$wpdb->posts} WHERE ID = %d);
6614 + ",
6615 + $object_id
6616 + ) );
6617 + break;
6618 +
6619 + case 'question' :
6620 + $course_id = $wpdb->get_var( $wpdb->prepare(
6621 + "SELECT topic.post_parent
6622 + FROM {$wpdb->posts} topic
6623 + INNER JOIN {$wpdb->posts} quiz
6624 + ON quiz.post_parent=topic.ID
6625 + INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
6626 + ON question.quiz_id=quiz.ID
6627 + WHERE question.question_id = %d;
6628 + ",
6629 + $object_id
6630 + ) );
6631 + break;
6632 +
6633 + case 'quiz_answer' :
6634 + $course_id = $wpdb->get_var( $wpdb->prepare(
6635 + "SELECT topic.post_parent
6636 + FROM {$wpdb->posts} topic
6637 + INNER JOIN {$wpdb->posts} quiz
6638 + ON quiz.post_parent=topic.ID
6639 + INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
6640 + ON question.quiz_id=quiz.ID
6641 + INNER JOIN {$wpdb->prefix}tutor_quiz_question_answers answer
6642 + ON answer.belongs_question_id=question.question_id
6643 + WHERE answer.answer_id = %d;
6644 + ",
6645 + $object_id
6646 + ) );
6647 + break;
6648 +
6649 + case 'attempt' :
6650 + $course_id = $wpdb->get_var( $wpdb->prepare(
6651 + "SELECT course_id
6652 + FROM {$wpdb->prefix}tutor_quiz_attempts
6653 + WHERE attempt_id=%d;
6654 + ",
6655 + $object_id
6656 + ) );
6657 + break;
7498 6658
7499 - case 'zoom_lesson':
7500 - case 'tutor_gm_topic':
7501 - case 'lesson':
7502 - case 'quiz':
7503 - case 'assignment':
7504 - $topic_id = wp_get_post_parent_id( $object_id );
7505 - if ( ! $topic_id ) {
7506 - $course_id = $wpdb->get_var(
7507 - $wpdb->prepare(
7508 - "SELECT meta_value
7509 - FROM {$wpdb->prefix}postmeta
7510 - WHERE post_id=%d AND meta_key='_tutor_course_id_for_lesson'",
7511 - $object_id
7512 - )
7513 - );
7514 - } else {
7515 - $course_id = wp_get_post_parent_id( $topic_id );
7516 - }
7517 - break;
7518 -
7519 - case 'assignment_submission':
7520 - $course_id = $wpdb->get_var(
7521 - $wpdb->prepare(
7522 - "SELECT DISTINCT _course.ID
7523 - FROM {$wpdb->posts} _course
7524 - INNER JOIN {$wpdb->posts} _topic ON _topic.post_parent=_course.ID
7525 - INNER JOIN {$wpdb->posts} _assignment ON _assignment.post_parent=_topic.ID
7526 - INNER JOIN {$wpdb->comments} _submission ON _submission.comment_post_ID=_assignment.ID
7527 - WHERE _submission.comment_ID=%d;",
7528 - $object_id
7529 - )
7530 - );
7531 - break;
7532 -
7533 - case 'question':
7534 - $course_id = $wpdb->get_var(
7535 - $wpdb->prepare(
7536 - "SELECT topic.post_parent
7537 - FROM {$wpdb->posts} topic
7538 - INNER JOIN {$wpdb->posts} quiz
7539 - ON quiz.post_parent=topic.ID
7540 - INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
7541 - ON question.quiz_id=quiz.ID
7542 - WHERE question.question_id = %d;
7543 - ",
7544 - $object_id
7545 - )
7546 - );
7547 - break;
7548 -
7549 - case 'quiz_answer':
7550 - $course_id = $wpdb->get_var(
7551 - $wpdb->prepare(
7552 - "SELECT topic.post_parent
7553 - FROM {$wpdb->posts} topic
7554 - INNER JOIN {$wpdb->posts} quiz
7555 - ON quiz.post_parent=topic.ID
7556 - INNER JOIN {$wpdb->prefix}tutor_quiz_questions question
7557 - ON question.quiz_id=quiz.ID
7558 - INNER JOIN {$wpdb->prefix}tutor_quiz_question_answers answer
7559 - ON answer.belongs_question_id=question.question_id
7560 - WHERE answer.answer_id = %d;
7561 - ",
7562 - $object_id
7563 - )
7564 - );
7565 - break;
7566 -
7567 - case 'attempt':
7568 - $course_id = $wpdb->get_var(
7569 - $wpdb->prepare(
7570 - "SELECT course_id
7571 - FROM {$wpdb->prefix}tutor_quiz_attempts
7572 - WHERE attempt_id=%d;
7573 - ",
7574 - $object_id
7575 - )
7576 - );
7577 - break;
7578 -
7579 - case 'attempt_answer':
7580 - $course_id = $wpdb->get_var(
7581 - $wpdb->prepare(
7582 - "SELECT course_id
7583 - FROM {$wpdb->prefix}tutor_quiz_attempts
7584 - WHERE attempt_id = (SELECT quiz_attempt_id FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id=%d)
7585 - ",
7586 - $object_id
7587 - )
7588 - );
7589 - break;
7590 -
7591 - case 'review':
7592 - case 'qa_question':
7593 - $question = get_comment( $object_id );
7594 - if ( is_a( $question, 'WP_Comment' ) ) {
7595 - $course_id = $question->comment_post_ID;
7596 - }
7597 - break;
7598 -
7599 - case 'instructor':
7600 - $course_ids = get_user_meta( $object_id, '_tutor_instructor_course_id' );
7601 - $course_ids = is_array( $course_ids ) ? $course_ids : array();
7602 - $course_id = array_filter( $course_ids, fn( $id ) => is_numeric( $id ) && $id );
7603 - break;
7604 - }
7605 -
7606 - TutorCache::set( $cache_key, $course_id );
6659 + case 'attempt_answer' :
6660 + $course_id = $wpdb->get_var( $wpdb->prepare(
6661 + "SELECT course_id
6662 + FROM {$wpdb->prefix}tutor_quiz_attempts
6663 + WHERE attempt_id = (SELECT quiz_attempt_id FROM {$wpdb->prefix}tutor_quiz_attempt_answers WHERE attempt_answer_id=%d)
6664 + ",
6665 + $object_id
6666 + ) );
6667 + break;
6668 + case 'review' :
6669 + case 'qa_question' :
6670 + $course_id = $wpdb->get_var( $wpdb->prepare(
6671 + "SELECT comment_post_ID
6672 + FROM {$wpdb->comments}
6673 + WHERE comment_ID = %d;
6674 + ",
6675 + $object_id
6676 + ) );
7607 6677 }
7608 6678
7609 6679 return $course_id;
7610 6680 }
7611 6681
7612 -
7613 6682 /**
7614 - * Return the course ID(s) by lession, quiz, answer etc.
6683 + * @return bool
6684 + *
6685 + * @since v1.7.7
7615 6686 *
7616 - * @since 1.7.9
7617 - *
7618 - * @param int $content_id content id.
7619 - *
7620 - * @return int
6687 + * Check if user can create, edit, delete various tutor contents such as lesson, quiz, answer etc.
7621 6688 */
7622 - public function get_course_id_by_subcontent( $content_id ) {
7623 - $mapping = array(
7624 - 'tutor_assignments' => 'assignment',
7625 - 'tutor_quiz' => 'quiz',
7626 - 'lesson' => 'lesson',
7627 - 'tutor_zoom_meeting' => 'zoom_meeting',
7628 - 'tutor_zoom_lesson' => 'zoom_lesson',
7629 - 'tutor_gm_course' => 'tutor_gm_course',
7630 - 'tutor_gm_topic' => 'tutor_gm_topic',
7631 - 'topics' => 'topic',
7632 - 'cb-lesson' => 'cb-lesson',
7633 - );
7634 -
7635 - $content_type = get_post_field( 'post_type', $content_id );
7636 -
7637 - // Differentiate standalone zoom meeting and zoom lesson.
7638 - if ( 'tutor_zoom_meeting' === $content_type ) {
7639 - $parent_id = wp_get_post_parent_id( $content_id );
7640 - $parent_type = get_post_field( 'post_type', $parent_id );
7641 -
7642 - $content_type = $parent_type === tutor()->course_post_type ? 'tutor_zoom_meeting' : 'tutor_zoom_lesson';
6689 + public function can_user_manage( $content, $object_id, $user_id=0, $allow_current_admin=true ) {
6690 +
6691 + if( $allow_current_admin && current_user_can( 'administrator' ) ) {
6692 + // Admin has access to everything
6693 + return true;
7643 6694 }
7644 - if ( 'tutor-google-meet' === $content_type ) {
7645 - $parent_id = wp_get_post_parent_id( $content_id );
7646 - $parent_type = get_post_field( 'post_type', $parent_id );
7647 6695
7648 - $content_type = $parent_type === tutor()->course_post_type ? 'tutor_gm_course' : 'tutor_gm_topic';
7649 - }
7650 -
7651 - return $this->get_course_id_by( $mapping[ $content_type ], $content_id );
7652 - }
7653 -
7654 - /**
7655 - * Check if user can create, edit, delete various tutor contents such as lesson, quiz, answer etc.
7656 - *
7657 - * @since 1.7.9
7658 - *
7659 - * @param string $content content.
7660 - * @param int $object_id object id.
7661 - * @param integer $user_id user id.
7662 - * @param boolean $allow_current_admin is allow current admin.
7663 - *
7664 - * @return boolean
7665 - */
7666 - public function can_user_manage( $content, $object_id, $user_id = 0, $allow_current_admin = true ) {
7667 - $user_id = (int) $this->get_user_id( $user_id );
7668 6696 $course_id = $this->get_course_id_by( $content, $object_id );
7669 6697
7670 - if ( $course_id ) {
7671 - if ( $allow_current_admin && current_user_can( 'administrator' ) ) {
7672 - // Admin has access to everything.
7673 - return true;
7674 - }
7675 -
6698 + if( $course_id ) {
6699 +
7676 6700 $instructors = $this->get_instructors_by_course( $course_id );
7677 - $instructor_ids = is_array( $instructors ) ? array_map(
7678 - function ( $instructor ) {
7679 - return (int) $instructor->ID;
7680 - },
7681 - $instructors
7682 - ) : array();
7683 -
6701 + $instructor_ids = is_array( $instructors ) ? array_map( function($instructor) {
6702 + return (int)$instructor->ID;
6703 + }, $instructors) : array();
6704 +
6705 + $user_id = (int)$this->get_user_id( $user_id );
7684 6706 $is_listed = in_array( $user_id, $instructor_ids );
7685 6707
7686 - if ( $is_listed ) {
7687 - return true;
7688 - }
6708 + return $is_listed;
7689 6709 }
7690 6710
7691 - global $wpdb;
7692 - switch ( $content ) {
7693 - case 'review':
7694 - case 'qa_question':
7695 - // Just check if own content. Instructor privilege already checked in the earlier blocks.
7696 - $id = $wpdb->get_var(
7697 - $wpdb->prepare(
7698 - "SELECT comment_ID
7699 - FROM {$wpdb->comments} WHERE user_id = %d AND comment_ID=%d",
7700 - $user_id,
7701 - $object_id
7702 - )
7703 - );
7704 -
7705 - return $id ? true : false;
7706 - }
7707 -
7708 6711 return false;
7709 6712 }
7710 6713
7711 6714 /**
6715 + * @return bool
6716 + *
6717 + * @since v1.7.9
6718 + *
7712 6719 * Check if user has access for content like lesson, quiz, assignment etc.
7713 - *
7714 - * @since 1.7.9
7715 - *
7716 - * @param string $content content.
7717 - * @param integer $object_id object id.
7718 - * @param integer $user_id user id.
7719 - *
7720 - * @return boolean
7721 6720 */
7722 - public function has_enrolled_content_access( $content, $object_id = 0, $user_id = 0 ) {
6721 + public function has_enrolled_content_access( $content, $object_id=0, $user_id=0 ) {
7723 6722 $user_id = $this->get_user_id( $user_id );
7724 6723 $object_id = $this->get_post_id( $object_id );
7725 6724 $course_id = $this->get_course_id_by( $content, $object_id );
6725 + $course_content_access = (bool) get_tutor_option( 'course_content_access_for_ia' );
7726 6726
7727 6727 do_action( 'tutor_before_enrolment_check', $course_id, $user_id );
7728 6728
7729 - if ( EnrollmentModel::is_enrolled( $course_id, $user_id ) || $this->has_user_course_content_access( $user_id, $course_id ) ) {
6729 + if ( $this->is_enrolled( $course_id, $user_id ) ) {
7730 6730 return true;
7731 6731 }
7732 -
7733 - // Check Lesson edit access to support page builders (eg: Oxygen).
7734 - if ( current_user_can( tutor()->instructor_role ) && $this->has_lesson_edit_access() ) {
6732 + if ( $course_content_access && ( current_user_can( 'administrator' ) || current_user_can( tutor()->instructor_role ) ) ) {
7735 6733 return true;
7736 6734 }
6735 + //Check Lesson edit access to support page builders (eg: Oxygen)
6736 + if ( current_user_can(tutor()->instructor_role) && tutils()->has_lesson_edit_access() ) {
6737 + return true;
6738 + }
7737 6739
7738 6740 return false;
7739 6741 }
7740 6742
7741 6743 /**
7742 - * Return the assignment deadline date in gmt based on duration and assignment creation date
6744 + * @return date
6745 + *
6746 + * @since v1.8.0
7743 6747 *
7744 - * @since 1.8.0
7745 - * @since 3.4.0 param $student_id and $course_id added.
7746 - * @since 3.5.0 param $format removed.
7747 - *
7748 - * @param int $assignment_id assignment id.
7749 - * @param mixed $fallback fallback.
7750 - * @param int $student_id the student id.
7751 - * @param int $course_id the course id.
7752 - * @param mixed $options options.
7753 - *
7754 - * @return string|false
6748 + * Return the assignment deadline date based on duration and assignment creation date
7755 6749 */
7756 - public function get_assignment_deadline_date_in_gmt( $assignment_id, $fallback = null, $student_id = 0, $course_id = 0, $options = null ) {
7757 - $options = $options ?? $this->get_assignment_option( $assignment_id );
7758 - $value = $this->avalue_dot( 'time_duration.value', $options );
7759 - $time = $this->avalue_dot( 'time_duration.time', $options );
7760 - $deadline_from_start = (bool) $this->avalue_dot( 'deadline_from_start', $options );
6750 + public function get_assignment_deadline_date( $assignment_id, $format=null, $fallback=null ) {
6751 +
6752 + ! $format ? $format='j F, Y, g:i a' : 0;
7761 6753
7762 - if ( ! $value ) {
6754 + $value = $this->get_assignment_option( $assignment_id, 'time_duration.value' );
6755 + $time = $this->get_assignment_option( $assignment_id, 'time_duration.time' );
6756 +
6757 + if ( !$value ) {
7763 6758 return $fallback;
7764 6759 }
7765 6760
7766 - $deadline_date = null;
7767 - $enrolled_date_gmt = '';
6761 + $publish_date = get_post_field( 'post_date', $assignment_id );
7768 6762
7769 - if ( $course_id && $student_id ) {
7770 - $enrolled_info = EnrollmentModel::is_enrolled( $course_id, $student_id );
7771 -
7772 - if ( $enrolled_info ) {
7773 - $enrolled_date_gmt = apply_filters( 'tutor_content_drip_assignment_deadline', strtotime( $enrolled_info->post_date_gmt ), $course_id, $assignment_id );
7774 - $enrolled_date_gmt = date( DateTimeHelper::FORMAT_MYSQL, $enrolled_date_gmt );
7775 - }
7776 - }
7777 -
7778 - $publish_date_gmt = get_post_field( 'post_date_gmt', $assignment_id );
7779 -
7780 - $deadline_date = strtotime( $enrolled_date_gmt ) < strtotime( $publish_date_gmt ) ? $publish_date_gmt : $enrolled_date_gmt;
7781 -
7782 - if ( $deadline_from_start ) {
7783 - $assignment_comment = tutor_utils()->get_single_comment_user_post_id( $assignment_id, $student_id );
7784 - if ( $assignment_comment && isset( $assignment_comment->comment_date_gmt ) ) {
7785 - $deadline_date = $assignment_comment->comment_date_gmt;
7786 - }
7787 - }
7788 -
7789 - $date = date_create( $deadline_date );
6763 + $date = date_create( $publish_date );
7790 6764 date_add( $date, date_interval_create_from_date_string( $value . ' ' . $time ) );
7791 6765
7792 - return date_format( $date, DateTimeHelper::FORMAT_MYSQL );
6766 + return date_format( $date, $format );
7793 6767 }
7794 6768
7795 6769 /**
7796 - * Return object from vendor package
7797 - *
7798 - * @since 1.8.4
7799 - *
7800 - * @return object
7801 - */
7802 - public function get_package_object() {
7803 - $params = func_get_args();
7804 -
7805 - $is_pro = $params[0];
7806 - $class = $params[1];
7807 - $class_args = array_slice( $params, 2 );
7808 - $root_path = $is_pro ? tutor_pro()->path : tutor()->path;
7809 -
7810 - require_once $root_path . '/vendor/autoload.php';
7811 -
7812 - $reflector = new \ReflectionClass( $class );
7813 - $object = $reflector->newInstanceArgs( $class_args );
7814 -
7815 - return $object;
7816 - }
7817 -
7818 - /**
7819 - * Check if user has specific role
7820 - *
7821 - * @since 1.8.9
7822 - *
7823 - * @param mixed $roles roles.
7824 - * @param integer $user_id user id.
7825 - *
7826 - * @return boolean
7827 - */
7828 - public function has_user_role( $roles, $user_id = 0 ) {
7829 -
7830 - // Prepare the user ID and roles array.
7831 - ! $user_id ? $user_id = get_current_user_id() : 0;
7832 - ! is_array( $roles ) ? $roles = array( $roles ) : 0;
7833 -
7834 - // Get the user data and it's role array.
7835 - $user = get_userdata( $user_id );
7836 - $role_list = ( is_object( $user ) && is_array( $user->roles ) ) ? $user->roles : array();
7837 -
7838 - // Check if at least one role exists.
7839 - $without_roles = array_diff( $roles, $role_list );
7840 - return count( $roles ) > count( $without_roles );
7841 - }
7842 -
7843 - /**
7844 - * Check if user can edit course
7845 - *
7846 - * @since 1.8.9
7847 - *
7848 - * @param int $user_id user id.
7849 - * @param int $course_id course id.
7850 - *
7851 - * @return boolean
7852 - */
7853 - public function can_user_edit_course( $user_id, $course_id ) {
7854 - return User::is_admin( $user_id ) || $this->is_instructor_of_this_course( $user_id, $course_id );
7855 - }
7856 -
7857 -
7858 - /**
7859 - * Check if course member limit full
7860 - *
7861 - * @since 1.9.0
7862 - *
7863 - * @param integer $course_id course id.
7864 - *
7865 - * @return boolean
7866 - */
7867 - public function is_course_fully_booked( $course_id = 0 ) {
7868 -
7869 - $total_enrolled = $this->count_enrolled_users_by_course( $course_id );
7870 - $maximum_students = (int) $this->get_course_settings( $course_id, 'maximum_students' );
7871 -
7872 - return $maximum_students && $maximum_students <= $total_enrolled;
7873 - }
7874 -
7875 - /**
7876 - * Check course is booked.
7877 - *
7878 - * @since 1.9.0
7879 - *
7880 - * @param integer $course_id course id.
7881 - *
7882 - * @return boolean
7883 - */
7884 - public function is_course_booked( $course_id = 0 ) {
7885 -
7886 - $total_enrolled = $this->count_enrolled_users_by_course( $course_id );
7887 - $maximum_students = (int) $this->get_course_settings( $course_id, 'maximum_students' );
7888 -
7889 - $total_booked = 100 / $maximum_students * $total_enrolled;
7890 -
7891 - return $total_booked;
7892 - }
7893 -
7894 - /**
7895 - * Check if current screen is under tutor dashboard
7896 - *
7897 - * @since 1.0.0
7898 - *
7899 - * @param string $subpage subpage.
7900 - *
7901 - * @return boolean
7902 - */
7903 - public function is_tutor_dashboard( $subpage = null ) {
7904 -
7905 - // To Do: Add subpage check later.
7906 -
7907 - if ( function_exists( 'is_admin' ) && is_admin() ) {
7908 - $screen = get_current_screen();
7909 - return is_object( $screen ) && $screen->parent_base == 'tutor';
7910 - }
7911 -
7912 - return false;
7913 - }
7914 -
7915 - /**
7916 - * Check if current screen tutor frontend dashboard
7917 - *
7918 - * @since 1.9.4
7919 - * @since 4.0.0 Subpage check support added.
7920 - * Example: assignments/submitted
7921 - *
7922 - * @param string $subpage subpage.
7923 - *
7924 - * @return boolean
7925 - */
7926 - public function is_tutor_frontend_dashboard( $subpage = '' ) {
7927 - global $wp_query;
7928 -
7929 - if ( $wp_query->is_page ) {
7930 - $dashboard_page = $this->array_get( 'tutor_dashboard_page', $wp_query->query_vars );
7931 -
7932 - if ( $subpage ) {
7933 - $subpage_parts = explode( '/', $subpage, 2 );
7934 - if ( isset( $subpage_parts[1] ) ) {
7935 - $dashboard_subpage = $this->array_get( 'tutor_dashboard_sub_page', $wp_query->query_vars );
7936 - return $dashboard_page == $subpage_parts[0] && $dashboard_subpage == $subpage_parts[1];
7937 - }
7938 - }
7939 -
7940 - if ( $subpage ) {
7941 - return $dashboard_page == $subpage;
7942 - }
7943 -
7944 - if ( $wp_query->queried_object && $wp_query->queried_object->ID ) {
7945 - $d_id = apply_filters( 'tutor_dashboard_page_id_filter', $this->get_option( 'tutor_dashboard_page_id' ) );
7946 - return $wp_query->queried_object->ID == $d_id;
7947 - }
7948 - }
7949 -
7950 - return false;
7951 - }
7952 -
7953 - /**
7954 - * Get unique slug.
7955 - *
7956 - * @since 1.9.4
7957 - *
7958 - * @param string $slug slug.
7959 - * @param string $post_type post type.
7960 - * @param boolean $num_assigned num of assigned.
7961 - *
7962 - * @return string
7963 - */
7964 - public function get_unique_slug( $slug, $post_type = null, $num_assigned = false ) {
7965 -
7966 - global $wpdb;
7967 - $existing_slug = $wpdb->get_var(
7968 - $wpdb->prepare(
7969 - "SELECT post_name
7970 - FROM {$wpdb->posts}
7971 - WHERE post_name=%s" . ( $post_type ? " AND post_type='{$post_type}' LIMIT 1" : '' ),
7972 - $slug
7973 - )
7974 - );
7975 -
7976 - if ( ! $existing_slug ) {
7977 - return $slug;
7978 - }
7979 -
7980 - if ( ! $num_assigned ) {
7981 - $new_slug = $slug . '-' . 2;
7982 - } else {
7983 - $new_slug = explode( '-', $slug );
7984 - $number = end( $new_slug ) + 1;
7985 -
7986 - array_pop( $new_slug );
7987 -
7988 - $new_slug = implode( '-', $new_slug ) . '-' . $number;
7989 - }
7990 -
7991 - return $this->get_unique_slug( $new_slug, $post_type, true );
7992 - }
7993 -
7994 - /**
7995 - * Get post content ids
7996 - *
7997 - * @since 1.9.4
7998 - *
7999 - * @param string $content_type like: lesson, quiz.
8000 - * @param string $ancestor_type like: course, topics.
8001 - * @param string $ancestor_ids ancestor like course or topic.
8002 - *
8003 - * @return array of ID cols
8004 - */
8005 - public function get_course_content_ids_by( $content_type, $ancestor_type, $ancestor_ids ) {
8006 - global $wpdb;
8007 - $ids = array();
8008 -
8009 - // Convert single id to array.
8010 - ! is_array( $ancestor_ids ) ? $ancestor_ids = array( $ancestor_ids ) : 0;
8011 - $ancestor_ids = implode( ',', $ancestor_ids );
8012 -
8013 - $prepare_ancestor_ids = str_replace( ',', '_', $ancestor_ids );
8014 - $cache_key = "tutor_get_content_ids_{$content_type}_{$ancestor_type}_{$prepare_ancestor_ids}";
8015 - $ids = TutorCache::get( $cache_key );
8016 -
8017 - if ( false === $ids ) {
8018 - switch ( $content_type ) {
8019 -
8020 - // Get lesson, quiz, assignment IDs.
8021 - case tutor()->lesson_post_type:
8022 - case 'tutor_quiz':
8023 - case 'tutor_assignments':
8024 - switch ( $ancestor_type ) {
8025 -
8026 - // Get lesson, quiz, assignment IDs by course ID.
8027 - case tutor()->course_post_type:
8028 - $content_ids = $wpdb->get_col(
8029 - $wpdb->prepare(
8030 - "SELECT content.ID FROM {$wpdb->posts} course
8031 - INNER JOIN {$wpdb->posts} topic ON course.ID=topic.post_parent
8032 - INNER JOIN {$wpdb->posts} content ON topic.ID=content.post_parent
8033 - WHERE course.ID IN ({$ancestor_ids}) AND content.post_type=%s",
8034 - $content_type
8035 - )
8036 - );
8037 -
8038 - // Assign id array to the variable.
8039 - is_array( $content_ids ) ? $ids = $content_ids : 0;
8040 - break 2;
8041 - }
8042 - break;
8043 -
8044 - default:
8045 - switch ( $ancestor_type ) {
8046 - // Get lesson, quiz, assignment IDs by course ID.
8047 - case 'topic':
8048 - $content_ids = $wpdb->get_col(
8049 - "SELECT content.ID FROM {$wpdb->posts} content
8050 - INNER JOIN {$wpdb->posts} topic ON topic.ID=content.post_parent
8051 - WHERE topic.ID IN ({$ancestor_ids})"
8052 - );
8053 -
8054 - is_array( $content_ids ) ? $ids = $content_ids : 0;
8055 - break;
8056 - }
8057 - }
8058 - TutorCache::set( $cache_key, $ids );
8059 - }
8060 -
8061 - return $ids;
8062 - }
8063 -
8064 - /**
8065 - * Get course element list
8066 - *
8067 - * @since 2.0.0
8068 - *
8069 - * @param string $content_type, content type like: lesson, assignment, quiz.
8070 - * @param string $ancestor_type, content type like: lesson, assignment, quiz.
8071 - * @param string $ancestor_ids, post_parent id.
8072 - *
8073 6770 * @return array
8074 - */
8075 - public function get_course_content_list( string $content_type, string $ancestor_type, string $ancestor_ids ) {
8076 - global $wpdb;
8077 - $ids = array();
8078 - // Convert single id to array.
8079 - ! is_array( $ancestor_ids ) ? $ancestor_ids = array( $ancestor_ids ) : 0;
8080 - $ancestor_ids = implode( ',', $ancestor_ids );
8081 - switch ( $content_type ) {
8082 - // Get lesson, quiz, assignment IDs.
8083 - case tutor()->lesson_post_type:
8084 - case 'tutor_quiz':
8085 - case 'tutor_assignments':
8086 - switch ( $ancestor_type ) {
8087 - // Get lesson, quiz, assignment IDs by course ID.
8088 - case tutor()->course_post_type:
8089 - $content_ids = $wpdb->get_results(
8090 - $wpdb->prepare(
8091 - "SELECT content.* FROM {$wpdb->posts} course
8092 - INNER JOIN {$wpdb->posts} topic ON course.ID = topic.post_parent
8093 - INNER JOIN {$wpdb->posts} content ON topic.ID = content.post_parent AND content.post_type = %s
8094 - WHERE course.ID IN ({$ancestor_ids})
8095 - ",
8096 - $content_type
8097 - )
8098 - );
8099 -
8100 - // Assign id array to the variable.
8101 - $ids = $content_ids;
8102 - break 2;
8103 - }
8104 - }
8105 -
8106 - return $ids;
8107 - }
8108 -
8109 - /**
8110 - * Sanitize array key abd values recursively
6771 + *
6772 + * @since v1.8.2
8111 6773 *
8112 - * @since 2.0.0
8113 - * @deprecated This function will be removed soon.
8114 - * It is discouraged to use in new implementations.
8115 - * Use Input::sanitize_array() instead.
8116 - *
8117 - * @param array $array array.
8118 - * @param array $skip skip.
8119 - *
8120 - * @return array
6774 + * Get earning chart data
8121 6775 */
8122 - public function sanitize_recursively( $array, $skip = array() ) {
8123 - $new_array = array();
8124 - if ( is_array( $array ) && ! empty( $array ) ) {
8125 - foreach ( $array as $key => $value ) {
8126 - $key = is_numeric( $key ) ? $key : sanitize_text_field( $key );
8127 - if ( in_array( $key, $skip ) ) {
8128 - $new_array[ $key ] = wp_kses_post( $value );
8129 - continue;
8130 - } elseif ( is_array( $value ) ) {
8131 - $new_array[ $key ] = $this->sanitize_recursively( $value );
8132 - continue;
8133 - }
8134 - // Leave numeric as it is.
8135 - $new_array[ $key ] = is_numeric( $value ) ? $value : sanitize_text_field( $value );
8136 - }
8137 - }
8138 - return $array;
8139 - }
8140 -
8141 - /**
8142 - * Get all courses along with topics & course materials for current student
8143 - *
8144 - * @since 1.9.10
8145 - *
8146 - * @return array
8147 - */
8148 - public function course_with_materials(): array {
8149 - $user_id = get_current_user_id();
8150 - $enrolled_courses = CourseModel::get_enrolled_courses_by_user( $user_id );
8151 -
8152 - if ( false === $enrolled_courses ) {
8153 - return array();
8154 - }
8155 - $data = array();
8156 - foreach ( $enrolled_courses->posts as $key => $course ) {
8157 - // Push courses.
8158 - array_push( $data, array( 'course' => array( 'title' => $course->post_title ) ) );
8159 - $topics = $this->get_topics( $course->ID );
8160 -
8161 - if ( ! is_null( $topics ) || count( $topics->posts ) ) {
8162 - foreach ( $topics->posts as $topic_key => $topic ) {
8163 - $materials = $this->get_course_contents_by_topic( $topic->ID, -1 );
8164 - if ( count( $materials->posts ) || ! is_null( $materials->posts ) ) {
8165 - $topic->materials = $materials->posts;
8166 - }
8167 - // Push topics.
8168 - array_push( $data[ $key ]['course'], array( 'topics' => $topic ) );
8169 - }
8170 - }
8171 - }
8172 - return $data;
8173 - }
8174 -
8175 - /**
8176 - * Get course duration
8177 - *
8178 - * @since 2.0.0
8179 - *
8180 - * @param int $course_id course id.
8181 - * @param bool $return_array return array.
8182 - * @param array $texts texts.
8183 - *
8184 - * @return string | array
8185 - */
8186 - public function get_course_duration( $course_id, $return_array, $texts = array(
8187 - 'h' => 'hr',
8188 - 'm' => 'min',
8189 - 's' => 'sec',
8190 - ) ) {
8191 - $duration = maybe_unserialize( get_post_meta( $course_id, '_course_duration', true ) );
8192 - $duration_hours = (int) $this->avalue_dot( 'hours', $duration, 0 );
8193 - $duration_minutes = (int) $this->avalue_dot( 'minutes', $duration, 0 );
8194 - $duration_seconds = (int) $this->avalue_dot( 'seconds', $duration, 0 );
8195 -
8196 - if ( $return_array ) {
8197 - return array(
8198 - 'duration' => $duration,
8199 - 'durationHours' => $duration_hours,
8200 - 'durationMinutes' => $duration_minutes,
8201 - 'durationSeconds' => $duration_seconds,
8202 - );
8203 - }
8204 -
8205 - if ( ! $duration_hours && ! $duration_minutes && ! $duration_seconds ) {
8206 - return '';
8207 - }
8208 -
8209 - return $duration_hours . $texts['h'] . ' ' .
8210 - $duration_minutes . $texts['m'] . ' ' .
8211 - $duration_seconds . $texts['s'];
8212 - }
8213 -
8214 - /**
8215 - * Prepare free addons data
8216 - *
8217 - * @since 2.0.0
8218 - *
8219 - * @return array
8220 - */
8221 - public function prepare_free_addons_data() {
8222 - $addons = apply_filters( 'tutor_pro_addons_lists_for_display', array() );
8223 - $plugins_data = $addons;
8224 -
8225 - $addons_config = get_option( 'tutor_addons_config' );
8226 - $has_pro = tutor()->has_pro;
8227 -
8228 - if ( is_array( $addons ) && count( $addons ) ) {
8229 - foreach ( $addons as $base_name => $addon ) {
8230 -
8231 - $addons_path = trailingslashit( tutor()->path . "assets/images/addons/{$base_name}" );
8232 - $addons_url = trailingslashit( tutor()->url . "assets/images/addons/{$base_name}" );
8233 -
8234 - $thumbnail_URL = tutor()->url . 'assets/images/tutor-plugin.png';
8235 - if ( file_exists( $addons_path . 'thumbnail.png' ) ) {
8236 - $thumbnail_URL = $addons_url . 'thumbnail.png';
8237 - } elseif ( file_exists( $addons_path . 'thumbnail.jpg' ) ) {
8238 - $thumbnail_URL = $addons_url . 'thumbnail.jpg';
8239 - } elseif ( file_exists( $addons_path . 'thumbnail.svg' ) ) {
8240 - $thumbnail_URL = $addons_url . 'thumbnail.svg';
8241 - }
8242 -
8243 - $plugins_data[ $base_name ]['url'] = $thumbnail_URL;
8244 -
8245 - // Add add-on enable status.
8246 - $addon_url = "tutor-pro/addons/{$base_name}/{$base_name}.php";
8247 -
8248 - $plugins_data[ $base_name ]['base_name'] = $base_name;
8249 - $plugins_data[ $base_name ]['is_enabled'] = $has_pro && isset( $addons_config[ $addon_url ]['is_enable'] ) ? (int) $addons_config[ $addon_url ]['is_enable'] : 0;
8250 - }
8251 - }
8252 -
8253 - $prepared_addons = array();
8254 - foreach ( $plugins_data as $tutor_addon ) {
8255 - array_push( $prepared_addons, $tutor_addon );
8256 - }
8257 -
8258 - return $prepared_addons;
8259 - }
8260 -
8261 - /**
8262 - * Get completed assignment number
8263 - *
8264 - * @since 2.0.0
8265 - *
8266 - * @param int $course_id course id | required.
8267 - * @param int $student_id student id | required.
8268 - *
8269 - * @return int
8270 - */
8271 - public function get_submitted_assignment_count( int $assignment_id, int $student_id ): int {
6776 + public function get_earning_chart( $user_id, $start_date, $end_date ) {
8272 6777 global $wpdb;
8273 - $assignments = $wpdb->get_var(
8274 - $wpdb->prepare(
8275 - " SELECT COUNT(*) FROM {$wpdb->posts} AS assignment
8276 - INNER JOIN {$wpdb->posts} AS topic
8277 - ON topic.ID = assignment.post_parent
8278 - INNER JOIN {$wpdb->posts} AS course
8279 - ON course.ID = topic.post_parent
8280 - INNER JOIN {$wpdb->comments} AS submit
8281 - ON submit.comment_post_ID = assignment.ID
8282 - WHERE assignment.post_type = %s
8283 - AND assignment.ID = %d
8284 - AND submit.user_id = %d
8285 - ",
8286 - 'tutor_assignments',
8287 - $assignment_id,
8288 - $student_id
8289 - )
8290 - );
8291 - return $assignments;
8292 - }
8293 6778
8294 - /**
8295 - * Get completed assignment number
8296 - *
8297 - * @since 2.0.0
8298 - *
8299 - * @param int $course_id course id | required.
8300 - * @param int $student_id student id | required.
8301 - *
8302 - * @return int
8303 - */
8304 - public function count_completed_assignment( int $course_id, int $student_id ): int {
8305 - global $wpdb;
8306 - $count = $wpdb->get_var(
8307 - $wpdb->prepare(
8308 - " SELECT COUNT(*) FROM {$wpdb->posts} AS assignment
8309 - INNER JOIN {$wpdb->posts} AS topic
8310 - ON topic.ID = assignment.post_parent
8311 - INNER JOIN {$wpdb->posts} AS course
8312 - ON course.ID = topic.post_parent
8313 - INNER JOIN {$wpdb->comments} AS submit
8314 - ON submit.comment_post_ID = assignment.ID
8315 - WHERE assignment.post_type = %s
8316 - AND course.ID = %d
8317 - AND submit.user_id = %d
8318 - ",
8319 - 'tutor_assignments',
8320 - $course_id,
8321 - $student_id
8322 - )
8323 - );
8324 - return $count ? $count : 0;
8325 - }
8326 -
8327 - /**
8328 - * Empty state template
8329 - *
8330 - * @since 2.0.0
8331 - *
8332 - * @param string $title title.
8333 - *
8334 - * @return mixed html
8335 - */
8336 - public function tutor_empty_state( string $title = 'No data yet!' ) {
8337 - ?>
8338 - <div class="tutor-empty-state td-empty-state tutor-p-32 tutor-text-center">
8339 - <img src="<?php echo esc_url( tutor()->url . 'assets/images/emptystate.svg' ); ?>" alt="<?php echo esc_attr( $title ); ?>" width="85%" />
8340 - <div class="tutor-fs-6 tutor-color-secondary tutor-text-center">
8341 - <?php echo esc_html( $title, 'tutor' ); ?>
8342 - </div>
8343 - </div>
8344 - <?php
8345 - }
8346 -
8347 - /**
8348 - * Render list empty state template
8349 - *
8350 - * @since 3.7.0
8351 - *
8352 - * @param array $data title and subtitle.
8353 - *
8354 - * @return void
8355 - */
8356 - public function render_list_empty_state( $data = array() ) {
8357 - tutor_load_template_from_custom_path( tutor()->path . 'views/elements/list-empty-state.php', $data );
8358 - }
8359 -
8360 - /**
8361 - * Get subtitle for list empty state.
8362 - *
8363 - * @since 3.7.0
8364 - *
8365 - * @return bool|string
8366 - */
8367 - public function get_list_empty_state_subtitle() {
8368 - $subtitle = __( 'Try adjusting your filters.', 'tutor' );
8369 -
8370 - $post_type = isset( $_GET['post-type'] ) ? true : false;
8371 - $course = isset( $_GET['course-id'] ) ? true : false;
8372 - $data = isset( $_GET['data'] ) ? true : false;
8373 - $date = isset( $_GET['date'] ) ? true : false;
8374 - $search = isset( $_GET['search'] ) ? true : false;
8375 - $category = isset( $_GET['category'] ) ? true : false;
8376 - $payment_status = isset( $_GET['payment-status'] ) ? true : false;
8377 - $subscription_type = isset( $_GET['subscription-type'] ) ? true : false;
8378 - $applies_to = isset( $_GET['applies_to'] ) ? true : false;
8379 -
8380 - if ( $post_type || $course || $data || $date || $search || $category || $payment_status || $subscription_type || $applies_to ) {
8381 - if ( $search ) {
8382 - return __( 'Try using different keywords.', 'tutor' );
8383 - }
8384 -
8385 - return $subtitle;
8386 - }
8387 -
8388 - return false;
8389 - }
8390 -
8391 - /**
8392 - * Get tutor TOC page link
8393 - * Settings > General > Terms and Conditions Page
8394 - *
8395 - * @since 2.0.5
8396 - *
8397 - * @return null | string
8398 - */
8399 - function get_toc_page_link() {
8400 - $tutor_toc_page_id = (int) get_tutor_option( 'tutor_toc_page_id' );
8401 - $tutor_toc_page_link = null;
8402 -
8403 - if ( ! in_array( $tutor_toc_page_id, array( 0, -1 ) ) ) {
8404 - $tutor_toc_page_link = get_page_link( $tutor_toc_page_id );
8405 - }
8406 -
8407 - return $tutor_toc_page_link;
8408 - }
8409 -
8410 - /**
8411 - * Get tutor Privacy Policay page link
8412 - * Settings > General > Privacy Policy
8413 - *
8414 - * @since 3.0.0
8415 - *
8416 - * @return null | string
8417 - */
8418 - function get_privacy_page_link() {
8419 - // Get wp privacy poicay page
8420 - $privacy_policy_url = get_privacy_policy_url();
8421 -
8422 - $tutor_privacy_page_id = (int) get_tutor_option( 'ecommerce_privacy_policy' );
8423 - $tutor_privacy_page_link = null;
8424 -
8425 - if ( ! in_array( $tutor_privacy_page_id, array( 0, -1 ) ) ) {
8426 - $tutor_privacy_page_link = get_page_link( $tutor_privacy_page_id );
8427 - } elseif ( $privacy_policy_url ) {
8428 - $tutor_privacy_page_link = $privacy_policy_url;
8429 - }
8430 -
8431 - return $tutor_privacy_page_link;
8432 - }
8433 -
8434 - /**
8435 - * Translate dynamic text, dynamic text is not translate while potting
8436 - * that's why define key here to make it translate able. It will put text in the pot file while compilling.
8437 - *
8438 - * @since 2.0.0
8439 - *
8440 - * @param string $key, pass key to get translate text | required.
8441 - *
8442 - * @return string
8443 - */
8444 - public function translate_dynamic_text( $key, $add_badge = false, $badge_tag = 'span' ): string {
8445 - $old_key = $key;
8446 - $key = trim( strtolower( $key ) );
8447 -
8448 - $key_value = tutor_get_translate_text();
8449 -
8450 - if ( $add_badge && isset( $key_value[ $key ] ) ) {
8451 - return '<' . $badge_tag . ' class="tutor-badge-label label-' . $key_value[ $key ]['badge'] . '">' .
8452 - $key_value[ $key ]['text'] .
8453 - '</' . $badge_tag . '>';
8454 - }
8455 -
8456 - // Revert to linear textual array.
8457 - $key_value = array_map(
8458 - function ( $kv ) {
8459 - return $kv['text'];
8460 - },
8461 - $key_value
8462 - );
8463 -
8464 - return isset( $key_value[ $key ] ) ? $key_value[ $key ] : $old_key;
8465 - }
8466 -
8467 - /**
8468 - * Show character as asterisk symbol for email
8469 - * it will replace character with asterisk till @ symbol
8470 - *
8471 - * @since 2.0.0
8472 - *
8473 - * @param string $email | required.
8474 - *
8475 - * @return string
8476 - */
8477 - function asterisks_email( string $email ): string {
8478 - if ( '' === $email ) {
8479 - return '';
8480 - }
8481 - $mail_part = explode( '@', $email );
8482 - $mail_part[0] = $this->asterisks_center_text( $mail_part[0] );
8483 - return $mail_part[0] . '@' . $mail_part[1];
8484 - }
8485 -
8486 - /**
8487 - * Show some character as asterisk symbol
8488 - * it will replace character with asterisk from the beginning and ending
8489 - *
8490 - * @since 2.0.0
8491 - * @since 4.0.0 param number_of_asterisks added.
8492 - *
8493 - * @param string $text | required.
8494 - * @param int $number_of_asterisks | optional. if not provided then it will be length of string minus 2.
8495 - *
8496 - * @return string
8497 - */
8498 - function asterisks_center_text( string $str, $number_of_asterisks = -1 ): string {
8499 - if ( '' === $str ) {
8500 - return '';
8501 - }
8502 -
8503 - $str_length = strlen( $str );
8504 - $astericks_str = str_repeat( '*', $number_of_asterisks > 0 ? $number_of_asterisks : $str_length - 2 );
8505 -
8506 - return substr( $str, 0, 2 ) . $astericks_str . substr( $str, $str_length - 2, 2 );
8507 - }
8508 -
8509 - /**
8510 - * Report frequencies that will be shown on the dropdown
8511 - *
8512 - * @since 2.0.0
8513 - *
8514 - * @return array
8515 - */
8516 - public function report_frequencies() {
8517 - $frequencies = array(
8518 - 'alltime' => __( 'All Time', 'tutor' ),
8519 - 'today' => __( 'Today', 'tutor' ),
8520 - 'last30days' => __( 'Last 30 Days', 'tutor' ),
8521 - 'last90days' => __( 'Last 90 Days', 'tutor' ),
8522 - 'last365days' => __( 'Last 365 Days', 'tutor' ),
8523 - 'custom' => __( 'Custom', 'tutor' ),
8524 - );
8525 - return $frequencies;
8526 - }
8527 -
8528 - /**
8529 - * Add interval days with today date. For ex: 10 days add with today
8530 - *
8531 - * @since 2.0.0
8532 - *
8533 - * @param string $interval | required.
8534 - */
8535 - public function add_days_with_today( $interval ) {
8536 - $today = date_create( date( 'Y-m-d' ) );
8537 - $add_days = date_add( $today, date_interval_create_from_date_string( $interval ) );
8538 - return $add_days;
8539 - }
8540 -
8541 - /**
8542 - * Subtract interval days from today date. For ex: 10 days back from today
8543 - *
8544 - * @since 2.0.0
8545 - *
8546 - * @param string $interval | required.
8547 - *
8548 - * @return mixed
8549 - */
8550 - public function sub_days_with_today( $interval ) {
8551 - $today = date_create( date( 'Y-m-d' ) );
8552 - $add_days = date_sub( $today, date_interval_create_from_date_string( $interval ) );
8553 - return $add_days;
8554 - }
8555 -
8556 - /**
8557 - * Get renderable column list for tables based on context
8558 - *
8559 - * @since 2.0.0
8560 - *
8561 - * @param string $page_key page key.
8562 - * @param string $context context.
8563 - * @param array $contexts contexts.
8564 - * @param mixed $filter_hook filter hook.
8565 - *
8566 - * @return array
8567 - */
8568 - public function get_table_columns_from_context( $page_key, $context, $contexts, $filter_hook = null ) {
8569 -
8570 - $fields = array();
8571 - $columns = $contexts[ $page_key ]['columns'];
8572 - $filter_hook ? $columns = apply_filters( $filter_hook, $contexts[ $page_key ]['columns'] ) : 0;
8573 -
8574 - $allowed = $contexts[ $page_key ]['contexts'][ $context ];
8575 - is_string( $allowed ) ? $allowed = $contexts[ $page_key ]['contexts'][ $allowed ] : 0; // By reference.
8576 -
8577 - if ( $allowed === true ) {
8578 - $fields = $columns;
8579 - } else {
8580 - foreach ( $columns as $key => $column ) {
8581 - in_array( $key, $allowed ) ? $fields[ $key ] = $column : 0;
8582 - }
8583 - }
8584 -
8585 - return $fields;
8586 - }
8587 -
8588 - /**
8589 - * Check a user has attempted a quiz
8590 - *
8591 - * @since 2.0.0
8592 - *
8593 - * @param string $user_id | user that taken course.
8594 - * @param string $quiz_id | quiz id that need to check wheather attempted or not.
8595 - *
8596 - * @return bool | true if attempted otherwise false.
8597 - */
8598 - public function has_attempted_quiz( $user_id, $quiz_id, $row = false ) {
8599 - global $wpdb;
8600 - // Sanitize data.
8601 - $user_id = sanitize_text_field( $user_id );
8602 - $quiz_id = sanitize_text_field( $quiz_id );
8603 - $attempted = $wpdb->get_row(
8604 - $wpdb->prepare(
8605 - "SELECT quiz_id
8606 - FROM {$wpdb->tutor_quiz_attempts}
8607 - WHERE user_id = %d
8608 - AND quiz_id = %d
8609 - ",
8610 - $user_id,
8611 - $quiz_id
8612 - )
8613 - );
8614 - return $attempted ? true : false;
8615 - }
8616 -
8617 - /**
8618 - * Course nav items
8619 - *
8620 - * @since 2.0.0
8621 - *
8622 - * @return mixed
8623 - */
8624 - public function course_nav_items() {
8625 6779 /**
8626 - * If current user has course content then enrollment is not
8627 - * required
8628 - *
8629 - * @since 2.0.6
6780 + * Format Date Name
8630 6781 */
8631 - $is_require_enrollment = ! $this->has_user_course_content_access();
8632 - $array = array(
8633 - 'info' => array(
8634 - 'title' => __( 'Course Info', 'tutor' ),
8635 - 'method' => 'tutor_course_info_tab',
8636 - ),
8637 - 'reviews' => array(
8638 - 'title' => __( 'Reviews', 'tutor' ),
8639 - 'method' => 'tutor_course_target_reviews_html',
8640 - ),
8641 - 'questions' => array(
8642 - 'title' => __( 'Q&A', 'tutor' ),
8643 - 'method' => 'tutor_course_question_and_answer',
8644 - 'require_enrolment' => $is_require_enrollment,
8645 - ),
8646 - 'announcements' => array(
8647 - 'title' => __( 'Announcements', 'tutor' ),
8648 - 'method' => 'tutor_course_announcements',
8649 - 'require_enrolment' => $is_require_enrollment,
8650 - ),
8651 - );
8652 - return $array;
8653 - }
6782 + $begin = new \DateTime( $start_date );
6783 + $end = new \DateTime( $end_date );
6784 + $interval = \DateInterval::createFromDateString( '1 day' );
6785 + $period = new \DatePeriod( $begin, $interval, $end );
8654 6786
8655 - /**
8656 - * Second to formated time.
8657 - *
8658 - * @since 2.0.0
8659 - *
8660 - * @param string $seconds seconds.
8661 - * @param string $type type.
8662 - *
8663 - * @return \DateInterval|false
8664 - */
8665 - public function second_to_formated_time( $seconds, $type = null ) {
8666 -
8667 - $dt_f = new \DateTime( '@0' );
8668 - $dt_t = new \DateTime( "@$seconds" );
8669 -
8670 - switch ( $type ) {
8671 -
8672 - case 'days':
8673 - $format = '%ad %hh';
8674 - break;
8675 -
8676 - case 'hours':
8677 - $format = '%d' > 0 ? '%hh %im %ss' : '%im %ss';
8678 - $format = '%h' > 0 ? '%im %ss' : $format;
8679 - break;
8680 -
8681 - case 'minutes':
8682 - $format = '%im %ss';
8683 - break;
8684 -
8685 - default:
8686 - $format = '%im %ss';
8687 - break;
6787 + $datesPeriod = array();
6788 + foreach ( $period as $dt ) {
6789 + $datesPeriod[ $dt->format( "Y-m-d" ) ] = 0;
8688 6790 }
8689 6791
8690 - return $dt_f->diff( $dt_t )->format( $format );
8691 - }
6792 + // Get statuses
6793 + $complete_status = tutor_utils()->get_earnings_completed_statuses();
6794 + $statuses = $complete_status;
6795 + $complete_status = "'" . implode( "','", $complete_status) . "'";
6796 +
6797 + $salesQuery = $wpdb->get_results( $wpdb->prepare(
6798 + "SELECT SUM(instructor_amount) AS total_earning,
6799 + DATE(created_at) AS date_format
6800 + FROM {$wpdb->prefix}tutor_earnings
6801 + WHERE user_id = %d
6802 + AND order_status IN({$complete_status})
6803 + AND (created_at BETWEEN %s AND %s)
6804 + GROUP BY date_format
6805 + ORDER BY created_at ASC;
6806 + ",
6807 + $user_id,
6808 + $start_date,
6809 + $end_date
6810 + ) );
8692 6811
8693 - /**
8694 - * Convert seconds to time.
8695 - *
8696 - * @since 2.0.0
8697 - *
8698 - * @param int $input_seconds seconds.
8699 - *
8700 - * @return string
8701 - */
8702 - public function seconds_to_time( $input_seconds ) {
8703 - $seconds_in_a_minute = 60;
8704 - $seconds_in_an_hour = 60 * $seconds_in_a_minute;
8705 - $seconds_in_a_day = 24 * $seconds_in_an_hour;
6812 + $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
6813 + $queried_date = wp_list_pluck( $salesQuery, 'date_format' );
6814 + $dateWiseSales = array_combine( $queried_date, $total_earning );
6815 + $chartData = array_merge( $datesPeriod, $dateWiseSales );
8706 6816
8707 - // Extract days.
8708 - $days = floor( $input_seconds / $seconds_in_a_day );
8709 -
8710 - // Extract hours.
8711 - $hour_seconds = $input_seconds % $seconds_in_a_day;
8712 - $hours = floor( $hour_seconds / $seconds_in_an_hour );
8713 -
8714 - // Extract minutes.
8715 - $minute_seconds = $hour_seconds % $seconds_in_an_hour;
8716 - $minutes = floor( $minute_seconds / $seconds_in_a_minute );
8717 -
8718 - // Extract the remaining seconds.
8719 - $remaining_seconds = $minute_seconds % $seconds_in_a_minute;
8720 - $seconds = ceil( $remaining_seconds );
8721 -
8722 - // Format and return.
8723 - $time_parts = array();
8724 - $sections = array(
8725 - 'day' => (int) $days,
8726 - 'hour' => (int) $hours,
8727 - 'minute' => (int) $minutes,
8728 - 'second' => (int) $seconds,
8729 - );
8730 -
8731 - foreach ( $sections as $unit => $value ) {
8732 - if ( $value > 0 ) {
8733 - $unit_name = $unit . ( $value == 1 ? '' : 's' );
8734 - $time_parts[] = $value . ' ' . $this->translate_dynamic_text( $unit_name );
8735 - }
6817 + foreach ( $chartData as $key => $salesCount ) {
6818 + unset( $chartData[ $key ] );
6819 + $formatDate = date('d M', strtotime($key));
6820 + $chartData[ $formatDate ] = $salesCount;
8736 6821 }
8737 6822
8738 - return implode( ', ', $time_parts );
8739 - }
6823 + $statements = tutor_utils()->get_earning_statements( $user_id, compact('start_date', 'end_date', 'statuses' ) );
6824 + $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'start_date', 'end_date' ) );
8740 6825
8741 - /**
8742 - * Get all contents (lesosn, assignment, zoom, quiz etc) that belong to this topic
8743 - *
8744 - * @since 2.0.0
8745 - *
8746 - * @param int $topic_id | topic id.
8747 - *
8748 - * @return array of objects on success | false on failure.
8749 - */
8750 - public function get_contents_by_topic( int $topic_id ) {
8751 - global $wpdb;
8752 - $topic_id = sanitize_text_field( $topic_id );
8753 - $contents = $wpdb->get_results(
8754 - $wpdb->prepare(
8755 - " SELECT content.ID, content.post_title, content.post_type
8756 - FROM {$wpdb->posts} AS topics
8757 - INNER JOIN {$wpdb->posts} AS content
8758 - ON content.post_parent = topics.ID
8759 - WHERE topics.post_type = 'topics'
8760 - AND topics.ID = %d
8761 - AND content.post_status = %s
8762 - ",
8763 - $topic_id,
8764 - 'publish'
8765 - )
8766 - );
8767 - return $contents;
8768 - }
8769 -
8770 - /**
8771 - * Get total number of contents & completed contents that belongs to this topic.
8772 - *
8773 - * @since 2.0.0
8774 - * @since 4.0.0 Return percentage of completed contents and $user_id parameter added.
8775 - *
8776 - * @param int $topic_id | all contents will be checked that belong to this topic.
8777 - * @param int $user_id | user id to check completed contents, if not passed then current user id will be used.
8778 - *
8779 - * @return array {
8780 - * contents:int,
8781 - * completed:int,
8782 - * percentage:float
8783 - * }
8784 - */
8785 - public function count_completed_contents_by_topic( int $topic_id, int $user_id = 0 ): array {
8786 - $topic_id = sanitize_text_field( $topic_id );
8787 - $contents = $this->get_contents_by_topic( $topic_id );
8788 - $user_id = $this->get_user_id( $user_id );
8789 - $completed = 0;
8790 -
8791 - $lesson_post_type = 'lesson';
8792 - $quiz_post_type = 'tutor_quiz';
8793 - $assignment_post_type = 'tutor_assignments';
8794 - $zoom_lesson_post_type = 'tutor_zoom_meeting';
8795 - $google_meet_post_type = 'tutor-google-meet';
8796 -
8797 - if ( $contents ) {
8798 - foreach ( $contents as $content ) {
8799 - switch ( $content->post_type ) {
8800 - case $lesson_post_type:
8801 - $is_lesson_completed = $this->is_completed_lesson( $content->ID, $user_id );
8802 - if ( $is_lesson_completed ) {
8803 - ++$completed;
8804 - }
8805 - break;
8806 - case $quiz_post_type:
8807 - $has_attempt = $this->has_attempted_quiz( $user_id, $content->ID );
8808 - if ( $has_attempt ) {
8809 - ++$completed;
8810 - }
8811 - break;
8812 - case $assignment_post_type:
8813 - $is_assignment_completed = $this->is_assignment_submitted( $content->ID, $user_id );
8814 - if ( $is_assignment_completed ) {
8815 - ++$completed;
8816 - }
8817 - break;
8818 - case $zoom_lesson_post_type:
8819 - if ( \class_exists( '\TUTOR_ZOOM\Zoom' ) ) {
8820 - $is_zoom_lesson_completed = \TUTOR_ZOOM\Zoom::is_zoom_lesson_done( '', $content->ID, $user_id );
8821 - if ( $is_zoom_lesson_completed ) {
8822 - ++$completed;
8823 - }
8824 - }
8825 - break;
8826 - case $google_meet_post_type:
8827 - if ( \class_exists( '\TutorPro\GoogleMeet\Frontend\Frontend' ) ) {
8828 - if ( \TutorPro\GoogleMeet\Validator\Validator::is_addon_enabled() ) {
8829 - $is_completed = \TutorPro\GoogleMeet\Frontend\Frontend::is_lesson_completed( false, $content->ID, $user_id );
8830 - if ( $is_completed ) {
8831 - ++$completed;
8832 - }
8833 - }
8834 - }
8835 - break;
8836 - default:
8837 - break;
8838 - }
8839 - }
8840 - }
8841 -
8842 - $total_contents = $this->count( $contents );
8843 - $percentage = $total_contents > 0 ? ( $completed / $total_contents ) * 100 : 0;
8844 -
8845 6826 return array(
8846 - 'contents' => $total_contents,
8847 - 'completed' => $completed,
8848 - 'percentage' => $percentage,
6827 + 'chartData' => $chartData,
6828 + 'statements' => $statements,
6829 + 'statuses' => $statuses,
6830 + 'begin' => $begin,
6831 + 'end' => $end,
6832 + 'earning_sum' => $earning_sum,
6833 + 'datesPeriod' => $datesPeriod
8849 6834 );
8850 6835 }
8851 6836
8852 6837 /**
8853 - * Text message for the list tables that will be visible
8854 - * if no record found or filter data not found
8855 - *
8856 - * @since 2.0.0
8857 - *
8858 - * @return string | not found text
8859 - */
8860 - public function not_found_text(): string {
8861 - // phpcs:disable WordPress.Security.NonceVerification.Missing
8862 - $course = isset( $_GET['course-id'] ) ? true : false;
8863 - $date = isset( $_GET['date'] ) ? true : false;
8864 - $search = isset( $_GET['search'] ) ? true : false;
8865 - $category = isset( $_GET['category'] ) ? true : false;
8866 - $text = array(
8867 - 'normal' => __( 'No Data Available in this Section', 'tutor' ),
8868 - 'filter' => __( 'No Data Found from your Search/Filter', 'tutor' ),
8869 - );
8870 -
8871 - if ( $course || $date || $search || $category ) {
8872 - return $text['filter'];
8873 - } else {
8874 - return $text['normal'];
8875 - }
8876 - }
8877 -
8878 -
8879 - /**
8880 - * Should show the disscussion menu on the student
8881 - * and instructor dashboard menu
8882 - *
8883 - * @since 4.0.0
8884 - *
8885 - * @return boolean
8886 - */
8887 - public function should_show_dicussion_menu(): bool {
8888 - $is_q_and_a_enabled = tutor_utils()->get_option( 'enable_q_and_a_on_course', false );
8889 - $is_lesson_comment_enabled = tutor_utils()->get_option( 'enable_comment_for_lesson', false );
8890 -
8891 - return $is_q_and_a_enabled || $is_lesson_comment_enabled;
8892 - }
8893 -
8894 -
8895 - /**
8896 - * Default config for tutor text editor
8897 - * Modify default param from here and pass to render_text_editor() method
8898 - *
8899 - * @since 2.0.0
8900 - *
8901 - * @param array $args array of arguments.
8902 - *
8903 - * @return array default config.
8904 - */
8905 - public function text_editor_config( $args = array() ) {
8906 - $default_args = array(
8907 - 'textarea_name' => 'tutor-global-text-editor',
8908 - 'plugins' => 'image',
8909 - 'tinymce' => array(
8910 - 'toolbar1' => 'bold,italic,underline,link,unlink,removeformat,image,bullist',
8911 - 'toolbar2' => '',
8912 - 'toolbar3' => '',
8913 - ),
8914 - 'file_picker_types' => 'image',
8915 - 'media_buttons' => false,
8916 - 'drag_drop_upload' => false,
8917 - 'quicktags' => false,
8918 - 'elementpath' => false,
8919 - 'wpautop' => false,
8920 - 'statusbar' => false,
8921 - 'editor_height' => 112,
8922 - 'editor_css' => '<style>
8923 - #wp-tutor-global-text-editor-wrap div.mce-toolbar-grp {
8924 - background-color: #fff;
8925 - }
8926 - </style>',
8927 - );
8928 - return wp_parse_args( $args, $default_args );
8929 - }
8930 -
8931 - /**
8932 - * Get config for profile bio editor.
8933 - *
8934 - * @since 2.2.4
8935 - *
8936 - * @param string $textarea_name textarea name for post request.
8937 - *
8938 6838 * @return array
8939 - */
8940 - public function get_profile_bio_editor_config( $textarea_name = 'tutor_profile_bio' ) {
8941 - return $this->text_editor_config(
8942 - array(
8943 - 'textarea_name' => $textarea_name,
8944 - 'tinymce' => array(
8945 - 'toolbar1' => 'bold,italic,underline,blockquote,bullist,numlist,alignleft,aligncenter,alignright,undo,redo,removeformat',
8946 - 'toolbar2' => '',
8947 - 'toolbar3' => '',
8948 - ),
8949 - )
8950 - );
8951 - }
8952 -
8953 - /**
8954 - * Get video sources.
6839 + *
6840 + * @since v1.8.2
8955 6841 *
8956 - * @since 2.0.0
8957 - *
8958 - * @param boolean $key_title_only key title only.
8959 - *
8960 - * @return array
6842 + * Get earning chart data yearly
8961 6843 */
8962 - public function get_video_sources( bool $key_title_only ) {
8963 -
8964 - $video_sources = array(
8965 - 'html5' => array(
8966 - 'title' => __( 'HTML 5 (mp4)', 'tutor' ),
8967 - 'icon' => 'html5',
8968 - ),
8969 - 'external_url' => array(
8970 - 'title' => __( 'External URL', 'tutor' ),
8971 - 'icon' => 'external_url',
8972 - ),
8973 - 'youtube' => array(
8974 - 'title' => __( 'YouTube', 'tutor' ),
8975 - 'icon' => 'youtube',
8976 - ),
8977 - 'vimeo' => array(
8978 - 'title' => __( 'Vimeo', 'tutor' ),
8979 - 'icon' => 'vimeo',
8980 - ),
8981 - 'embedded' => array(
8982 - 'title' => __( 'Embedded', 'tutor' ),
8983 - 'icon' => 'embedded',
8984 - ),
8985 - 'shortcode' => array(
8986 - 'title' => __( 'Shortcode', 'tutor' ),
8987 - 'icon' => 'code',
8988 - ),
8989 - );
8990 - $video_sources = apply_filters( 'tutor_preferred_video_sources', $video_sources );
8991 -
8992 - if ( $key_title_only ) {
8993 - foreach ( $video_sources as $key => $data ) {
8994 - $video_sources[ $key ] = $data['title'];
8995 - }
8996 - }
8997 - return $video_sources;
8998 - }
8999 -
9000 - /**
9001 - * Convert date to wp timezone compatible date. Timezone will be get from settings
9002 - * NOTE: date_i18n translate able string is not supported
9003 - *
9004 - * @since 2.0.0
9005 - * @since 2.2.5 $format param added to modify the format if required.
9006 - *
9007 - * @param string $date string date time to convert.
9008 - * @param string $format format of date time.
9009 - *
9010 - * @return string formated date-time.
9011 - */
9012 - public function convert_date_into_wp_timezone( string $date, ?string $format = null ): string {
9013 - $date = new \DateTime( $date );
9014 - $date->setTimezone( wp_timezone() );
9015 - return $date->format( ! is_null( $format ) ? $format : get_option( 'date_format' ) . ', ' . get_option( 'time_format' ) );
9016 - }
9017 -
9018 - /**
9019 - * Tutor custom header.
9020 - *
9021 - * @since 2.0.0
9022 - *
9023 - * @return void
9024 - */
9025 - public function tutor_custom_header() {
9026 - global $wp_version;
9027 - if ( version_compare( $wp_version, '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && wp_is_block_theme() ) {
9028 - ?>
9029 - <!doctype html>
9030 - <html <?php language_attributes(); ?>>
9031 - <head>
9032 - <meta charset="<?php bloginfo( 'charset' ); ?>">
9033 - <?php wp_head(); ?>
9034 - </head>
9035 - <body <?php body_class(); ?>>
9036 - <?php wp_body_open(); ?>
9037 - <div class="wp-site-blocks">
9038 - <?php
9039 - $theme = wp_get_theme();
9040 - $theme_slug = $theme->get( 'TextDomain' );
9041 - echo do_blocks( '<!-- wp:template-part {"slug":"header","theme":"' . $theme_slug . '","tagName":"header","className":"site-header","layout":{"inherit":true}} /-->' );
9042 - } else {
9043 - get_header();
9044 - }
9045 - }
9046 -
9047 - /**
9048 - * Tutor Custom Header
9049 - *
9050 - * @since 2.0.0
9051 - */
9052 - public function tutor_custom_footer() {
9053 - global $wp_version;
9054 - if ( version_compare( $wp_version, '5.9', '>=' ) && function_exists( 'wp_is_block_theme' ) && true === wp_is_block_theme() ) {
9055 - $theme = wp_get_theme();
9056 - $theme_slug = $theme->get( 'TextDomain' );
9057 - echo do_blocks( '<!-- wp:template-part {"slug":"footer","theme":"' . $theme_slug . '","tagName":"footer","className":"site-footer","layout":{"inherit":true}} /-->' );
9058 - echo '</div>';
9059 - wp_footer();
9060 - echo '</body>';
9061 - echo '</html>';
9062 - } else {
9063 - get_footer();
9064 - }
9065 - }
9066 -
9067 - /**
9068 - * Can user retake course.
9069 - *
9070 - * @since 2.0.0
9071 - *
9072 - * @return boolean
9073 - */
9074 - public function can_user_retake_course() {
9075 - if ( ! EnrollmentModel::is_enrolled() ) {
9076 - return false;
9077 - }
9078 -
9079 - $completed_lessons = $this->get_completed_lesson_count_by_course();
9080 - $completed_percent = $this->get_course_completed_percent();
9081 - $is_completed_course = $this->is_completed_course();
9082 - $retake_course = $this->get_option( 'course_retake_feature', false ) && ( $is_completed_course || $completed_percent >= 100 );
9083 -
9084 - return $retake_course;
9085 - }
9086 -
9087 -
9088 - /**
9089 - * Clean unnecessary html code from the content
9090 - *
9091 - * @since 2.0.1
9092 - *
9093 - * @param string $content content.
9094 - * @param array $allowed allowed.
9095 - *
9096 - * @return string
9097 - */
9098 - public function clean_html_content( $content = '', $allowed = array() ) {
9099 -
9100 - $default = array(
9101 - 'div' => array(
9102 - 'class' => 1,
9103 - 'style' => 1,
9104 - ),
9105 - 'b' => array( 'style' => 1 ),
9106 - 'strong' => array( 'style' => 1 ),
9107 - 'i' => array( 'style' => 1 ),
9108 - 'u' => array( 'style' => 1 ),
9109 - 'h1' => array( 'style' => 1 ),
9110 - 'h2' => array( 'style' => 1 ),
9111 - 'h3' => array( 'style' => 1 ),
9112 - 'h4' => array( 'style' => 1 ),
9113 - 'h5' => array( 'style' => 1 ),
9114 - 'h6' => array( 'style' => 1 ),
9115 - 'a' => array(
9116 - 'href' => array(
9117 - 'minlen' => 3,
9118 - 'maxlen' => 100,
9119 - ),
9120 - 'target' => 1,
9121 - 'style' => 1,
9122 - ),
9123 - 'p' => array( 'style' => 1 ),
9124 - 'img' => array(
9125 - 'src' => 1,
9126 - 'alt' => 1,
9127 - 'style' => 1,
9128 - ),
9129 - 'pre' => array( 'style' => 1 ),
9130 - 'ul' => array( 'style' => 1 ),
9131 - 'ol' => array( 'style' => 1 ),
9132 - 'li' => array( 'style' => 1 ),
9133 - );
9134 -
9135 - $allowed = wp_parse_args( $allowed, $default );
9136 -
9137 - return wp_kses( $content, $allowed );
9138 - }
9139 -
9140 - /**
9141 - * Get predefined icon
9142 - *
9143 - * @since 2.0.2
9144 - * @since 4.0.0 param $name, $width, $height & $attributes added.
9145 - *
9146 - * @param string $name name.
9147 - * @param int $width the svg icon width.
9148 - * @param int $height the svg icon height.
9149 - * @param array $attributes svg attributes.
9150 - *
9151 - * @return string
9152 - */
9153 - public function get_svg_icon( $name = '', $width = 16, $height = 16, $attributes = array() ) {
9154 - $icon_path = tutor()->path . 'assets/icons/' . $name . '.svg';
9155 - return $this->get_svg(
9156 - $icon_path,
9157 - array(
9158 - 'width' => $width,
9159 - 'height' => $height,
9160 - 'attributes' => array_merge(
9161 - array(
9162 - 'fill' => 'none',
9163 - 'role' => 'presentation',
9164 - 'aria-hidden' => 'true',
9165 - ),
9166 - $attributes
9167 - ),
9168 - )
9169 - );
9170 - }
9171 -
9172 - /**
9173 - * Get SVG content for inline rendering.
9174 - *
9175 - * @since 4.0.0
9176 - *
9177 - * @param string $path Absolute path to the SVG file.
9178 - * @param array $options {
9179 - * output?: bool,
9180 - * width?: string|int|null,
9181 - * height?: string|int|null,
9182 - * attributes?: array<string, string>
9183 - * } $options Optional settings.
9184 - * @return string
9185 - */
9186 - public function get_svg( string $path, array $options = array() ): string {
9187 - $options = array_merge(
9188 - array(
9189 - 'width' => null,
9190 - 'height' => null,
9191 - 'attributes' => array(),
9192 - ),
9193 - $options
9194 - );
9195 -
9196 - if ( ! file_exists( $path ) ) {
9197 - return '';
9198 - }
9199 -
9200 - $svg_content = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
9201 - if ( false === $svg_content ) {
9202 - return '';
9203 - }
9204 -
9205 - if ( ! empty( $options['width'] ) || ! empty( $options['height'] ) || ! empty( $options['attributes'] ) ) {
9206 - $svg_content = preg_replace_callback(
9207 - '/<svg\b[^>]*>/i',
9208 - static function ( $matches ) use ( $options ) {
9209 - $svg_tag = preg_replace( '/\s(?:width|height)="[^"]*"/i', '', $matches[0] );
9210 -
9211 - foreach ( $options['attributes'] as $key => $value ) {
9212 - $svg_tag = preg_replace( '/\s' . preg_quote( $key, '/' ) . '="[^"]*"/i', '', $svg_tag );
9213 - }
9214 -
9215 - $svg_tag = rtrim( substr( $svg_tag, 0, -1 ) );
9216 -
9217 - if ( ! empty( $options['width'] ) ) {
9218 - $svg_tag .= ' width="' . esc_attr( (string) $options['width'] ) . '"';
9219 - }
9220 -
9221 - if ( ! empty( $options['height'] ) ) {
9222 - $svg_tag .= ' height="' . esc_attr( (string) $options['height'] ) . '"';
9223 - }
9224 -
9225 - foreach ( $options['attributes'] as $key => $value ) {
9226 - $svg_tag .= ' ' . esc_attr( $key ) . '="' . esc_attr( (string) $value ) . '"';
9227 - }
9228 -
9229 - return $svg_tag . '>';
9230 - },
9231 - $svg_content,
9232 - 1
9233 - );
9234 - }
9235 -
9236 - $escaped = wp_kses( $svg_content, Input::allow_svg( array() ) );
9237 -
9238 - return $escaped;
9239 - }
9240 -
9241 - /**
9242 - * Render SVG content.
9243 - *
9244 - * @since 4.0.0
9245 - *
9246 - * @param string $path Absolute path to the SVG file.
9247 - * @param array $options Optional settings passed to get_svg().
9248 - *
9249 - * @return void
9250 - */
9251 - public function render_svg( string $path, array $options = array() ): void {
9252 - echo $this->get_svg( $path, $options ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
9253 - }
9254 -
9255 - /**
9256 - * Get theme-aware SVG content for inline rendering.
9257 - *
9258 - * @since 4.0.0
9259 - *
9260 - * @param string $path Relative asset path to the SVG file.
9261 - * @param array $options Optional settings passed to get_svg().
9262 - * @return string
9263 - */
9264 - public function get_themed_svg( string $path, array $options = array() ): string {
9265 - $resolved = UrlHelper::resolve_asset( ltrim( $path, '/' ) );
9266 -
9267 - if ( ! $resolved ) {
9268 - return '';
9269 - }
9270 -
9271 - return $this->get_svg( $resolved['path'], $options );
9272 - }
9273 -
9274 - /**
9275 - * Render theme-aware SVG content.
9276 - *
9277 - * @since 4.0.0
9278 - *
9279 - * @param string $path Relative asset path to the SVG file.
9280 - * @param array $options Optional settings passed to get_themed_svg().
9281 - *
9282 - * @return void
9283 - */
9284 - public function render_themed_svg( string $path, array $options = array() ): void {
9285 - echo $this->get_themed_svg( $path, $options ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
9286 - }
9287 -
9288 - /**
9289 - * Conver Hex to RGB
9290 - *
9291 - * @since 2.0.2
9292 - *
9293 - * @param string $color color.
9294 - *
9295 - * @return string
9296 - */
9297 - public function hex2rgb( string $color ) {
9298 -
9299 - $default = '0, 0, 0';
9300 -
9301 - if ( '' === $color ) {
9302 - return '';
9303 - }
9304 -
9305 - if ( strpos( $color, 'var(--' ) === 0 ) {
9306 - return preg_replace( '/[^A-Za-z0-9_)(\-,.]/', '', $color );
9307 - }
9308 -
9309 - // Convert hex to rgb.
9310 - if ( '#' === $color[0] ) {
9311 - $color = substr( $color, 1 );
9312 - } else {
9313 - return $default;
9314 - }
9315 -
9316 - // Check if color has 6 or 3 characters and get values.
9317 - if ( strlen( $color ) == 6 ) {
9318 - $hex = array( $color[0] . $color[1], $color[2] . $color[3], $color[4] . $color[5] );
9319 - } elseif ( strlen( $color ) == 3 ) {
9320 - $hex = array( $color[0] . $color[0], $color[1] . $color[1], $color[2] . $color[2] );
9321 - } else {
9322 - return $default;
9323 - }
9324 -
9325 - $rgb = array_map( 'hexdec', $hex );
9326 -
9327 - return implode( ', ', $rgb );
9328 - }
9329 -
9330 - /**
9331 - * Convert HEX to HSL
9332 - *
9333 - * @since 4.0.0
9334 - *
9335 - * @param string $hex HEX color code.
9336 - *
9337 - * @return array
9338 - */
9339 - public function hex_to_hsl( $hex ) {
9340 - $hex = ltrim( $hex, '#' );
9341 - if ( strlen( $hex ) == 3 ) {
9342 - $hex = $hex[0] . $hex[0] . $hex[1] . $hex[1] . $hex[2] . $hex[2];
9343 - }
9344 - $r = hexdec( substr( $hex, 0, 2 ) ) / 255;
9345 - $g = hexdec( substr( $hex, 2, 2 ) ) / 255;
9346 - $b = hexdec( substr( $hex, 4, 2 ) ) / 255;
9347 -
9348 - $max = max( $r, $g, $b );
9349 - $min = min( $r, $g, $b );
9350 - $l = ( $max + $min ) / 2;
9351 -
9352 - if ( $min === $max ) {
9353 - $h = $s = 0; //phpcs:ignore
9354 - } else {
9355 - $d = $max - $min;
9356 - $s = $l > 0.5 ? $d / ( 2 - $max - $min ) : $d / ( $max + $min );
9357 - switch ( $max ) {
9358 - case $r:
9359 - $h = ( $g - $b ) / $d + ( $g < $b ? 6 : 0 );
9360 - break;
9361 - case $g:
9362 - $h = ( $b - $r ) / $d + 2;
9363 - break;
9364 - case $b:
9365 - $h = ( $r - $g ) / $d + 4;
9366 - break;
9367 - }
9368 - $h /= 6;
9369 - }
9370 - return array(
9371 - 'h' => $h * 360,
9372 - 's' => $s * 100,
9373 - 'l' => $l * 100,
9374 - );
9375 - }
9376 -
9377 - /**
9378 - * Convert HSL to HEX
9379 - *
9380 - * @since 4.0.0
9381 - *
9382 - * @param string $h H color value.
9383 - * @param string $s S color value.
9384 - * @param string $l L color value.
9385 - *
9386 - * @return array
9387 - */
9388 - public function hsl_to_hex( $h, $s, $l ) {
9389 - $h /= 360;
9390 - $s /= 100;
9391 - $l /= 100;
9392 - if ( 0 === $s ) {
9393 - $r = $g = $b = $l; //phpcs:ignore
9394 - } else {
9395 - $hue2rgb = function ( $p, $q, $t ) {
9396 - if ( $t < 0 ) {
9397 - ++$t;
9398 - }
9399 - if ( $t > 1 ) {
9400 - --$t;
9401 - }
9402 - if ( $t < 1 / 6 ) {
9403 - return $p + ( $q - $p ) * 6 * $t;
9404 - }
9405 - if ( $t < 1 / 2 ) {
9406 - return $q;
9407 - }
9408 - if ( $t < 2 / 3 ) {
9409 - return $p + ( $q - $p ) * ( 2 / 3 - $t ) * 6;
9410 - }
9411 - return $p;
9412 - };
9413 - $q = $l < 0.5 ? $l * ( 1 + $s ) : $l + $s - $l * $s;
9414 - $p = 2 * $l - $q;
9415 - $r = $hue2rgb( $p, $q, $h + 1 / 3 );
9416 - $g = $hue2rgb( $p, $q, $h );
9417 - $b = $hue2rgb( $p, $q, $h - 1 / 3 );
9418 - }
9419 - return sprintf( '#%02x%02x%02x', round( $r * 255 ), round( $g * 255 ), round( $b * 255 ) );
9420 - }
9421 -
9422 - /**
9423 - * Get brand color
9424 - *
9425 - * @since 4.0.0
9426 - *
9427 - * @return string
9428 - */
9429 - public function get_brand_color() {
9430 - $legacy_brand_color = tutor_utils()->get_option( 'tutor_primary_color' );
9431 - return $legacy_brand_color ? $legacy_brand_color : tutor_utils()->get_option( 'brand_color', Options_V2::DEFAULT_BRAND_COLOR );
9432 - }
9433 -
9434 - /**
9435 - * Get default brand color
9436 - *
9437 - * @since 4.0.0
9438 - *
9439 - * @return string
9440 - */
9441 - public function get_default_brand_color() {
9442 - $legacy_brand_color = tutor_utils()->get_option( 'tutor_primary_color' );
9443 - return $legacy_brand_color ? $legacy_brand_color : Options_V2::DEFAULT_BRAND_COLOR;
9444 - }
9445 -
9446 - /**
9447 - * Get course builder screen.
9448 - *
9449 - * @since 2.0.0
9450 - *
9451 - * @return string|null
9452 - */
9453 - public function get_course_builder_screen() {
9454 - $builder_screen = null;
9455 - if ( is_admin() ) {
9456 - $screen = get_current_screen();
9457 - if ( is_object( $screen ) && 'post' === $screen->base && tutor()->course_post_type === $screen->id ) {
9458 - $builder_screen = $screen->is_block_editor ? 'gutenberg' : 'classic';
9459 - }
9460 - } elseif ( $this->is_tutor_frontend_dashboard( 'create-course' ) ) {
9461 - $builder_screen = 'frontend';
9462 - }
9463 -
9464 - return apply_filters( 'tutor_builder_screen', $builder_screen );
9465 - }
9466 -
9467 - /**
9468 - * Get total number of course
9469 - *
9470 - * @since 2.0.2
9471 - *
9472 - * @return int
9473 - */
9474 - public function get_total_course() {
6844 + public function get_earning_chart_yearly( $user_id, $year ) {
9475 6845 global $wpdb;
9476 - $course_post_type = tutor()->course_post_type;
9477 6846
9478 - $sql = "SELECT COUNT(ID)
9479 - FROM {$wpdb->posts}
9480 - WHERE post_type = %s
9481 - AND post_status = %s";
6847 + $complete_status = tutor_utils()->get_earnings_completed_statuses();
6848 + $statuses = $complete_status;
6849 + $complete_status = "'" . implode( "','", $complete_status) . "'";
9482 6850
9483 - return $wpdb->get_var( $wpdb->prepare( $sql, $course_post_type, 'publish' ) );
9484 - }
6851 + $salesQuery = $wpdb->get_results( $wpdb->prepare(
6852 + "SELECT SUM(instructor_amount) AS total_earning,
6853 + MONTHNAME(created_at) AS month_name
6854 + FROM {$wpdb->prefix}tutor_earnings
6855 + WHERE user_id = %d
6856 + AND order_status IN({$complete_status})
6857 + AND YEAR(created_at) = %s
6858 + GROUP BY MONTH (created_at)
6859 + ORDER BY MONTH(created_at) ASC;
6860 + ",
6861 + $user_id,
6862 + $year
6863 + ) );
9485 6864
9486 - /**
9487 - * Get total number of enrolled course
9488 - *
9489 - * @since 2.0.2
9490 - *
9491 - * @return int
9492 - */
9493 - public function get_total_enrolled_course() {
9494 - global $wpdb;
6865 + $total_earning = wp_list_pluck( $salesQuery, 'total_earning' );
6866 + $months = wp_list_pluck( $salesQuery, 'month_name' );
6867 + $monthWiseSales = array_combine( $months, $total_earning );
9495 6868
9496 - $sql = "SELECT COUNT(DISTINCT enroll.ID)
9497 - FROM {$wpdb->posts} enroll INNER JOIN {$wpdb->posts} course ON enroll.post_parent=course.ID
9498 - WHERE enroll.post_type = 'tutor_enrolled'
9499 - AND enroll.post_status = 'completed'
9500 - AND course.post_type=%s";
6869 + $dataFor = 'yearly';
9501 6870
9502 - return $wpdb->get_var( $wpdb->prepare( $sql, tutor()->course_post_type ) );
9503 - }
9504 -
9505 - /**
9506 - * Get total number of question
9507 - *
9508 - * @since 2.0.2
9509 - *
9510 - * @return int
9511 - */
9512 - public function get_total_question() {
9513 - global $wpdb;
9514 -
9515 - $sql = "SELECT COUNT(DISTINCT question.question_id)
9516 - FROM {$wpdb->prefix}tutor_quiz_questions question
9517 - INNER JOIN {$wpdb->posts} quiz ON question.quiz_id=quiz.ID
9518 - INNER JOIN {$wpdb->posts} topic ON quiz.post_parent=topic.ID
9519 - INNER JOIN {$wpdb->posts} course ON topic.post_parent=course.ID
9520 - WHERE course.post_type=%s
9521 - AND quiz.post_type='tutor_quiz'";
9522 -
9523 - return $wpdb->get_var( $wpdb->prepare( $sql, tutor()->course_post_type ) );
9524 - }
9525 -
9526 - /**
9527 - * Get total number of review
9528 - *
9529 - * @since 2.0.2
9530 - *
9531 - * @return int
9532 - */
9533 - public function get_total_review() {
9534 - global $wpdb;
9535 -
9536 - $sql = "SELECT COUNT(comment_ID)
9537 - FROM {$wpdb->comments}
9538 - WHERE comment_type = %s
9539 - AND comment_approved = %s ";
9540 -
9541 - return $wpdb->get_var( $wpdb->prepare( $sql, 'tutor_course_rating', 'approved' ) );
9542 - }
9543 -
9544 - /**
9545 - * Assign child count
9546 - *
9547 - * @since 2.0.0
9548 - *
9549 - * @param array $course_meta course meta.
9550 - * @param string $post_type post type.
9551 - *
9552 - * @return array
9553 - */
9554 - private function assign_child_count( array $course_meta, $post_type ) {
9555 - global $wpdb;
9556 - $id_array = array_keys( $course_meta );
9557 -
9558 - if ( ! count( $id_array ) ) {
9559 - return $course_meta;
6871 + /**
6872 + * Format yearly
6873 + */
6874 + $emptyMonths = array();
6875 + for ( $m=1; $m <= 12; $m++ ) {
6876 + $emptyMonths[ date('F', mktime( 0, 0, 0, $m, 1, date( 'Y' ) ) ) ] = 0;
9560 6877 }
9561 6878
9562 - $course_ids = implode( ',', $id_array );
6879 + $chartData = array_merge( $emptyMonths, $monthWiseSales );
6880 + $statements = tutor_utils()->get_earning_statements( $user_id, compact('year', 'dataFor', 'statuses' ) );
6881 + $earning_sum = tutor_utils()->get_earning_sum( $user_id, compact( 'year', 'dataFor' ) );
9563 6882
9564 - $results = $wpdb->get_results(
9565 - "SELECT ID, post_parent AS course_id
9566 - FROM {$wpdb->posts}
9567 - WHERE post_parent IN ({$course_ids})
9568 - AND post_type='{$post_type}'
9569 - AND post_status IN ('completed', 'publish', 'approved')"
9570 - );
9571 -
9572 - foreach ( $results as $result ) {
9573 - ++$course_meta[ $result->course_id ][ $post_type ];
9574 - }
9575 -
9576 - return $course_meta;
6883 + return [
6884 + 'chartData' => $chartData,
6885 + 'statements' => $statements,
6886 + 'earning_sum' => $earning_sum
6887 + ];
9577 6888 }
9578 6889
9579 6890 /**
9580 - * Get course meta data.
6891 + * @return object
6892 + *
6893 + * @since v1.8.4
9581 6894 *
9582 - * @param int|int[] $course_id course id.
9583 - *
9584 - * @return mixed
6895 + * Return object from vendor package
9585 6896 */
9586 - public function get_course_meta_data( $course_id ) {
9587 - global $wpdb;
6897 + function get_package_object() {
9588 6898
9589 - // Prepare course IDs to get quiz count based on.
9590 - $course_ids = is_array( $course_id ) ? $course_id : array( $course_id );
9591 - $course_ids = array_map(
9592 - function ( $id ) {
9593 - return (int) $id;
9594 - },
9595 - $course_ids
9596 - );
9597 - $course_ids = implode( ',', $course_ids );
6899 + $params = func_get_args();
6900 +
6901 + $is_pro = $params[0];
6902 + $class = $params[1];
6903 + $class_args = array_slice( $params, 2 );
6904 + $root_path = $is_pro ? tutor_pro()->path : tutor()->path;
9598 6905
9599 - if ( empty( $course_ids ) ) {
9600 - return array();
9601 - }
6906 + require_once $root_path . '/vendor/autoload.php';
6907 +
6908 + $reflector = new \ReflectionClass( $class );
6909 + $object = $reflector->newInstanceArgs( $class_args );
9602 6910
9603 - // Get course meta.
9604 - $results = $wpdb->get_results(
9605 - "SELECT DISTINCT course.ID AS course_id,
9606 - content.ID AS content_id,
9607 - content.post_type AS content_type
9608 - FROM {$wpdb->posts} course
9609 - LEFT JOIN {$wpdb->posts} topic ON course.ID=topic.post_parent
9610 - LEFT JOIN {$wpdb->posts} content ON topic.ID=content.post_parent
9611 - LEFT JOIN {$wpdb->posts} enrollment ON course.ID=enrollment.post_parent
9612 - WHERE topic.post_parent IN ($course_ids)"
9613 - );
9614 -
9615 - // Count contents by course IDs.
9616 - $course_meta = array();
9617 - foreach ( $results as $result ) {
9618 - // Create course key.
9619 - if ( ! array_key_exists( $result->course_id, $course_meta ) ) {
9620 - $course_meta[ $result->course_id ] = array(
9621 - 'tutor_assignments' => array(),
9622 - 'tutor_quiz' => array(),
9623 - 'lesson' => array(),
9624 - 'topics' => 0,
9625 - 'tutor_enrolled' => 0,
9626 - );
9627 - }
9628 -
9629 - $content_type = $result->content_type ?? '';
9630 -
9631 - // Create content key.
9632 - if ( ! array_key_exists( $content_type, $course_meta[ $result->course_id ] ) ) {
9633 - $course_meta[ $result->course_id ][ $content_type ] = array();
9634 - }
9635 -
9636 - try {
9637 - if ( $result->content_id ) {
9638 - $course_meta[ $result->course_id ][ $content_type ][] = $result->content_id;
9639 - }
9640 - } catch ( \Throwable $th ) {
9641 - tutor_log( 'Affected course ID : ' . $result->course_id . ' Error : ' . $th->getMessage() );
9642 - }
9643 - }
9644 -
9645 - // Unify counts.
9646 - foreach ( $course_meta as $index => $meta ) {
9647 - foreach ( $meta as $key => $ids ) {
9648 - $course_meta[ $index ][ $key ] = is_numeric( $ids ) ? $ids : count( array_unique( $ids ) );
9649 - }
9650 - }
9651 -
9652 - $course_meta = $this->assign_child_count( $course_meta, 'tutor_enrolled' );
9653 - $course_meta = $this->assign_child_count( $course_meta, 'topics' );
9654 -
9655 - // Return single count if the course id was single.
9656 - if ( ! is_array( $course_id ) ) {
9657 - return isset( $course_meta[ $course_id ] ) ? $course_meta[ $course_id ] : 0;
9658 - }
9659 -
9660 - return $course_meta;
6911 + return $object;
9661 6912 }
9662 6913
9663 6914 /**
9664 - * Get local time from unix/gmt date
9665 - *
9666 - * @since 2.0.1
9667 - *
9668 - * @param string $time time.
9669 - * @param string $date_format date format.
9670 - *
9671 - * @return string
9672 - */
9673 - public function get_local_time_from_unix( $time, $date_format = null ) {
9674 - $output_format = $date_format ? $date_format : get_option( 'date_format' ) . ', ' . get_option( 'time_format' );
9675 - return get_date_from_gmt( $time, $output_format );
9676 - }
9677 -
9678 - /**
9679 - * Format course content time duration
9680 - * For ex: lesson video play time, quiz time, assignment time etc.
9681 - *
9682 - * @since 2.0.3
9683 - *
9684 - * @param string $time_duration time duration.
9685 - *
9686 - * @return string
9687 - */
9688 - public function course_content_time_format( string $time_duration ): string {
9689 - $new_formatted_time = '';
9690 - $time_duration_array = explode( ':', $time_duration );
9691 - if ( is_array( $time_duration_array ) && count( $time_duration_array ) ) {
9692 - $count_fraction = count( $time_duration_array );
9693 - $first_fraction = (int) $time_duration_array[0];
9694 - if ( 3 === $count_fraction && $first_fraction < 1 ) {
9695 - unset( $time_duration_array[0] );
9696 - }
9697 - foreach ( $time_duration_array as $key => $value ) {
9698 - // If exists hour fraction but not 00 then skip it.
9699 - $new_formatted_time .= sprintf( '%02d', $value ) . ':';
9700 - }
9701 - }
9702 - return rtrim( $new_formatted_time, ':' );
9703 - }
9704 -
9705 - /**
9706 - * Check user has course content access.
9707 - *
9708 - * @since 2.0.6
9709 - *
9710 - * @param integer $user_id user id.
9711 - * @param integer $course_id course id.
9712 - *
9713 6915 * @return boolean
6916 + *
6917 + * @since v1.8.9
6918 + *
6919 + * Check if user has specific role
9714 6920 */
9715 - public function has_user_course_content_access( $user_id = 0, $course_id = 0 ) {
9716 - $user_id = $this->get_user_id( $user_id );
9717 - $course_id = $this->get_post_id( $course_id );
6921 + public function has_user_role($roles, $user_id = 0) {
6922 +
6923 + !$user_id ? $user_id = get_current_user_id() : 0;
6924 + !is_array($roles) ? $roles = array($roles) : 0;
6925 +
6926 + $user = get_userdata($user_id);
6927 + $role_list = is_array($user->roles) ? $user->roles : array();
9718 6928
9719 - $is_administrator = $this->has_user_role( 'administrator', $user_id );
9720 - $is_instructor = $this->is_instructor_of_this_course( $user_id, $course_id );
6929 + $without_roles = array_diff($roles, $role_list);
9721 6930
9722 - $course_content_access = (bool) get_tutor_option( 'course_content_access_for_ia' );
9723 - $has_access = $course_content_access && ( $is_administrator || $is_instructor );
9724 -
9725 - return $has_access;
6931 + return count($roles) > count($without_roles);
9726 6932 }
9727 6933
9728 6934 /**
9729 - * Get current page slug
9730 - *
9731 - * @since 2.1.3
9732 - *
9733 - * @return string current page slug
6935 + * @return boolean
6936 + *
6937 + * @since v1.8.9
6938 + *
6939 + * Check if user can edit course
9734 6940 */
9735 - public function get_current_page_slug() {
9736 - global $wp_query;
9737 - $current_page = '';
9738 - $query_vars = $wp_query->query_vars;
9739 - if ( is_admin() && Input::has( 'page' ) ) {
9740 - $current_page = Input::get( 'page' );
9741 - } else {
9742 - $current_page = isset( $query_vars['tutor_dashboard_page'] ) ? sanitize_text_field( $query_vars['tutor_dashboard_page'] ) : '';
9743 - }
9744 - return $current_page;
6941 + public function can_user_edit_course($user_id, $course_id)
6942 + {
6943 + return $this->has_user_role(array('administrator', 'editor')) || $this->is_instructor_of_this_course($user_id, $course_id);
9745 6944 }
9746 -
9747 - /**
9748 - * Get allowed tags for avatar, useful while using wp_kses
9749 - *
9750 - * @since 2.1.4
9751 - *
9752 - * @param array $tags additional tags.
9753 - *
9754 - * @return array allowed tags
9755 - */
9756 - public function allowed_avatar_tags( array $tags = array() ): array {
9757 - $defaults = array(
9758 - 'a' => array(
9759 - 'href' => true,
9760 - 'class' => true,
9761 - 'id' => true,
9762 - 'target' => true,
9763 - ),
9764 - 'img' => array(
9765 - 'src' => true,
9766 - 'class' => true,
9767 - 'id' => true,
9768 - 'title' => true,
9769 - 'alt' => true,
9770 - ),
9771 - 'div' => array(
9772 - 'class' => true,
9773 - 'id' => true,
9774 - ),
9775 - 'span' => array(
9776 - 'class' => true,
9777 - 'id' => true,
9778 - ),
9779 - );
9780 - return wp_parse_args( $tags, $defaults );
9781 - }
9782 -
9783 - /**
9784 - * Get allowed profile bio tags for tutor text editor.
9785 - *
9786 - * @since 3.4.2
9787 - *
9788 - * @param array $tags the list of tags allowed.
9789 - *
9790 - * @return array
9791 - */
9792 - public function allowed_profile_bio_tags( $tags = array() ) {
9793 - $supported_tags = array(
9794 - 'p' => array(),
9795 - 'br' => array(),
9796 - 'span' => array(
9797 - 'style' => true,
9798 - ),
9799 - 'strong' => array(),
9800 - 'b' => array(),
9801 - 'em' => array(),
9802 - 'i' => array(),
9803 - 'u' => array(),
9804 - 'blockquote' => array(),
9805 - 'ul' => array(),
9806 - 'ol' => array(),
9807 - 'li' => array(),
9808 - 'del' => array(),
9809 - 'ins' => array(),
9810 - 'sub' => array(),
9811 - 'sup' => array(),
9812 - 'a' => array(
9813 - 'href' => true,
9814 - 'title' => true,
9815 - 'target' => true,
9816 - 'rel' => true,
9817 - ),
9818 - );
9819 - return wp_parse_args( $tags, $supported_tags );
9820 - }
9821 -
9822 - /**
9823 - * Get allowed basic inline tags, useful while using wp_kses.
9824 - *
9825 - * @since 4.0.0
9826 - *
9827 - * @param array $tags additional tags.
9828 - *
9829 - * @return array
9830 - */
9831 - public function allowed_basic_inline_tags( array $tags = array() ): array {
9832 - $defaults = array(
9833 - 'br' => array(),
9834 - 'b' => array(),
9835 - 'em' => array(),
9836 - 'i' => array(),
9837 - 'span' => array(),
9838 - 'strong' => array(),
9839 - 'u' => array(),
9840 - );
9841 -
9842 - return wp_parse_args( $tags, $defaults );
9843 - }
9844 -
9845 - /**
9846 - * Get allowed tags for avatar, useful while using wp_kses
9847 - *
9848 - * @since 2.1.4
9849 - *
9850 - * @param array $tags additional tags.
9851 - *
9852 - * @return array allowed tags
9853 - */
9854 - public function allowed_icon_tags( array $tags = array() ): array {
9855 - $defaults = array(
9856 - 'span' => array(
9857 - 'class' => true,
9858 - 'id' => true,
9859 - ),
9860 - 'i' => array(
9861 - 'class' => true,
9862 - 'id' => true,
9863 - ),
9864 - );
9865 - return wp_parse_args( $tags, $defaults );
9866 - }
9867 -
9868 - /**
9869 - * Get user name to display
9870 - *
9871 - * It will return display name if not empty, if empty
9872 - * then it will return first name & last name or if display
9873 - * name & user same it will return first & last name (if ot emtpy)
9874 - * if first & last name empty then it will return user_login name
9875 - *
9876 - * @since 2.1.6
9877 - *
9878 - * @param integer $user_id user id.
9879 - *
9880 - * @return string
9881 - */
9882 - public function display_name( int $user_id ): string {
9883 - $name = '';
9884 - $user_data = get_userdata( $user_id );
9885 -
9886 - if ( is_a( $user_data, 'WP_User' ) ) {
9887 - $display_name = $user_data->display_name;
9888 - $user_name = $user_data->user_login;
9889 - $custom_name = trim( trim( $user_data->first_name ) . ' ' . trim( $user_data->last_name ) );
9890 -
9891 - if ( $display_name ) {
9892 - $name = $display_name === $user_name && $custom_name ? $custom_name : $display_name;
9893 - } else {
9894 - $name = $custom_name ? $custom_name : $user_name;
9895 - }
9896 - }
9897 - return $name;
9898 - }
9899 -
9900 - /**
9901 - * Get error message by error code
9902 - *
9903 - * @since 2.1.9
9904 - *
9905 - * @param string $key error code.
9906 - *
9907 - * @return string error message.
9908 - */
9909 - public function error_message( $key = '401' ) {
9910 - $error_message = __( 'Something went wrong', 'tutor' );
9911 -
9912 - $error_messages = apply_filters(
9913 - 'tutor_default_error_messages',
9914 - array(
9915 - '401' => __( 'You are not authorzied to perform this action', 'tutor' ),
9916 - 'nonce' => __( 'Nonce not matched. Action failed!', 'tutor' ),
9917 - 'invalid_req' => __( 'Invalid request', 'tutor' ),
9918 - 'authentication' => __( 'Authentication failed', 'tutor' ),
9919 - 'authorization' => __( 'Authorization required', 'tutor' ),
9920 - 'not_found' => __( 'Requested resource not found', 'tutor' ),
9921 - 'server_error' => __( 'Internal server error', 'tutor' ),
9922 - 'timeout' => __( 'Request timed out', 'tutor' ),
9923 - 'forbidden' => __( 'Access to this resource is forbidden', 'tutor' ),
9924 - 'method_not_allowed' => __( 'HTTP method not allowed', 'tutor' ),
9925 - 'too_many_requests' => __( 'Too many requests', 'tutor' ),
9926 - 'validation_error' => __( 'Validation error', 'tutor' ),
9927 - 'database_error' => __( 'Database operation failed', 'tutor' ),
9928 - 'file_not_found' => __( 'Requested file not found', 'tutor' ),
9929 - 'unsupported_media' => __( 'Unsupported media type', 'tutor' ),
9930 - )
9931 - );
9932 -
9933 - if ( array_key_exists( $key, $error_messages ) ) {
9934 - $error_message = $error_messages[ $key ];
9935 - }
9936 -
9937 - return $error_message;
9938 - }
9939 -
9940 - /**
9941 - * Get remote plugin information by plugin slug.
9942 - *
9943 - * @since 2.2.4
9944 - *
9945 - * @param string $plugin_slug plugin slug.
9946 - *
9947 - * @return object|bool if success return object otherwise return false;
9948 - */
9949 - public function get_remote_plugin_info( $plugin_slug = 'tutor' ) {
9950 - $response = wp_remote_get( "https://api.wordpress.org/plugins/info/1.0/{$plugin_slug}.json" );
9951 - if ( is_wp_error( $response ) ) {
9952 - return false;
9953 - }
9954 -
9955 - return (object) json_decode( $response['body'], true );
9956 - }
9957 -
9958 - /**
9959 - * Get the latest available version of a plugin from WordPress.org's update-check API,
9960 - * with optional transient caching.
9961 - *
9962 - * @param string $plugin_file Plugin file path relative to plugins dir, e.g. "tutor/tutor.php".
9963 - * @param bool $use_cache Whether to read/write the transient cache. Default true.
9964 - * @param int $cache_expiry Cache lifetime in seconds. Default 5 minutes.
9965 - *
9966 - * @return string|false Latest version string on success, false if not found / on error.
9967 - */
9968 - public function get_wp_org_update_version( $plugin_file, $use_cache = true, $cache_expiry = 5 * MINUTE_IN_SECONDS ) {
9969 -
9970 - $cache_key = 'wp_org_update_' . md5( $plugin_file );
9971 -
9972 - if ( $use_cache ) {
9973 - // Return cached result if available (including cached "not found" results).
9974 - $cached = get_transient( $cache_key );
9975 - if ( false !== $cached ) {
9976 - return ( '__none__' === $cached ) ? false : $cached;
9977 - }
9978 - }
9979 -
9980 - $body = array(
9981 - 'plugins' => wp_json_encode(
9982 - array(
9983 - 'plugins' => array(
9984 - $plugin_file => array(),
9985 - ),
9986 - )
9987 - ),
9988 - );
9989 -
9990 - $response = wp_remote_post(
9991 - 'https://api.wordpress.org/plugins/update-check/1.1/',
9992 - array(
9993 - 'timeout' => 10,
9994 - 'headers' => array(
9995 - 'Content-Type' => 'application/x-www-form-urlencoded',
9996 - 'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ),
9997 - ),
9998 - 'body' => $body,
9999 - )
10000 - );
10001 -
10002 - $version = false;
10003 -
10004 - if ( ! is_wp_error( $response ) ) {
10005 - $code = wp_remote_retrieve_response_code( $response );
10006 - $data = json_decode( wp_remote_retrieve_body( $response ), true );
10007 -
10008 - if ( 200 === (int) $code && ! empty( $data['plugins'][ $plugin_file ]['new_version'] ) ) {
10009 - $version = $data['plugins'][ $plugin_file ]['new_version'];
10010 - }
10011 - }
10012 -
10013 - if ( $use_cache ) {
10014 - // Cache the version string, or a "not found" marker so we don't hammer the API on repeated misses.
10015 - set_transient( $cache_key, false === $version ? '__none__' : $version, $cache_expiry );
10016 - }
10017 -
10018 - return $version;
10019 - }
10020 -
10021 -
10022 - /**
10023 - * Get editor list for post content.
10024 - *
10025 - * @since 3.0.0
10026 - *
10027 - * @param int $post_id post id.
10028 - *
10029 - * @return array
10030 - */
10031 - public function get_editor_list( $post_id ) {
10032 - $editors = array();
10033 -
10034 - $gutenberg_enabled = (bool) tutor_utils()->get_option( 'enable_gutenberg_course_edit' );
10035 - if ( $gutenberg_enabled ) {
10036 - $name = 'gutenberg';
10037 - $editors[ $name ] = array(
10038 - 'name' => $name,
10039 - 'label' => __( 'Gutenberg', 'tutor' ),
10040 - 'link' => add_query_arg(
10041 - array(
10042 - 'post' => $post_id,
10043 - 'action' => 'edit',
10044 - ),
10045 - get_admin_url( null, 'post.php' )
10046 - ),
10047 - );
10048 - }
10049 -
10050 - if ( is_plugin_active( 'droip/droip.php' ) ) {
10051 - $name = 'droip';
10052 - $editors[ $name ] = array(
10053 - 'name' => $name,
10054 - 'label' => __( 'Droip', 'tutor' ),
10055 - 'link' => add_query_arg(
10056 - array(
10057 - 'action' => 'droip',
10058 - 'post_id' => $post_id,
10059 - ),
10060 - get_permalink( $post_id )
10061 - ),
10062 - );
10063 - }
10064 -
10065 - if ( is_plugin_active( 'elementor/elementor.php' ) ) {
10066 - $post_type = get_post_type( $post_id );
10067 - $elementor_cpt_support = get_option( 'elementor_cpt_support' );
10068 - if ( is_array( $elementor_cpt_support ) && in_array( $post_type, $elementor_cpt_support ) ) {
10069 - $name = 'elementor';
10070 - $editors[ $name ] = array(
10071 - 'name' => $name,
10072 - 'label' => __( 'Elementor', 'tutor' ),
10073 - 'link' => add_query_arg(
10074 - array(
10075 - 'post' => $post_id,
10076 - 'action' => $name,
10077 - ),
10078 - get_admin_url( null, 'post.php' )
10079 - ),
10080 - );
10081 - }
10082 - }
10083 -
10084 - return apply_filters( 'tutor_course_builder_editor_list', $editors, $post_id );
10085 - }
10086 -
10087 - /**
10088 - * Check which editor is used for edit content.
10089 - *
10090 - * @since 3.0.0
10091 - *
10092 - * @param int $post_id post id.
10093 - *
10094 - * @return string
10095 - */
10096 - public function get_editor_used( $post_id ) {
10097 - $name = 'classic';
10098 - $editor = array(
10099 - 'name' => $name,
10100 - 'label' => __( 'Classic Editor', 'tutor' ),
10101 - 'link' => '',
10102 - );
10103 -
10104 - $content = get_post_field( 'post_content', $post_id );
10105 - if ( has_blocks( $content ) ) {
10106 - $name = 'gutenberg';
10107 - }
10108 -
10109 - if ( 'builder' === get_post_meta( $post_id, '_elementor_edit_mode', true ) ) {
10110 - $name = 'elementor';
10111 - }
10112 -
10113 - if ( 'droip' === get_post_meta( $post_id, 'droip_editor_mode', true ) ) {
10114 - $name = 'droip';
10115 - }
10116 -
10117 - $editor_list = $this->get_editor_list( $post_id );
10118 - if ( isset( $editor_list[ $name ] ) ) {
10119 - $editor = $editor_list[ $name ];
10120 - }
10121 -
10122 - return apply_filters( 'tutor_course_builder_editor_used', $editor, $post_id );
10123 - }
10124 -
10125 - /**
10126 - * Upload base64 string image.
10127 - *
10128 - * @since 3.0.0
10129 - *
10130 - * @param string $base64_image_str base64 image string.
10131 - * @param string $filename filename.
10132 - * @param bool $add_to_media Optional. Whether to add the file to WordPress media library. Default true.
10133 - *
10134 - * @return object consist of id, title, url. When $add_to_media is false, id is 0.
10135 - *
10136 - * @throws \Exception If upload failed.
10137 - */
10138 - public function upload_base64_image( $base64_image_str, $filename = null, $add_to_wp_media = true ) {
10139 - try {
10140 - $arr = explode( ',', $base64_image_str, 2 );
10141 - if ( ! isset( $arr[1] ) ) {
10142 - throw new \Exception( 'Invalid base64 string' );
10143 - }
10144 -
10145 - $filename = empty( $filename ) ? uniqid( 'image-' ) . '.png' : $filename;
10146 - $image_data = base64_decode( $arr[1] );
10147 - $uploaded = wp_upload_bits( $filename, null, $image_data );
10148 -
10149 - if ( ! empty( $uploaded['error'] ) ) {
10150 - throw new \Exception( $uploaded['error'] );
10151 - }
10152 -
10153 - if ( $add_to_wp_media ) {
10154 - $attachment = array(
10155 - 'guid' => $uploaded['url'],
10156 - 'post_mime_type' => $uploaded['type'],
10157 - 'post_title' => $filename,
10158 - 'post_content' => '',
10159 - 'post_status' => 'inherit',
10160 - );
10161 -
10162 - $media_id = wp_insert_attachment( $attachment, $uploaded['file'] );
10163 - $attach_data = wp_generate_attachment_metadata( $media_id, $uploaded['file'] );
10164 - wp_update_attachment_metadata( $media_id, $attach_data );
10165 - } else {
10166 - $media_id = 0;
10167 - }
10168 -
10169 - return (object) array(
10170 - 'id' => $media_id,
10171 - 'url' => $uploaded['url'],
10172 - 'title' => $filename,
10173 - );
10174 -
10175 - } catch ( \Exception $e ) {
10176 - throw new \Exception( $e->getMessage() );
10177 - }
10178 - }
10179 -
10180 - /**
10181 - * Get readable next cron schedule time.
10182 - *
10183 - * @since 3.0.0
10184 - *
10185 - * @param string $cron_hook cron hook name.
10186 - * @param array $args arguments.
10187 - *
10188 - * @return string
10189 - */
10190 - public function get_readable_next_schedule( $cron_hook, $args = array() ) {
10191 - $next_timestamp = wp_next_scheduled( $cron_hook, $args );
10192 - if ( false === $next_timestamp ) {
10193 - return null;
10194 - }
10195 -
10196 - /* translators: %s: timestamp */
10197 - return sprintf( __( '%s left', 'tutor' ), human_time_diff( $next_timestamp ) );
10198 - }
10199 -
10200 - /**
10201 - * Extract version details.
10202 - *
10203 - * @since 3.0.0
10204 - *
10205 - * @param string $version version number.
10206 - *
10207 - * @return object {
10208 - * @property string $version version.
10209 - * @property bool $is_stable is stable or not.
10210 - * @property int $major marjor version part.
10211 - * @property int $minor minor version part.
10212 - * @property int $patch patch version part.
10213 - * @property string $status status of version, can be beta, RC, alpha or stable.
10214 - * }
10215 - */
10216 - public function extract_version_details( $version ) {
10217 - $info = array(
10218 - 'version' => $version,
10219 - );
10220 -
10221 - if ( strpos( $version, 'beta' ) !== false ) {
10222 - $info['status'] = 'beta';
10223 - } elseif ( strpos( $version, 'RC' ) !== false ) {
10224 - $info['status'] = 'RC';
10225 - } elseif ( strpos( $version, 'alpha' ) !== false ) {
10226 - $info['status'] = 'alpha';
10227 - } else {
10228 - $info['status'] = 'stable';
10229 - }
10230 -
10231 - $info['is_stable'] = 'stable' === $info['status'];
10232 -
10233 - if ( preg_match( '/^(\d+)\.(\d+)\.(\d+)/', $version, $matches ) ) {
10234 - $info['major'] = (int) $matches[1];
10235 - $info['minor'] = (int) $matches[2];
10236 - $info['patch'] = (int) $matches[3];
10237 - }
10238 -
10239 - return (object) $info;
10240 - }
10241 -
10242 - /**
10243 - * Delete student course comment by providing the student and course id
10244 - *
10245 - * @since 3.4.0
10246 - *
10247 - * @param int $student_id Student id.
10248 - * @param int $course_id Course id.
10249 - *
10250 - * @return bool
10251 - */
10252 - public function delete_student_course_comment( int $student_id, int $course_id ): bool {
10253 - global $wpdb;
10254 - return QueryHelper::delete(
10255 - $wpdb->comments,
10256 - array(
10257 - 'user_id' => $student_id,
10258 - 'comment_post_ID' => $course_id,
10259 - )
10260 - );
10261 - }
10262 -
10263 - /**
10264 - * Create unique username.
10265 - *
10266 - * @since 3.4.1
10267 - *
10268 - * @param string $username Username.
10269 - *
10270 - * @return string
10271 - */
10272 - public function create_unique_username( string $username ) {
10273 - $username = trim( $username );
10274 -
10275 - // If username is email then remove domain part from it.
10276 - if ( filter_var( $username, FILTER_VALIDATE_EMAIL ) ) {
10277 - $username = strstr( $username, '@', true );
10278 - }
10279 -
10280 - // Sanitize and convert to snake_case.
10281 - $username = str_replace( '-', '_', sanitize_title( $username ) );
10282 -
10283 - // Add postfix to username if exists and make sure it's unique.
10284 - $original_username = $username;
10285 - $counter = 1;
10286 -
10287 - while ( get_user_by( 'login', $username ) ) {
10288 - $username = $original_username . '_' . $counter;
10289 - ++$counter;
10290 - }
10291 -
10292 - return $username;
10293 - }
10294 -
10295 - /**
10296 - * Build term tree
10297 - *
10298 - * @since 3.6.0
10299 - *
10300 - * @param array $terms Terms array.
10301 - * @param integer $parent Parent id.
10302 - *
10303 - * @return array
10304 - */
10305 - public function build_term_tree( $terms, $parent = 0 ) {
10306 - $branch = array();
10307 - foreach ( $terms as $term ) {
10308 - if ( (int) $term->parent === (int) $parent ) {
10309 - $children = $this->build_term_tree( $terms, $term->term_id );
10310 - if ( $children ) {
10311 - $term->children = $children;
10312 - }
10313 - $branch[] = $term;
10314 - }
10315 - }
10316 - return $branch;
10317 - }
10318 -
10319 - /**
10320 - * Render SVG icon
10321 - *
10322 - * @since 3.7.0
10323 - * @deprecated 4.0.0 Use \Tutor\Components\SvgIcon::make()->name( $name )->render() instead.
10324 - *
10325 - * @param string $name Icon name.
10326 - * @param integer $width Icon width.
10327 - * @param integer $height Icon height.
10328 - * @param array $attributes Custom attributes.
10329 - *
10330 - * @return void
10331 - */
10332 - public function render_svg_icon( $name, $width = 16, $height = 16, $attributes = array() ) {
10333 - echo $this->get_svg_icon( $name, $width, $height, $attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
10334 - }
10335 -
10336 - /**
10337 - * Get SVG icon url
10338 - *
10339 - * @since 3.7.0
10340 - *
10341 - * @param string $name Icon name.
10342 - *
10343 - * @return string
10344 - */
10345 - public function get_svg_icon_url( $name ) {
10346 - return tutor()->url . 'assets/icons/' . $name . '.svg';
10347 - }
10348 -
10349 - /**
10350 - * Get script locale data for dynamic scripts
10351 - *
10352 - * @since 3.7.0
10353 - *
10354 - * @param string $filename Filename.
10355 - * @param string $locale Locale.
10356 - *
10357 - * @return array|null
10358 - */
10359 - public function get_script_locale_data( string $filename, string $locale = 'en_US' ) {
10360 - $hash = md5( "assets/js/lazy-chunks/{$filename}.js" );
10361 - $json_path = WP_CONTENT_DIR . "/languages/plugins/tutor-{$locale}-{$hash}.json";
10362 -
10363 - if ( file_exists( $json_path ) ) {
10364 - $contents = file_get_contents( $json_path );
10365 - $data = json_decode( $contents, true );
10366 - return $data['locale_data'][ $data['domain'] ];
10367 - }
10368 -
10369 - return null;
10370 - }
10371 -
10372 - /**
10373 - * Get currency configuration from active monetization system.
10374 - *
10375 - * @since 4.0.0
10376 - *
10377 - * @param string $monetize_by Optional. Monetization provider key.
10378 - * (e.g., 'wc', 'edd', 'pmpro').
10379 - *
10380 - * @return array{
10381 - * currency: string,
10382 - * symbol: string,
10383 - * position: string,
10384 - * decimal_separator: string,
10385 - * thousand_separator: string
10386 - * no_of_decimal: int
10387 - * }
10388 - */
10389 - public function get_monetization_currency_config( $monetize_by = '' ): array {
10390 -
10391 - $monetize_by = empty( $monetize_by ) ? $this->get_option( 'monetize_by' ) : $monetize_by;
10392 -
10393 - // WooCommerce.
10394 - if ( 'wc' === $monetize_by ) {
10395 - return array(
10396 - 'symbol' => get_woocommerce_currency_symbol(),
10397 - 'position' => get_option( 'woocommerce_currency_pos' ),
10398 - 'decimal_separator' => wc_get_price_decimal_separator(),
10399 - 'thousand_separator' => wc_get_price_thousand_separator(),
10400 - 'no_of_decimal' => wc_get_price_decimals(),
10401 - );
10402 - }
10403 -
10404 - // Easy Digital Downloads.
10405 - if ( 'edd' === $monetize_by ) {
10406 - $position = edd_get_option( 'currency_position', 'before' ) === 'before' ? 'left' : 'right';
10407 - return array(
10408 - 'symbol' => edd_currency_symbol( edd_get_currency() ),
10409 - 'position' => $position,
10410 - 'decimal_separator' => edd_get_option( 'decimal_separator', '.' ),
10411 - 'thousand_separator' => edd_get_option( 'thousands_separator', ',' ),
10412 - );
10413 - }
10414 -
10415 - // Paid Memberships Pro.
10416 - if ( 'pmpro' === $monetize_by && function_exists( 'pmpro_get_currency' ) ) {
10417 - $currency = pmpro_get_currency();
10418 - return array(
10419 - 'symbol' => $currency['symbol'] ?? '',
10420 - 'position' => $currency['position'] ?? '',
10421 - 'decimal_separator' => $currency['decimal_separator'] ?? '',
10422 - 'thousand_separator' => $currency['thousands_separator'] ?? '',
10423 - 'no_of_decimal' => (int) $currency['decimals'] ?? 2,
10424 - );
10425 - }
10426 -
10427 - // Tutor.
10428 - return array(
10429 - 'symbol' => Settings::get_currency_symbol_by_code( tutor_utils()->get_option( OptionKeys::CURRENCY_CODE ) ),
10430 - 'position' => tutor_utils()->get_option( OptionKeys::CURRENCY_POSITION, true ),
10431 - 'thousand_separator' => tutor_utils()->get_option( OptionKeys::THOUSAND_SEPARATOR, true ),
10432 - 'decimal_separator' => tutor_utils()->get_option( OptionKeys::DECIMAL_SEPARATOR, true ),
10433 - 'no_of_decimal' => (int) tutor_utils()->get_option( OptionKeys::NUMBER_OF_DECIMALS, true ),
10434 - );
10435 - }
10436 -
10437 - /**
10438 - * Get the icon constant based on the given post type.
10439 - *
10440 - * @since 4.0.0
10441 - *
10442 - * @param string $post_type The post type slug.
10443 - *
10444 - * @return string Icon constant associated with the post type.
10445 - */
10446 - public static function get_icon_by_post_type( $post_type ): string {
10447 - switch ( $post_type ) {
10448 - case 'tutor_assignments':
10449 - return Icon::ASSIGNMENT;
10450 - case 'tutor-google-meet':
10451 - return Icon::GOOGLE_MEET_COLORIZE;
10452 - case 'tutor_quiz':
10453 - return Icon::QUIZ;
10454 - case 'tutor_zoom_meeting':
10455 - return Icon::ZOOM_COLORIZE;
10456 - case 'lesson':
10457 - return Icon::LESSON;
10458 - default:
10459 - return '';
10460 - }
10461 - }
10462 -
10463 - /**
10464 - * Is kids mode active
10465 - *
10466 - * @since 4.0.0
10467 - *
10468 - * @return bool
10469 - */
10470 - public function is_kids_mode(): bool {
10471 - $user_id = get_current_user_id();
10472 - if ( $user_id && User::is_student_view() ) {
10473 - $user_learning_mood = UserPreference::get( 'learning_mood', Options_V2::LEARNING_MODE_MODERN );
10474 - return Options_V2::LEARNING_MODE_KIDS === $user_learning_mood;
10475 - }
10476 -
10477 - return Options_V2::LEARNING_MODE_KIDS === tutor_utils()->get_option( 'learning_mode' ) && User::is_student_view();
10478 - }
10479 -
10480 - /**
10481 - * Is legacy learning mode active?
10482 - *
10483 - * @since 4.0.0
10484 - *
10485 - * @return bool
10486 - */
10487 - public function is_legacy_learning_mode(): bool {
10488 - return Options_V2::LEARNING_MODE_LEGACY === $this->get_option( 'learning_mode' );
10489 - }
10490 -
10491 - /**
10492 - * Check if the data is multi dimensional array
10493 - *
10494 - * @since 4.0.2
10495 - *
10496 - * @param array $data Array value to check with.
10497 - *
10498 - * @return bool
10499 - */
10500 - public function is_multi_dimensional_array( array $data ): bool {
10501 - return isset( $data[0] ) && is_array( $data[0] );
10502 - }
10503 -}
6945 +}