PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
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
← All changes | inc/custom-post-types/quiz.php +517 -498 4.3.84.4.8 View file →
@@ -1,498 +1,517 @@
1 -<?php
2 -/**
3 - * Class LP_Quiz_Post_Type
4 - *
5 - * @author ThimPress
6 - * @package LearnPress/Classes
7 - * @version 4.0.0
8 - */
9 -
10 -use LearnPress\Models\QuizPostModel;
11 -
12 -defined( 'ABSPATH' ) || exit();
13 -
14 -if ( ! class_exists( 'LP_Quiz_Post_Type' ) ) {
15 -
16 - /**
17 - * Class LP_Quiz_Post_Type
18 - */
19 - final class LP_Quiz_Post_Type extends LP_Abstract_Post_Type {
20 -
21 - /**
22 - * @var null
23 - */
24 - protected static $_instance = null;
25 -
26 - /**
27 - * @var array
28 - */
29 - public static $metaboxes = array();
30 -
31 - /**
32 - * @var string
33 - */
34 - protected $_post_type = LP_QUIZ_CPT;
35 -
36 - /**
37 - * LP_Quiz_Post_Type constructor.
38 - *
39 - * @param $post_type
40 - * @param mixed
41 - */
42 - public function __construct() {
43 -
44 - //$this->add_map_method( 'before_delete', 'before_delete_quiz' );
45 -
46 - add_action( 'learn-press/admin/after-enqueue-scripts', array( $this, 'data_quiz_editor' ) );
47 -
48 - add_filter( 'views_edit-' . LP_QUIZ_CPT, array( $this, 'views_pages' ), 10 );
49 - add_filter( 'posts_where_paged', array( $this, 'posts_where_paged' ), 10 );
50 -
51 - parent::__construct();
52 - }
53 -
54 - /**
55 - * Add filters to lesson view.
56 - *
57 - * @since 3.0.0
58 - *
59 - * @param array $views
60 - *
61 - * @return array
62 - */
63 - public function views_pages( array $views ): array {
64 - $count_unassigned_quiz = LP_Course_DB::getInstance()->get_total_item_unassigned( LP_QUIZ_CPT );
65 -
66 - if ( $count_unassigned_quiz > 0 ) {
67 - $views['unassigned'] = sprintf(
68 - '<a href="%s" class="%s">%s <span class="count">(%d)</span></a>',
69 - admin_url( 'edit.php?post_type=' . LP_QUIZ_CPT . '&unassigned=yes' ),
70 - isset( $_GET['unassigned'] ) ? 'current' : '',
71 - __( 'Unassigned', 'learnpress' ),
72 - $count_unassigned_quiz
73 - );
74 - }
75 -
76 - return $views;
77 - }
78 -
79 - /**
80 - * Register quiz post type.
81 - */
82 - public function args_register_post_type(): array {
83 - $args = apply_filters(
84 - 'lp_quiz_post_type_args',
85 - array(
86 - 'labels' => array(
87 - 'name' => esc_html__( 'Quizzes', 'learnpress' ),
88 - 'menu_name' => esc_html__( 'Quizzes', 'learnpress' ),
89 - 'singular_name' => esc_html__( 'Quiz', 'learnpress' ),
90 - 'add_new_item' => esc_html__( 'Add A New Quiz', 'learnpress' ),
91 - 'edit_item' => esc_html__( 'Edit Quiz', 'learnpress' ),
92 - 'all_items' => esc_html__( 'Quizzes', 'learnpress' ),
93 - 'view_item' => esc_html__( 'View Quiz', 'learnpress' ),
94 - 'add_new' => esc_html__( 'New Quiz', 'learnpress' ),
95 - 'update_item' => esc_html__( 'Update Quiz', 'learnpress' ),
96 - 'search_items' => esc_html__( 'Search Quizzes', 'learnpress' ),
97 - 'not_found' => sprintf( __( 'You haven\'t had any quizzes yet. Click <a href="%s">Add new</a> to start', 'learnpress' ), admin_url( 'post-new.php?post_type=lp_quiz' ) ),
98 - 'not_found_in_trash' => esc_html__( 'There was no quiz found in the trash', 'learnpress' ),
99 - ),
100 - 'public' => true,
101 - 'publicly_queryable' => true,
102 - 'show_ui' => true,
103 - 'has_archive' => false,
104 - 'capability_type' => LP_LESSON_CPT,
105 - 'map_meta_cap' => true,
106 - 'show_in_menu' => 'learn_press',
107 - 'show_in_rest' => true,
108 - 'show_in_admin_bar' => true,
109 - 'show_in_nav_menus' => true,
110 - 'supports' => array(
111 - 'title',
112 - 'editor',
113 - 'revisions',
114 - ),
115 - 'hierarchical' => true,
116 - 'rewrite' => array(
117 - 'slug' => 'quizzes',
118 - 'hierarchical' => true,
119 - 'with_front' => false,
120 - ),
121 - 'exclude_from_search' => true,
122 - )
123 - );
124 -
125 - return $args;
126 - }
127 -
128 - /**
129 - * Load data for quiz editor.
130 - *
131 - * @since 3.0.0
132 - */
133 - public function data_quiz_editor() {
134 - if ( LP_QUIZ_CPT !== get_post_type() ) {
135 - return;
136 - }
137 -
138 - global $post;
139 -
140 - $quiz = LP_Quiz::get_quiz( $post->ID );
141 -
142 - $user_id = get_current_user_id();
143 - $default_new_question_type = get_user_meta( $user_id, '_learn_press_memorize_question_types', true ) ? get_user_meta( $user_id, '_learn_press_memorize_question_types', true ) : 'true_or_false';
144 -
145 - $hidden_questions = get_post_meta( $post->ID, '_lp_hidden_questions', true );
146 - $hidden_questions_settings = get_post_meta( $post->ID, '_hidden_questions_settings', true );
147 -
148 - wp_localize_script(
149 - 'learn-press-admin-quiz-editor',
150 - 'lp_quiz_editor',
151 - apply_filters(
152 - 'learn-press/admin-localize-quiz-editor',
153 - array(
154 - 'root' => array(
155 - 'quiz_id' => $post->ID,
156 - 'ajax' => admin_url( '' ),
157 - 'action' => 'admin_quiz_editor',
158 - 'nonce' => wp_create_nonce( 'learnpress_admin_quiz_editor' ),
159 - 'types' => LP_Question::get_types(),
160 - 'default_new' => $default_new_question_type,
161 - ),
162 - 'chooseItems' => array(
163 - 'open' => false,
164 - 'addedItems' => array(),
165 - 'items' => array(),
166 - ),
167 - 'i18n' => apply_filters(
168 - 'learn-press/quiz-editor/i18n',
169 - array(
170 - 'option' => esc_html__( 'Option', 'learnpress' ),
171 - 'unique' => learn_press_uniqid(),
172 - 'back' => esc_html__( 'Back', 'learnpress' ),
173 - 'selected_items' => esc_html__( 'Selected items', 'learnpress' ),
174 - 'new_option' => esc_html__( 'New Option', 'learnpress' ),
175 - 'confirm_trash_question' => esc_html__( 'Do you want to move the "{{QUESTION_NAME}}" question to the trash?', 'learnpress' ),
176 - 'question_labels' => array(
177 - 'singular' => esc_html__( 'Question', 'learnpress' ),
178 - 'plural' => esc_html__( 'Questions', 'learnpress' ),
179 - ),
180 - 'confirm_remove_blanks' => esc_html__( 'Are you sure to remove all the blanks?', 'learnpress' ),
181 - )
182 - ),
183 - 'listQuestions' => array(
184 - 'questions' => $quiz->quiz_editor_get_questions(),
185 - 'hidden_questions' => ! empty( $hidden_questions ) ? $hidden_questions : array(),
186 - 'hidden_questions_settings' => $hidden_questions_settings ? $hidden_questions_settings : array(),
187 - 'disableUpdateList' => false,
188 - 'supportAnswerOptions' => learn_press_get_question_support_answer_options(),
189 - ),
190 - )
191 - )
192 - );
193 - }
194 -
195 - /**
196 - * Delete all questions assign to quiz.
197 - *
198 - * @since 3.0.0
199 - *
200 - * @param $post_id
201 - */
202 - public function before_delete_quiz( $post_id ) {
203 - if ( get_post_type( $post_id ) !== LP_QUIZ_CPT ) {
204 - return;
205 - }
206 -
207 - $curd = new LP_Quiz_CURD();
208 - // remove question from course items
209 - $curd->delete( $post_id );
210 - }
211 -
212 - /**
213 - * Admin editor
214 - *
215 - * @since 3.3.0
216 - * @version 1.0.1
217 - * @return void
218 - */
219 - public function admin_editor() {
220 - global $post;
221 -
222 - $quiz_id = $post->ID;
223 - $quizPostModel = QuizPostModel::find( $quiz_id, true );
224 - if ( ! $quizPostModel instanceof QuizPostModel ) {
225 - return;
226 - }
227 -
228 - do_action( 'learn-press/admin/edit-quiz/layout', $quizPostModel );
229 - }
230 -
231 - /**
232 - * Add columns to admin manage quiz page
233 - *
234 - * @param array $columns
235 - *
236 - * @return array
237 - */
238 - public function columns_head( $columns ) {
239 - $pos = array_search( 'title', array_keys( $columns ) );
240 -
241 - if ( false !== $pos && ! array_key_exists( LP_COURSE_CPT, $columns ) ) {
242 - $columns = array_merge(
243 - array_slice( $columns, 0, $pos + 1 ),
244 - array(
245 - 'instructor' => esc_html__( 'Author', 'learnpress' ),
246 - LP_COURSE_CPT => esc_html__( 'Course', 'learnpress' ),
247 - 'num_of_question' => esc_html__( 'Questions', 'learnpress' ),
248 - 'duration' => esc_html__( 'Duration', 'learnpress' ),
249 - ),
250 - array_slice( $columns, $pos + 1 )
251 - );
252 - }
253 -
254 - unset( $columns['taxonomy-lesson-tag'] );
255 - $user = wp_get_current_user();
256 -
257 - if ( in_array( 'lp_teacher', $user->roles ) ) {
258 - unset( $columns['instructor'] );
259 - }
260 -
261 - if ( ! empty( $columns['author'] ) ) {
262 - unset( $columns['author'] );
263 - }
264 -
265 - return $columns;
266 - }
267 -
268 - /**
269 - * Display content for custom column
270 - *
271 - * @param string $name
272 - * @param int $post_id
273 - */
274 - public function columns_content( $name, $post_id = 0 ) {
275 - $quizPostModel = QuizPostModel::find( $post_id, true );
276 - if ( ! $quizPostModel ) {
277 - return;
278 - }
279 -
280 - switch ( $name ) {
281 - case 'instructor':
282 - $this->column_instructor( $post_id );
283 - break;
284 - case 'lp_course':
285 - $this->_get_item_course( $post_id );
286 - break;
287 - case 'num_of_question':
288 - $count = $quizPostModel->count_questions();
289 -
290 - printf(
291 - '<span class="lp-label-counter %s" title="%s">%s</span>',
292 - ! $count ? 'disabled' : '',
293 - $count ?
294 - sprintf( _n( '%d question', '%d questions', $count, 'learnpress' ), $count ) :
295 - __( 'This quiz has no questions', 'learnpress' ),
296 - $count
297 - );
298 - break;
299 - case 'duration':
300 - $duration_str = $quizPostModel->get_duration();
301 - $duration_arr = explode( ' ', $duration_str );
302 - $duration = $duration_arr[0];
303 - $duration_type = $duration_arr[1];
304 -
305 - if ( $duration > 0 ) {
306 - $duration_str = LP_Datetime::get_string_plural_duration( $duration, $duration_type );
307 - } else {
308 - $duration_str = __( 'Unlimited', 'learnpress' );
309 - }
310 -
311 - echo esc_html( $duration_str );
312 - break;
313 - case 'preview':
314 - printf(
315 - '<input type="checkbox" class="learn-press-checkbox learn-press-toggle-item-preview" %s value="%s" data-nonce="%s" />',
316 - get_post_meta( $post_id, '_lp_preview', true ) == 'yes' ? ' checked="checked"' : '',
317 - $post_id,
318 - wp_create_nonce( 'learn-press-toggle-item-preview' )
319 - );
320 - break;
321 - default:
322 - break;
323 -
324 - }
325 - }
326 -
327 - /**
328 - * @param $fields
329 - *
330 - * @return string
331 - */
332 - public function posts_fields( $fields ): string {
333 - global $wpdb;
334 -
335 - if ( ! $this->is_page_list_posts_on_backend() ) {
336 - return $fields;
337 - }
338 -
339 - $fields = ' DISTINCT ' . $fields;
340 -
341 - if ( $this->get_order_by() == 'question-count' ) {
342 - $fields .= ", (SELECT count(*) FROM {$wpdb->prefix}learnpress_quiz_questions qq WHERE {$wpdb->posts}.ID = qq.quiz_id ) as question_count";
343 - }
344 -
345 - return $fields;
346 - }
347 -
348 - /**
349 - * @param $join
350 - *
351 - * @return string
352 - */
353 - public function posts_join_paged( $join ): string {
354 - if ( ! $this->is_page_list_posts_on_backend() ) {
355 - return $join;
356 - }
357 -
358 - return $join;
359 - }
360 -
361 - /**
362 - * @param $where
363 - *
364 - * @return mixed|string
365 - */
366 - public function posts_where_paged( $where ) {
367 - if ( ! $this->is_page_list_posts_on_backend() ) {
368 - return $where;
369 - }
370 -
371 - global $wpdb;
372 -
373 - if ( 'yes' === LP_Request::get( 'unassigned' ) ) {
374 - $where .= $wpdb->prepare(
375 - "
376 - AND {$wpdb->posts}.ID NOT IN(
377 - SELECT si.item_id
378 - FROM {$wpdb->learnpress_section_items} si
379 - INNER JOIN {$wpdb->posts} p ON p.ID = si.item_id
380 - WHERE p.post_type = %s
381 - )
382 - ",
383 - LP_QUIZ_CPT
384 - );
385 - }
386 -
387 - return $where;
388 - }
389 -
390 - /**
391 - * @param $order_by_statement
392 - *
393 - * @return string
394 - */
395 - public function posts_orderby( $order_by_statement ) {
396 - global $wpdb;
397 -
398 - if ( ! $this->is_page_list_posts_on_backend() ) {
399 - return $order_by_statement;
400 - }
401 -
402 - $orderby = $this->get_order_by();
403 - $order = $this->get_order_sort();
404 -
405 - if ( $order && $orderby ) {
406 - switch ( $orderby ) {
407 - case 'course-name':
408 - $order_by_statement = "post_title {$order}";
409 - break;
410 - case 'question-count':
411 - $order_by_statement = "question_count {$order}";
412 - break;
413 - default:
414 - $order_by_statement = "{$wpdb->posts}.post_title {$order}";
415 - }
416 - }
417 -
418 - return $order_by_statement;
419 - }
420 -
421 - /**
422 - * @param $columns
423 - *
424 - * @return mixed
425 - */
426 - public function sortable_columns( $columns ) {
427 - $columns['instructor'] = 'author';
428 - $columns[ LP_COURSE_CPT ] = 'course-name';
429 - $columns['num_of_question'] = 'question-count';
430 -
431 - return $columns;
432 - }
433 -
434 - /**
435 - * Quiz assigned view.
436 - *
437 - * @since 3.0.0
438 - */
439 - // public static function quiz_assigned() {
440 - // learn_press_admin_view( 'meta-boxes/course/assigned.php' );
441 - // }
442 -
443 - public function meta_boxes() {
444 - return array(
445 - 'quiz_assigned' => array(
446 - 'title' => esc_html__( 'Assigned', 'learnpress' ),
447 - 'callback' => function ( $post ) {
448 - learn_press_admin_view( 'meta-boxes/course/assigned.php' );
449 - },
450 - 'context' => 'side',
451 - 'priority' => 'high',
452 - ),
453 - 'quiz-editor' => array(
454 - 'title' => esc_html__( 'Questions', 'learnpress' ),
455 - 'callback' => array( $this, 'admin_editor' ),
456 - 'context' => 'normal',
457 - 'priority' => 'high',
458 - ),
459 - );
460 - }
461 -
462 - /**
463 - * @return LP_Quiz_Post_Type|null
464 - */
465 - public static function instance() {
466 - if ( ! self::$_instance ) {
467 - self::$_instance = new self();
468 - }
469 -
470 - return self::$_instance;
471 - }
472 -
473 - /**
474 - * Handle when save post.
475 - *
476 - * @param int $post_id
477 - * @param WP_Post|null $post
478 - * @param bool $is_update
479 - *
480 - * @return void
481 - * @since 4.2.7.6
482 - * @version 1.0.0
483 - */
484 - public function save_post( int $post_id = 0, ?WP_Post $post = null, bool $is_update = false ) {
485 - // Clear cache get quiz by id
486 - $lpCache = new LP_Cache();
487 - $lpCache->clear( "quizPostModel/find/{$post_id}" );
488 - $lpCache->clear( "quizModel/find/{$post_id}" );
489 -
490 - // Clear cache get question_ids of quiz
491 - $lp_quiz_cache = LP_Quiz_Cache::instance();
492 - $lp_quiz_cache->clear( "$post_id/question_ids" );
493 - }
494 - }
495 -
496 - // LP_Quiz_Post_Type
497 - $quiz_post_type = LP_Quiz_Post_Type::instance();
498 -}
1 +<?php
2 +/**
3 + * Class LP_Quiz_Post_Type
4 + *
5 + * @author ThimPress
6 + * @package LearnPress/Classes
7 + * @version 4.0.0
8 + */
9 +
10 +use LearnPress\Databases\PostDB;
11 +use LearnPress\Filters\QuizPostFilter;
12 +use LearnPress\Models\PostModel;
13 +use LearnPress\Models\QuizPostModel;
14 +use LearnPress\Models\WPTables\QuizzesTable;
15 +
16 +defined( 'ABSPATH' ) || exit();
17 +
18 +if ( ! class_exists( 'LP_Quiz_Post_Type' ) ) {
19 +
20 + /**
21 + * Class LP_Quiz_Post_Type
22 + */
23 + final class LP_Quiz_Post_Type extends LP_Abstract_Post_Type {
24 +
25 + /**
26 + * @var null
27 + */
28 + protected static $_instance = null;
29 +
30 + /**
31 + * @var array
32 + */
33 + public static $metaboxes = array();
34 +
35 + /**
36 + * @var string
37 + */
38 + protected $_post_type = LP_QUIZ_CPT;
39 +
40 + /**
41 + * @var string
42 + */
43 + protected $_screen_list = 'edit-' . LP_QUIZ_CPT;
44 +
45 + /**
46 + * LP_Quiz_Post_Type constructor.
47 + *
48 + * @param $post_type
49 + * @param mixed
50 + */
51 + public function __construct() {
52 +
53 + //$this->add_map_method( 'before_delete', 'before_delete_quiz' );
54 +
55 + add_action( 'learn-press/admin/after-enqueue-scripts', array( $this, 'data_quiz_editor' ) );
56 +
57 + add_filter( 'views_edit-' . LP_QUIZ_CPT, array( $this, 'views_pages' ), 10 );
58 + add_action( 'posts_pre_query', array( $this, 'posts_pre_query' ), 999, 2 );
59 + // add_filter( 'posts_where_paged', array( $this, 'posts_where_paged' ), 10 );
60 +
61 + parent::__construct();
62 + }
63 +
64 + /**
65 + * Declare class name of table list quizzes.
66 + *
67 + * @param string $class_name
68 + * @param array $args
69 + *
70 + * @return string
71 + * @since 4.2.9.5
72 + */
73 + public function wp_list_table_class_name( $class_name, $args ) {
74 + if ( $this->check_class_name_handle_table( $args['screen'] ) ) {
75 + $class_name = QuizzesTable::class;
76 + }
77 +
78 + return $class_name;
79 + }
80 +
81 + /**
82 + * Add filters to lesson view.
83 + *
84 + * @since 3.0.0
85 + *
86 + * @param array $views
87 + *
88 + * @return array
89 + */
90 + public function views_pages( array $views ): array {
91 + $count_unassigned_quiz = LP_Course_DB::getInstance()->get_total_item_unassigned( LP_QUIZ_CPT );
92 +
93 + if ( $count_unassigned_quiz > 0 ) {
94 + $views['unassigned'] = sprintf(
95 + '<a href="%s" class="%s">%s <span class="count">(%d)</span></a>',
96 + admin_url( 'edit.php?post_type=' . LP_QUIZ_CPT . '&unassigned=yes' ),
97 + isset( $_GET['unassigned'] ) ? 'current' : '',
98 + __( 'Unassigned', 'learnpress' ),
99 + $count_unassigned_quiz
100 + );
101 + }
102 +
103 + return $views;
104 + }
105 +
106 + /**
107 + * Register quiz post type.
108 + */
109 + public function args_register_post_type(): array {
110 + $args = apply_filters(
111 + 'lp_quiz_post_type_args',
112 + array(
113 + 'labels' => array(
114 + 'name' => esc_html__( 'Quizzes', 'learnpress' ),
115 + 'menu_name' => esc_html__( 'Quizzes', 'learnpress' ),
116 + 'singular_name' => esc_html__( 'Quiz', 'learnpress' ),
117 + 'add_new_item' => esc_html__( 'Add A New Quiz', 'learnpress' ),
118 + 'edit_item' => esc_html__( 'Edit Quiz', 'learnpress' ),
119 + 'all_items' => esc_html__( 'Quizzes', 'learnpress' ),
120 + 'view_item' => esc_html__( 'View Quiz', 'learnpress' ),
121 + 'add_new' => esc_html__( 'New Quiz', 'learnpress' ),
122 + 'update_item' => esc_html__( 'Update Quiz', 'learnpress' ),
123 + 'search_items' => esc_html__( 'Search Quizzes', 'learnpress' ),
124 + 'not_found' => sprintf( __( 'You haven\'t had any quizzes yet. Click <a href="%s">Add new</a> to start', 'learnpress' ), admin_url( 'post-new.php?post_type=lp_quiz' ) ),
125 + 'not_found_in_trash' => esc_html__( 'There was no quiz found in the trash', 'learnpress' ),
126 + ),
127 + 'public' => true,
128 + 'publicly_queryable' => true,
129 + 'show_ui' => true,
130 + 'has_archive' => false,
131 + 'capability_type' => LP_LESSON_CPT,
132 + 'map_meta_cap' => true,
133 + 'show_in_menu' => 'learn_press',
134 + 'show_in_rest' => true,
135 + 'show_in_admin_bar' => true,
136 + 'show_in_nav_menus' => true,
137 + 'supports' => array(
138 + 'title',
139 + 'editor',
140 + 'revisions',
141 + ),
142 + 'hierarchical' => false, // Quizzes have no parent-child hierarchy.
143 + 'rewrite' => array(
144 + 'slug' => 'quizzes',
145 + 'hierarchical' => true,
146 + 'with_front' => false,
147 + ),
148 + 'exclude_from_search' => true,
149 + )
150 + );
151 +
152 + return $args;
153 + }
154 +
155 + /**
156 + * Load data for quiz editor.
157 + *
158 + * @since 3.0.0
159 + */
160 + public function data_quiz_editor() {
161 + if ( LP_QUIZ_CPT !== get_post_type() ) {
162 + return;
163 + }
164 +
165 + global $post;
166 +
167 + $quiz = LP_Quiz::get_quiz( $post->ID );
168 +
169 + $user_id = get_current_user_id();
170 + $default_new_question_type = get_user_meta( $user_id, '_learn_press_memorize_question_types', true ) ? get_user_meta( $user_id, '_learn_press_memorize_question_types', true ) : 'true_or_false';
171 +
172 + $hidden_questions = get_post_meta( $post->ID, '_lp_hidden_questions', true );
173 + $hidden_questions_settings = get_post_meta( $post->ID, '_hidden_questions_settings', true );
174 +
175 + wp_localize_script(
176 + 'learn-press-admin-quiz-editor',
177 + 'lp_quiz_editor',
178 + apply_filters(
179 + 'learn-press/admin-localize-quiz-editor',
180 + array(
181 + 'root' => array(
182 + 'quiz_id' => $post->ID,
183 + 'ajax' => admin_url( '' ),
184 + 'action' => 'admin_quiz_editor',
185 + 'nonce' => wp_create_nonce( 'learnpress_admin_quiz_editor' ),
186 + 'types' => LP_Question::get_types(),
187 + 'default_new' => $default_new_question_type,
188 + ),
189 + 'chooseItems' => array(
190 + 'open' => false,
191 + 'addedItems' => array(),
192 + 'items' => array(),
193 + ),
194 + 'i18n' => apply_filters(
195 + 'learn-press/quiz-editor/i18n',
196 + array(
197 + 'option' => esc_html__( 'Option', 'learnpress' ),
198 + 'unique' => learn_press_uniqid(),
199 + 'back' => esc_html__( 'Back', 'learnpress' ),
200 + 'selected_items' => esc_html__( 'Selected items', 'learnpress' ),
201 + 'new_option' => esc_html__( 'New Option', 'learnpress' ),
202 + 'confirm_trash_question' => esc_html__( 'Do you want to move the "{{QUESTION_NAME}}" question to the trash?', 'learnpress' ),
203 + 'question_labels' => array(
204 + 'singular' => esc_html__( 'Question', 'learnpress' ),
205 + 'plural' => esc_html__( 'Questions', 'learnpress' ),
206 + ),
207 + 'confirm_remove_blanks' => esc_html__( 'Are you sure to remove all the blanks?', 'learnpress' ),
208 + )
209 + ),
210 + 'listQuestions' => array(
211 + 'questions' => $quiz->quiz_editor_get_questions(),
212 + 'hidden_questions' => ! empty( $hidden_questions ) ? $hidden_questions : array(),
213 + 'hidden_questions_settings' => $hidden_questions_settings ? $hidden_questions_settings : array(),
214 + 'disableUpdateList' => false,
215 + 'supportAnswerOptions' => learn_press_get_question_support_answer_options(),
216 + ),
217 + )
218 + )
219 + );
220 + }
221 +
222 + /**
223 + * Delete all questions assign to quiz.
224 + *
225 + * @since 3.0.0
226 + *
227 + * @param $post_id
228 + */
229 + public function before_delete_quiz( $post_id ) {
230 + if ( get_post_type( $post_id ) !== LP_QUIZ_CPT ) {
231 + return;
232 + }
233 +
234 + $curd = new LP_Quiz_CURD();
235 + // remove question from course items
236 + $curd->delete( $post_id );
237 + }
238 +
239 + /**
240 + * Admin editor
241 + *
242 + * @since 3.3.0
243 + * @version 1.0.1
244 + * @return void
245 + */
246 + public function admin_editor() {
247 + global $post;
248 +
249 + $quiz_id = $post->ID;
250 + $quizPostModel = QuizPostModel::find( $quiz_id, true );
251 + if ( ! $quizPostModel instanceof QuizPostModel ) {
252 + return;
253 + }
254 +
255 + do_action( 'learn-press/admin/edit-quiz/layout', $quizPostModel );
256 + }
257 +
258 + /**
259 + * Query lp quizzes in admin via Post DB
260 + *
261 + * @param array $posts
262 + * @param WP_Query $wp_query
263 + *
264 + * @return array|WP_Query
265 + * @since 4.4.8
266 + * @version 1.0.0
267 + */
268 + public function posts_pre_query( $posts, $wp_query ) {
269 + try {
270 + if ( ! is_admin() ) {
271 + return $posts;
272 + }
273 +
274 + // Check screen
275 + $curren_screen = get_current_screen();
276 + if ( ! $curren_screen || $curren_screen->id !== 'edit-' . LP_QUIZ_CPT ) {
277 + return $posts;
278 + }
279 +
280 + $post_type = $wp_query->get( 'post_type' );
281 +
282 + if ( empty( $post_type ) || $post_type !== LP_QUIZ_CPT ) {
283 + return $posts;
284 + }
285 +
286 + $posts_per_page = get_user_option( "edit_{$post_type}_per_page", get_current_user_id() );
287 + if ( empty( $posts_per_page ) ) {
288 + $posts_per_page = 20;
289 + }
290 +
291 + $paged = max( 1, get_query_var( 'paged' ) );
292 + $author = $wp_query->get( 'author' );
293 + $status = $wp_query->get( 'post_status' );
294 + $search = $wp_query->get( 's' );
295 + $month = $wp_query->get( 'm' );
296 + $orderby = LP_Request::get_param( 'orderby', '', 'key' );
297 + $order = LP_Request::get_param( 'order', '', 'key' );
298 +
299 + $filter = new QuizPostFilter();
300 + $filter->only_fields = [ 'p.ID', 'p.post_title', 'p.post_author', 'p.post_date', 'p.post_date_gmt' ];
301 + $filter->field_count = 'p.ID';
302 + $filter->page = $paged;
303 + $filter->limit = $posts_per_page;
304 + $post_db = PostDB::getInstance();
305 +
306 + if ( ! empty( $status ) ) {
307 + $filter->post_status = array( $status );
308 + }
309 +
310 + if ( ! empty( $author ) ) {
311 + $filter->post_author = absint( $author );
312 + }
313 +
314 + if ( ! empty( $search ) ) {
315 + $filter->post_title = sanitize_text_field( wp_unslash( $search ) );
316 + }
317 +
318 + if ( ! empty( $month ) && is_numeric( $month ) && strlen( (string) $month ) === 6 ) {
319 + $filter->where[] = $post_db->wpdb->prepare(
320 + 'AND YEAR(p.post_date) = %d AND MONTH(p.post_date) = %d',
321 + substr( $month, 0, 4 ),
322 + substr( $month, 4, 2 )
323 + );
324 + }
325 +
326 + // Exclude status auto-draft
327 + $filter->where[] = $post_db->wpdb->prepare( 'AND p.post_status != %s', PostModel::STATUS_AUTO_DRAFT );
328 +
329 + // Add question count field
330 + $filter->only_fields[] = "(SELECT COUNT(*) FROM {$post_db->tb_lp_quiz_questions} qq_count
331 + WHERE qq_count.quiz_id = p.ID) AS question_count";
332 +
333 + // Join sections/courses when sorting by course-name
334 + if ( $orderby === 'course-name' ) {
335 + $filter->join[] = "LEFT JOIN {$post_db->wpdb->prefix}learnpress_section_items si ON p.ID = si.item_id";
336 + $filter->join[] = "LEFT JOIN {$post_db->wpdb->prefix}learnpress_sections s ON s.section_id = si.section_id";
337 + $filter->join[] = "LEFT JOIN {$post_db->wpdb->posts} c ON c.ID = s.section_course_id";
338 + }
339 +
340 + // Filter unassigned
341 + if ( 'yes' === LP_Request::get_param( 'unassigned', '', 'key' ) ) {
342 + $filter->where[] = "AND p.ID NOT IN(
343 + SELECT si.item_id
344 + FROM {$post_db->wpdb->learnpress_section_items} si
345 + )";
346 + }
347 +
348 + if ( $orderby === 'course-name' ) {
349 + $filter->order_by = 'c.post_title';
350 + } elseif ( $orderby === 'question-count' ) {
351 + $filter->order_by = 'question_count';
352 + } elseif ( $orderby === 'title' ) {
353 + $filter->order_by = 'p.post_title';
354 + } elseif ( $orderby === 'author' ) {
355 + $filter->order_by = 'p.post_author';
356 + } elseif ( $orderby === 'date' ) {
357 + $filter->order_by = 'p.post_date';
358 + } else {
359 + $filter->order_by = 'p.menu_order';
360 + }
361 +
362 + $filter->order = strtolower( $order ) === 'asc' ? 'ASC' : 'DESC';
363 +
364 + // Get lp quizzes
365 + $total_rows = 0;
366 + $lp_quizzes = $post_db->get_posts( $filter, $total_rows );
367 +
368 + $wp_query->post_count = count( $lp_quizzes );
369 + $wp_query->found_posts = $total_rows;
370 + $wp_query->max_num_pages = (int) ceil( $total_rows / $posts_per_page );
371 + $posts = $lp_quizzes;
372 + } catch ( Throwable $e ) {
373 + LP_Debug::error_log( $e );
374 + }
375 +
376 + return $posts;
377 + }
378 +
379 + /*public function posts_fields( $fields ): string {
380 + global $wpdb;
381 +
382 + if ( ! $this->is_page_list_posts_on_backend() ) {
383 + return $fields;
384 + }
385 +
386 + $fields = ' DISTINCT ' . $fields;
387 +
388 + if ( $this->get_order_by() == 'question-count' ) {
389 + $fields .= ", (SELECT count(*) FROM {$wpdb->prefix}learnpress_quiz_questions qq WHERE {$wpdb->posts}.ID = qq.quiz_id ) as question_count";
390 + }
391 +
392 + return $fields;
393 + }
394 +
395 + public function posts_join_paged( $join ): string {
396 + if ( ! $this->is_page_list_posts_on_backend() ) {
397 + return $join;
398 + }
399 +
400 + return $join;
401 + }
402 +
403 + public function posts_where_paged( $where ) {
404 + if ( ! $this->is_page_list_posts_on_backend() ) {
405 + return $where;
406 + }
407 +
408 + global $wpdb;
409 +
410 + if ( 'yes' === LP_Request::get( 'unassigned' ) ) {
411 + $where .= $wpdb->prepare(
412 + "
413 + AND {$wpdb->posts}.ID NOT IN(
414 + SELECT si.item_id
415 + FROM {$wpdb->learnpress_section_items} si
416 + INNER JOIN {$wpdb->posts} p ON p.ID = si.item_id
417 + WHERE p.post_type = %s
418 + )
419 + ",
420 + LP_QUIZ_CPT
421 + );
422 + }
423 +
424 + return $where;
425 + }
426 +
427 + public function posts_orderby( $order_by_statement ) {
428 + global $wpdb;
429 +
430 + if ( ! $this->is_page_list_posts_on_backend() ) {
431 + return $order_by_statement;
432 + }
433 +
434 + $orderby = $this->get_order_by();
435 + $order = $this->get_order_sort();
436 +
437 + if ( $order && $orderby ) {
438 + switch ( $orderby ) {
439 + case 'course-name':
440 + $order_by_statement = "post_title {$order}";
441 + break;
442 + case 'question-count':
443 + $order_by_statement = "question_count {$order}";
444 + break;
445 + default:
446 + $order_by_statement = "{$wpdb->posts}.post_title {$order}";
447 + }
448 + }
449 +
450 + return $order_by_statement;
451 + }*/
452 +
453 + /**
454 + * Quiz assigned view.
455 + *
456 + * @since 3.0.0
457 + */
458 + // public static function quiz_assigned() {
459 + // learn_press_admin_view( 'meta-boxes/course/assigned.php' );
460 + // }
461 +
462 + public function meta_boxes() {
463 + return array(
464 + 'quiz_assigned' => array(
465 + 'title' => esc_html__( 'Assigned', 'learnpress' ),
466 + 'callback' => function ( $post ) {
467 + learn_press_admin_view( 'meta-boxes/course/assigned.php' );
468 + },
469 + 'context' => 'side',
470 + 'priority' => 'high',
471 + ),
472 + 'quiz-editor' => array(
473 + 'title' => esc_html__( 'Questions', 'learnpress' ),
474 + 'callback' => array( $this, 'admin_editor' ),
475 + 'context' => 'normal',
476 + 'priority' => 'high',
477 + ),
478 + );
479 + }
480 +
481 + /**
482 + * @return LP_Quiz_Post_Type|null
483 + */
484 + public static function instance() {
485 + if ( ! self::$_instance ) {
486 + self::$_instance = new self();
487 + }
488 +
489 + return self::$_instance;
490 + }
491 +
492 + /**
493 + * Handle when save post.
494 + *
495 + * @param int $post_id
496 + * @param WP_Post|null $post
497 + * @param bool $is_update
498 + *
499 + * @return void
500 + * @since 4.2.7.6
501 + * @version 1.0.0
502 + */
503 + public function save_post( int $post_id = 0, ?WP_Post $post = null, bool $is_update = false ) {
504 + // Clear cache get quiz by id
505 + $lpCache = new LP_Cache();
506 + $lpCache->clear( "quizPostModel/find/{$post_id}" );
507 + $lpCache->clear( "quizModel/find/{$post_id}" );
508 +
509 + // Clear cache get question_ids of quiz
510 + $lp_quiz_cache = LP_Quiz_Cache::instance();
511 + $lp_quiz_cache->clear( "$post_id/question_ids" );
512 + }
513 + }
514 +
515 + // LP_Quiz_Post_Type
516 + $quiz_post_type = LP_Quiz_Post_Type::instance();
517 +}