PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.4
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.4
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
learnpress / inc / jwt / rest-api / version1 / class-lp-rest-quiz-v1-controller.php

class-lp-rest-quiz-v1-controller.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.4, at inc/jwt/rest-api/version1/class-lp-rest-quiz-v1-controller.php

752 lines 22.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 class LP_Jwt_Quiz_V1_Controller extends LP_REST_Jwt_Posts_Controller {
3 protected $namespace = 'learnpress/v1';
4
5 protected $rest_base = 'quiz';
6
7 protected $post_type = LP_QUIZ_CPT;
8
9 protected $hierarchical = true;
10
11 public function register_routes() {
12 register_rest_route(
13 $this->namespace,
14 '/' . $this->rest_base,
15 array(
16 array(
17 'methods' => WP_REST_Server::READABLE,
18 'callback' => array( $this, 'get_items' ),
19 'permission_callback' => array( $this, 'get_items_permissions_check' ),
20 'args' => $this->get_collection_params(),
21 ),
22 'schema' => array( $this, 'get_public_item_schema' ),
23 )
24 );
25
26 register_rest_route(
27 $this->namespace,
28 '/' . $this->rest_base . '/(?P<id>[\d]+)',
29 array(
30 'args' => array(
31 'id' => array(
32 'description' => esc_html__( 'A unique identifier for the resource.', 'learnpress' ),
33 'type' => 'integer',
34 ),
35 ),
36 array(
37 'methods' => WP_REST_Server::READABLE,
38 'callback' => array( $this, 'get_item' ),
39 'permission_callback' => array( $this, 'get_item_permissions_check' ),
40 'args' => array(
41 'context' => $this->get_context_param(
42 array(
43 'default' => 'view',
44 )
45 ),
46 ),
47 ),
48 'schema' => array( $this, 'get_public_item_schema' ),
49 )
50 );
51
52 register_rest_route(
53 $this->namespace,
54 '/' . $this->rest_base . '/start',
55 array(
56 'args' => array(
57 'id' => array(
58 'description' => esc_html__( 'Quiz ID.', 'learnpress' ),
59 'type' => 'integer',
60 ),
61 ),
62 array(
63 'methods' => WP_REST_Server::CREATABLE,
64 'callback' => array( $this, 'start_quiz' ),
65 'permission_callback' => array( $this, 'get_item_permissions_check' ),
66 ),
67 )
68 );
69
70 register_rest_route(
71 $this->namespace,
72 '/' . $this->rest_base . '/check_answer',
73 array(
74 'args' => array(
75 'id' => array(
76 'description' => esc_html__( 'Quiz ID.', 'learnpress' ),
77 'type' => 'integer',
78 ),
79 'question_id' => array(
80 'description' => esc_html__( 'Question ID.', 'learnpress' ),
81 'type' => 'integer',
82 ),
83 ),
84 array(
85 'methods' => WP_REST_Server::CREATABLE,
86 'callback' => array( $this, 'check_quiz' ),
87 'permission_callback' => array( $this, 'get_item_permissions_check' ),
88 ),
89 )
90 );
91
92 register_rest_route(
93 $this->namespace,
94 '/' . $this->rest_base . '/finish',
95 array(
96 'args' => array(
97 'id' => array(
98 'description' => esc_html__( 'Quiz ID.', 'learnpress' ),
99 'type' => 'integer',
100 ),
101 'answered' => array(
102 'description' => esc_html__( 'Answer all questions.', 'learnpress' ),
103 'type' => 'object',
104 ),
105 ),
106 array(
107 'methods' => WP_REST_Server::CREATABLE,
108 'callback' => array( $this, 'submit_quiz' ),
109 'permission_callback' => array( $this, 'get_item_permissions_check' ),
110 ),
111 )
112 );
113 }
114
115 /**
116 * Checks if a course can be read.
117 *
118 * Correctly handles courses with the inherit status.
119 *
120 * @author Nhamdv
121 *
122 * @return bool Whether the post can be read.
123 * */
124 public function check_read_permission( $post_id ) {
125 if ( empty( absint( $post_id ) ) ) {
126 return false;
127 }
128
129 $post = get_post( $post_id );
130
131 if ( ! $post ) {
132 return false;
133 }
134
135 if ( lp_rest_check_post_permissions( $this->post_type, 'read', $post_id ) ) {
136 return true;
137 }
138
139 $post_status_obj = get_post_status_object( $post->post_status );
140 if ( ! $post_status_obj || ! $post_status_obj->public ) {
141 return false;
142 }
143
144 $user_id = get_current_user_id();
145
146 if ( ! $user_id ) {
147 return false;
148 }
149
150 $user = learn_press_get_user( $user_id );
151
152 // Get course ID by lesson ID assigned.
153 $course_id = $this->get_course_by_item_id( $post_id );
154
155 if ( empty( $course_id ) ) {
156 return false;
157 }
158
159 $can_view_content_course = $user->can_view_content_course( $course_id );
160
161 $can_view_item = $user->can_view_item( $post_id, $can_view_content_course );
162
163 if ( ! $can_view_item->flag ) {
164 return false;
165 }
166
167 // Can we read the parent if we're inheriting?
168 if ( 'inherit' === $post->post_status && $post->post_parent > 0 ) {
169 $parent = get_post( $post->post_parent );
170
171 if ( $parent ) {
172 return $this->check_read_permission( $parent );
173 }
174 }
175
176 return true;
177 }
178
179 protected function get_course_by_item_id( $item_id ) {
180 static $output;
181
182 global $wpdb;
183
184 if ( empty( $item_id ) ) {
185 return false;
186 }
187
188 if ( ! isset( $output ) ) {
189 $output = $wpdb->get_var(
190 $wpdb->prepare(
191 "SELECT c.ID FROM {$wpdb->posts} c
192 INNER JOIN {$wpdb->learnpress_sections} s ON c.ID = s.section_course_id
193 INNER JOIN {$wpdb->learnpress_section_items} si ON si.section_id = s.section_id
194 WHERE si.item_id = %d ORDER BY si.section_id DESC LIMIT 1
195 ",
196 $item_id
197 )
198 );
199 }
200
201 if ( $output ) {
202 return absint( $output );
203 }
204
205 return false;
206 }
207
208 protected function get_object( $quiz = 0 ) {
209 global $post;
210
211 if ( false === $quiz && isset( $post, $post->ID ) && LP_QUIZ_CPT === get_post_type( $post->ID ) ) {
212 $id = absint( $post->ID );
213 } elseif ( is_numeric( $quiz ) ) {
214 $id = $quiz;
215 } elseif ( $quiz instanceof LP_Quiz ) {
216 $id = $quiz->get_id();
217 } elseif ( ! empty( $quiz->ID ) ) {
218 $id = $quiz->ID;
219 }
220
221 return new LP_Quiz( $id );
222 }
223
224 public function start_quiz( $request ) {
225 $response = new LP_REST_Response();
226 $quiz_id = isset( $request['id'] ) ? absint( $request['id'] ) : '';
227 $course_id = $this->get_course_by_item_id( $quiz_id );
228
229 if ( empty( $quiz_id ) || empty( $course_id ) ) {
230 $response->status = 'error';
231 $response->message = esc_html__( 'There is no Quiz ID or Quiz assigned in the course.', 'learnpress' );
232
233 return rest_ensure_response( $response );
234 }
235
236 if ( ! class_exists( 'LP_REST_Users_Controller' ) ) {
237 include_once LP_PLUGIN_PATH . 'inc/rest-api/v1/frontend/class-lp-rest-users-controller.php';
238 }
239
240 $controller = new LP_REST_Users_Controller();
241
242 $request->set_param( 'course_id', $course_id );
243 $request->set_param( 'item_id', $quiz_id );
244
245 return $controller->start_quiz( $request );
246 }
247
248 public function check_quiz( $request ) {
249 $response = new LP_REST_Response();
250 $quiz_id = isset( $request['id'] ) ? absint( $request['id'] ) : '';
251 $question_id = isset( $request['question_id'] ) ? absint( $request['question_id'] ) : '';
252 $answered = isset( $request['answered'] ) ? wp_unslash( $request['answered'] ) : '';
253 $course_id = $this->get_course_by_item_id( $quiz_id );
254
255 if ( empty( $quiz_id ) || empty( $course_id ) ) {
256 $response->status = 'error';
257 $response->message = esc_html__( 'There is no Quiz ID or Quiz assigned in the course.', 'learnpress' );
258
259 return rest_ensure_response( $response );
260 }
261
262 if ( ! class_exists( 'LP_REST_Users_Controller' ) ) {
263 include_once LP_PLUGIN_PATH . 'inc/rest-api/v1/frontend/class-lp-rest-users-controller.php';
264 }
265
266 $controller = new LP_REST_Users_Controller();
267
268 $request->set_param( 'answered', $answered );
269 $request->set_param( 'question_id', $question_id );
270 $request->set_param( 'course_id', $course_id );
271 $request->set_param( 'item_id', $quiz_id );
272
273 return $controller->check_answer( $request );
274 }
275
276 public function submit_quiz( $request ) {
277 $response = new LP_REST_Response();
278 $quiz_id = isset( $request['id'] ) ? absint( $request['id'] ) : '';
279 $answered = isset( $request['answered'] ) ? wp_unslash( $request['answered'] ) : '';
280
281 $course_id = $this->get_course_by_item_id( $quiz_id );
282
283 if ( empty( $quiz_id ) || empty( $course_id ) ) {
284 $response->status = 'error';
285 $response->message = esc_html__( 'There is no Quiz ID or Quiz assigned in the course.', 'learnpress' );
286
287 return rest_ensure_response( $response );
288 }
289
290 if ( ! isset( $request['answered'] ) ) {
291 $response->status = 'error';
292 $response->message = esc_html__( 'No Answer param.', 'learnpress' );
293
294 return rest_ensure_response( $response );
295 }
296
297 if ( ! class_exists( 'LP_REST_Users_Controller' ) ) {
298 include_once LP_PLUGIN_PATH . 'inc/rest-api/v1/frontend/class-lp-rest-users-controller.php';
299 }
300
301 $controller = new LP_REST_Users_Controller();
302
303 $request->set_param( 'answered', $answered );
304 $request->set_param( 'course_id', $course_id );
305 $request->set_param( 'item_id', $quiz_id );
306
307 return $controller->submit_quiz( $request );
308 }
309
310 public function prepare_object_for_response( $object, $request ) {
311 $context = ! empty( $request['context'] ) ? $request['context'] : 'view';
312 $data = $this->get_quiz_data( $object, $context, $request );
313
314 $response = rest_ensure_response( $data );
315
316 return apply_filters( "lp_jwt_rest_prepare_{$this->post_type}_object", $response, $object, $request );
317 }
318
319 protected function get_quiz_data( $object, $context = 'view' ) {
320 $request = func_num_args() >= 2 ? func_get_arg( 2 ) : new WP_REST_Request( '', '', array( 'context' => $context ) );
321 $fields = $this->get_fields_for_response( $request );
322
323 $id = ! empty( $object->ID ) ? $object->ID : $object->get_id();
324 $post = get_post( $id );
325 $data = array();
326
327 $assigned = $this->get_assigned( $id );
328 if ( ! empty( $assigned ) && method_exists( $object, 'set_course' ) ) {
329 $course_id = $assigned['course']['id'];
330 $object->set_course( $course_id );
331 }
332
333 foreach ( $fields as $field ) {
334 switch ( $field ) {
335 case 'id':
336 $data['id'] = $id;
337 break;
338 case 'name':
339 $data['name'] = $post->post_title;
340 break;
341 case 'slug':
342 $data['slug'] = $post->post_name;
343 break;
344 case 'permalink':
345 $data['permalink'] = $object->get_permalink();
346 break;
347 case 'date_created':
348 $data['date_created'] = lp_jwt_prepare_date_response( $post->post_date_gmt, $post->post_date );
349 break;
350 case 'date_created_gmt':
351 $data['date_created_gmt'] = lp_jwt_prepare_date_response( $post->post_date_gmt );
352 break;
353 case 'date_modified':
354 $data['date_modified'] = lp_jwt_prepare_date_response( $post->post_modified_gmt, $post->post_modified );
355 break;
356 case 'date_modified_gmt':
357 $data['date_modified_gmt'] = lp_jwt_prepare_date_response( $post->post_modified_gmt );
358 break;
359 case 'status':
360 $data['status'] = $post->post_status;
361 break;
362 case 'content':
363 $data['content'] = 'view' === $context ? apply_filters( 'the_content', $post->post_content ) : $post->post_content;
364 break;
365 case 'excerpt':
366 $data['excerpt'] = $post->post_excerpt;
367 break;
368 case 'can_finish_course':
369 $data['can_finish_course'] = $this->check_can_finish_course( $id );
370 break;
371 case 'duration':
372 $data['duration'] = learn_press_get_post_translated_duration( $id, esc_html__( 'Lifetime', 'learnpress' ) );
373 break;
374 case 'assigned':
375 $data['assigned'] = $assigned;
376 break;
377 case 'questions':
378 $data['questions'] = $this->get_quiz_results( $object, true )['questions'] ?? array();
379 break;
380 case 'results':
381 $data['results'] = $this->get_quiz_results( $object );
382 break;
383 }
384 }
385
386 $data['meta_data'] = $this->get_course_meta( $id );
387
388 return $data;
389 }
390
391 public function check_can_finish_course( $id ) {
392 $user = learn_press_get_current_user();
393
394 if ( ! $user || ! $id ) {
395 return false;
396 }
397
398 $course_id = $this->get_course_by_item_id( $id );
399
400 if ( empty( $course_id ) ) {
401 return false;
402 }
403
404 $course = learn_press_get_course( $course_id );
405
406 if ( $user && $course ) {
407 $check = $user->can_show_finish_course_btn( $course );
408
409 if ( $check['status'] === 'success' ) {
410 return true;
411 }
412
413 return false;
414 }
415
416 return false;
417 }
418
419 public function get_quiz_results( $quiz, $get_question = false ) {
420 $output = array(
421 'status' => '',
422 );
423
424 $user = learn_press_get_current_user();
425
426 if ( ! $user || ! $quiz ) {
427 return $output;
428 }
429
430 $id = ! empty( $quiz->ID ) ? $quiz->ID : $quiz->get_id();
431
432 $course_id = $this->get_course_by_item_id( $id );
433
434 if ( empty( $course_id ) ) {
435 return $output;
436 }
437
438 $user_course = $user->get_course_data( $course_id );
439 $user_quiz = $user_course ? $user_course->get_item( $id ) : false;
440 $show_check = $quiz->get_instant_check();
441 $show_correct_review = $quiz->get_show_correct_review();
442 $answered = array();
443 $status = '';
444 $checked_questions = array();
445 $question_ids = $quiz->get_question_ids();
446
447 if ( $user_quiz ) {
448 $status = $user_quiz->get_status();
449 $quiz_results = $user_quiz->get_results( '' );
450 $checked_questions = $user_quiz->get_checked_questions();
451 $expiration_time = $user_quiz->get_expiration_time();
452
453 $output = array(
454 'status' => $status,
455 'attempts' => $user_quiz->get_attempts(),
456 'checked_questions' => $checked_questions,
457 'start_time' => lp_jwt_prepare_date_response( $user_quiz->get_start_time()->toSql() ),
458 'retaken' => absint( $user_quiz->get_retaken_count() ),
459 );
460
461 $output['total_time'] = $user_quiz->get_timestamp_remaining();
462
463 if ( $quiz_results ) {
464 $output['results'] = $quiz_results->get();
465 $answered = $quiz_results->getQuestions();
466 $question_ids = $quiz_results->getQuestions( 'ids' );
467 }
468
469 $output['answered'] = ! empty( $answered ) ? (object) $answered : new stdClass();
470 $output['question_ids'] = array_map( 'absint', array_values( $question_ids ) );
471 }
472
473 $duration = $quiz->get_duration();
474
475 $array = array(
476 'passing_grade' => $quiz->get_passing_grade(),
477 'negative_marking' => $quiz->get_negative_marking(),
478 'instant_check' => $quiz->get_instant_check(),
479 'retake_count' => (float) $quiz->get_retake_count(),
480 'questions_per_page' => $quiz->get_pagination(),
481 'page_numbers' => get_post_meta( $quiz->get_id(), '_lp_pagination_numbers', true ) === 'yes',
482 'review_questions' => $quiz->get_review_questions(),
483 'support_options' => learn_press_get_question_support_answer_options(),
484 'duration' => $duration ? $duration->get() : false,
485 );
486
487 if ( function_exists( 'learn_press_rest_prepare_user_questions' ) && $get_question ) {
488 $questions = learn_press_rest_prepare_user_questions(
489 $question_ids,
490 array(
491 'instant_check' => $show_check,
492 'quiz_status' => $status,
493 'checked_questions' => $checked_questions,
494 'answered' => $answered,
495 'show_correct_review' => $show_correct_review,
496 )
497 );
498
499 $output['questions'] = $questions;
500 }
501
502 return array_merge( $array, $output );
503 }
504
505 public function get_course_meta( $id ) {
506 if ( ! class_exists( 'LP_Meta_Box_Quiz' ) ) {
507 include_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/quiz/settings.php';
508 }
509
510 $metabox = new LP_Meta_Box_Quiz();
511
512 $output = array();
513 foreach ( $metabox->metabox( $id ) as $meta_key => $object ) {
514 if ( is_a( $object, 'LP_Meta_Box_Field' ) ) {
515 $object->id = $meta_key;
516 $output[ $meta_key ] = $object->meta_value( $id );
517 }
518 }
519
520 return $output;
521 }
522
523 public function get_assigned( int $id ) : array {
524 $courses = learn_press_get_item_courses( $id );
525
526 $output = array();
527
528 if ( $courses ) {
529 foreach ( $courses as $course ) {
530 $output['course'] = array(
531 'id' => $course->ID,
532 'title' => $course->post_title,
533 'slug' => $course->post_name,
534 'content' => $course->post_content,
535 'author' => $course->post_author,
536 );
537 }
538 }
539
540 return $output;
541 }
542
543 public function get_all_question( object $quiz ) : array {
544 $questions = array();
545
546 if ( function_exists( 'learn_press_rest_prepare_user_questions' ) ) {
547 $questions = learn_press_rest_prepare_user_questions(
548 $quiz->get_question_ids(),
549 array(
550 'instant_check' => $quiz->get_instant_check(),
551 'show_correct_review' => $quiz->get_show_correct_review(),
552 )
553 );
554 }
555
556 return $questions;
557 }
558
559 public function get_item_schema() {
560 $schema = array(
561 '$schema' => 'http://json-schema.org/draft-04/schema#',
562 'title' => $this->post_type,
563 'type' => 'object',
564 'properties' => array(
565 'id' => array(
566 'description' => __( 'A unique identifier for the resource.', 'learnpress' ),
567 'type' => 'integer',
568 'context' => array( 'view', 'edit' ),
569 'readonly' => true,
570 ),
571 'name' => array(
572 'description' => __( 'Course name.', 'learnpress' ),
573 'type' => 'string',
574 'context' => array( 'view', 'edit' ),
575 ),
576 'slug' => array(
577 'description' => __( 'Course slug.', 'learnpress' ),
578 'type' => 'string',
579 'context' => array( 'view', 'edit' ),
580 ),
581 'permalink' => array(
582 'description' => __( 'Course URL.', 'learnpress' ),
583 'type' => 'string',
584 'format' => 'uri',
585 'context' => array( 'view', 'edit' ),
586 'readonly' => true,
587 ),
588 'date_created' => array(
589 'description' => __( "The date the Course was created, in the site's timezone.", 'learnpress' ),
590 'type' => 'date-time',
591 'context' => array( 'view', 'edit' ),
592 'readonly' => true,
593 ),
594 'date_created_gmt' => array(
595 'description' => __( 'The date the Course was created, as GMT.', 'learnpress' ),
596 'type' => 'date-time',
597 'context' => array( 'view', 'edit' ),
598 'readonly' => true,
599 ),
600 'date_modified' => array(
601 'description' => __( "The date the Course was last modified, in the site's timezone.", 'learnpress' ),
602 'type' => 'date-time',
603 'context' => array( 'view', 'edit' ),
604 'readonly' => true,
605 ),
606 'date_modified_gmt' => array(
607 'description' => __( 'The date the Course was last modified, as GMT.', 'learnpress' ),
608 'type' => 'date-time',
609 'context' => array( 'view', 'edit' ),
610 'readonly' => true,
611 ),
612 'status' => array(
613 'description' => __( 'Course status (post status).', 'learnpress' ),
614 'type' => 'string',
615 'default' => 'publish',
616 'enum' => array_merge( array_keys( get_post_statuses() ), array( 'future' ) ),
617 'context' => array( 'view', 'edit' ),
618 ),
619 'content' => array(
620 'description' => __( 'Course content.', 'learnpress' ),
621 'type' => 'string',
622 'context' => array( 'view', 'edit' ),
623 ),
624 'excerpt' => array(
625 'description' => __( 'Retrieves the course excerpt..', 'learnpress' ),
626 'type' => 'string',
627 'context' => array( 'view', 'edit' ),
628 ),
629 'can_finish_course' => array(
630 'description' => __( 'Can finish the course', 'learnpress' ),
631 'type' => 'boolean',
632 'context' => array( 'view' ),
633 'readonly' => true,
634 ),
635 'duration' => array(
636 'description' => __( 'Duration', 'learnpress' ),
637 'type' => 'string',
638 'context' => array( 'view' ),
639 ),
640 'assigned' => array(
641 'description' => __( 'Assigned.', 'learnpress' ),
642 'type' => 'array',
643 'context' => array( 'view', 'edit' ),
644 'items' => array(
645 'id' => array(
646 'description' => __( 'Item ID.', 'learnpress' ),
647 'type' => 'integer',
648 'context' => array( 'view', 'edit' ),
649 ),
650 'title' => array(
651 'description' => __( 'Title.', 'learnpress' ),
652 'type' => 'string',
653 'context' => array( 'view', 'edit' ),
654 ),
655 'slug' => array(
656 'description' => __( 'Item slug.', 'learnpress' ),
657 'type' => 'string',
658 'context' => array( 'view', 'edit' ),
659 ),
660 'content' => array(
661 'description' => __( 'Item Content.', 'learnpress' ),
662 'type' => 'string',
663 'context' => array( 'view', 'edit' ),
664 ),
665 'author' => array(
666 'description' => __( 'Item Author.', 'learnpress' ),
667 'type' => 'integer',
668 'context' => array( 'view', 'edit' ),
669 ),
670 ),
671 ),
672 'questions' => array(
673 'description' => __( 'List all of the Quiz Questions.', 'learnpress' ),
674 'type' => 'array',
675 'context' => array( 'view', 'edit' ),
676 'items' => array(
677 'description' => __( 'Question items.', 'learnpress' ),
678 'type' => 'object',
679 'context' => array( 'view', 'edit' ),
680 'items' => array(
681 'id' => array(
682 'description' => __( 'Item ID.', 'learnpress' ),
683 'type' => 'integer',
684 'context' => array( 'view', 'edit' ),
685 ),
686 'type' => array(
687 'description' => __( 'Item Type.', 'learnpress' ),
688 'type' => 'string',
689 'context' => array( 'view', 'edit' ),
690 ),
691 'title' => array(
692 'description' => __( 'Item title.', 'learnpress' ),
693 'type' => 'string',
694 'context' => array( 'view', 'edit' ),
695 ),
696 'content' => array(
697 'description' => __( 'Item Content.', 'learnpress' ),
698 'type' => 'string',
699 'context' => array( 'view', 'edit' ),
700 ),
701 'point' => array(
702 'description' => __( 'Point.', 'learnpress' ),
703 'type' => 'integer',
704 'context' => array( 'view', 'edit' ),
705 ),
706 'hint' => array(
707 'description' => __( 'Question Hint.', 'learnpress' ),
708 'type' => 'string',
709 'context' => array( 'view', 'edit' ),
710 ),
711 'options' => array(
712 'description' => __( 'Question Options.', 'learnpress' ),
713 'type' => 'array',
714 'context' => array( 'view', 'edit' ),
715 'items' => array(
716 'description' => __( 'Question items.', 'learnpress' ),
717 'type' => 'object',
718 'context' => array( 'view', 'edit' ),
719 'items' => array(
720 'title' => array(
721 'description' => __( 'Item title.', 'learnpress' ),
722 'type' => 'string',
723 'context' => array( 'view', 'edit' ),
724 ),
725 'value' => array(
726 'description' => __( 'Item value.', 'learnpress' ),
727 'type' => 'string',
728 'context' => array( 'view', 'edit' ),
729 ),
730 'uid' => array(
731 'description' => __( 'Item id.', 'learnpress' ),
732 'type' => 'integer',
733 'context' => array( 'view', 'edit' ),
734 ),
735 ),
736 ),
737 ),
738 ),
739 ),
740 ),
741 'results' => array(
742 'description' => __( 'Retrieves the quiz result..', 'learnpress' ),
743 'type' => 'array',
744 'context' => array( 'view', 'edit' ),
745 ),
746 ),
747 );
748
749 return $this->add_additional_fields_schema( $schema );
750 }
751 }
752