PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.2.2
Tutor LMS – eLearning and online course solution v2.2.2
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
457 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\Helpers\QueryHelper;
14 use Tutor\Models\CourseModel;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit;
18 }
19 /**
20 * Course List class
21 *
22 * @since 2.0.0
23 */
24 class Course_List {
25 /**
26 * Trait for utilities
27 *
28 * @var $page_title
29 */
30
31 use Backend_Page_Trait;
32
33 /**
34 * Page Title
35 *
36 * @var $page_title
37 */
38 public $page_title;
39
40 /**
41 * Bulk Action
42 *
43 * @var $bulk_action
44 */
45 public $bulk_action = true;
46
47 /**
48 * Constructor
49 *
50 * @return void
51 * @since 2.0.0
52 */
53 public function __construct() {
54 $this->page_title = __( 'Courses', 'tutor' );
55 /**
56 * Handle bulk action
57 *
58 * @since v2.0.0
59 */
60 add_action( 'wp_ajax_tutor_course_list_bulk_action', array( $this, 'course_list_bulk_action' ) );
61 /**
62 * Handle ajax request for updating course status
63 *
64 * @since v2.0.0
65 */
66 add_action( 'wp_ajax_tutor_change_course_status', array( $this, 'tutor_change_course_status' ) );
67 /**
68 * Handle ajax request for delete course
69 *
70 * @since v2.0.0
71 */
72 add_action( 'wp_ajax_tutor_course_delete', array( $this, 'tutor_course_delete' ) );
73 }
74
75 /**
76 * Prepare bulk actions that will show on dropdown options
77 *
78 * @return array
79 * @since 2.0.0
80 */
81 public function prepare_bulk_actions(): array {
82 $actions = array(
83 $this->bulk_action_default(),
84 $this->bulk_action_publish(),
85 $this->bulk_action_pending(),
86 $this->bulk_action_draft(),
87 );
88
89 $active_tab = Input::get( 'data', '' );
90
91 if ( 'trash' === $active_tab ) {
92 array_push( $actions, $this->bulk_action_delete() );
93 }
94 if ( 'trash' !== $active_tab ) {
95 array_push( $actions, $this->bulk_action_trash() );
96 }
97 return apply_filters( 'tutor_course_bulk_actions', $actions );
98 }
99
100 /**
101 * Available tabs that will visible on the right side of page navbar
102 *
103 * @param string $category_slug category slug.
104 * @param integer $course_id course ID.
105 * @param string $date selected date | optional.
106 * @param string $search search by user name or email | optional.
107 *
108 * @return array
109 *
110 * @since v2.0.0
111 */
112 public function tabs_key_value( $category_slug, $course_id, $date, $search ): array {
113 $url = get_pagenum_link();
114
115 $all = self::count_course( 'all', $category_slug, $course_id, $date, $search );
116 $mine = self::count_course( 'mine', $category_slug, $course_id, $date, $search );
117 $published = self::count_course( 'publish', $category_slug, $course_id, $date, $search );
118 $draft = self::count_course( 'draft', $category_slug, $course_id, $date, $search );
119 $pending = self::count_course( 'pending', $category_slug, $course_id, $date, $search );
120 $trash = self::count_course( 'trash', $category_slug, $course_id, $date, $search );
121
122 $tabs = array(
123 array(
124 'key' => 'all',
125 'title' => __( 'All', 'tutor' ),
126 'value' => $all,
127 'url' => $url . '&data=all',
128 ),
129 array(
130 'key' => 'mine',
131 'title' => __( 'Mine', 'tutor' ),
132 'value' => $mine,
133 'url' => $url . '&data=mine',
134 ),
135 array(
136 'key' => 'published',
137 'title' => __( 'Published', 'tutor' ),
138 'value' => $published,
139 'url' => $url . '&data=published',
140 ),
141 array(
142 'key' => 'draft',
143 'title' => __( 'Draft', 'tutor' ),
144 'value' => $draft,
145 'url' => $url . '&data=draft',
146 ),
147 array(
148 'key' => 'pending',
149 'title' => __( 'Pending', 'tutor' ),
150 'value' => $pending,
151 'url' => $url . '&data=pending',
152 ),
153 array(
154 'key' => 'trash',
155 'title' => __( 'Trash', 'tutor' ),
156 'value' => $trash,
157 'url' => $url . '&data=trash',
158 ),
159 );
160 return apply_filters( 'tutor_course_tabs', $tabs );
161 }
162
163 /**
164 * Count courses by status & filters
165 * Count all | min | published | pending | draft
166 *
167 * @param string $status | required.
168 * @param string $category_slug course category | optional.
169 * @param string $course_id selected course id | optional.
170 * @param string $date selected date | optional.
171 * @param string $search_term search by user name or email | optional.
172 *
173 * @return int
174 *
175 * @since 2.0.0
176 */
177 protected static function count_course( string $status, $category_slug = '', $course_id = '', $date = '', $search_term = '' ): int {
178 $user_id = get_current_user_id();
179 $status = sanitize_text_field( $status );
180 $course_id = sanitize_text_field( $course_id );
181 $date = sanitize_text_field( $date );
182 $search_term = sanitize_text_field( $search_term );
183 $category_slug = sanitize_text_field( $category_slug );
184
185 $args = array(
186 'post_type' => tutor()->course_post_type,
187 );
188
189 if ( 'all' === $status || 'mine' === $status ) {
190 $args['post_status'] = array( 'publish', 'pending', 'draft', 'private' );
191 } else {
192 $args['post_status'] = array( $status );
193 }
194
195 // Author query.
196 if ( 'mine' === $status || ! current_user_can( 'administrator' ) ) {
197 $args['author'] = $user_id;
198 }
199
200 $date_filter = sanitize_text_field( $date );
201
202 $year = date( 'Y', strtotime( $date_filter ) );
203 $month = date( 'm', strtotime( $date_filter ) );
204 $day = date( 'd', strtotime( $date_filter ) );
205
206 // Add date query.
207 if ( '' !== $date_filter ) {
208 $args['date_query'] = array(
209 array(
210 'year' => $year,
211 'month' => $month,
212 'day' => $day,
213 ),
214 );
215 }
216
217 if ( '' !== $course_id ) {
218 $args['p'] = $course_id;
219 }
220
221 // Search filter.
222 if ( '' !== $search_term ) {
223 $args['s'] = $search_term;
224 }
225
226 // Category filter.
227 if ( '' !== $category_slug ) {
228 $args['tax_query'] = array(
229 array(
230 'taxonomy' => 'course-category',
231 'field' => 'slug',
232 'terms' => $category_slug,
233 ),
234 );
235 }
236
237 $the_query = new \WP_Query( $args );
238
239 return ! is_null( $the_query ) && isset( $the_query->found_posts ) ? $the_query->found_posts : $the_query;
240
241 }
242
243 /**
244 * Handle bulk action for enrollment cancel | delete
245 *
246 * @return void
247 * @since 2.0.0
248 */
249 public function course_list_bulk_action() {
250
251 tutor_utils()->checking_nonce();
252
253 // Check if user is privileged.
254 if ( ! current_user_can( 'administrator' ) ) {
255 wp_send_json_error( tutor_utils()->error_message() );
256 }
257
258 $action = Input::post( 'bulk-action', '' );
259 $bulk_ids = Input::post( 'bulk-ids', '' );
260 if ( '' === $action || '' === $bulk_ids ) {
261 wp_send_json_error( array( 'message' => __( 'Please select appropriate action', 'tutor' ) ) );
262 exit;
263 }
264
265 if ( 'delete' === $action ) {
266 // Do action before delete.
267 do_action( 'before_tutor_course_bulk_action_delete', $bulk_ids );
268
269 $delete_courses = self::bulk_delete_course( $bulk_ids );
270
271 do_action( 'after_tutor_course_bulk_action_delete', $bulk_ids );
272 $delete_courses ? wp_send_json_success() : wp_send_json_error( array( 'message' => __( 'Could not delete selected courses', 'tutor' ) ) );
273 exit;
274 }
275
276 /**
277 * Do action before course update
278 *
279 * @param string $action (publish | pending | draft | trash).
280 * @param array $bulk_ids, course id.
281 */
282 do_action( 'before_tutor_course_bulk_action_update', $action, $bulk_ids );
283
284 $update_status = self::update_course_status( $action, $bulk_ids );
285
286 do_action( 'after_tutor_course_bulk_action_update', $action, $bulk_ids );
287
288 $update_status ? wp_send_json_success() : wp_send_json_error(
289 array(
290 'message' => 'Could not update course status',
291 'tutor',
292 )
293 );
294
295 exit;
296 }
297
298 /**
299 * Handle ajax request for updating course status
300 *
301 * @return void
302 * @since 2.0.0
303 */
304 public static function tutor_change_course_status() {
305 tutor_utils()->checking_nonce();
306
307 // Check if user is privileged.
308 if ( ! current_user_can( 'administrator' ) ) {
309 wp_send_json_error( tutor_utils()->error_message() );
310 }
311
312 $status = Input::post( 'status' );
313 $id = Input::post( 'id' );
314
315 $args = array(
316 'ID' => $id,
317 'post_status' => $status,
318 );
319 wp_update_post( $args );
320
321 wp_send_json_success();
322 exit;
323 }
324
325 /**
326 * Handle ajax request for deleting course
327 *
328 * @since 2.0.0
329 *
330 * @return void JSON response
331 */
332 public static function tutor_course_delete() {
333 tutor_utils()->checking_nonce();
334
335 // Check if user is privileged.
336 $roles = array( User::ADMIN, User::INSTRUCTOR );
337 if ( ! User::has_any_role( $roles ) ) {
338 wp_send_json_error( tutor_utils()->error_message() );
339 }
340
341 $id = Input::post( 'id', 0, Input::TYPE_INT );
342 $delete = CourseModel::delete_course( $id );
343
344 if ( $delete ) {
345 wp_send_json_success( __( 'Course has been deleted ', 'tutor' ) );
346 } else {
347 wp_send_json_error( __( 'Course delete failed ', 'tutor' ) );
348 }
349
350 exit;
351 }
352
353 /**
354 * Execute bulk delete action
355 *
356 * @param string $bulk_ids ids that need to update.
357 * @return bool
358 * @since 2.0.0
359 */
360 public static function bulk_delete_course( $bulk_ids ): bool {
361 $bulk_ids = explode( ',', sanitize_text_field( $bulk_ids ) );
362
363 foreach ( $bulk_ids as $post_id ) {
364 CourseModel::delete_course( $post_id );
365 }
366
367 return true;
368 }
369
370 /**
371 * Update course status
372 *
373 * @param string $status for updating course status.
374 * @param string $bulk_ids comma separated ids.
375 *
376 * @return bool
377 *
378 * @since 2.0.0
379 */
380 public static function update_course_status( string $status, $bulk_ids ): bool {
381 global $wpdb;
382 $post_table = $wpdb->posts;
383 $status = sanitize_text_field( $status );
384 $bulk_ids = sanitize_text_field( $bulk_ids );
385
386 $ids = array_map( 'intval', explode( ',', $bulk_ids ) );
387 $in_clause = QueryHelper::prepare_in_clause( $ids );
388
389 $update = $wpdb->query(
390 $wpdb->prepare(
391 "UPDATE {$post_table} SET post_status = %s WHERE ID IN ($in_clause)", //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
392 $status
393 )
394 );
395
396 return true;
397 }
398
399 /**
400 * Get course enrollment list with student info
401 *
402 * @param int $course_id int | required.
403 * @return array
404 * @since 2.0.0
405 */
406 public static function course_enrollments_with_student_details( int $course_id ) {
407 global $wpdb;
408 $course_id = sanitize_text_field( $course_id );
409 $course_completed = 0;
410 $course_inprogress = 0;
411
412 $enrollments = $wpdb->get_results(
413 $wpdb->prepare(
414 "SELECT enroll.ID AS enroll_id, enroll.post_author AS enroll_author, user.*, course.ID AS course_id
415 FROM {$wpdb->posts} AS enroll
416 LEFT JOIN {$wpdb->users} AS user ON user.ID = enroll.post_author
417 LEFT JOIN {$wpdb->posts} AS course ON course.ID = enroll.post_parent
418 WHERE enroll.post_type = %s
419 AND enroll.post_status = %s
420 AND enroll.post_parent = %d
421 ",
422 'tutor_enrolled',
423 'completed',
424 $course_id
425 )
426 );
427
428 foreach ( $enrollments as $enrollment ) {
429 $course_progress = tutor_utils()->get_course_completed_percent( $course_id, $enrollment->enroll_author );
430 if ( 100 == $course_progress ) {
431 $course_completed++;
432 } else {
433 $course_inprogress++;
434 }
435 }
436
437 return array(
438 'enrollments' => $enrollments,
439 'total_completed' => $course_completed,
440 'total_inprogress' => $course_inprogress,
441 'total_enrollments' => count( $enrollments ),
442 );
443 }
444
445 /**
446 * Check wheather course is public or not
447 *
448 * @param integer $course_id course id to check with.
449 * @return boolean true if public otherwise false.
450 * @since 1.0.0
451 */
452 public static function is_public( int $course_id ): bool {
453 $is_public = get_post_meta( $course_id, '_tutor_is_public_course', true );
454 return 'yes' === $is_public ? true : false;
455 }
456 }
457