1: <?php
2: if ( ! defined( 'ABSPATH' ) ) exit;
3:
4: 5: 6: 7: 8: 9: 10: 11: 12: 13:
14: class Sensei_Quiz {
15: public $token;
16: public $meta_fields;
17: public $file;
18:
19: 20: 21: 22: 23: 24:
25: public function __construct ( $file = __FILE__ ) {
26: $this->file = $file;
27: $this->token = 'quiz';
28: $this->meta_fields = array( 'quiz_passmark', 'quiz_lesson', 'quiz_type', 'quiz_grade_type', 'pass_required','enable_quiz_reset' );
29: add_action( 'save_post', array( $this, 'update_after_lesson_change' ));
30:
31:
32: add_action( 'template_redirect', array( $this, 'reset_button_click_listener' ) );
33:
34:
35: add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'user_quiz_submit_listener' ) );
36:
37:
38: add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'user_save_quiz_answers_listener' ) );
39:
40:
41: add_action( 'sensei_single_quiz_content_inside_before', array( $this, 'load_global_quiz_data' ), 80 );
42:
43: add_action( 'template_redirect', array ( $this, 'quiz_has_no_questions') );
44:
45:
46: add_action( 'delete_post', array( $this, 'maybe_delete_quiz' ) );
47:
48: }
49:
50: 51: 52: 53: 54: 55:
56: public function update_after_lesson_change( $post_id ){
57:
58:
59:
60: if ( ! isset( $_POST['post_type'] )
61: || 'lesson' !== $_POST['post_type']
62: || wp_is_post_revision( $post_id ) ) {
63: return;
64: }
65:
66:
67: $saved_lesson = get_post( $post_id );
68: $new_lesson_author_id = $saved_lesson->post_author;
69:
70:
71: $quiz_id = Sensei()->lesson->lesson_quizzes( $post_id );
72: if ( ! $quiz_id ) {
73: return;
74: }
75:
76:
77: $my_post = array(
78: 'ID' => $quiz_id,
79: 'post_author' => $new_lesson_author_id,
80: 'post_name' => $saved_lesson->post_name,
81: );
82:
83:
84: remove_action( 'save_post', array( $this, 'update_author' ) );
85:
86:
87: wp_update_post( $my_post );
88: }
89:
90:
91: 92: 93: 94: 95: 96: 97:
98: public function get_lesson_id( $quiz_id ){
99:
100: if( empty( $quiz_id ) || ! intval( $quiz_id ) > 0 ){
101: global $post;
102: if( 'quiz' == get_post_type( $post ) ){
103: $quiz_id = $post->ID;
104: }else{
105: return false;
106: }
107:
108: }
109:
110: $quiz = get_post( $quiz_id );
111: $lesson_id = $quiz->post_parent;
112:
113: return $lesson_id;
114:
115: }
116:
117:
118: 119: 120: 121: 122: 123: 124:
125: public function user_save_quiz_answers_listener(){
126:
127: if( ! isset( $_POST[ 'quiz_save' ])
128: || !isset( $_POST[ 'sensei_question' ] )
129: || empty( $_POST[ 'sensei_question' ] )
130: || ! wp_verify_nonce( $_POST['woothemes_sensei_save_quiz_nonce'], 'woothemes_sensei_save_quiz_nonce' ) > 1 ) {
131: return;
132: }
133:
134: global $post;
135: $lesson_id = $this->get_lesson_id( $post->ID );
136: $quiz_answers = $_POST[ 'sensei_question' ];
137:
138: self::save_user_answers( $quiz_answers, $_FILES , $lesson_id , get_current_user_id() );
139:
140:
141: remove_action( 'sensei_single_quiz_content_inside_before', 'user_save_quiz_answers_listener' );
142:
143: }
144:
145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159:
160: public static function save_user_answers( $quiz_answers, $files = array(), $lesson_id , $user_id = 0 ){
161:
162: if( ! ( $user_id > 0 ) ){
163: $user_id = get_current_user_id();
164: }
165:
166:
167: if( empty( $lesson_id ) || empty( $user_id )
168: || 'lesson' != get_post_type( $lesson_id )
169: ||!get_userdata( $user_id )
170: || !is_array( $quiz_answers ) ){
171:
172: return false;
173:
174: }
175:
176:
177: $activity_logged = Sensei_Utils::sensei_start_lesson( $lesson_id, $user_id );
178:
179:
180: $prepared_answers = self::prepare_form_submitted_answers( $quiz_answers , $files );
181:
182:
183: $answers_saved = Sensei_Utils::add_user_data( 'quiz_answers', $lesson_id, $prepared_answers, $user_id ) ;
184:
185:
186: if( intval( $answers_saved ) > 0){
187:
188:
189: $transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id;
190: set_transient( $transient_key, $prepared_answers, 10 * DAY_IN_SECONDS );
191:
192:
193:
194:
195: $questions_asked_csv = get_comment_meta( $activity_logged, 'questions_asked', true );
196: if( empty( $questions_asked_csv ) ){
197: $questions_asked_csv = implode( ',', array_keys( $quiz_answers ) );
198: update_comment_meta( $activity_logged, 'questions_asked', $questions_asked_csv );
199: }
200:
201:
202:
203: Sensei()->frontend->messages = '<div class="sensei-message note">' . __( 'Quiz Saved Successfully.', 'woothemes-sensei' ) . '</div>';
204: }
205:
206: return $answers_saved;
207:
208: }
209:
210: 211: 212: 213: 214: 215: 216: 217: 218: 219: 220: 221: 222: 223: 224:
225: public function get_user_answers( $lesson_id, $user_id ){
226:
227: $answers = false;
228:
229: if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id )
230: || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) {
231: return false;
232: }
233:
234:
235: $transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id;
236: $transient_cached_answers = get_transient( $transient_key );
237:
238:
239: if( !empty( $transient_cached_answers ) && false != $transient_cached_answers ){
240:
241: $encoded_user_answers = $transient_cached_answers;
242:
243: }else{
244:
245: $encoded_user_answers = Sensei_Utils::get_user_data( 'quiz_answers', $lesson_id , $user_id );
246:
247: }
248:
249: if( ! is_array( $encoded_user_answers ) ){
250: return false;
251: }
252:
253:
254: set_transient( $transient_key, $encoded_user_answers, 10 * DAY_IN_SECONDS);
255:
256:
257: foreach( $encoded_user_answers as $question_id => $encoded_answer ) {
258: $decoded_answer = base64_decode( $encoded_answer );
259: $answers[$question_id] = maybe_unserialize( $decoded_answer );
260: }
261:
262: return $answers;
263:
264: }
265:
266:
267: 268: 269: 270: 271: 272: 273: 274: 275:
276: public function reset_button_click_listener( ){
277:
278: if( ! isset( $_POST[ 'quiz_reset' ])
279: || ! wp_verify_nonce( $_POST['woothemes_sensei_reset_quiz_nonce'], 'woothemes_sensei_reset_quiz_nonce' ) > 1 ) {
280:
281: return;
282: }
283:
284: global $post;
285: $current_quiz_id = $post->ID;
286: $lesson_id = $this->get_lesson_id( $current_quiz_id );
287:
288:
289: $this->reset_user_lesson_data( $lesson_id, get_current_user_id() );
290:
291:
292: remove_action( 'template_redirect', array( $this, 'reset_button_click_listener' ) );
293:
294: }
295:
296: 297: 298: 299: 300: 301: 302: 303: 304: 305: 306: 307:
308: public function user_quiz_submit_listener() {
309:
310:
311: if( ! isset( $_POST[ 'quiz_complete' ])
312: || !isset( $_POST[ 'sensei_question' ] )
313: || empty( $_POST[ 'sensei_question' ] )
314: || ! wp_verify_nonce( $_POST['woothemes_sensei_complete_quiz_nonce'], 'woothemes_sensei_complete_quiz_nonce' ) > 1 ) {
315: return;
316: }
317:
318: global $post, $current_user;
319: $lesson_id = $this->get_lesson_id( $post->ID );
320: $quiz_answers = $_POST[ 'sensei_question' ];
321:
322: self::submit_answers_for_grading( $quiz_answers, $_FILES , $lesson_id , $current_user->ID );
323:
324: }
325:
326: 327: 328: 329: 330: 331: 332: 333: 334: 335:
336: public function load_global_quiz_data(){
337:
338: global $post, $current_user;
339: $this->data = new stdClass();
340:
341:
342: $grade = 0;
343:
344:
345: $lesson_quiz_questions = Sensei()->lesson->lesson_quiz_questions( $post->ID );
346:
347: $quiz_lesson_id = absint( get_post_meta( $post->ID, '_quiz_lesson', true ) );
348:
349:
350: $quiz_grade_type = get_post_meta( $post->ID, '_quiz_grade_type', true );
351:
352:
353: $pass_required = get_post_meta( $post->ID, '_pass_required', true );
354:
355:
356: $quiz_passmark = abs( round( doubleval( get_post_meta( $post->ID, '_quiz_passmark', true ) ), 2 ) );
357:
358:
359: $lesson_id = Sensei()->quiz->get_lesson_id( $post->ID );
360: $user_quizzes = Sensei()->quiz->get_user_answers( $lesson_id, get_current_user_id() );
361: $user_lesson_status = Sensei_Utils::user_lesson_status( $quiz_lesson_id, $current_user->ID );
362: $user_quiz_grade = 0;
363: if( isset( $user_lesson_status->comment_ID ) ) {
364: $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true );
365: }
366:
367: if ( ! is_array($user_quizzes) ) { $user_quizzes = array(); }
368:
369:
370: $user_lesson_end = Sensei_Utils::user_completed_lesson( $user_lesson_status );
371: $user_lesson_complete = false;
372: if ( $user_lesson_end ) {
373: $user_lesson_complete = true;
374: }
375:
376: $reset_allowed = get_post_meta( $post->ID, '_enable_quiz_reset', true );
377:
378: if( 'on' == $reset_allowed ) {
379: $reset_allowed = 1;
380: }
381:
382:
383:
384: $this->data->user_quiz_grade = $user_quiz_grade;
385: $this->data->quiz_passmark = $quiz_passmark;
386: $this->data->quiz_lesson = $quiz_lesson_id;
387: $this->data->quiz_grade_type = $quiz_grade_type;
388: $this->data->user_lesson_end = $user_lesson_end;
389: $this->data->user_lesson_complete = $user_lesson_complete;
390: $this->data->lesson_quiz_questions = $lesson_quiz_questions;
391: $this->data->reset_quiz_allowed = $reset_allowed;
392:
393: }
394:
395:
396: 397: 398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408:
409: public static function prepare_form_submitted_answers( $unprepared_answers, $files ){
410:
411:
412: $prepared_answers = array();
413:
414:
415: if( empty( $unprepared_answers ) || ! is_array( $unprepared_answers ) ){
416: return false;
417: }
418:
419:
420: foreach( $unprepared_answers as $question_id => $answer ) {
421:
422:
423: $question_type = Sensei()->question->get_question_type( $question_id );
424:
425:
426: if( 0 == get_magic_quotes_gpc() ) {
427: $answer = wp_unslash( $answer );
428: }
429:
430:
431: if( 'multi-line' == $question_type ) {
432: $answer = esc_html( $answer );
433: }elseif( 'file-upload' == $question_type ){
434: $file_key = 'file_upload_' . $question_id;
435: if( isset( $files[ $file_key ] ) ) {
436: $attachment_id = Sensei_Utils::upload_file( $files[ $file_key ] );
437: if( $attachment_id ) {
438: $answer = $attachment_id;
439: }
440: }
441: }
442:
443: $prepared_answers[ $question_id ] = base64_encode( maybe_serialize( $answer ) );
444:
445: }
446:
447: return $prepared_answers;
448: }
449:
450: 451: 452: 453: 454: 455: 456: 457: 458: 459: 460: 461: 462:
463: public function reset_user_lesson_data( $lesson_id , $user_id = 0 ){
464:
465:
466: if( empty( $lesson_id ) || empty( $user_id )
467: || 'lesson' != get_post_type( $lesson_id )
468: || ! get_userdata( $user_id ) ){
469: return false;
470: }
471:
472:
473:
474:
475: $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id );
476: if( ! isset( $user_lesson_status->comment_ID ) ) {
477:
478: return false;
479: }
480:
481:
482: $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
483: $course_id = Sensei()->lesson->get_course_id( $lesson_id );
484:
485:
486: $answers_transient_key = 'sensei_answers_'.$user_id.'_'.$lesson_id;
487: $grades_transient_key = 'quiz_grades_'.$user_id.'_'.$lesson_id;
488: $answers_feedback_transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id;
489: delete_transient( $answers_transient_key );
490: delete_transient( $grades_transient_key );
491: delete_transient( $answers_feedback_transient_key );
492:
493:
494: $deleted_answers = Sensei_Utils::delete_user_data( 'quiz_answers', $lesson_id, $user_id );
495: $deleted_grades = Sensei_Utils::delete_user_data( 'quiz_grades', $lesson_id, $user_id );
496: $deleted_user_feedback = Sensei_Utils::delete_user_data( 'quiz_answers_feedback', $lesson_id, $user_id );
497:
498:
499: Sensei_Utils::sensei_delete_quiz_answers( $quiz_id, $user_id );
500:
501: Sensei_Utils::update_lesson_status( $user_id , $lesson_id, 'in-progress', array( 'questions_asked' => '', 'grade' => '' ) );
502:
503:
504: Sensei_Utils::update_course_status( $user_id, $course_id );
505:
506:
507: do_action( 'sensei_user_lesson_reset', $user_id, $lesson_id );
508: if( ! is_admin() ) {
509: Sensei()->notices->add_notice( __( 'Quiz Reset Successfully.', 'woothemes-sensei' ) , 'info');
510: }
511:
512: return ( $deleted_answers && $deleted_grades ) ;
513:
514: }
515:
516: 517: 518: 519: 520: 521: 522: 523: 524: 525: 526: 527: 528: 529: 530: 531:
532: public static function submit_answers_for_grading( $quiz_answers , $files = array() , $lesson_id , $user_id = 0 ){
533:
534: $answers_submitted = false;
535:
536:
537: if( ! intval( $user_id ) > 0 ) {
538: $user_id = get_current_user_id();
539: }
540:
541:
542: if( empty( $lesson_id ) || empty( $user_id )
543: || 'lesson' != get_post_type( $lesson_id )
544: ||!get_userdata( $user_id )
545: || !is_array( $quiz_answers ) ){
546:
547: return false;
548:
549: }
550:
551:
552: $grade = 0;
553:
554:
555: $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
556:
557:
558: $quiz_grade_type = get_post_meta( $quiz_id, '_quiz_grade_type', true );
559:
560:
561: $pass_required = get_post_meta( $quiz_id, '_pass_required', true );
562:
563:
564: $quiz_pass_percentage = abs( round( doubleval( get_post_meta( $quiz_id, '_quiz_passmark', true ) ), 2 ) );
565:
566:
567:
568:
569:
570: $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id );
571: if( ! isset( $user_lesson_status->comment_ID ) ){
572: $user_lesson_status_id = Sensei_Utils::user_start_lesson( $user_id, $lesson_id );
573: $user_lesson_status = get_comment($user_lesson_status);
574: }
575: $questions_asked = isset( $user_lesson_status->comment_ID ) ? get_comment_meta( $user_lesson_status->comment_ID, 'questions_asked', true ): array();
576: if( empty( $questions_asked ) ){
577:
578: $questions_asked = array_keys( $quiz_answers );
579: $questions_asked_string = implode( ',', $questions_asked );
580:
581:
582: update_comment_meta( $user_lesson_status->comment_ID, 'questions_asked', $questions_asked_string );
583:
584: }
585:
586:
587: self::save_user_answers( $quiz_answers , $files , $lesson_id , $user_id );
588:
589:
590: $grade = Sensei_Grading::grade_quiz_auto( $quiz_id, $quiz_answers, 0 , $quiz_grade_type );
591:
592:
593: $lesson_metadata = array();
594: $lesson_status = 'ungraded';
595:
596:
597: $answers_submitted = true;
598:
599:
600: if ('auto' == $quiz_grade_type && ! is_wp_error( $grade ) ) {
601:
602:
603: if ( 'on' == $pass_required ) {
604:
605:
606: if ( $quiz_pass_percentage <= $grade ) {
607:
608: $lesson_status = 'passed';
609:
610: } else {
611:
612: $lesson_status = 'failed';
613:
614: }
615:
616: } else {
617:
618:
619: $lesson_status = 'graded';
620:
621: }
622:
623: $lesson_metadata['grade'] = $grade;
624:
625: }
626:
627: Sensei_Utils::update_lesson_status( $user_id, $lesson_id, $lesson_status, $lesson_metadata );
628:
629: if( 'passed' == $lesson_status || 'graded' == $lesson_status ){
630:
631: 632: 633: 634: 635: 636: 637: 638:
639: do_action( 'sensei_user_lesson_end', $user_id, $lesson_id );
640:
641: }
642:
643: 644: 645: 646: 647: 648: 649: 650: 651: 652: 653: 654:
655: do_action( 'sensei_user_quiz_submitted', $user_id, $quiz_id, $grade, $quiz_pass_percentage, $quiz_grade_type );
656:
657: return $answers_submitted;
658:
659: }
660:
661: 662: 663: 664: 665: 666: 667: 668: 669: 670: 671: 672: 673: 674:
675: public function get_user_question_answer( $lesson_id, $question_id, $user_id = 0 ){
676:
677:
678: if( empty( $lesson_id ) || empty( $question_id )
679: || ! ( intval( $lesson_id ) > 0 )
680: || ! ( intval( $question_id ) > 0 )
681: || 'lesson' != get_post_type( $lesson_id )
682: || 'question' != get_post_type( $question_id )) {
683:
684: return false;
685: }
686:
687: if( ! ( intval( $user_id ) > 0 ) ){
688: $user_id = get_current_user_id();
689: }
690:
691: $users_answers = $this->get_user_answers( $lesson_id, $user_id );
692:
693: if( !$users_answers || empty( $users_answers )
694: || ! is_array( $users_answers ) || ! isset( $users_answers[ $question_id ] ) ){
695:
696:
697: $comment = Sensei_Utils::sensei_check_for_activity( array( 'post_id' => $question_id, 'user_id' => $user_id, 'type' => 'sensei_user_answer' ), true );
698:
699: if( ! isset( $comment->comment_content ) ){
700: return NULL;
701: }
702:
703: return maybe_unserialize( base64_decode( $comment->comment_content ) );
704: }
705:
706: return $users_answers[ $question_id ];
707:
708: }
709:
710: 711: 712: 713: 714: 715: 716: 717: 718: 719: 720: 721: 722: 723: 724: 725: 726:
727: public function set_user_grades( $quiz_grades, $lesson_id, $user_id = 0 ){
728:
729:
730: if( ! intval( $user_id ) > 0 ) {
731: $user_id = get_current_user_id();
732: }
733:
734:
735: if( empty( $lesson_id ) || empty( $user_id )
736: || 'lesson' != get_post_type( $lesson_id )
737: ||!get_userdata( $user_id )
738: || !is_array( $quiz_grades ) ){
739:
740: return false;
741:
742: }
743:
744: $success = false;
745:
746:
747: $comment_meta_id = Sensei_Utils::add_user_data( 'quiz_grades', $lesson_id, $quiz_grades, $user_id );
748:
749:
750: if( intval( $comment_meta_id ) > 0 ) {
751:
752: $success = true;
753:
754: $transient_key = 'quiz_grades_'. $user_id . '_' . $lesson_id;
755: set_transient( $transient_key, $quiz_grades, 10 * DAY_IN_SECONDS );
756: }
757:
758: return $success;
759:
760: }
761:
762: 763: 764: 765: 766: 767: 768: 769: 770: 771: 772: 773:
774: public function get_user_grades( $lesson_id, $user_id = 0 ){
775:
776: $user_grades = array();
777:
778:
779: if( ! intval( $user_id ) > 0 ) {
780: $user_id = get_current_user_id();
781: }
782:
783: if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id )
784: || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) {
785: return false;
786: }
787:
788:
789: $transient_key = 'quiz_grades_'. $user_id . '_' . $lesson_id;
790: $user_grades = get_transient( $transient_key );
791:
792:
793: if( empty( $user_grades ) || false != $user_grades ){
794:
795: $user_grades = Sensei_Utils::get_user_data( 'quiz_grades', $lesson_id, $user_id );
796:
797:
798: set_transient( $transient_key, $user_grades, 10 * DAY_IN_SECONDS );
799:
800: }
801:
802:
803: if( ! is_array( $user_grades ) ){
804: return false;
805: }
806:
807: return $user_grades;
808:
809: }
810:
811: 812: 813: 814: 815: 816: 817: 818: 819: 820: 821: 822: 823: 824: 825:
826: public function get_user_question_grade( $lesson_id, $question_id, $user_id = 0 ){
827:
828:
829: if( empty( $lesson_id ) || empty( $question_id )
830: || ! ( intval( $lesson_id ) > 0 )
831: || ! ( intval( $question_id ) > 0 )
832: || 'lesson' != get_post_type( $lesson_id )
833: || 'question' != get_post_type( $question_id )) {
834:
835: return false;
836: }
837:
838: $all_user_grades = self::get_user_grades( $lesson_id,$user_id );
839:
840: if( ! $all_user_grades || ! isset( $all_user_grades[ $question_id ] ) ){
841:
842:
843: $args = array(
844: 'post_id' => $question_id,
845: 'user_id' => $user_id,
846: 'type' => 'sensei_user_answer'
847: );
848:
849: $question_activity = Sensei_Utils::sensei_check_for_activity( $args , true );
850: $fall_back_grade = false;
851: if( isset( $question_activity->comment_ID ) ){
852: $fall_back_grade = get_comment_meta( $question_activity->comment_ID , 'user_grade', true );
853: }
854:
855: return $fall_back_grade;
856:
857: }
858:
859: return $all_user_grades[ $question_id ];
860:
861: }
862:
863: 864: 865: 866: 867: 868: 869: 870: 871: 872: 873: 874: 875: 876: 877: 878: 879: 880:
881: public function save_user_answers_feedback( $answers_feedback, $lesson_id , $user_id = 0 ){
882:
883:
884: if( empty( $lesson_id ) || empty( $user_id )
885: || 'lesson' != get_post_type( $lesson_id )
886: ||!get_userdata( $user_id )
887: || !is_array( $answers_feedback ) ){
888:
889: return false;
890:
891: }
892:
893:
894:
895: if ( !( 0 < intval( Sensei_Utils::user_started_lesson( $lesson_id, $user_id) ) ) ) {
896: Sensei_Utils::sensei_start_lesson( $lesson_id, $user_id );
897: }
898:
899:
900: $encoded_answers_feedback = array();
901: foreach( $answers_feedback as $question_id => $feedback ){
902: $encoded_answers_feedback[ $question_id ] = base64_encode( $feedback );
903: }
904:
905:
906: $feedback_saved = Sensei_Utils::add_user_data( 'quiz_answers_feedback', $lesson_id , $encoded_answers_feedback, $user_id ) ;
907:
908:
909: if( intval( $feedback_saved ) > 0){
910:
911:
912: $transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id;
913: set_transient( $transient_key, $encoded_answers_feedback, 10 * DAY_IN_SECONDS );
914:
915: }
916:
917: return $feedback_saved;
918:
919: }
920:
921: 922: 923: 924: 925: 926: 927: 928: 929: 930: 931: 932: 933: 934: 935: 936: 937:
938: public function get_user_answers_feedback( $lesson_id , $user_id = 0 ){
939:
940: $answers_feedback = array();
941:
942:
943: if( ! intval( $user_id ) > 0 ) {
944: $user_id = get_current_user_id();
945: }
946:
947: if ( ! intval( $lesson_id ) > 0 || 'lesson' != get_post_type( $lesson_id )
948: || ! intval( $user_id ) > 0 || !get_userdata( $user_id ) ) {
949: return false;
950: }
951:
952:
953: $transient_key = 'sensei_answers_feedback_'.$user_id.'_'.$lesson_id;
954: $encoded_feedback = get_transient( $transient_key );
955:
956:
957: if( empty( $encoded_feedback ) || !$encoded_feedback ){
958:
959: $encoded_feedback = Sensei_Utils::get_user_data( 'quiz_answers_feedback', $lesson_id, $user_id );
960:
961:
962: set_transient( $transient_key, $encoded_feedback, 10 * DAY_IN_SECONDS);
963:
964: }
965:
966:
967: if( ! is_array( $encoded_feedback ) ){
968: return false;
969: }
970:
971: foreach( $encoded_feedback as $question_id => $feedback ){
972:
973: $answers_feedback[ $question_id ] = base64_decode( $feedback );
974:
975: }
976:
977: return $answers_feedback;
978:
979: }
980:
981: 982: 983: 984: 985: 986: 987: 988: 989: 990: 991: 992: 993: 994: 995:
996: public function get_user_question_feedback( $lesson_id, $question_id, $user_id = 0 ){
997:
998: $feedback = false;
999:
1000:
1001: if( empty( $lesson_id ) || empty( $question_id )
1002: || ! ( intval( $lesson_id ) > 0 )
1003: || ! ( intval( $question_id ) > 0 )
1004: || 'lesson' != get_post_type( $lesson_id )
1005: || 'question' != get_post_type( $question_id )) {
1006:
1007: return false;
1008: }
1009:
1010:
1011: $all_feedback = $this->get_user_answers_feedback( $lesson_id, $user_id );
1012:
1013: if( !$all_feedback || empty( $all_feedback )
1014: || ! is_array( $all_feedback ) || ! isset( $all_feedback[ $question_id ] ) ){
1015:
1016:
1017:
1018:
1019: $args = array(
1020: 'post_id' => $question_id,
1021: 'user_id' => $user_id,
1022: 'type' => 'sensei_user_answer'
1023: );
1024: $question_activity = Sensei_Utils::sensei_check_for_activity( $args , true );
1025:
1026:
1027: if( isset( $question_activity->comment_ID ) ){
1028: $feedback = base64_decode( get_comment_meta( $question_activity->comment_ID , 'answer_note', true ) );
1029: }
1030:
1031:
1032: if( empty( $feedback ) ){
1033: $feedback = get_post_meta( $question_id, '_answer_feedback', true );
1034: }
1035:
1036: return $feedback;
1037:
1038: }
1039:
1040: return $all_feedback[ $question_id ];
1041:
1042: }
1043:
1044: 1045: 1046: 1047: 1048: 1049: 1050: 1051: 1052: 1053: 1054:
1055:
1056: public function quiz_has_no_questions() {
1057:
1058: if( ! is_singular( 'quiz' ) ) {
1059: return;
1060: }
1061:
1062: global $post;
1063:
1064: $lesson_id = $this->get_lesson_id($post->ID);
1065:
1066: $has_questions = get_post_meta( $lesson_id, '_quiz_has_questions', true );
1067:
1068: $lesson = get_post($lesson_id);
1069:
1070: if ( is_singular('quiz') && ! $has_questions && $_SERVER['REQUEST_URI'] != "/lesson/$lesson->post_name" ) {
1071:
1072: wp_redirect(get_permalink($lesson->ID), 301);
1073: exit;
1074:
1075: }
1076:
1077: }
1078:
1079: 1080: 1081: 1082: 1083:
1084: public static function deprecate_quiz_sensei_single_main_content_hook(){
1085:
1086: sensei_do_deprecated_action('sensei_single_main_content', '1.9.0', 'sensei_single_quiz_content_inside_before or sensei_single_quiz_content_inside_after');
1087:
1088: }
1089: 1090: 1091: 1092: 1093:
1094: public static function deprecate_quiz_sensei_quiz_single_title_hook(){
1095:
1096: sensei_do_deprecated_action('sensei_quiz_single_title', '1.9.0', 'sensei_single_quiz_content_inside_before ');
1097:
1098: }
1099:
1100: 1101: 1102: 1103: 1104: 1105: 1106: 1107:
1108: public static function single_quiz_title( $title, $post_id = 0 ){
1109:
1110: if( 'quiz' == get_post_type( $post_id ) ){
1111:
1112: $title_with_no_quizzes = $title;
1113:
1114:
1115: if( 1 < substr_count( strtoupper( $title_with_no_quizzes ), 'QUIZ' ) ){
1116:
1117:
1118: $title_with_no_quizzes = str_replace( 'quiz', '', $title );
1119: $title_with_no_quizzes = str_replace( 'Quiz', '', $title_with_no_quizzes );
1120: $title_with_no_quizzes = str_replace( 'QUIZ', '', $title_with_no_quizzes );
1121:
1122: }
1123:
1124: $title = $title_with_no_quizzes . ' ' . __( 'Quiz', 'woothemes-sensei' );
1125: }
1126:
1127: 1128: 1129:
1130: return apply_filters( 'sensei_single_title', $title, get_post_type( ) );
1131:
1132: }
1133:
1134: 1135: 1136: 1137: 1138: 1139: 1140: 1141:
1142: public static function start_quiz_questions_loop(){
1143:
1144: global $sensei_question_loop;
1145:
1146:
1147: $sensei_question_loop['current'] = -1;
1148: $sensei_question_loop['total'] = 0;
1149: $sensei_question_loop['questions'] = array();
1150:
1151:
1152: $questions = Sensei()->lesson->lesson_quiz_questions( get_the_ID() );
1153:
1154: if( count( $questions ) > 0 ){
1155:
1156: $sensei_question_loop['total'] = count( $questions );
1157: $sensei_question_loop['questions'] = $questions;
1158: $sensei_question_loop['quiz_id'] = get_the_ID();
1159:
1160: }
1161:
1162: }
1163:
1164: 1165: 1166: 1167: 1168: 1169: 1170: 1171:
1172: public static function stop_quiz_questions_loop(){
1173:
1174: $sensei_question_loop['total'] = 0;
1175: $sensei_question_loop['questions'] = array();
1176: $sensei_question_loop['quiz_id'] = '';
1177:
1178: }
1179:
1180: 1181: 1182: 1183: 1184:
1185: public static function the_title(){
1186: ?>
1187: <header>
1188:
1189: <h1>
1190:
1191: <?php
1192: 1193: 1194:
1195: echo apply_filters( 'sensei_single_title', get_the_title( get_post() ), get_post_type( get_the_ID() ) );
1196: ?>
1197:
1198: </h1>
1199:
1200: </header>
1201:
1202: <?php
1203: }
1204:
1205: 1206: 1207: 1208: 1209:
1210: public static function the_user_status_message( $quiz_id ){
1211:
1212: $lesson_id = Sensei()->quiz->get_lesson_id( $quiz_id );
1213: $status = Sensei_Utils::sensei_user_quiz_status_message( $lesson_id , get_current_user_id() );
1214: echo '<div class="sensei-message ' . $status['box_class'] . '">' . $status['message'] . '</div>';
1215:
1216: }
1217:
1218: 1219: 1220: 1221: 1222: 1223: 1224:
1225: public static function deprecate_sensei_quiz_action_buttons_hook(){
1226:
1227: sensei_do_deprecated_action( 'sensei_quiz_action_buttons', '1.9.0', 'sensei_single_quiz_questions_after');
1228:
1229: }
1230:
1231: 1232: 1233: 1234: 1235: 1236:
1237: public static function action_buttons() {
1238:
1239: global $post, $current_user;
1240:
1241: $lesson_id = Sensei()->quiz->get_lesson_id( $post->ID );
1242: $lesson_course_id = (int) get_post_meta( $lesson_id, '_lesson_course', true );
1243: $lesson_prerequisite = (int) get_post_meta( $lesson_id, '_lesson_prerequisite', true );
1244: $show_actions = true;
1245: $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $current_user->ID );
1246:
1247:
1248: $user_quiz_grade = '';
1249: if( ! empty( $user_lesson_status ) ){
1250: $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true );
1251: }
1252:
1253:
1254: if( intval( $lesson_prerequisite ) > 0 ) {
1255:
1256:
1257: $show_actions = Sensei_Utils::user_completed_lesson( $lesson_prerequisite, $current_user->ID );
1258:
1259: }
1260: if ( $show_actions && is_user_logged_in() && Sensei_Utils::user_started_course( $lesson_course_id, $current_user->ID ) ) {
1261:
1262:
1263: $reset_quiz_allowed = get_post_meta( $post->ID, '_enable_quiz_reset', true ); ?>
1264:
1265: <!-- Action Nonce's -->
1266: <input type="hidden" name="woothemes_sensei_complete_quiz_nonce" id="woothemes_sensei_complete_quiz_nonce"
1267: value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_complete_quiz_nonce' ) ); ?>" />
1268: <input type="hidden" name="woothemes_sensei_reset_quiz_nonce" id="woothemes_sensei_reset_quiz_nonce"
1269: value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_reset_quiz_nonce' ) ); ?>" />
1270: <input type="hidden" name="woothemes_sensei_save_quiz_nonce" id="woothemes_sensei_save_quiz_nonce"
1271: value="<?php echo esc_attr( wp_create_nonce( 'woothemes_sensei_save_quiz_nonce' ) ); ?>" />
1272: <!--#end Action Nonce's -->
1273:
1274: <?php if ( '' == $user_quiz_grade) { ?>
1275:
1276: <span><input type="submit" name="quiz_complete" class="quiz-submit complete" value="<?php _e( 'Complete Quiz', 'woothemes-sensei' ); ?>"/></span>
1277:
1278: <span><input type="submit" name="quiz_save" class="quiz-submit save" value="<?php _e( 'Save Quiz', 'woothemes-sensei' ); ?>"/></span>
1279:
1280: <?php }
1281:
1282: <?php if ( isset( $reset_quiz_allowed ) && $reset_quiz_allowed ) { ?>
1283:
1284: <span><input type="submit" name="quiz_reset" class="quiz-submit reset" value="<?php _e( 'Reset Quiz', 'woothemes-sensei' ); ?>"/></span>
1285:
1286: <?php } ?>
1287:
1288: <?php }
1289:
1290: }
1291:
1292: 1293: 1294: 1295: 1296: 1297: 1298: 1299: 1300: 1301:
1302: public static function get_user_quiz_grade( $lesson_id, $user_id ){
1303:
1304:
1305: $user_lesson_status = Sensei_Utils::user_lesson_status( $lesson_id, $user_id );
1306: $user_quiz_grade = 0;
1307: if( isset( $user_lesson_status->comment_ID ) ) {
1308: $user_quiz_grade = get_comment_meta( $user_lesson_status->comment_ID, 'grade', true );
1309: }
1310:
1311: return (double) $user_quiz_grade;
1312:
1313: }
1314:
1315: 1316: 1317: 1318: 1319: 1320: 1321: 1322: 1323: 1324: 1325:
1326: public static function is_reset_allowed( $lesson_id ){
1327:
1328: $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
1329:
1330: $reset_allowed = get_post_meta( $quiz_id, '_enable_quiz_reset', true );
1331:
1332: if( 'on' == $reset_allowed ) {
1333: $reset_allowed = 1;
1334: }
1335:
1336: return (bool) $reset_allowed;
1337:
1338: }
1339:
1340: 1341: 1342: 1343: 1344:
1345: public static function is_pass_required( $lesson_id ) {
1346:
1347: $quiz_id = Sensei()->lesson->lesson_quizzes( $lesson_id );
1348:
1349: $reset_allowed = get_post_meta( $quiz_id, '_pass_required', true );
1350:
1351: if( 'on' == $reset_allowed ) {
1352: $reset_allowed = 1;
1353: }
1354:
1355: return (bool) $reset_allowed;
1356: }
1357:
1358: 1359: 1360: 1361: 1362:
1363: public function maybe_delete_quiz( $post_id ){
1364:
1365: $quiz_id = Sensei()->lesson->lesson_quizzes( $post_id );
1366:
1367: if ( empty( $quiz_id ) || 'lesson' != get_post_type( $post_id ) ) {
1368: return;
1369: }
1370:
1371: wp_delete_post( $quiz_id );
1372:
1373:
1374: }
1375:
1376: }
1377:
1378:
1379:
1380: 1381: 1382: 1383: 1384:
1385: class WooThemes_Sensei_Quiz extends Sensei_Quiz{}
1386: