PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.1.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.1.7
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / custom-post-types / course.php

course.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.1.7, at inc/custom-post-types/course.php

609 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Class LP_Course_Post_Type
4 *
5 * @author ThimPress
6 * @package LearnPress/Classes
7 * @version 3.0.0
8 */
9
10 defined( 'ABSPATH' ) || exit();
11
12 if ( ! class_exists( 'LP_Course_Post_Type' ) ) {
13
14 /**
15 * Class LP_Course_Post_Type
16 */
17 final class LP_Course_Post_Type extends LP_Abstract_Post_Type {
18 /**
19 * @var null
20 */
21 protected static $_instance = null;
22
23 /**
24 * @var string
25 */
26 protected $_post_type = LP_COURSE_CPT;
27
28 /**
29 * Constructor
30 */
31 public function __construct() {
32 parent::__construct();
33
34 add_action( 'init', array( $this, 'register_taxonomy' ) );
35 add_filter( 'posts_where_paged', array( $this, '_posts_where_paged_course_items' ), 10 );
36 add_filter( 'posts_join_paged', array( $this, '_posts_join_paged_course_items' ), 10 );
37
38 // Comment by tungnx
39 // add_action( 'learn-press/admin/after-enqueue-scripts', array( $this, 'data_course_editor' ) );
40 add_action( 'admin_enqueue_scripts', array( $this, 'add_script_data' ) );
41 }
42
43 public function add_script_data() {
44 global $post, $pagenow;
45
46 if ( empty( $post ) || ( get_post_type() !== $this->_post_type ) || ! in_array( $pagenow, array( 'post.php', 'post-new.php' ) ) ) {
47 return;
48 }
49
50 $course = learn_press_get_course( $post->ID );
51 $hidden_sections = get_post_meta( $post->ID, '_admin_hidden_sections', true );
52
53 $data = apply_filters(
54 'learn-press/admin-localize-course-editor',
55 array(
56 'root' => array(
57 'course_id' => $post->ID,
58 'auto_draft' => get_post_status( $post->ID ) == 'auto-draft',
59 'ajax' => admin_url( 'index.php' ),
60 'disable_curriculum' => false,
61 'action' => 'admin_course_editor',
62 'nonce' => wp_create_nonce( 'learnpress_update_curriculum' ),
63 ),
64 'chooseItems' => array(
65 'types' => learn_press_course_get_support_item_types(),
66 'open' => false,
67 'addedItems' => array(),
68 'items' => array(),
69 ),
70 'i18n' => array(
71 'item' => __( 'item', 'learnpress' ),
72 'new_section_item' => __( 'Create a new', 'learnpress' ),
73 'back' => __( 'Back', 'learnpress' ),
74 'selected_items' => __( 'Selected items', 'learnpress' ),
75 'confirm_trash_item' => __( 'Do you want to remove item "{{ITEM_NAME}}" to trash?', 'learnpress' ),
76 'item_labels' => array(
77 'singular' => __( 'Item', 'learnpress' ),
78 'plural' => __( 'Items', 'learnpress' ),
79 ),
80 'notice_sale_price' => __( 'Course sale price must less than the regular price', 'learnpress' ),
81 'notice_price' => __( 'Course price must greater than the sale price', 'learnpress' ),
82 'notice_sale_start_date' => __( 'Sale start date must before sale end date', 'learnpress' ),
83 'notice_sale_end_date' => __( 'Sale end date must after sale start date', 'learnpress' ),
84 'notice_invalid_date' => __( 'Invalid date', 'learnpress' ),
85 ),
86 'sections' => array(
87 'sections' => $course->get_curriculum_raw(),
88 'hidden_sections' => ! empty( $hidden_sections ) ? $hidden_sections : array(),
89 'urlEdit' => admin_url( 'post.php?action=edit&post=' ),
90 ),
91 )
92 );
93
94 learn_press_admin_assets()->add_script_data( 'learn-press-admin-course-editor', $data );
95 }
96
97 /**
98 * Register course post type.
99 */
100 public function args_register_post_type() : array {
101 $settings = LP_Settings::instance();
102 $labels = array(
103 'name' => _x( 'Courses', 'Post Type General Name', 'learnpress' ),
104 'singular_name' => _x( 'Course', 'Post Type Singular Name', 'learnpress' ),
105 'menu_name' => __( 'Courses', 'learnpress' ),
106 'parent_item_colon' => __( 'Parent Item:', 'learnpress' ),
107 'all_items' => __( 'Courses', 'learnpress' ),
108 'view_item' => __( 'View Course', 'learnpress' ),
109 'add_new_item' => __( 'Add New Course', 'learnpress' ),
110 'add_new' => __( 'Add New', 'learnpress' ),
111 'edit_item' => __( 'Edit Course', 'learnpress' ),
112 'update_item' => __( 'Update Course', 'learnpress' ),
113 'search_items' => __( 'Search Courses', 'learnpress' ),
114 'not_found' => sprintf( __( 'You haven\'t had any courses yet. Click <a href="%s">Add new</a> to start', 'learnpress' ), admin_url( 'post-new.php?post_type=lp_course' ) ),
115 'not_found_in_trash' => __( 'No course found in Trash', 'learnpress' ),
116 );
117 $course_base = $settings->get( 'course_base' );
118 $course_permalink = empty( $course_base ) ? _x( 'courses', 'slug', 'learnpress' ) : $course_base;
119
120 $courses_page_id = learn_press_get_page_id( 'courses' );
121
122 $has_archive = $courses_page_id && get_post( $courses_page_id ) ? urldecode( get_page_uri( $courses_page_id ) ) : 'courses';
123
124 $args = array(
125 'labels' => $labels,
126 'public' => true,
127 'query_var' => true,
128 'publicly_queryable' => true,
129 'show_ui' => true,
130 'has_archive' => $has_archive,
131 'capability_type' => $this->_post_type,
132 'map_meta_cap' => true,
133 'show_in_menu' => 'learn_press',
134 'show_in_admin_bar' => true,
135 'show_in_nav_menus' => true,
136 'show_in_rest' => true,
137 'taxonomies' => array( 'course_category', 'course_tag' ),
138 'supports' => array( 'title', 'editor', 'thumbnail', 'revisions', 'comments', 'excerpt' ),
139 'hierarchical' => false,
140 'rewrite' => $course_permalink ? array(
141 'slug' => untrailingslashit( $course_permalink ),
142 'with_front' => false,
143 ) : false,
144 );
145
146 return $args;
147 }
148
149 /**
150 * Register course taxonomy.
151 */
152 public function register_taxonomy() {
153 $settings = LP_Settings::instance();
154
155 $category_base = $settings->get( 'course_category_base' );
156
157 register_taxonomy(
158 'course_category',
159 array( LP_COURSE_CPT ),
160 array(
161 'label' => __( 'Course Categories', 'learnpress' ),
162 'labels' => array(
163 'name' => __( 'Course Categories', 'learnpress' ),
164 'menu_name' => __( 'Course Category', 'learnpress' ),
165 'singular_name' => __( 'Category', 'learnpress' ),
166 'add_new_item' => __( 'Add New Course Category', 'learnpress' ),
167 'all_items' => __( 'All Categories', 'learnpress' ),
168 ),
169 'query_var' => true,
170 'public' => true,
171 'hierarchical' => true,
172 'show_ui' => true,
173 'show_in_menu' => 'learn_press',
174 'show_admin_column' => true,
175 'show_in_admin_bar' => true,
176 'show_in_nav_menus' => true,
177 'show_in_rest' => true,
178 'rewrite' => array(
179 'slug' => empty( $category_base ) ? _x( 'course-category', 'slug', 'learnpress' ) : $category_base,
180 'hierarchical' => true,
181 'with_front' => false,
182 ),
183 )
184 );
185
186 $tag_base = $settings->get( 'course_tag_base' );
187
188 register_taxonomy(
189 'course_tag',
190 array( LP_COURSE_CPT ),
191 array(
192 'labels' => array(
193 'name' => __( 'Course Tags', 'learnpress' ),
194 'singular_name' => __( 'Tag', 'learnpress' ),
195 'search_items' => __( 'Search Course Tags', 'learnpress' ),
196 'popular_items' => __( 'Popular Course Tags', 'learnpress' ),
197 'all_items' => __( 'All Course Tags', 'learnpress' ),
198 'parent_item' => null,
199 'parent_item_colon' => null,
200 'edit_item' => __( 'Edit Course Tag', 'learnpress' ),
201 'update_item' => __( 'Update Course Tag', 'learnpress' ),
202 'add_new_item' => __( 'Add New Course Tag', 'learnpress' ),
203 'new_item_name' => __( 'New Course Tag Name', 'learnpress' ),
204 'separate_items_with_commas' => __( 'Separate tags with commas', 'learnpress' ),
205 'add_or_remove_items' => __( 'Add or remove tags', 'learnpress' ),
206 'choose_from_most_used' => __( 'Choose from the most used tags', 'learnpress' ),
207 'menu_name' => __( 'Course Tags', 'learnpress' ),
208 ),
209 'public' => true,
210 'hierarchical' => false,
211 'show_ui' => true,
212 'show_in_menu' => 'learn_press',
213 'update_count_callback' => '_update_post_term_count',
214 'query_var' => true,
215 'show_in_rest' => true,
216 'rewrite' => array(
217 'slug' => empty( $tag_base ) ? _x( 'course-tag', 'slug', 'learnpress' ) : $tag_base,
218 'with_front' => false,
219 ),
220 )
221 );
222 }
223
224 /**
225 * Load data for course editor.
226 *
227 * @since 3.0.0
228 * @editor tungnx
229 * @reason not use
230 */
231 /*
232 public function data_course_editor() {
233 if ( LP_COURSE_CPT !== get_post_type() ) {
234 return;
235 }
236
237 }*/
238
239 /**
240 * Delete course sections before delete course.
241 *
242 * @param int $post_id
243 * @since 3.0.0
244 * @editor tungnx
245 * @since modify 4.0.9
246 */
247 public function before_delete( int $post_id ) {
248 // course curd
249 // $curd = new LP_Course_CURD();
250 // $curd->remove_course( $post_id );
251 $course = learn_press_get_course( $post_id );
252 if ( ! $course ) {
253 return;
254 }
255 $course->delete_relate_data_when_delete_course();
256 }
257
258 /**
259 * @param string $fields
260 *
261 * @return string
262 */
263 public function posts_fields( $fields ): string {
264 if ( ! $this->is_page_list_posts_on_backend() ) {
265 return $fields;
266 }
267
268 $fields = ' DISTINCT ' . $fields;
269 if ( $this->get_order_by() == 'price' ) {
270 $fields .= ', pm_price.meta_value as course_price';
271 }
272
273 return $fields;
274 }
275
276 public function _posts_join_paged_course_items( $join ) {
277 global $wpdb;
278
279 $course_id = $this->_filter_items_by_course();
280 if ( $course_id || ( LP_Request::get( 'orderby' ) == 'course-name' ) ) {
281 $join .= " LEFT JOIN {$wpdb->prefix}learnpress_section_items si ON {$wpdb->posts}.ID = si.item_id";
282 $join .= " LEFT JOIN {$wpdb->prefix}learnpress_sections s ON s.section_id = si.section_id";
283 $join .= " LEFT JOIN {$wpdb->posts} c ON c.ID = s.section_course_id";
284 }
285
286 return $join;
287 }
288
289 public function _posts_where_paged_course_items( $where ) {
290 global $wpdb;
291
292 $course_id = $this->_filter_items_by_course();
293 if ( $course_id ) {
294 $where .= $wpdb->prepare( ' AND (c.ID = %d)', $course_id );
295 $where .= $wpdb->prepare( " AND {$wpdb->posts}.post_status = %s", 'publish' );
296 }
297
298 return $where;
299 }
300
301 /**
302 * @param $join
303 *
304 * @return string
305 */
306 public function posts_join_paged( $join ) {
307 global $wpdb;
308
309 if ( ! $this->is_page_list_posts_on_backend() ) {
310 return $join;
311 }
312
313 $join .= " LEFT JOIN {$wpdb->postmeta} pm_price ON pm_price.post_id = {$wpdb->posts}.ID AND pm_price.meta_key = '_lp_price'";
314
315 return $join;
316 }
317
318 /**
319 * @param $where
320 *
321 * @return mixed|string
322 */
323 public function posts_where_paged( $where ) {
324 global $wpdb;
325
326 if ( ! $this->is_page_list_posts_on_backend() ) {
327 return $where;
328 }
329
330 $filter_price = LP_Helper::sanitize_params_submitted( $_REQUEST['filter_price'] ?? 0 );
331
332 if ( array_key_exists( 'filter_price', $_REQUEST ) ) {
333 if ( $filter_price == 0 ) {
334 $where .= ' AND ( pm_price.meta_value IS NULL || pm_price.meta_value = 0 )';
335 } else {
336 $where .= $wpdb->prepare( ' AND ( pm_price.meta_value = %s )', $filter_price );
337 }
338 }
339
340 $not_in = $wpdb->prepare(
341 "
342 SELECT ID
343 FROM {$wpdb->posts} p
344 INNER JOIN {$wpdb->postmeta} pm ON pm.post_id = p.ID AND pm.meta_key = %s
345 WHERE pm.meta_value = %s
346 ",
347 '_lp_preview_course',
348 'yes'
349 );
350
351 $where .= " AND {$wpdb->posts}.ID NOT IN( {$not_in} )";
352
353 return $where;
354 }
355
356 /**
357 * @param $orderby
358 *
359 * @return string
360 */
361 public function posts_orderby( $orderby ) {
362 if ( ! $this->is_page_list_posts_on_backend() ) {
363 return $orderby;
364 }
365
366 $order = $this->get_order_sort();
367 switch ( $this->get_order_by() ) {
368 case 'price':
369 $orderby = "pm_price.meta_value {$order}";
370 }
371
372 return $orderby;
373 }
374
375 /**
376 * @param $columns
377 *
378 * @return mixed
379 */
380 public function sortable_columns( $columns ) {
381 $columns['instructor'] = 'author';
382 $columns['price'] = 'price';
383
384 return $columns;
385 }
386
387 /**
388 * Use when enable Gutenberg.
389 *
390 * @return void
391 */
392 public function admin_editor() {
393 $course = LP_Course::get_course();
394
395 learn_press_admin_view( 'course/editor' );
396 }
397
398 /**
399 * Delete all sections in a course and reset auto increment
400 */
401 private function _reset_sections() {
402 global $wpdb, $post;
403
404 $wpdb->query(
405 $wpdb->prepare(
406 "
407 DELETE FROM si
408 USING {$wpdb->learnpress_section_items} si
409 INNER JOIN {$wpdb->learnpress_sections} s ON s.section_id = si.section_id
410 INNER JOIN {$wpdb->posts} p ON p.ID = s.section_course_id
411 WHERE p.ID = %d
412 ",
413 $post->ID
414 )
415 );
416 $wpdb->query(
417 "
418 ALTER TABLE {$wpdb->learnpress_section_items} AUTO_INCREMENT = 1
419 "
420 );
421
422 $wpdb->query(
423 $wpdb->prepare(
424 "
425 DELETE FROM {$wpdb->learnpress_sections}
426 WHERE section_course_id = %d
427 ",
428 $post->ID
429 )
430 );
431 $wpdb->query(
432 "
433 ALTER TABLE {$wpdb->learnpress_sections} AUTO_INCREMENT = 1
434 "
435 );
436 }
437
438 /**
439 * Add columns to admin manage course page
440 *
441 * @param array $columns
442 *
443 * @return array
444 */
445 public function columns_head( $columns ) {
446 $user = wp_get_current_user();
447 $keys = array_keys( $columns );
448 $values = array_values( $columns );
449 $pos = array_search( 'title', $keys );
450
451 if ( ! empty( $columns['author'] ) ) {
452 unset( $columns['author'] );
453 }
454
455 if ( $pos !== false ) {
456 array_splice( $keys, $pos + 1, 0, array( 'instructor', 'sections', 'students', 'price' ) );
457 array_splice(
458 $values,
459 $pos + 1,
460 0,
461 array(
462 esc_html__( 'Author', 'learnpress' ),
463 esc_html__( 'Content', 'learnpress' ),
464 esc_html__( 'Students', 'learnpress' ),
465 esc_html__( 'Price', 'learnpress' ),
466 )
467 );
468
469 if ( $pos === 0 ) {
470 array_unshift( $keys, 'thumbnail' );
471 array_unshift( $values, esc_html__( 'Thumbnail', 'learnpress' ) );
472 } else {
473 array_splice( $keys, $pos, 0, array( 'thumbnail' ) );
474 array_splice( $values, $pos, 0, array( esc_html__( 'Thumbnail', 'learnpress' ) ) );
475 }
476
477 $columns = array_combine( $keys, $values );
478 } else {
479 $columns['instructor'] = esc_html__( 'Author', 'learnpress' );
480 $columns['sections'] = esc_html__( 'Content', 'learnpress' );
481 $columns['students'] = esc_html__( 'Students', 'learnpress' );
482 $columns['price'] = esc_html__( 'Price', 'learnpress' );
483 }
484
485 $columns['taxonomy-course_category'] = esc_html__( 'Categories', 'learnpress' );
486
487 if ( in_array( 'lp_teacher', $user->roles ) ) {
488 unset( $columns['instructor'] );
489 }
490
491 return apply_filters( 'lp/admin/courses/columns', $columns );
492 }
493
494 /**
495 * Print content for custom column
496 *
497 * @param string
498 * @param int
499 */
500 public function columns_content( $column, $post_id = 0 ) {
501 global $post;
502
503 $course = learn_press_get_course( $post->ID );
504
505 switch ( $column ) {
506 case 'thumbnail':
507 echo wp_kses_post( $course->get_image( 'thumbnail' ) );
508 break;
509 case 'instructor':
510 $this->column_instructor( $post->ID );
511 break;
512 case 'sections':
513 $curd = new LP_Course_CURD();
514 $number_sections = $curd->count_sections( $post_id );
515 if ( $number_sections ) {
516 $output = sprintf( _n( '<strong>%d</strong> section', '<strong>%d</strong> sections', $number_sections, 'learnpress' ), $number_sections );
517 $html_items = array();
518 $post_types = get_post_types( null, 'objects' );
519
520 foreach ( learn_press_get_course_item_types() as $item_type ) {
521 $count_item = $course->count_items( $item_type );
522
523 if ( ! $count_item ) {
524 continue;
525 }
526
527 $post_type_object = $post_types[ $item_type ];
528 $singular_name = $post_type_object->labels->singular_name;
529 $plural_name = $post_type_object->label;
530 $html_items[] = sprintf( _n( '<strong>%d</strong> ' . $singular_name, '<strong>%d</strong> ' . $plural_name, $count_item, 'learnpress' ), $count_item );
531 }
532
533 $html_items = apply_filters( 'learn-press/course-count-items', $html_items );
534
535 if ( $html_items ) {
536 $output .= ' (' . implode( ', ', $html_items ) . ')';
537 }
538
539 echo wp_kses_post( $output );
540 } else {
541 esc_html_e( 'No content', 'learnpress' );
542 }
543
544 break;
545
546 case 'price':
547 echo wp_kses_post( $course->get_course_price_html() );
548 break;
549 case 'students':
550 $count = $course->get_total_user_enrolled_or_purchased();
551 echo '<span class="lp-label-counter' . ( ! $count ? ' disabled' : '' ) . '">' . ( $count ? $count : 0 ) . '</span>';
552 break;
553 }
554 }
555
556 public function meta_boxes() {
557 return array(
558 'course-editor' => array(
559 'title' => esc_html__( 'Curriculum', 'learnpress' ),
560 'callback' => array( $this, 'admin_editor' ),
561 'context' => 'normal',
562 'priority' => 'high',
563 ),
564 );
565 }
566
567 /**
568 * Save course post
569 * Should write run background if handle big and need more time
570 *
571 * @param int $post_id
572 * @param WP_Post $post
573 * @since 4.0.9
574 * @version 1.0.0
575 * @editor tungnx
576 * @see LP_Background_Single_Course::handle()
577 */
578 public function save( int $post_id = 0, WP_Post $post = null ) {
579 // Save in background.
580 $bg = LP_Background_Single_Course::instance();
581
582 $bg->data(
583 array(
584 'handle_name' => 'save_post',
585 'course_id' => $post_id,
586 'data' => $_POST ?? array(),
587 )
588 )->dispatch();
589 }
590
591 /**
592 * Instance LP_Course_Post_Type.
593 *
594 * @return LP_Course_Post_Type|null
595 */
596 public static function instance() {
597 if ( ! self::$_instance ) {
598 self::$_instance = new self();
599 }
600
601 return self::$_instance;
602 }
603 }
604
605 $course_post_type = LP_Course_Post_Type::instance();
606
607 // $course_post_type->add_meta_box( 'course-editor', esc_html__( 'Curriculum', 'learnpress' ), 'admin_editor', 'normal', 'high' );
608 }
609