PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.2.0
Tutor LMS – eLearning and online course solution v2.2.0
3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / Course_List.php
tutor / classes Last commit date
Addons.php 3 years ago Admin.php 3 years ago Ajax.php 3 years ago Announcements.php 3 years ago Assets.php 3 years ago Backend_Page_Trait.php 3 years ago Course.php 3 years ago Course_Embed.php 3 years ago Course_Filter.php 3 years ago Course_List.php 3 years ago Course_Settings_Tabs.php 3 years ago Course_Widget.php 3 years ago Custom_Validation.php 3 years ago Dashboard.php 3 years ago FormHandler.php 3 years ago Frontend.php 3 years ago Gutenberg.php 3 years ago Input.php 3 years ago Instructor.php 3 years ago Instructors_List.php 3 years ago Lesson.php 3 years ago Options_V2.php 3 years ago Post_types.php 3 years ago Private_Course_Access.php 3 years ago Q_and_A.php 3 years ago Question_Answers_List.php 3 years ago Quiz.php 3 years ago Quiz_Attempts_List.php 3 years ago RestAPI.php 3 years ago Reviews.php 3 years ago Rewrite_Rules.php 3 years ago Shortcode.php 3 years ago Student.php 3 years ago Students_List.php 3 years ago Taxonomies.php 3 years ago Template.php 3 years ago Theme_Compatibility.php 3 years ago Tools.php 3 years ago Tools_V2.php 3 years ago Tutor.php 3 years ago TutorEDD.php 3 years ago Tutor_Base.php 3 years ago Tutor_Setup.php 3 years ago Upgrader.php 3 years ago User.php 3 years ago Utils.php 3 years ago Video_Stream.php 3 years ago Withdraw.php 3 years ago Withdraw_Requests_List.php 3 years ago WooCommerce.php 3 years ago
Course_List.php
452 lines
1 <?php
2 /**
3 * Manage Course List
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 2.0.0
9 */
10
11 namespace TUTOR;
12
13 use Tutor\Models\CourseModel;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit;
17 }
18 /**
19 * Course List class
20 *
21 * @since 2.0.0
22 */
23 class Course_List {
24 /**
25 * Trait for utilities
26 *
27 * @var $page_title
28 */
29
30 use Backend_Page_Trait;
31
32 /**
33 * Page Title
34 *
35 * @var $page_title
36 */
37 public $page_title;
38
39 /**
40 * Bulk Action
41 *
42 * @var $bulk_action
43 */
44 public $bulk_action = true;
45
46 /**
47 * Constructor
48 *
49 * @return void
50 * @since 2.0.0
51 */
52 public function __construct() {
53 $this->page_title = __( 'Courses', 'tutor' );
54 /**
55 * Handle bulk action
56 *
57 * @since v2.0.0
58 */
59 add_action( 'wp_ajax_tutor_course_list_bulk_action', array( $this, 'course_list_bulk_action' ) );
60 /**
61 * Handle ajax request for updating course status
62 *
63 * @since v2.0.0
64 */
65 add_action( 'wp_ajax_tutor_change_course_status', array( __CLASS__, 'tutor_change_course_status' ) );
66 /**
67 * Handle ajax request for delete course
68 *
69 * @since v2.0.0
70 */
71 add_action( 'wp_ajax_tutor_course_delete', array( __CLASS__, 'tutor_course_delete' ) );
72 }
73
74 /**
75 * Prepare bulk actions that will show on dropdown options
76 *
77 * @return array
78 * @since 2.0.0
79 */
80 public function prepare_bulk_actions(): array {
81 $actions = array(
82 $this->bulk_action_default(),
83 $this->bulk_action_publish(),
84 $this->bulk_action_pending(),
85 $this->bulk_action_draft(),
86 );
87
88 $active_tab = Input::get( 'data', '' );
89
90 if ( 'trash' === $active_tab ) {
91 array_push( $actions, $this->bulk_action_delete() );
92 }
93 if ( 'trash' !== $active_tab ) {
94 array_push( $actions, $this->bulk_action_trash() );
95 }
96 return apply_filters( 'tutor_course_bulk_actions', $actions );
97 }
98
99 /**
100 * Available tabs that will visible on the right side of page navbar
101 *
102 * @param string $category_slug category slug.
103 * @param integer $course_id course ID.
104 * @param string $date selected date | optional.
105 * @param string $search search by user name or email | optional.
106 *
107 * @return array
108 *
109 * @since v2.0.0
110 */
111 public function tabs_key_value( $category_slug, $course_id, $date, $search ): array {
112 $url = get_pagenum_link();
113
114 $all = self::count_course( 'all', $category_slug, $course_id, $date, $search );
115 $mine = self::count_course( 'mine', $category_slug, $course_id, $date, $search );
116 $published = self::count_course( 'publish', $category_slug, $course_id, $date, $search );
117 $draft = self::count_course( 'draft', $category_slug, $course_id, $date, $search );
118 $pending = self::count_course( 'pending', $category_slug, $course_id, $date, $search );
119 $trash = self::count_course( 'trash', $category_slug, $course_id, $date, $search );
120
121 $tabs = array(
122 array(
123 'key' => 'all',
124 'title' => __( 'All', 'tutor' ),
125 'value' => $all,
126 'url' => $url . '&data=all',
127 ),
128 array(
129 'key' => 'mine',
130 'title' => __( 'Mine', 'tutor' ),
131 'value' => $mine,
132 'url' => $url . '&data=mine',
133 ),
134 array(
135 'key' => 'published',
136 'title' => __( 'Published', 'tutor' ),
137 'value' => $published,
138 'url' => $url . '&data=published',
139 ),
140 array(
141 'key' => 'draft',
142 'title' => __( 'Draft', 'tutor' ),
143 'value' => $draft,
144 'url' => $url . '&data=draft',
145 ),
146 array(
147 'key' => 'pending',
148 'title' => __( 'Pending', 'tutor' ),
149 'value' => $pending,
150 'url' => $url . '&data=pending',
151 ),
152 array(
153 'key' => 'trash',
154 'title' => __( 'Trash', 'tutor' ),
155 'value' => $trash,
156 'url' => $url . '&data=trash',
157 ),
158 );
159 return apply_filters( 'tutor_course_tabs', $tabs );
160 }
161
162 /**
163 * Count courses by status & filters
164 * Count all | min | published | pending | draft
165 *
166 * @param string $status | required.
167 * @param string $category_slug course category | optional.
168 * @param string $course_id selected course id | optional.
169 * @param string $date selected date | optional.
170 * @param string $search_term search by user name or email | optional.
171 *
172 * @return int
173 *
174 * @since 2.0.0
175 */
176 protected static function count_course( string $status, $category_slug = '', $course_id = '', $date = '', $search_term = '' ): int {
177 $user_id = get_current_user_id();
178 $status = sanitize_text_field( $status );
179 $course_id = sanitize_text_field( $course_id );
180 $date = sanitize_text_field( $date );
181 $search_term = sanitize_text_field( $search_term );
182 $category_slug = sanitize_text_field( $category_slug );
183
184 $args = array(
185 'post_type' => tutor()->course_post_type,
186 );
187
188 if ( 'all' === $status || 'mine' === $status ) {
189 $args['post_status'] = array( 'publish', 'pending', 'draft', 'private' );
190 } else {
191 $args['post_status'] = array( $status );
192 }
193
194 // Author query.
195 if ( 'mine' === $status || ! current_user_can( 'administrator' ) ) {
196 $args['author'] = $user_id;
197 }
198
199 $date_filter = sanitize_text_field( $date );
200
201 $year = date( 'Y', strtotime( $date_filter ) );
202 $month = date( 'm', strtotime( $date_filter ) );
203 $day = date( 'd', strtotime( $date_filter ) );
204
205 // Add date query.
206 if ( '' !== $date_filter ) {
207 $args['date_query'] = array(
208 array(
209 'year' => $year,
210 'month' => $month,
211 'day' => $day,
212 ),
213 );
214 }
215
216 if ( '' !== $course_id ) {
217 $args['p'] = $course_id;
218 }
219
220 // Search filter.
221 if ( '' !== $search_term ) {
222 $args['s'] = $search_term;
223 }
224
225 // Category filter.
226 if ( '' !== $category_slug ) {
227 $args['tax_query'] = array(
228 array(
229 'taxonomy' => 'course-category',
230 'field' => 'slug',
231 'terms' => $category_slug,
232 ),
233 );
234 }
235
236 $the_query = new \WP_Query( $args );
237
238 return ! is_null( $the_query ) && isset( $the_query->found_posts ) ? $the_query->found_posts : $the_query;
239
240 }
241
242 /**
243 * Handle bulk action for enrollment cancel | delete
244 *
245 * @return void
246 * @since 2.0.0
247 */
248 public function course_list_bulk_action() {
249
250 tutor_utils()->checking_nonce();
251
252 // Check if user is privileged.
253 if ( ! current_user_can( 'administrator' ) || ! current_user_can( tutor()->instructor_role ) ) {
254 wp_send_json_error( tutor_utils()->error_message() );
255 }
256
257 $action = Input::post( 'bulk-action', '' );
258 $bulk_ids = Input::post( 'bulk-ids', '' );
259 if ( '' === $action || '' === $bulk_ids ) {
260 wp_send_json_error( array( 'message' => __( 'Please select appropriate action', 'tutor' ) ) );
261 exit;
262 }
263
264 if ( 'delete' === $action ) {
265 // Do action before delete.
266 do_action( 'before_tutor_course_bulk_action_delete', $bulk_ids );
267
268 $delete_courses = self::bulk_delete_course( $bulk_ids );
269
270 do_action( 'after_tutor_course_bulk_action_delete', $bulk_ids );
271 $delete_courses ? wp_send_json_success() : wp_send_json_error( array( 'message' => __( 'Could not delete selected courses', 'tutor' ) ) );
272 exit;
273 }
274
275 /**
276 * Do action before course update
277 *
278 * @param string $action (publish | pending | draft | trash).
279 * @param array $bulk_ids, course id.
280 */
281 do_action( 'before_tutor_course_bulk_action_update', $action, $bulk_ids );
282
283 $update_status = self::update_course_status( $action, $bulk_ids );
284
285 do_action( 'after_tutor_course_bulk_action_update', $action, $bulk_ids );
286
287 $update_status ? wp_send_json_success() : wp_send_json_error(
288 array(
289 'message' => 'Could not update course status',
290 'tutor',
291 )
292 );
293
294 exit;
295 }
296
297 /**
298 * Handle ajax request for updating course status
299 *
300 * @return void
301 * @since 2.0.0
302 */
303 public static function tutor_change_course_status() {
304 tutor_utils()->checking_nonce();
305
306 // Check if user is privileged.
307 if ( ! current_user_can( 'administrator' ) || ! current_user_can( tutor()->instructor_role ) ) {
308 wp_send_json_error( tutor_utils()->error_message() );
309 }
310
311 $status = Input::post( 'status' );
312 $id = Input::post( 'id' );
313
314 $args = array(
315 'ID' => $id,
316 'post_status' => $status,
317 );
318 wp_update_post( $args );
319
320 wp_send_json_success();
321 exit;
322 }
323
324 /**
325 * Handle ajax request for deleting course
326 *
327 * @since 2.0.0
328 *
329 * @return void JSON response
330 */
331 public static function tutor_course_delete() {
332 tutor_utils()->checking_nonce();
333
334 // Check if user is privileged.
335 $roles = array( User::ADMIN, User::INSTRUCTOR );
336 if ( ! User::has_any_role( $roles ) ) {
337 wp_send_json_error( tutor_utils()->error_message() );
338 }
339
340 $id = Input::post( 'id', 0, Input::TYPE_INT );
341 $delete = CourseModel::delete_course( $id );
342
343 if ( $delete ) {
344 wp_send_json_success( __( 'Course has been deleted ', 'tutor' ) );
345 } else {
346 wp_send_json_error( __( 'Course delete failed ', 'tutor' ) );
347 }
348
349 exit;
350 }
351
352 /**
353 * Execute bulk delete action
354 *
355 * @param string $bulk_ids ids that need to update.
356 * @return bool
357 * @since 2.0.0
358 */
359 public static function bulk_delete_course( $bulk_ids ): bool {
360 $bulk_ids = explode( ',', sanitize_text_field( $bulk_ids ) );
361
362 foreach ( $bulk_ids as $post_id ) {
363 CourseModel::delete_course( $post_id );
364 }
365
366 return true;
367 }
368
369 /**
370 * Update course status
371 *
372 * @param string $status for updating course status.
373 * @param string $bulk_ids comma separated ids.
374 *
375 * @return bool
376 *
377 * @since 2.0.0
378 */
379 public static function update_course_status( string $status, $bulk_ids ): bool {
380 global $wpdb;
381 $post_table = $wpdb->posts;
382 $status = sanitize_text_field( $status );
383 $bulk_ids = sanitize_text_field( $bulk_ids );
384 $update = $wpdb->query(
385 $wpdb->prepare(
386 "UPDATE {$post_table} SET post_status = %s WHERE ID IN ($bulk_ids)", //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
387 $status
388 )
389 );
390
391 return true;
392 }
393
394 /**
395 * Get course enrollment list with student info
396 *
397 * @param int $course_id int | required.
398 * @return array
399 * @since 2.0.0
400 */
401 public static function course_enrollments_with_student_details( int $course_id ) {
402 global $wpdb;
403 $course_id = sanitize_text_field( $course_id );
404 $course_completed = 0;
405 $course_inprogress = 0;
406
407 $enrollments = $wpdb->get_results(
408 $wpdb->prepare(
409 "SELECT enroll.ID AS enroll_id, enroll.post_author AS enroll_author, user.*, course.ID AS course_id
410 FROM {$wpdb->posts} AS enroll
411 LEFT JOIN {$wpdb->users} AS user ON user.ID = enroll.post_author
412 LEFT JOIN {$wpdb->posts} AS course ON course.ID = enroll.post_parent
413 WHERE enroll.post_type = %s
414 AND enroll.post_status = %s
415 AND enroll.post_parent = %d
416 ",
417 'tutor_enrolled',
418 'completed',
419 $course_id
420 )
421 );
422
423 foreach ( $enrollments as $enrollment ) {
424 $course_progress = tutor_utils()->get_course_completed_percent( $course_id, $enrollment->enroll_author );
425 if ( 100 == $course_progress ) {
426 $course_completed++;
427 } else {
428 $course_inprogress++;
429 }
430 }
431
432 return array(
433 'enrollments' => $enrollments,
434 'total_completed' => $course_completed,
435 'total_inprogress' => $course_inprogress,
436 'total_enrollments' => count( $enrollments ),
437 );
438 }
439
440 /**
441 * Check wheather course is public or not
442 *
443 * @param integer $course_id course id to check with.
444 * @return boolean true if public otherwise false.
445 * @since 1.0.0
446 */
447 public static function is_public( int $course_id ): bool {
448 $is_public = get_post_meta( $course_id, '_tutor_is_public_course', true );
449 return 'yes' === $is_public ? true : false;
450 }
451 }
452