PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 2.1.4
Tutor LMS – eLearning and online course solution v2.1.4
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
431 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 $action = Input::post( 'bulk-action', '' );
253 $bulk_ids = Input::post( 'bulk-ids', '' );
254
255 if ( '' === $action || '' === $bulk_ids ) {
256 wp_send_json_error( array( 'message' => __( 'Please select appropriate action', 'tutor' ) ) );
257 exit;
258 }
259
260 if ( 'delete' === $action ) {
261 // Do action before delete.
262 do_action( 'before_tutor_course_bulk_action_delete', $bulk_ids );
263
264 $delete_courses = self::bulk_delete_course( $bulk_ids );
265
266 do_action( 'after_tutor_course_bulk_action_delete', $bulk_ids );
267 $delete_courses ? wp_send_json_success() : wp_send_json_error( array( 'message' => __( 'Could not delete selected courses', 'tutor' ) ) );
268 exit;
269 }
270
271 /**
272 * Do action before course update
273 *
274 * @param string $action (publish | pending | draft | trash).
275 * @param array $bulk_ids, course id.
276 */
277 do_action( 'before_tutor_course_bulk_action_update', $action, $bulk_ids );
278
279 $update_status = self::update_course_status( $action, $bulk_ids );
280
281 do_action( 'after_tutor_course_bulk_action_update', $action, $bulk_ids );
282
283 $update_status ? wp_send_json_success() : wp_send_json_error(
284 array(
285 'message' => 'Could not update course status',
286 'tutor',
287 )
288 );
289
290 exit;
291 }
292
293 /**
294 * Handle ajax request for updating course status
295 *
296 * @return void
297 * @since 2.0.0
298 */
299 public static function tutor_change_course_status() {
300 tutor_utils()->checking_nonce();
301 $status = Input::post( 'status' );
302 $id = Input::post( 'id' );
303
304 $args = array(
305 'ID' => $id,
306 'post_status' => $status,
307 );
308 wp_update_post( $args );
309
310 wp_send_json_success();
311 exit;
312 }
313
314 /**
315 * Handle ajax request for deleting course
316 *
317 * @return json response
318 * @since 2.0.0
319 */
320 public static function tutor_course_delete() {
321 tutor_utils()->checking_nonce();
322
323 $id = Input::post( 'id', 0, Input::TYPE_INT );
324 $delete = CourseModel::delete_course( $id );
325
326 return wp_send_json( $delete );
327 exit;
328 }
329
330 /**
331 * Execute bulk delete action
332 *
333 * @param string $bulk_ids ids that need to update.
334 * @return bool
335 * @since 2.0.0
336 */
337 public static function bulk_delete_course( $bulk_ids ): bool {
338 $bulk_ids = explode( ',', sanitize_text_field( $bulk_ids ) );
339
340 foreach ( $bulk_ids as $post_id ) {
341 CourseModel::delete_course( $post_id );
342 }
343
344 return true;
345 }
346
347 /**
348 * Update course status
349 *
350 * @param string $status for updating course status.
351 * @param string $bulk_ids comma separated ids.
352 *
353 * @return bool
354 *
355 * @since 2.0.0
356 */
357 public static function update_course_status( string $status, $bulk_ids ): bool {
358 global $wpdb;
359 $post_table = $wpdb->posts;
360 $status = sanitize_text_field( $status );
361 $bulk_ids = sanitize_text_field( $bulk_ids );
362
363 $update = $wpdb->query(
364 $wpdb->prepare(
365 "UPDATE {$post_table} SET post_status = %s WHERE ID IN ($bulk_ids)", //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
366 $status
367 )
368 );
369
370 return true;
371 }
372
373 /**
374 * Get course enrollment list with student info
375 *
376 * @param int $course_id int | required.
377 * @return array
378 * @since 2.0.0
379 */
380 public static function course_enrollments_with_student_details( int $course_id ) {
381 global $wpdb;
382 $course_id = sanitize_text_field( $course_id );
383 $course_completed = 0;
384 $course_inprogress = 0;
385
386 $enrollments = $wpdb->get_results(
387 $wpdb->prepare(
388 "SELECT enroll.ID AS enroll_id, enroll.post_author AS enroll_author, user.*, course.ID AS course_id
389 FROM {$wpdb->posts} AS enroll
390 LEFT JOIN {$wpdb->users} AS user ON user.ID = enroll.post_author
391 LEFT JOIN {$wpdb->posts} AS course ON course.ID = enroll.post_parent
392 WHERE enroll.post_type = %s
393 AND enroll.post_status = %s
394 AND enroll.post_parent = %d
395 ",
396 'tutor_enrolled',
397 'completed',
398 $course_id
399 )
400 );
401
402 foreach ( $enrollments as $enrollment ) {
403 $course_progress = tutor_utils()->get_course_completed_percent( $course_id, $enrollment->enroll_author );
404 if ( 100 == $course_progress ) {
405 $course_completed++;
406 } else {
407 $course_inprogress++;
408 }
409 }
410
411 return array(
412 'enrollments' => $enrollments,
413 'total_completed' => $course_completed,
414 'total_inprogress' => $course_inprogress,
415 'total_enrollments' => count( $enrollments ),
416 );
417 }
418
419 /**
420 * Check wheather course is public or not
421 *
422 * @param integer $course_id course id to check with.
423 * @return boolean true if public otherwise false.
424 * @since 1.0.0
425 */
426 public static function is_public( int $course_id ): bool {
427 $is_public = get_post_meta( $course_id, '_tutor_is_public_course', true );
428 return 'yes' === $is_public ? true : false;
429 }
430 }
431