PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.9
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.9
4.4.9 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 All 140 releases
← All changes | inc/custom-post-types/course.php +320 -319 4.1.7.3.2 → 4.4.9 View file →
@@ -3,11 +3,18 @@
3 3 * Class LP_Course_Post_Type
4 4 *
5 5 * @author ThimPress
6 6 * @package LearnPress/Classes
7 - * @version 3.0.0
7 + * @version 3.0.3
8 8 */
9 9
10 +use LearnPress\Databases\PostDB;
11 +use LearnPress\Filters\CoursePostFilter;
12 +use LearnPress\Models\CourseModel;
13 +use LearnPress\Models\CoursePostModel;
14 +use LearnPress\Models\PostModel;
15 +use LearnPress\Models\WPTables\CoursesTable;
16 +
10 17 defined( 'ABSPATH' ) || exit();
11 18
12 19 if ( ! class_exists( 'LP_Course_Post_Type' ) ) {
13 20
@@ -18,15 +25,12 @@
18 25 /**
19 26 * @var null
20 27 */
21 28 protected static $_instance = null;
29 + protected $_post_type = LP_COURSE_CPT;
30 + protected $_screen_list = 'edit-' . LP_COURSE_CPT;
22 31
23 32 /**
24 - * @var string
25 - */
26 - protected $_post_type = LP_COURSE_CPT;
27 -
28 - /**
29 33 * Constructor
30 34 */
31 35 public function __construct() {
32 36 parent::__construct();
@@ -31,75 +35,20 @@
31 35 public function __construct() {
32 36 parent::__construct();
33 37
34 38 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' ) );
39 + add_action( 'posts_pre_query', array( $this, 'posts_pre_query' ), 999, 2 );
40 + // add_filter( 'posts_where_paged', array( $this, '_posts_where_paged_course_items' ), 10 );
41 + // add_filter( 'posts_join_paged', array( $this, '_posts_join_paged_course_items' ), 10 );
41 42 }
42 43
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 the "{{ITEM_NAME}}" item from the trash?', 'learnpress' ),
76 - 'item_labels' => array(
77 - 'singular' => __( 'Item', 'learnpress' ),
78 - 'plural' => __( 'Items', 'learnpress' ),
79 - ),
80 - 'notice_sale_price' => __( 'The course sale price must be less than the regular price', 'learnpress' ),
81 - 'notice_price' => __( 'The course price must be greater than the sale price', 'learnpress' ),
82 - 'notice_sale_start_date' => __( 'The sale start date must be before the sale end date', 'learnpress' ),
83 - 'notice_sale_end_date' => __( 'The sale end date must be after the 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 44 /**
98 45 * Register course post type.
99 46 */
100 - public function args_register_post_type() : array {
101 - $settings = LP_Settings::instance();
47 + public function args_register_post_type(): array {
48 + // Support Quick Edit multiple courses change author
49 + add_post_type_support( LP_COURSE_CPT, 'author' );
50 +
102 51 $labels = array(
103 52 'name' => _x( 'Courses', 'Post Type General Name', 'learnpress' ),
104 53 'singular_name' => _x( 'Course', 'Post Type Singular Name', 'learnpress' ),
105 54 'menu_name' => __( 'Courses', 'learnpress' ),
@@ -110,18 +59,21 @@
110 59 'add_new' => __( 'Add New', 'learnpress' ),
111 60 'edit_item' => __( 'Edit Course', 'learnpress' ),
112 61 'update_item' => __( 'Update Course', 'learnpress' ),
113 62 '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' ) ),
63 + 'not_found' => sprintf(
64 + __( 'You have not had any courses yet. Click <a href="%s">Add new</a> to start', 'learnpress' ),
65 + admin_url( 'post-new.php?post_type=lp_course' )
66 + ),
115 67 'not_found_in_trash' => __( 'There was no course found in the trash', 'learnpress' ),
116 68 );
117 - $course_base = $settings->get( 'course_base' );
118 - $course_permalink = empty( $course_base ) ? _x( 'courses', 'slug', 'learnpress' ) : $course_base;
69 + $course_base = LP_Settings::get_option( 'course_base', 'courses' );
70 + $course_permalink = empty( $course_base ) ? 'courses' : $course_base;
119 71
72 + // Set to $has_archive return link to courses page, is_archive will check is true
120 73 $courses_page_id = learn_press_get_page_id( 'courses' );
74 + $has_archive = $courses_page_id ? urldecode( get_page_uri( $courses_page_id ) ) : 'courses';
121 75
122 - $has_archive = $courses_page_id && get_post( $courses_page_id ) ? urldecode( get_page_uri( $courses_page_id ) ) : 'courses';
123 -
124 76 $args = array(
125 77 'labels' => $labels,
126 78 'public' => true,
127 79 'query_var' => true,
@@ -136,9 +88,9 @@
136 88 'show_in_rest' => true,
137 89 'taxonomies' => array( 'course_category', 'course_tag' ),
138 90 'supports' => array( 'title', 'editor', 'thumbnail', 'revisions', 'comments', 'excerpt' ),
139 91 'hierarchical' => false,
140 - 'rewrite' => $course_permalink ? array(
92 + 'rewrite' => ! empty( $course_permalink ) ? array(
141 93 'slug' => untrailingslashit( $course_permalink ),
142 94 'with_front' => false,
143 95 ) : false,
144 96 );
@@ -149,12 +101,9 @@
149 101 /**
150 102 * Register course taxonomy.
151 103 */
152 104 public function register_taxonomy() {
153 - $settings = LP_Settings::instance();
154 -
155 - $category_base = $settings->get( 'course_category_base' );
156 -
105 + $category_base = LP_Settings::get_option( 'course_category_base' );
157 106 register_taxonomy(
158 107 'course_category',
159 108 array( LP_COURSE_CPT ),
160 109 array(
@@ -175,9 +124,9 @@
175 124 'show_in_admin_bar' => true,
176 125 'show_in_nav_menus' => true,
177 126 'show_in_rest' => true,
178 127 'rewrite' => array(
179 - 'slug' => empty( $category_base ) ? _x( 'course-category', 'slug', 'learnpress' ) : $category_base,
128 + 'slug' => empty( $category_base ) ? 'course-category' : $category_base,
180 129 'hierarchical' => true,
181 130 'with_front' => false,
182 131 ),
183 132 )
@@ -182,10 +131,9 @@
182 131 ),
183 132 )
184 133 );
185 134
186 - $tag_base = $settings->get( 'course_tag_base' );
187 -
135 + $tag_base = LP_Settings::get_option( 'course_tag_base' );
188 136 register_taxonomy(
189 137 'course_tag',
190 138 array( LP_COURSE_CPT ),
191 139 array(
@@ -213,9 +161,9 @@
213 161 'update_count_callback' => '_update_post_term_count',
214 162 'query_var' => true,
215 163 'show_in_rest' => true,
216 164 'rewrite' => array(
217 - 'slug' => empty( $tag_base ) ? _x( 'course-tag', 'slug', 'learnpress' ) : $tag_base,
165 + 'slug' => empty( $tag_base ) ? 'course-tag' : $tag_base,
218 166 'with_front' => false,
219 167 ),
220 168 )
221 169 );
@@ -221,34 +169,41 @@
221 169 );
222 170 }
223 171
224 172 /**
225 - * Load data for course editor.
173 + * Declare class name of table list courses.
226 174 *
227 - * @since 3.0.0
228 - * @editor tungnx
229 - * @reason not use
175 + * @param string $class_name
176 + * @param array $args
177 + *
178 + * @return string
179 + * @since 4.2.9.5
230 180 */
231 - /*
232 - public function data_course_editor() {
233 - if ( LP_COURSE_CPT !== get_post_type() ) {
234 - return;
181 + public function wp_list_table_class_name( $class_name, $args ) {
182 + if ( $this->check_class_name_handle_table( $args['screen'] ) ) {
183 + $class_name = CoursesTable::class;
235 184 }
236 185
237 - }*/
186 + return $class_name;
187 + }
238 188
239 189 /**
240 190 * Delete course sections before delete course.
241 191 *
242 192 * @param int $post_id
193 + *
194 + * @throws Exception
195 + * @since modify 4.0.9
243 196 * @since 3.0.0
244 197 * @editor tungnx
245 - * @since modify 4.0.9
246 198 */
247 199 public function before_delete( int $post_id ) {
248 - // course curd
249 - // $curd = new LP_Course_CURD();
250 - // $curd->remove_course( $post_id );
200 + // Delete course from table learnpress_courses
201 + $courseModel = CourseModel::find( $post_id, true );
202 + if ( $courseModel ) {
203 + $courseModel->delete();
204 + }
205 +
251 206 $course = learn_press_get_course( $post_id );
252 207 if ( ! $course ) {
253 208 return;
254 209 }
@@ -255,13 +210,140 @@
255 210 $course->delete_relate_data_when_delete_course();
256 211 }
257 212
258 213 /**
259 - * @param string $fields
214 + * Query lp courses in admin via Post DB
260 215 *
261 - * @return string
216 + * @param array $posts
217 + * @param WP_Query $wp_query
218 + *
219 + * @return array
220 + * @since 4.4.8
221 + * @version 1.0.0
262 222 */
263 - public function posts_fields( $fields ): string {
223 + public function posts_pre_query( $posts, $wp_query ) {
224 + try {
225 + if ( ! is_admin() ) {
226 + return $posts;
227 + }
228 +
229 + // Check screen
230 + if ( ! function_exists( 'get_current_screen' ) ) {
231 + return $posts;
232 + }
233 +
234 + $curren_screen = get_current_screen();
235 + if ( ! $curren_screen || $curren_screen->id !== 'edit-' . LP_COURSE_CPT ) {
236 + return $posts;
237 + }
238 +
239 + $post_type = $wp_query->get( 'post_type' );
240 +
241 + if ( empty( $post_type ) || $post_type !== LP_COURSE_CPT ) {
242 + return $posts;
243 + }
244 +
245 + // Convert params from WP_Query to CoursePostFilter
246 + $posts_per_page = get_user_option( "edit_{$post_type}_per_page", get_current_user_id() );
247 + if ( empty( $posts_per_page ) ) {
248 + $posts_per_page = 20;
249 + }
250 +
251 + $paged = max( 1, get_query_var( 'paged' ) );
252 + $author = $wp_query->get( 'author' );
253 + $status = $wp_query->get( 'post_status' );
254 + $search = $wp_query->get( 's' );
255 + $month = $wp_query->get( 'm' );
256 + $orderby = LP_Request::get_param( 'orderby', '', 'key' );
257 + $order = LP_Request::get_param( 'order', '', 'key' );
258 + $filter_price = LP_Helper::sanitize_params_submitted( $_REQUEST['filter_price'] ?? '' );
259 +
260 + $filter = new CoursePostFilter();
261 + $filter->page = $paged;
262 + $filter->limit = $posts_per_page;
263 + $filter->only_fields = array_map(
264 + function ( $field ) {
265 + return "p.{$field}";
266 + },
267 + $filter->all_fields
268 + );
269 + $filter->field_count = 'p.ID';
270 + $post_db = PostDB::getInstance();
271 +
272 + if ( ! empty( $status ) ) {
273 + $filter->post_status = array( $status );
274 + }
275 +
276 + if ( ! empty( $author ) ) {
277 + $filter->post_author = absint( $author );
278 + }
279 +
280 + if ( ! empty( $search ) ) {
281 + $filter->post_title = sanitize_text_field( wp_unslash( $search ) );
282 + }
283 +
284 + if ( ! empty( $month ) && is_numeric( $month ) && strlen( (string) $month ) === 6 ) {
285 + $filter->where[] = $post_db->wpdb->prepare(
286 + 'AND YEAR(p.post_date) = %d AND MONTH(p.post_date) = %d',
287 + substr( $month, 0, 4 ),
288 + substr( $month, 4, 2 )
289 + );
290 + }
291 +
292 + /*$has_price_filter = false;
293 + if ( array_key_exists( 'filter_price', $_REQUEST ) && $filter_price !== '' ) {
294 + $filter_price = floatval( $filter_price );
295 + $has_price_filter = true;
296 + }
297 +
298 + if ( $orderby === 'price' || $has_price_filter ) {
299 + $filter->join[] = "LEFT JOIN {$post_db->wpdb->postmeta} pm_price ON pm_price.post_id = p.ID AND pm_price.meta_key = '_lp_price'";
300 + }
301 +
302 + if ( $has_price_filter ) {
303 + if ( $filter_price == 0 ) {
304 + $filter->where[] = 'AND ( pm_price.meta_value IS NULL || pm_price.meta_value = 0 )';
305 + } else {
306 + $filter->where[] = $post_db->wpdb->prepare( ' AND ( pm_price.meta_value = %s )', $filter_price );
307 + }
308 + }*/
309 +
310 + // Exclude status auto-draft
311 + $filter->where[] = $post_db->wpdb->prepare( 'AND p.post_status != %s', PostModel::STATUS_AUTO_DRAFT );
312 +
313 + if ( $orderby === 'price' ) {
314 + $filter->join[] = "LEFT JOIN {$post_db->wpdb->postmeta} pm_price
315 + ON pm_price.post_id = p.ID
316 + AND pm_price.meta_key = '_lp_price'";
317 + $filter->order_by = 'CAST(pm_price.meta_value AS UNSIGNED)';
318 + } elseif ( $orderby === 'title' ) {
319 + $filter->order_by = 'p.post_title';
320 + } elseif ( $orderby === 'author' ) {
321 + $filter->order_by = 'p.post_author';
322 + } elseif ( $orderby === 'date' ) {
323 + $filter->order_by = 'p.post_date';
324 + } else {
325 + $filter->order_by = 'p.menu_order';
326 + }
327 +
328 + $filter->order = strtolower( $order ) === 'asc' ? 'ASC' : 'DESC';
329 +
330 + // Get lp courses
331 + $total_rows = 0;
332 + $lp_courses = $post_db->get_posts( $filter, $total_rows );
333 +
334 + $wp_query->post_count = count( $lp_courses );
335 + $wp_query->found_posts = $total_rows;
336 + $wp_query->max_num_pages = (int) ceil( $total_rows / $posts_per_page );
337 + $posts = $lp_courses;
338 + } catch ( Throwable $e ) {
339 + LP_Debug::error_log( $e );
340 + }
341 +
342 + return $posts;
343 + }
344 +
345 + /*public function posts_fields( $fields ): string {
264 346 if ( ! $this->is_page_list_posts_on_backend() ) {
265 347 return $fields;
266 348 }
267 349
@@ -276,9 +358,9 @@
276 358 public function _posts_join_paged_course_items( $join ) {
277 359 global $wpdb;
278 360
279 361 $course_id = $this->_filter_items_by_course();
280 - if ( $course_id || ( LP_Request::get( 'orderby' ) == 'course-name' ) ) {
362 + if ( $course_id || LP_Request::get_param( 'orderby' ) === 'course-name' ) {
281 363 $join .= " LEFT JOIN {$wpdb->prefix}learnpress_section_items si ON {$wpdb->posts}.ID = si.item_id";
282 364 $join .= " LEFT JOIN {$wpdb->prefix}learnpress_sections s ON s.section_id = si.section_id";
283 365 $join .= " LEFT JOIN {$wpdb->posts} c ON c.ID = s.section_course_id";
284 366 }
@@ -297,13 +379,8 @@
297 379
298 380 return $where;
299 381 }
300 382
301 - /**
302 - * @param $join
303 - *
304 - * @return string
305 - */
306 383 public function posts_join_paged( $join ) {
307 384 global $wpdb;
308 385
309 386 if ( ! $this->is_page_list_posts_on_backend() ) {
@@ -309,18 +386,17 @@
309 386 if ( ! $this->is_page_list_posts_on_backend() ) {
310 387 return $join;
311 388 }
312 389
390 + if ( ! isset( $_GET['orderby'] ) || $_GET['orderby'] !== 'price' ) {
391 + return $join;
392 + }
393 +
313 394 $join .= " LEFT JOIN {$wpdb->postmeta} pm_price ON pm_price.post_id = {$wpdb->posts}.ID AND pm_price.meta_key = '_lp_price'";
314 395
315 396 return $join;
316 397 }
317 398
318 - /**
319 - * @param $where
320 - *
321 - * @return mixed|string
322 - */
323 399 public function posts_where_paged( $where ) {
324 400 global $wpdb;
325 401
326 402 if ( ! $this->is_page_list_posts_on_backend() ) {
@@ -336,29 +412,11 @@
336 412 $where .= $wpdb->prepare( ' AND ( pm_price.meta_value = %s )', $filter_price );
337 413 }
338 414 }
339 415
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 416 return $where;
354 417 }
355 418
356 - /**
357 - * @param $orderby
358 - *
359 - * @return string
360 - */
361 419 public function posts_orderby( $orderby ) {
362 420 if ( ! $this->is_page_list_posts_on_backend() ) {
363 421 return $orderby;
364 422 }
@@ -365,231 +423,176 @@
365 423
366 424 $order = $this->get_order_sort();
367 425 switch ( $this->get_order_by() ) {
368 426 case 'price':
369 - $orderby = "pm_price.meta_value {$order}";
427 + $orderby = "CAST(pm_price.meta_value AS UNSIGNED) {$order}";
370 428 }
371 429
372 430 return $orderby;
373 - }
431 + }*/
374 432
375 433 /**
376 - * @param $columns
434 + * Save course post
377 435 *
378 - * @return mixed
436 + * @param int $post_id
437 + * @param WP_Post|null $post
438 + * @param bool $is_update
439 + *
440 + * @since 4.2.6.9
441 + * @version 1.0.3
379 442 */
380 - public function sortable_columns( $columns ) {
381 - $columns['instructor'] = 'author';
382 - $columns['price'] = 'price';
443 + public function save_post( int $post_id, ?WP_Post $post = null, bool $is_update = false ) {
444 + try {
445 + $wp_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
446 + // Save to table learnpress_courses
447 + LP_Install::instance()->create_table_courses();
448 + if ( empty( $post ) ) {
449 + $post = get_post( $post_id );
450 + }
383 451
384 - return $columns;
385 - }
452 + /*if ( $post->post_status === 'auto-draft' ) {
453 + return;
454 + }*/
386 455
387 - /**
388 - * Use when enable Gutenberg.
389 - *
390 - * @return void
391 - */
392 - public function admin_editor() {
393 - $course = LP_Course::get_course();
456 + $courseModel = CourseModel::find( $post_id, true );
457 + if ( ! $courseModel ) {
458 + $courseModel = new CourseModel( $post );
459 + }
394 460
395 - learn_press_admin_view( 'course/editor' );
396 - }
461 + // Get all metadata of post
462 + $all_metadata = $courseModel->get_post_model()->get_all_metadata();
463 + $courseModel->meta_data = $all_metadata;
464 + // Temporary unset _elementor_page_assets of El, reason by method get_all_metadata get not use maybe_unserialize, make save invalid serialize
465 + $courseModel->meta_data->_elementor_page_assets = [];
397 466
398 - /**
399 - * Delete all sections in a course and reset auto increment
400 - */
401 - private function _reset_sections() {
402 - global $wpdb, $post;
467 + // Merge object post and courseModel
468 + $new_obj = (array) $post;
469 + $old_obj = (array) $courseModel;
470 + $old_now = array_merge( $old_obj, $new_obj );
471 + $courseModel = new CourseModel( $old_now );
403 472
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 - );
473 + // Save option single course
474 + include_once LP_PLUGIN_PATH . 'inc/admin/class-lp-admin.php';
475 + $lp_meta_box_course = new LP_Meta_Box_Course();
476 + $ground_fields = $lp_meta_box_course->metabox( $courseModel->ID );
477 + // Save meta fields
478 + foreach ( $ground_fields as $fields ) {
479 + if ( ! isset( $fields['content'] ) ) {
480 + continue;
481 + }
482 + foreach ( $fields['content'] as $meta_key => $option ) {
483 + $option->id = $meta_key;
484 + if ( ! $option instanceof LP_Meta_Box_Field ) {
485 + continue;
486 + }
421 487
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 - }
488 + if ( isset( $_POST[ $meta_key ] ) && ! empty( $wp_screen ) && LP_COURSE_CPT === $wp_screen->id ) {
489 + $value_saved = $option->save( $courseModel->ID );
490 + if ( ! empty( $value_saved ) ) {
491 + $courseModel->meta_data->{$meta_key} = $value_saved;
492 + } else {
493 + $courseModel->meta_data->{$meta_key} = maybe_unserialize(
494 + get_post_meta( $courseModel->ID, $meta_key, true )
495 + );
496 + }
497 + } elseif ( ! $is_update ) {
498 + if ( isset( $courseModel->meta_data->{$meta_key} ) ) {
499 + continue;
500 + }
501 + $courseModel->meta_data->{$meta_key} = $option->default ?? '';
502 + } elseif ( ! empty( $wp_screen ) && LP_COURSE_CPT === $wp_screen->id ) {
503 + $value_saved = $option->save( $courseModel->ID );
504 + $courseModel->meta_data->{$meta_key} = $value_saved;
505 + }
506 + }
507 + }
437 508
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 );
509 + // For case bulk edit multiple courses change author
510 + $bulk_edit = LP_Request::get_param( 'bulk_edit', false );
511 + if ( ! empty( $bulk_edit ) ) {
512 + $post_author = LP_Request::get_param( 'post_author', 0, 'int' );
513 + if ( $post_author != -1 ) { // -1 is for no change author
514 + $courseModel->post_author = $post_author;
515 + }
516 + } elseif ( ! empty( $_REQUEST['_post_author'] ) ) {
517 + // Not use key 'post_author' on single edit course, it special key of WP, Gutenberg save will not submit this key.
518 + $courseModel->post_author = LP_Request::get_param( '_post_author', 0, 'int' );
519 + /**
520 + * Save author to post table
521 + * Not use PostModel::save() or CoursePostModel::save() here
522 + * because it calls wp_update_post(), has hook 'save_post', it will cause infinite loop
523 + */
524 + $lp_db = LP_Database::getInstance();
525 + $filter_update = new LP_Post_Type_Filter();
526 + $filter_update->collection = $lp_db->tb_posts;
527 + $filter_update->set[] = "post_author = {$courseModel->post_author}";
528 + $filter_update->where[] = $lp_db->wpdb->prepare( 'AND ID = %d', $courseModel->ID );
529 + $lp_db->update_execute( $filter_update );
530 + clean_post_cache( $post->ID );
531 + } elseif ( isset( $_POST['post_author'] ) && isset( $_POST['screen'] ) && $_POST['screen'] === 'edit-' . LP_COURSE_CPT ) {
532 + // For case quick edit change author.
533 + $courseModel->post_author = LP_Request::get_param( 'post_author', 0, 'int' );
534 + }
450 535
451 - if ( ! empty( $columns['author'] ) ) {
452 - unset( $columns['author'] );
453 - }
536 + $this->save_price( $courseModel );
537 + $courseModel->save();
538 + // End save to table learnpress_courses
454 539
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,
540 + // Save extra info course
541 + // Save in background.
542 + $bg = LP_Background_Single_Course::instance();
543 + $bg->data(
461 544 array(
462 - esc_html__( 'Author', 'learnpress' ),
463 - esc_html__( 'Content', 'learnpress' ),
464 - esc_html__( 'Students', 'learnpress' ),
465 - esc_html__( 'Price', 'learnpress' ),
545 + 'handle_name' => 'save_post',
546 + 'course_id' => $post_id,
547 + 'data' => $_POST ?? [],
466 548 )
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' );
549 + )->dispatch();
550 + } catch ( Throwable $e ) {
551 + LP_Debug::error_log( $e );
483 552 }
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 553 }
493 554
494 555 /**
495 - * Print content for custom column
556 + * Save price course
496 557 *
497 - * @param string
498 - * @param int
558 + * @return void
559 + * @throws Exception
499 560 */
500 - public function columns_content( $column, $post_id = 0 ) {
501 - global $post;
561 + protected function save_price( CourseModel &$courseObj ) {
562 + $coursePost = new CoursePostModel( $courseObj );
502 563
503 - $course = learn_press_get_course( $post->ID );
564 + $regular_price = $courseObj->get_regular_price();
565 + $sale_price = $courseObj->get_sale_price();
566 + if ( (float) $regular_price < 0 ) {
567 + $courseObj->meta_data->{CoursePostModel::META_KEY_REGULAR_PRICE} = '';
568 + $regular_price = $courseObj->get_regular_price();
569 + }
504 570
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' );
571 + if ( $sale_price !== '' && (float) $sale_price > (float) $regular_price ) {
572 + $courseObj->meta_data->{CoursePostModel::META_KEY_SALE_PRICE} = '';
573 + $sale_price = $courseObj->get_sale_price();
574 + }
519 575
520 - foreach ( learn_press_get_course_item_types() as $item_type ) {
521 - $count_item = $course->count_items( $item_type );
576 + // Save sale regular price and sale price to table postmeta
577 + $coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_REGULAR_PRICE, $regular_price );
578 + $coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_SALE_PRICE, $sale_price );
522 579
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;
580 + $has_sale = $courseObj->has_sale_price();
581 + if ( $has_sale ) {
582 + $courseObj->is_sale = 1;
583 + $coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_IS_SALE, 1 );
584 + } else {
585 + $courseObj->is_sale = 0;
586 + delete_post_meta( $courseObj->get_id(), CoursePostModel::META_KEY_IS_SALE );
553 587 }
554 - }
555 588
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 - );
589 + // Set price to sort on lists.
590 + $courseObj->price_to_sort = $courseObj->get_price();
591 + $coursePost->save_meta_value_by_key( CoursePostModel::META_KEY_PRICE, $courseObj->price_to_sort );
565 592 }
566 593
567 594 /**
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 595 * Instance LP_Course_Post_Type.
593 596 *
594 597 * @return LP_Course_Post_Type|null
595 598 */
@@ -602,7 +605,5 @@
602 605 }
603 606 }
604 607
605 608 $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 }