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/Models/PostModel.php +659 -630 4.3.8 → 4.4.9 View file →
@@ -1,630 +1,659 @@
1 -<?php
2 -
3 -/**
4 - * Class Course
5 - * To replace class LP_User_Item
6 - *
7 - * @package LearnPress/Classes
8 - * @version 1.0.8
9 - * @since 4.2.6.9
10 - */
11 -
12 -namespace LearnPress\Models;
13 -
14 -use Exception;
15 -use LearnPress;
16 -use LearnPress\Databases\PostDB;
17 -use LearnPress\Filters\FilterBase;
18 -use LearnPress\Filters\PostFilter;
19 -use LP_Cache;
20 -use LP_Post_Meta_DB;
21 -use LP_Post_Meta_Filter;
22 -use LP_Post_Type_Filter;
23 -
24 -use stdClass;
25 -use Throwable;
26 -use WP_Error;
27 -use WP_Post;
28 -use WP_Term;
29 -
30 -defined( 'ABSPATH' ) || exit();
31 -
32 -class PostModel {
33 - /**
34 - * Auto increment, Primary key
35 - *
36 - * @var int
37 - */
38 - public $ID = 0;
39 - public $post_author = 0;
40 - public $post_date = null;
41 - public $post_date_gmt = null;
42 - public $post_modified = null;
43 - public $post_modified_gmt = null;
44 - public $post_content = '';
45 - public $post_title = '';
46 - public $post_excerpt = '';
47 - public $post_status = '';
48 - public $post_password = '';
49 - public $post_name = '';
50 - public $post_type = 'post';
51 - public $post_parent = 0;
52 - /**
53 - * @var stdClass all meta data
54 - */
55 - public $meta_data = null;
56 - /**
57 - * @var stdClass all meta data
58 - */
59 - public $is_got_meta_data;
60 - /**
61 - * @var string only for set same property with class WP_Post
62 - */
63 - public $filter;
64 -
65 - const STATUS_PUBLISH = 'publish';
66 - const STATUS_TRASH = 'trash';
67 - const STATUS_DRAFT = 'draft';
68 - const STATUS_PRIVATE = 'private';
69 - const STATUS_PENDING = 'pending';
70 - const STATUS_FEATURE = 'future';
71 - const STATUS_AUTO_DRAFT = 'auto-draft';
72 - const VISIBILITY_PASSWORD = 'password';
73 -
74 - /**
75 - * If data get from database, map to object.
76 - * Else create new object to save data to database.
77 - *
78 - * @param array|object|mixed $data
79 - */
80 - public function __construct( $data = null ) {
81 - if ( $data ) {
82 - $this->map_to_object( $data );
83 - }
84 -
85 - if ( is_null( $this->meta_data ) ) {
86 - $this->meta_data = new stdClass();
87 - }
88 - }
89 -
90 - /**
91 - * Get user model
92 - *
93 - * @return false|UserModel
94 - * @since 4.2.6.9
95 - * @version 1.0.1
96 - */
97 - public function get_author_model() {
98 - if ( ! empty( $this->post_author ) ) {
99 - $author_id = $this->post_author;
100 - } else {
101 - $author_id = get_post_field( 'post_author', $this );
102 - }
103 -
104 - return UserModel::find( $author_id, true );
105 - }
106 -
107 - /**
108 - * Map array, object data to PostModel.
109 - * Use for data get from database.
110 - *
111 - * @param array|object|mixed $data
112 - *
113 - * @return PostModel|static
114 - */
115 - public function map_to_object( $data ): PostModel {
116 - foreach ( $data as $key => $value ) {
117 - if ( property_exists( $this, $key ) ) {
118 - $this->{$key} = $value;
119 - }
120 - }
121 -
122 - return $this;
123 - }
124 -
125 - /**
126 - * Get post course by ID
127 - *
128 - * @param int $post_id
129 - * @param bool $check_cache
130 - *
131 - * @return false|PostModel
132 - * @version 1.0.0
133 - * @since 4.3.2
134 - */
135 - public static function find_by_id( int $post_id, bool $check_cache = false ) {
136 - $filter = new PostFilter();
137 - $filter->ID = $post_id;
138 - $filter->post_type = ( new static() )->post_type;
139 -
140 - $type = ( new static() )->post_type;
141 - $key_cache = "postModel/find/{$post_id}/" . $type;
142 - $lp_cache = new LP_Cache();
143 -
144 - // Check first load cache
145 - $postModel = LP_Cache::cache_load_first( 'get', $key_cache );
146 - if ( false !== $postModel ) {
147 - return $postModel;
148 - }
149 -
150 - // Check cache
151 - if ( $check_cache ) {
152 - $quizPostModel = $lp_cache->get_cache( $key_cache );
153 - if ( $quizPostModel instanceof QuizPostModel ) {
154 - return $quizPostModel;
155 - }
156 - }
157 -
158 - $postModel = self::get_item_model_from_db( $filter );
159 - // Set cache
160 - if ( $postModel instanceof PostModel ) {
161 - $lp_cache->set_cache( $key_cache, $postModel );
162 - }
163 - LP_Cache::cache_load_first( 'set', $key_cache, $postModel );
164 -
165 - return $postModel;
166 - }
167 -
168 - /**
169 - * Get post from database.
170 - * If not exists, return false.
171 - * If exists, return PostModel.
172 - *
173 - * @param LP_Post_Type_Filter|FilterBase $filter
174 - *
175 - * @return PostModel|false|static
176 - * @version 1.0.2
177 - */
178 - public static function get_item_model_from_db( $filter ) {
179 - $lp_post_db = PostDB::getInstance();
180 - $post_model = false;
181 -
182 - try {
183 - if ( empty( $filter->post_type ) ) {
184 - $filter->post_type = ( new static() )->post_type;
185 - }
186 -
187 - $lp_post_db->get_query_single_row( $filter );
188 - $query_single_row = $lp_post_db->get_posts( $filter );
189 - $post_rs = $lp_post_db->wpdb->get_row( $query_single_row );
190 -
191 - if ( $post_rs instanceof stdClass ) {
192 - $post_model = new static( $post_rs );
193 - }
194 - } catch ( Throwable $e ) {
195 - error_log( __METHOD__ . ': ' . $e->getMessage() );
196 - }
197 -
198 - return $post_model;
199 - }
200 -
201 - /**
202 - * Get all meta_data, all keys of a user it
203 - *
204 - * @return stdClass|null
205 - * @throws Exception
206 - * @version 1.0.1
207 - * @since 4.2.6.9
208 - */
209 - public function get_all_metadata() {
210 - if ( ! isset( $this->is_got_meta_data ) ) {
211 - $lp_item_meta_db = LP_Post_Meta_DB::getInstance();
212 - $filter = new LP_Post_Meta_Filter();
213 - $filter->post_id = $this->get_id();
214 - $filter->run_query_count = false;
215 - $filter->limit = - 1;
216 -
217 - $metadata_rs = $lp_item_meta_db->get_post_metas( $filter );
218 - if ( ! $metadata_rs instanceof stdClass ) {
219 - $this->meta_data = new stdClass();
220 - foreach ( $metadata_rs as $value ) {
221 - $this->meta_data->{$value->meta_key} = maybe_unserialize( $value->meta_value );
222 - }
223 - }
224 -
225 - $this->is_got_meta_data = 1;
226 - }
227 -
228 - return $this->meta_data;
229 - }
230 -
231 - /**
232 - * Check capabilities to create new post.
233 - *
234 - * @return bool
235 - * @since 4.2.9.4
236 - * @version 1.0.0
237 - */
238 - public function check_capabilities_create(): bool {
239 - return true;
240 - }
241 -
242 - /**
243 - * Check capabilities to update post.
244 - *
245 - * @return bool
246 - * @since 4.2.9.4
247 - * @version 1.0.0
248 - */
249 - public function check_capabilities_update(): bool {
250 - return true;
251 - }
252 -
253 - /**
254 - * Check capabilities of item's course.
255 - * Check user current can edit it.
256 - *
257 - * @return void
258 - * @throws Exception
259 - * @version 1.0.0
260 - * @since 4.2.9
261 - */
262 - public function check_capabilities_create_item_course() {
263 - $course_item_types = CourseModel::item_types_support();
264 - // Questions not type item of course, it is type item of quiz, but need check here.
265 - $course_item_types[] = LP_QUESTION_CPT;
266 - if ( ! in_array( $this->post_type, $course_item_types, true ) ) {
267 - return;
268 - }
269 -
270 - $user = wp_get_current_user();
271 - if ( ! user_can( $user, 'edit_' . LP_LESSON_CPT . 's' ) ) {
272 - throw new Exception( __( 'You do not have permission to create item.', 'learnpress' ) );
273 - }
274 - }
275 -
276 - /**
277 - * Check capabilities of item's course.
278 - * Check user current can edit it.
279 - *
280 - * @return void
281 - * @throws Exception
282 - * @version 1.0.0
283 - * @since 4.2.9
284 - */
285 - public function check_capabilities_update_item_course() {
286 - $course_item_types = CourseModel::item_types_support();
287 - // Questions not type item of course, it is type item of quiz, but need check here.
288 - $course_item_types[] = LP_QUESTION_CPT;
289 - if ( ! in_array( $this->post_type, $course_item_types, true ) ) {
290 - return;
291 - }
292 -
293 - $user = wp_get_current_user();
294 - if ( ! user_can( $user, 'edit_' . LP_LESSON_CPT, $this->ID ) ) {
295 - throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) );
296 - }
297 - }
298 -
299 - /**
300 - * Update data to database.
301 - *
302 - * If user_item_id is empty, insert new data, else update data.
303 - *
304 - * @throws Exception
305 - * @since 4.2.5
306 - * @version 1.0.4
307 - */
308 - public function save( bool $force_save = false ) {
309 - $data = get_object_vars( $this );
310 -
311 - if ( ! empty( $this->meta_data ) ) {
312 - $data['meta_input'] = [];
313 - foreach ( $this->meta_data as $key_meta => $value_meta ) {
314 - $data['meta_input'][ $key_meta ] = $value_meta;
315 - }
316 - }
317 -
318 - // Check if exists course id.
319 - if ( empty( $this->ID ) ) { // Insert data.
320 - // Check permission
321 - if ( ! $force_save ) {
322 - if ( ! $this->check_capabilities_create() ) {
323 - throw new Exception( __( 'You do not have permission to create item.', 'learnpress' ) );
324 - }
325 -
326 - $this->check_capabilities_create_item_course();
327 - }
328 -
329 - unset( $data['ID'] );
330 - $post_id = wp_insert_post( $data, true );
331 - } else { // Update data.
332 - // Check permission
333 - if ( ! $force_save ) {
334 - if ( ! $this->check_capabilities_update() ) {
335 - throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) );
336 - }
337 -
338 - $this->check_capabilities_update_item_course();
339 - }
340 -
341 - $post_id = wp_update_post( $data, true );
342 - }
343 -
344 - if ( is_wp_error( $post_id ) ) {
345 - throw new Exception( $post_id->get_error_message() );
346 - } else {
347 - $this->ID = $post_id;
348 - }
349 -
350 - $post = get_post( $this->ID );
351 - foreach ( get_object_vars( $post ) as $property => $value ) {
352 - // If property is not exists in PostModel, skip it.
353 - if ( ! property_exists( $this, $property ) ) {
354 - continue;
355 - }
356 - $this->{$property} = $value;
357 - }
358 -
359 - $this->clean_caches();
360 - }
361 -
362 - /**
363 - * Delete row
364 - *
365 - * @throws Exception
366 - * @since 4.3.6
367 - * @version 1.0.0
368 - */
369 - public function delete() {
370 - wp_delete_post( $this->get_id(), true );
371 -
372 - // Clear cache
373 - $this->clean_caches();
374 - }
375 -
376 - /**
377 - * Clean caches.
378 - *
379 - * @return void
380 - */
381 - public function clean_caches() {
382 - // Clear cache.
383 - }
384 -
385 - /**
386 - * @return int
387 - */
388 - public function get_id(): int {
389 - return (int) $this->ID;
390 - }
391 -
392 - /**
393 - * Get image url of post.
394 - *
395 - * @param string|int[] $size
396 - *
397 - * @return string
398 - * @since 4.2.6.9
399 - * @version 1.0.3
400 - */
401 - public function get_image_url( $size = 'post-thumbnail' ): string {
402 - $image_url = '';
403 -
404 - if ( has_post_thumbnail( $this ) ) {
405 - if ( is_string( $size ) ) {
406 - $image_url = get_the_post_thumbnail_url( $this, $size );
407 - } elseif ( is_array( $size ) && count( $size ) === 2 ) {
408 - // Check file crop is existing.
409 - $attachment_id = get_post_thumbnail_id( $this );
410 - $file_path = get_attached_file( $attachment_id );
411 - $file_url = wp_get_attachment_url( $attachment_id );
412 - $upload_dir = wp_upload_dir();
413 - $base_dir = $upload_dir['basedir'];
414 -
415 - // Get file path with size.
416 - $file_path_arr = explode( '.', $file_path );
417 - $file_path_length = count( $file_path_arr );
418 - $extension = end( $file_path_arr );
419 - unset( $file_path_arr[ $file_path_length - 1 ] );
420 - $file_path_join = implode( '.', $file_path_arr );
421 - $file_path_with_size = $file_path_join . '-' . $size[0] . 'x' . $size[1] . '.' . $extension;
422 - if ( file_exists( $file_path_with_size ) ) {
423 - $file_url_arr = explode( '.', $file_url );
424 - $file_url_length = count( $file_url_arr );
425 - $url_extension = end( $file_url_arr );
426 - unset( $file_url_arr[ $file_url_length - 1 ] );
427 - $file_url_join = implode( '.', $file_url_arr );
428 - $image_url = $file_url_join . '-' . $size[0] . 'x' . $size[1] . '.' . $url_extension;
429 - } else {
430 - // Custom crop size for image.
431 - $resized_file = wp_get_image_editor( $file_path );
432 -
433 - if ( ! is_wp_error( $resized_file ) ) {
434 - $resized_file->resize( $size[0], $size[1], true );
435 - $resized_image = $resized_file->save( $file_path_with_size );
436 -
437 - if ( ! is_wp_error( $resized_image ) ) {
438 - // Build the URL for the resized image
439 - $imag_dir = $resized_image['path'];
440 - $imag_dir = str_replace( $base_dir, '', $imag_dir );
441 - $image_url = $upload_dir['baseurl'] . $imag_dir;
442 - }
443 - }
444 - }
445 - }
446 - }
447 -
448 - if ( empty( $image_url ) ) {
449 - $image_url = LearnPress::instance()->image( 'no-image.png' );
450 - }
451 -
452 - return $image_url;
453 - }
454 -
455 - /**
456 - * Get meta value by key.
457 - *
458 - * @param string $key
459 - * @param mixed $default_value
460 - * @param bool $single
461 - *
462 - * @return false|mixed
463 - */
464 - public function get_meta_value_by_key( string $key, $default_value = false, bool $single = true ) {
465 - if ( $this->meta_data instanceof stdClass && isset( $this->meta_data->{$key} ) ) {
466 - return maybe_unserialize( $this->meta_data->{$key} );
467 - }
468 -
469 - $value = get_post_meta( $this->ID, $key, $single );
470 - if ( empty( $value ) ) {
471 - $value = $default_value;
472 - }
473 -
474 - $value = maybe_unserialize( $value );
475 - $this->meta_data->{$key} = $value;
476 -
477 - return $value;
478 - }
479 -
480 - /**
481 - * Get meta value by key.
482 - *
483 - * @param string $key
484 - * @param mixed $value
485 - * @param bool $fore_update
486 - *
487 - * @return void
488 - * @throws Exception
489 - * @since 4.2.6.9
490 - * @version 1.0.3
491 - */
492 - public function save_meta_value_by_key( string $key, $value, bool $fore_update = false ) {
493 - // Check permission
494 - if ( ! $fore_update ) {
495 - if ( ! $this->check_capabilities_update() ) {
496 - throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) );
497 - }
498 - $this->check_capabilities_create_item_course();
499 - }
500 -
501 - $this->meta_data->{$key} = $value;
502 - update_post_meta( $this->ID, $key, $value );
503 - }
504 -
505 - /**
506 - * Get categories of course.
507 - *
508 - * @return array|WP_Term[]
509 - * @version 1.0.1
510 - * @since 4.2.3
511 - */
512 - public function get_categories(): array {
513 - $wpPost = new WP_Post( $this );
514 - $categories = get_the_terms( $wpPost, LP_COURSE_CATEGORY_TAX );
515 - if ( ! $categories || $categories instanceof WP_Error ) {
516 - $categories = array();
517 - }
518 -
519 - return $categories;
520 - }
521 -
522 - /**
523 - * Get tags of course.
524 - *
525 - * @return array|WP_Term[]
526 - * @version 1.0.1
527 - * @since 4.2.7.2
528 - */
529 - public function get_tags(): array {
530 - $wpPost = new WP_Post( $this );
531 - $tags = get_the_terms( $wpPost, LP_COURSE_TAXONOMY_TAG );
532 - if ( ! $tags || $tags instanceof WP_Error ) {
533 - $tags = array();
534 - }
535 -
536 - return $tags;
537 - }
538 -
539 - /**
540 - * Get permalink of post
541 - *
542 - * @return string
543 - */
544 - public function get_permalink(): string {
545 - $permalink = get_permalink( $this );
546 - if ( empty( $permalink ) ) {
547 - $permalink = '';
548 - }
549 -
550 - return $permalink;
551 - }
552 -
553 - /**
554 - * Get the content of WP
555 - *
556 - * @return string
557 - */
558 - public function get_the_content(): string {
559 - $content = get_the_content( null, false, $this );
560 - $content = apply_filters( 'the_content', $content );
561 - $content = str_replace( ']]>', ']]&gt;', $content );
562 -
563 - return $content;
564 - }
565 -
566 - /**
567 - * Get excerpt of WP
568 - *
569 - * @return string
570 - */
571 - public function get_the_excerpt(): string {
572 - $content = get_the_excerpt( $this );
573 -
574 - return $content;
575 - }
576 -
577 - /**
578 - * Get title of course
579 - *
580 - * @return string
581 - */
582 - public function get_the_title(): string {
583 - return get_the_title( $this );
584 - }
585 -
586 - /**
587 - * Get edit link of post
588 - *
589 - * @return string|null
590 - * @since 4.2.7.4
591 - * @version 1.0.1
592 - */
593 - public function get_edit_link() {
594 - return admin_url( "post.php?post=$this->ID&action=edit" );
595 - /**
596 - * Not using get_edit_post_link() because it may not return the correct link in some cases
597 - * get_post_type_object is null.
598 - */
599 - //return get_edit_post_link( $this->get_id() );
600 - }
601 -
602 - /**
603 - * Get i18n status
604 - *
605 - * @return string
606 - */
607 - public function get_status_i18n(): string {
608 - switch ( $this->post_status ) {
609 - case self::STATUS_PUBLISH:
610 - return __( 'Published', 'learnpress' );
611 - case self::STATUS_FEATURE:
612 - return __( 'Scheduled', 'learnpress' );
613 - case self::STATUS_TRASH:
614 - return __( 'Trash', 'learnpress' );
615 - case self::STATUS_DRAFT:
616 - return __( 'Draft', 'learnpress' );
617 - case self::STATUS_PRIVATE:
618 - return __( 'Private', 'learnpress' );
619 - case self::STATUS_PENDING:
620 - return __( 'Pending', 'learnpress' );
621 - case self::STATUS_AUTO_DRAFT:
622 - return __( 'Auto Draft', 'learnpress' );
623 - case self::VISIBILITY_PASSWORD:
624 - return __( 'Protected', 'learnpress' );
625 -
626 - default:
627 - return ucfirst( $this->post_status );
628 - }
629 - }
630 -}
1 +<?php
2 +
3 +/**
4 + * Class Course
5 + * To replace class LP_User_Item
6 + *
7 + * @package LearnPress/Classes
8 + * @version 1.0.8
9 + * @since 4.2.6.9
10 + */
11 +
12 +namespace LearnPress\Models;
13 +
14 +use Exception;
15 +use LearnPress;
16 +use LearnPress\Databases\PostDB;
17 +use LearnPress\Filters\FilterBase;
18 +use LearnPress\Filters\PostFilter;
19 +use LearnPress\Services\CourseService;
20 +use LP_Cache;
21 +use LP_Debug;
22 +use LP_Post_Meta_DB;
23 +use LP_Post_Meta_Filter;
24 +use LP_Post_Type_Filter;
25 +
26 +use stdClass;
27 +use Throwable;
28 +use WP_Error;
29 +use WP_Post;
30 +use WP_Term;
31 +
32 +defined( 'ABSPATH' ) || exit();
33 +
34 +class PostModel {
35 + /**
36 + * Auto increment, Primary key
37 + *
38 + * @var int
39 + */
40 + public $ID = 0;
41 + public $post_author = 0;
42 + public $post_date = null;
43 + public $post_date_gmt = null;
44 + public $post_modified = null;
45 + public $post_modified_gmt = null;
46 + public $post_content = '';
47 + public $post_title = '';
48 + public $post_excerpt = '';
49 + public $post_status = '';
50 + public $post_password = '';
51 + public $post_name = '';
52 + public $post_type = 'post';
53 + public $post_parent = 0;
54 + /**
55 + * @var stdClass all meta data
56 + */
57 + public $meta_data = null;
58 + /**
59 + * @var stdClass all meta data
60 + */
61 + public $is_got_meta_data;
62 + /**
63 + * @var string only for set same property with class WP_Post
64 + */
65 + public $filter;
66 +
67 + const STATUS_PUBLISH = 'publish';
68 + const STATUS_TRASH = 'trash';
69 + const STATUS_DRAFT = 'draft';
70 + const STATUS_PRIVATE = 'private';
71 + const STATUS_PENDING = 'pending';
72 + const STATUS_FEATURE = 'future';
73 + const STATUS_AUTO_DRAFT = 'auto-draft';
74 + const VISIBILITY_PASSWORD = 'password';
75 +
76 + /**
77 + * If data get from database, map to object.
78 + * Else create new object to save data to database.
79 + *
80 + * @param array|object|mixed $data
81 + */
82 + public function __construct( $data = null ) {
83 + if ( $data ) {
84 + $this->map_to_object( $data );
85 + }
86 +
87 + $this->get_metadata();
88 + }
89 +
90 + /**
91 + * Get user model
92 + *
93 + * @return false|UserModel
94 + * @since 4.2.6.9
95 + * @version 1.0.1
96 + */
97 + public function get_author_model() {
98 + if ( ! empty( $this->post_author ) ) {
99 + $author_id = $this->post_author;
100 + } else {
101 + $author_id = get_post_field( 'post_author', $this );
102 + }
103 +
104 + return UserModel::find( $author_id, true );
105 + }
106 +
107 + /**
108 + * Map array, object data to PostModel.
109 + * Use for data get from database.
110 + *
111 + * @param array|object|mixed $data
112 + *
113 + * @return PostModel|static
114 + */
115 + public function map_to_object( $data ): PostModel {
116 + foreach ( $data as $key => $value ) {
117 + if ( property_exists( $this, $key ) ) {
118 + $this->{$key} = $value;
119 + }
120 + }
121 +
122 + return $this;
123 + }
124 +
125 + /**
126 + * Get post course by ID
127 + *
128 + * @param int $post_id
129 + * @param bool $check_cache
130 + *
131 + * @return false|PostModel
132 + * @version 1.0.1
133 + * @since 4.3.2
134 + */
135 + public static function find_by_id( int $post_id, bool $check_cache = false ) {
136 + $filter = new PostFilter();
137 + $filter->ID = $post_id;
138 + $filter->post_type = ( new static() )->post_type;
139 +
140 + $type = ( new static() )->post_type;
141 + $key_cache = "postModel/find/{$post_id}/" . $type;
142 + $lp_cache = new LP_Cache();
143 +
144 + // Check first load cache
145 + $postModel = LP_Cache::cache_load_first( 'get', $key_cache );
146 + if ( false !== $postModel ) {
147 + return $postModel;
148 + }
149 +
150 + // Check cache
151 + if ( $check_cache ) {
152 + $postModel = $lp_cache->get_cache( $key_cache );
153 + if ( $postModel instanceof PostModel ) {
154 + return $postModel;
155 + }
156 + }
157 +
158 + $postModel = self::get_item_model_from_db( $filter );
159 + // Set cache
160 + if ( $postModel instanceof PostModel ) {
161 + $lp_cache->set_cache( $key_cache, $postModel );
162 + }
163 + LP_Cache::cache_load_first( 'set', $key_cache, $postModel );
164 +
165 + return $postModel;
166 + }
167 +
168 + /**
169 + * Get post from database.
170 + * If not exists, return false.
171 + * If exists, return PostModel.
172 + *
173 + * @param LP_Post_Type_Filter|FilterBase $filter
174 + *
175 + * @return PostModel|false|static
176 + * @version 1.0.2
177 + */
178 + public static function get_item_model_from_db( $filter ) {
179 + $lp_post_db = PostDB::getInstance();
180 + $post_model = false;
181 +
182 + try {
183 + if ( empty( $filter->post_type ) ) {
184 + $filter->post_type = ( new static() )->post_type;
185 + }
186 +
187 + $lp_post_db->get_query_single_row( $filter );
188 + $query_single_row = $lp_post_db->get_posts( $filter );
189 + $post_rs = $lp_post_db->wpdb->get_row( $query_single_row );
190 +
191 + if ( $post_rs instanceof stdClass ) {
192 + $post_model = new static( $post_rs );
193 + }
194 + } catch ( Throwable $e ) {
195 + LP_Debug::error_log( $e );
196 + }
197 +
198 + return $post_model;
199 + }
200 +
201 + /**
202 + * Return object metadata
203 + *
204 + * @return stdClass
205 + * @since 4.4.8.1
206 + * @version 1.0.0
207 + */
208 + public function get_metadata(): stdClass {
209 + if ( is_null( $this->meta_data ) ) {
210 + $this->meta_data = new stdClass();
211 + }
212 +
213 + return $this->meta_data;
214 + }
215 +
216 + /**
217 + * Get all meta_data, all keys of a user it
218 + *
219 + * @return stdClass|null
220 + * @throws Exception
221 + * @version 1.0.1
222 + * @since 4.2.6.9
223 + */
224 + public function get_all_metadata() {
225 + if ( ! isset( $this->is_got_meta_data ) ) {
226 + $lp_item_meta_db = LP_Post_Meta_DB::getInstance();
227 + $filter = new LP_Post_Meta_Filter();
228 + $filter->post_id = $this->get_id();
229 + $filter->run_query_count = false;
230 + $filter->limit = - 1;
231 +
232 + $metadata_rs = $lp_item_meta_db->get_post_metas( $filter );
233 + if ( ! $metadata_rs instanceof stdClass ) {
234 + $this->meta_data = new stdClass();
235 + foreach ( $metadata_rs as $value ) {
236 + $this->meta_data->{$value->meta_key} = maybe_unserialize( $value->meta_value );
237 + }
238 + }
239 +
240 + $this->is_got_meta_data = 1;
241 + }
242 +
243 + return $this->meta_data;
244 + }
245 +
246 + /**
247 + * Check capabilities to create new post.
248 + *
249 + * @return bool
250 + * @since 4.2.9.4
251 + * @version 1.0.1
252 + */
253 + public function check_capabilities_create(): bool {
254 + //return current_user_can( 'edit_' . $this->post_type . 's' );
255 + return true;
256 + }
257 +
258 + /**
259 + * Check capabilities to update post.
260 + *
261 + * @return bool
262 + * @since 4.2.9.4
263 + * @version 1.0.1
264 + */
265 + public function check_capabilities_update(): bool {
266 + //return current_user_can( 'edit_' . $this->post_type, $this->ID );
267 + return true;
268 + }
269 +
270 + /**
271 + * Check capabilities of item's course.
272 + * Check user current can edit it.
273 + *
274 + * @return void
275 + * @throws Exception
276 + * @version 1.0.1
277 + * @since 4.2.9
278 + */
279 + public function check_capabilities_create_item_course() {
280 + $user = wp_get_current_user();
281 + if ( ! user_can( $user, 'edit_' . LP_LESSON_CPT . 's' ) ) {
282 + throw new Exception( __( 'You do not have permission to create item.', 'learnpress' ) );
283 + }
284 + }
285 +
286 + /**
287 + * Check capabilities of item's course.
288 + * Check user current can edit it.
289 + *
290 + * @return void
291 + * @throws Exception
292 + * @version 1.0.1
293 + * @since 4.2.9
294 + */
295 + public function check_capabilities_update_item_course() {
296 + $user = wp_get_current_user();
297 + if ( ! user_can( $user, 'edit_' . LP_LESSON_CPT, $this->ID ) ) {
298 + throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) );
299 + }
300 + }
301 +
302 + /**
303 + * Update data to database.
304 + *
305 + * If user_item_id is empty, insert new data, else update data.
306 + *
307 + * @throws Exception
308 + * @since 4.2.5
309 + * @version 1.0.6
310 + */
311 + public function save( bool $force_save = false ) {
312 + $data = get_object_vars( $this );
313 +
314 + $metadata = $this->get_metadata();
315 + if ( ! empty( $metadata ) ) {
316 + $data['meta_input'] = [];
317 + foreach ( $metadata as $key_meta => $value_meta ) {
318 + $data['meta_input'][ $key_meta ] = $value_meta;
319 + }
320 + }
321 +
322 + // Check if exists course id.
323 + if ( empty( $this->ID ) ) { // Insert data.
324 + // Check permission
325 + if ( ! $force_save ) {
326 + if ( CourseService::check_is_item_type_of_course( $this->post_type )
327 + || LP_QUESTION_CPT === $this->post_type ) {
328 + $this->check_capabilities_create_item_course();
329 + } elseif ( ! $this->check_capabilities_create() ) {
330 + throw new Exception( __( 'You do not have permission to create item.', 'learnpress' ) );
331 + }
332 + }
333 +
334 + unset( $data['ID'] );
335 + $post_id = wp_insert_post( $data, true );
336 + } else { // Update data.
337 + // Check permission
338 + if ( ! $force_save ) {
339 + if ( courseservice::check_is_item_type_of_course( $this->post_type )
340 + || LP_QUESTION_CPT === $this->post_type ) {
341 + $this->check_capabilities_update_item_course();
342 + } elseif ( ! $this->check_capabilities_update() ) {
343 + throw new exception( __( 'you do not have permission to edit this item.', 'learnpress' ) );
344 + }
345 + }
346 +
347 + $post_id = wp_update_post( $data, true );
348 + }
349 +
350 + if ( is_wp_error( $post_id ) ) {
351 + throw new Exception( $post_id->get_error_message() );
352 + } else {
353 + $this->ID = $post_id;
354 + }
355 +
356 + $post = get_post( $this->ID );
357 + foreach ( get_object_vars( $post ) as $property => $value ) {
358 + // If property is not exists in PostModel, skip it.
359 + if ( ! property_exists( $this, $property ) ) {
360 + continue;
361 + }
362 + $this->{$property} = $value;
363 + }
364 +
365 + $this->clean_caches();
366 + }
367 +
368 + /**
369 + * Delete row
370 + *
371 + * @throws Exception
372 + * @since 4.3.6
373 + * @version 1.0.0
374 + */
375 + public function delete() {
376 + wp_delete_post( $this->get_id(), true );
377 +
378 + // Clear cache
379 + $this->clean_caches();
380 + }
381 +
382 + /**
383 + * Clean caches.
384 + *
385 + * @return void
386 + */
387 + public function clean_caches() {
388 + // Clear cache.
389 + }
390 +
391 + /**
392 + * @return int
393 + */
394 + public function get_id(): int {
395 + return (int) $this->ID;
396 + }
397 +
398 + /**
399 + * Get image url of post.
400 + *
401 + * @param string|int[] $size
402 + *
403 + * @return string
404 + * @since 4.2.6.9
405 + * @version 1.0.3
406 + */
407 + public function get_image_url( $size = 'post-thumbnail' ): string {
408 + $image_url = '';
409 +
410 + if ( has_post_thumbnail( $this ) ) {
411 + if ( is_string( $size ) ) {
412 + $image_url = get_the_post_thumbnail_url( $this, $size );
413 + } elseif ( is_array( $size ) && count( $size ) === 2 ) {
414 + // Check file crop is existing.
415 + $attachment_id = get_post_thumbnail_id( $this );
416 + $file_path = get_attached_file( $attachment_id );
417 + $file_url = wp_get_attachment_url( $attachment_id );
418 + $upload_dir = wp_upload_dir();
419 + $base_dir = $upload_dir['basedir'];
420 +
421 + // Get file path with size.
422 + $file_path_arr = explode( '.', $file_path );
423 + $file_path_length = count( $file_path_arr );
424 + $extension = end( $file_path_arr );
425 + unset( $file_path_arr[ $file_path_length - 1 ] );
426 + $file_path_join = implode( '.', $file_path_arr );
427 + $file_path_with_size = $file_path_join . '-' . $size[0] . 'x' . $size[1] . '.' . $extension;
428 + if ( file_exists( $file_path_with_size ) ) {
429 + $file_url_arr = explode( '.', $file_url );
430 + $file_url_length = count( $file_url_arr );
431 + $url_extension = end( $file_url_arr );
432 + unset( $file_url_arr[ $file_url_length - 1 ] );
433 + $file_url_join = implode( '.', $file_url_arr );
434 + $image_url = $file_url_join . '-' . $size[0] . 'x' . $size[1] . '.' . $url_extension;
435 + } else {
436 + // Custom crop size for image.
437 + $resized_file = wp_get_image_editor( $file_path );
438 +
439 + if ( ! is_wp_error( $resized_file ) ) {
440 + $resized_file->resize( $size[0], $size[1], true );
441 + $resized_image = $resized_file->save( $file_path_with_size );
442 +
443 + if ( ! is_wp_error( $resized_image ) ) {
444 + // Build the URL for the resized image
445 + $imag_dir = $resized_image['path'];
446 + $imag_dir = str_replace( $base_dir, '', $imag_dir );
447 + $image_url = $upload_dir['baseurl'] . $imag_dir;
448 + }
449 + }
450 + }
451 + }
452 + }
453 +
454 + if ( empty( $image_url ) ) {
455 + $image_url = LearnPress::instance()->image( 'no-image.png' );
456 + }
457 +
458 + return $image_url;
459 + }
460 +
461 + /**
462 + * Get meta value by key.
463 + *
464 + * @param string $key
465 + * @param mixed $default_value
466 + * @param bool $single
467 + *
468 + * @return false|mixed
469 + * @since 4.2.6.9
470 + * @version 1.0.3
471 + */
472 + public function get_meta_value_by_key( string $key, $default_value = false, bool $single = true ) {
473 + $metadata = $this->get_metadata();
474 + if ( isset( $metadata->{$key} ) ) {
475 + return maybe_unserialize( $metadata->{$key} );
476 + }
477 +
478 + $value = get_post_meta( $this->ID, $key, $single );
479 + if ( empty( $value ) ) {
480 + $value = $default_value;
481 + }
482 +
483 + $value = maybe_unserialize( $value );
484 + $this->set_meta_value_by_key( $key, $value );
485 +
486 + return $value;
487 + }
488 +
489 + /**
490 + * Set meta value by key
491 + *
492 + * @param string $key
493 + * @param mixed $value
494 + *
495 + * @since 4.4.8.1
496 + * @version 1.0.0
497 + * @return void
498 + */
499 + public function set_meta_value_by_key( string $key, $value ) {
500 + $metadata = $this->get_metadata();
501 + $metadata->{$key} = $value;
502 +
503 + $this->meta_data = $metadata;
504 + }
505 +
506 + /**
507 + * Get meta value by key.
508 + *
509 + * @param string $key
510 + * @param mixed $value
511 + * @param bool $fore_update
512 + *
513 + * @return void
514 + * @throws Exception
515 + * @since 4.2.6.9
516 + * @version 1.0.4
517 + */
518 + public function save_meta_value_by_key( string $key, $value, bool $fore_update = false ) {
519 + // Check permission
520 + if ( ! $fore_update ) {
521 + // Check permission if is item type of course
522 + if ( CourseService::check_is_item_type_of_course( $this->post_type )
523 + || LP_QUESTION_CPT === $this->post_type ) {
524 + $this->check_capabilities_update_item_course();
525 + } elseif ( ! $this->check_capabilities_update() ) {
526 + throw new Exception( __( 'You do not have permission to edit this item.', 'learnpress' ) );
527 + }
528 + }
529 +
530 + $this->set_meta_value_by_key( $key, $value );
531 + update_post_meta( $this->ID, $key, $value );
532 + }
533 +
534 + /**
535 + * Get categories of course.
536 + *
537 + * @return array|WP_Term[]
538 + * @version 1.0.1
539 + * @since 4.2.3
540 + */
541 + public function get_categories(): array {
542 + $wpPost = new WP_Post( $this );
543 + $categories = get_the_terms( $wpPost, LP_COURSE_CATEGORY_TAX );
544 + if ( ! $categories || $categories instanceof WP_Error ) {
545 + $categories = array();
546 + }
547 +
548 + return $categories;
549 + }
550 +
551 + /**
552 + * Get tags of course.
553 + *
554 + * @return array|WP_Term[]
555 + * @version 1.0.1
556 + * @since 4.2.7.2
557 + */
558 + public function get_tags(): array {
559 + $wpPost = new WP_Post( $this );
560 + $tags = get_the_terms( $wpPost, LP_COURSE_TAXONOMY_TAG );
561 + if ( ! $tags || $tags instanceof WP_Error ) {
562 + $tags = array();
563 + }
564 +
565 + return $tags;
566 + }
567 +
568 + /**
569 + * Get permalink of post
570 + *
571 + * @return string
572 + */
573 + public function get_permalink(): string {
574 + $permalink = get_permalink( $this );
575 + if ( empty( $permalink ) ) {
576 + $permalink = '';
577 + }
578 +
579 + return $permalink;
580 + }
581 +
582 + /**
583 + * Get the content of WP
584 + *
585 + * @return string
586 + */
587 + public function get_the_content(): string {
588 + $content = get_the_content( null, false, $this );
589 + $content = apply_filters( 'the_content', $content );
590 + $content = str_replace( ']]>', ']]&gt;', $content );
591 +
592 + return $content;
593 + }
594 +
595 + /**
596 + * Get excerpt of WP
597 + *
598 + * @return string
599 + */
600 + public function get_the_excerpt(): string {
601 + $content = get_the_excerpt( $this );
602 +
603 + return $content;
604 + }
605 +
606 + /**
607 + * Get title of course
608 + *
609 + * @return string
610 + */
611 + public function get_the_title(): string {
612 + return get_the_title( $this );
613 + }
614 +
615 + /**
616 + * Get edit link of post
617 + *
618 + * @return string|null
619 + * @since 4.2.7.4
620 + * @version 1.0.1
621 + */
622 + public function get_edit_link() {
623 + return admin_url( "post.php?post=$this->ID&action=edit" );
624 + /**
625 + * Not using get_edit_post_link() because it may not return the correct link in some cases
626 + * get_post_type_object is null.
627 + */
628 + //return get_edit_post_link( $this->get_id() );
629 + }
630 +
631 + /**
632 + * Get i18n status
633 + *
634 + * @return string
635 + */
636 + public function get_status_i18n(): string {
637 + switch ( $this->post_status ) {
638 + case self::STATUS_PUBLISH:
639 + return __( 'Published', 'learnpress' );
640 + case self::STATUS_FEATURE:
641 + return __( 'Scheduled', 'learnpress' );
642 + case self::STATUS_TRASH:
643 + return __( 'Trash', 'learnpress' );
644 + case self::STATUS_DRAFT:
645 + return __( 'Draft', 'learnpress' );
646 + case self::STATUS_PRIVATE:
647 + return __( 'Private', 'learnpress' );
648 + case self::STATUS_PENDING:
649 + return __( 'Pending', 'learnpress' );
650 + case self::STATUS_AUTO_DRAFT:
651 + return __( 'Auto Draft', 'learnpress' );
652 + case self::VISIBILITY_PASSWORD:
653 + return __( 'Protected', 'learnpress' );
654 +
655 + default:
656 + return ucfirst( $this->post_status );
657 + }
658 + }
659 +}