PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.5
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.5
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
learnpress / inc / question / class-lp-question-fill-in-blanks.php

class-lp-question-fill-in-blanks.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.5, at inc/question/class-lp-question-fill-in-blanks.php

467 lines 11.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * LP_Question_Fill_In_Blanks
4 *
5 * @author ThimPress
6 * @package LearnPress/Templates
7 * @version 4.0.0
8 * @extends LP_Question
9 */
10
11 defined( 'ABSPATH' ) || exit();
12
13 if ( ! class_exists( 'LP_Question_Fill_In_Blanks' ) ) {
14
15 /**
16 * Class LP_Question_Fill_In_Blanks
17 */
18 class LP_Question_Fill_In_Blanks extends LP_Question {
19 /**
20 * Type of this question.
21 *
22 * @var string
23 */
24 protected $_question_type = 'fill_in_blanks';
25
26 /**
27 * @var bool
28 */
29 protected $_answer_options = false;
30
31 /**
32 * LP_Question_Fill_In_Blanks constructor.
33 *
34 * @param null $the_question
35 * @param null $args
36 *
37 * @throws Exception
38 */
39 public function __construct( $the_question = null, $args = null ) {
40 parent::__construct( $the_question, $args );
41
42 add_filter(
43 'learn-press/question-editor/localize-script',
44 array( $this, 'sanitize_question_answers' ),
45 1000
46 );
47
48 add_action( 'learn-press/before-clear-question', array( $this, 'clear_question_answer_meta' ) );
49
50 add_filter(
51 'learn-press/quiz-editor/question-answers-data',
52 array( $this, 'admin_editor_question_answers' ),
53 10,
54 3
55 );
56 add_filter(
57 'learn-press/question-editor/question-answers-data',
58 array( $this, 'admin_editor_question_answers' ),
59 10,
60 3
61 );
62
63 add_filter( 'learn-press/question/fib/regex-content', array( $this, 'match_shortcode_api' ), 10, 4 );
64 }
65
66 public function fib_get_ids( $content ) {
67 $output = array();
68
69 if ( ! empty( $content ) ) {
70 preg_match_all(
71 '/' . get_shortcode_regex( array( 'fib' ) ) . '/',
72 $content,
73 $all_shortcode,
74 PREG_SET_ORDER
75 );
76
77 if ( ! empty( $all_shortcode ) ) {
78 foreach ( $all_shortcode as $shortcode ) {
79 $atts = shortcode_parse_atts( $shortcode[0] );
80
81 if ( empty( $atts['id'] ) ) {
82 $ida = explode( '=', str_replace( ']', '', $atts[1] ) );
83 $ids = isset( $ida[1] ) ? str_replace( '"', '', $ida[1] ) : '';
84 } else {
85 $ids = $atts['id'];
86 }
87
88 $output[] = $ids;
89 }
90 }
91 }
92
93 return $output;
94 }
95
96 public function match_shortcode_api( $content, $answer_id, $show_answer = false, $answered = '' ) {
97 if ( ! empty( $content ) ) {
98 preg_match_all(
99 '/' . get_shortcode_regex( array( 'fib' ) ) . '/',
100 $content,
101 $all_shortcode,
102 PREG_SET_ORDER
103 );
104
105 if ( ! empty( $all_shortcode ) ) {
106 foreach ( $all_shortcode as $shortcode ) {
107 $atts = shortcode_parse_atts( $shortcode[0] );
108
109 if ( empty( $atts['id'] ) ) {
110 $ida = explode( '=', str_replace( ']', '', $atts[1] ) );
111 $ids = isset( $ida[1] ) ? str_replace( '"', '', $ida[1] ) : '';
112 } else {
113 $ids = $atts['id'];
114 }
115
116 $fill = $atts['fill'] ?? '';
117
118 $new_str = ' {{FIB_' . esc_attr( $ids ) . '}} ';
119
120 $content = str_replace( $shortcode[0], $new_str, $content );
121 }
122 }
123 }
124
125 return $content;
126 }
127
128 public function get_answer_data( $content, $answer_id, $answered = '' ) {
129 $output = array();
130
131 if ( ! empty( $content ) ) {
132 preg_match_all(
133 '/' . get_shortcode_regex( array( 'fib' ) ) . '/',
134 $content,
135 $all_shortcode,
136 PREG_SET_ORDER
137 );
138
139 if ( ! empty( $all_shortcode ) ) {
140 foreach ( $all_shortcode as $shortcode ) {
141 $atts = shortcode_parse_atts( $shortcode[0] );
142
143 if ( empty( $atts['id'] ) ) {
144 $ida = explode( '=', str_replace( ']', '', $atts[1] ) );
145 $ids = isset( $ida[1] ) ? str_replace( '"', '', $ida[1] ) : '';
146 } else {
147 $ids = $atts['id'];
148 }
149
150 $fill = $atts['fill'] ?? '';
151
152 if ( is_array( $answered ) ) {
153 $answer = $answered[ $ids ] ?? '';
154 } else {
155 $answer = '';
156 }
157
158 $is_correct = false;
159
160 $blanks = learn_press_get_question_answer_meta( $answer_id, '_blanks', true );
161
162 if ( ! empty( $blanks ) ) {
163 $is_correct = $this->check_answer( $blanks[ $ids ] ?? [], $answer );
164 }
165
166 $output[ $ids ]['is_correct'] = $is_correct;
167 $output[ $ids ]['answer'] = $answer;
168 $output[ $ids ]['correct'] = $fill;
169 }
170 }
171 }
172
173 return $output;
174 }
175
176 public function sanitize_question_answers( $data ) {
177 global $post;
178
179 if ( $post && ( $post->ID == $this->get_id() ) && isset( $data['root'] ) ) {
180 if ( isset( $data['root']['answers'] ) ) {
181 $answers = array();
182 $old_answers = reset( $data['root']['answers'] );
183
184 foreach ( $old_answers as $k => $v ) {
185 if ( $k == '0' ) {
186 $answers['title'] = str_replace( array( '=\"', '\"' ), array( '="', '"' ), $v );
187 } else {
188 $answers[ $k ] = $v;
189 }
190 }
191 $data['root']['answers'] = array( $answers );
192 }
193 }
194
195 return $data;
196 }
197
198 public function admin_editor_question_answers( $answers, $question_id, $quiz_id ) {
199 $question = learn_press_get_question( $question_id );
200
201 if ( ! $question ) {
202 return $answers;
203 }
204
205 if ( 'fill_in_blanks' !== $question->get_type() ) {
206 return $answers;
207 }
208
209 if ( $answers ) {
210 foreach ( $answers as $k => $answer ) {
211 $blanks = learn_press_get_question_answer_meta(
212 $answer['question_answer_id'],
213 '_blanks',
214 true
215 );
216 $answers[ $k ]['blanks'] = ! empty( $blanks ) ? array_values( $blanks ) : array();
217 }
218 }
219
220 return $answers;
221 }
222
223 /**
224 * Clear answer meta of the question
225 *
226 * @param $question_id
227 *
228 * @since 4.0.0
229 * @version 1.0.1
230 */
231 public function clear_question_answer_meta( $question_id ) {
232 try {
233 $question = LP_Question::get_question( $question_id );
234 $answers = $question->get_answers();
235
236 foreach ( $answers as $answer ) {
237 $answer_id = $answer->get_id();
238 $lp_db = LP_Database::getInstance();
239 $filter = new LP_Question_Answermeta_Filter();
240 $filter->collection = $lp_db->tb_lp_question_answermeta;
241 $filter->where[] = $lp_db->wpdb->prepare( "AND learnpress_question_answer_id = %s", $answer_id );
242 $lp_db->delete_execute( $filter );
243 }
244 } catch ( Throwable $e ) {
245 error_log( __METHOD__ . ': ' . $e->getMessage() );
246 }
247 }
248
249 /**
250 * Get answer options of the question
251 *
252 * @param array $args - Optional.
253 *
254 * @return mixed
255 */
256 public function get_answer_options( $args = array() ) {
257
258 $args = wp_parse_args(
259 $args,
260 array(
261 'exclude' => '',
262 'map' => '',
263 'answer' => '',
264 )
265 );
266
267 if ( $args['exclude'] && is_string( $args['exclude'] ) ) {
268 $exclude = array_map( 'trim', explode( ',', $args['exclude'] ) );
269 } else {
270 $exclude = $args['exclude'];
271 }
272
273 $map = $args['map'];
274
275 $options = $this->get_data( 'answer_options' );
276
277 // Remove key if it present in $exclude.
278 if ( $options && ( $exclude || $map ) ) {
279 $exclude = array_flip( $exclude );
280
281 foreach ( $options as $k => $option ) {
282 $is_true = ! isset( $exclude['is_true'] );
283 $fib_answer = ! empty( $args['answer'] ) ? $args['answer'] : '';
284 $title = $option['title'];
285 $option['title'] = apply_filters( 'learn-press/question/fib/regex-content', $title, $option['question_answer_id'], $is_true, $fib_answer );
286 $option['ids'] = $this->fib_get_ids( $title );
287 $option['title_api'] = wp_strip_all_tags( $this->match_shortcode_api( $title, $option['question_answer_id'], $is_true, $fib_answer ) );
288 $option['answers'] = $is_true ? $this->get_answer_data( $title, $option['question_answer_id'], $fib_answer ) : array();
289
290 foreach ( $map as $k_map => $v_map ) {
291 if ( array_key_exists( $k_map, $option ) ) {
292 $option[ $v_map ] = $option[ $k_map ];
293 $exclude[ $k_map ] = 1;
294 }
295 }
296
297 $options[ $k ] = array_diff_key( $option, $exclude );
298 }
299 }
300
301 return apply_filters( 'learn-press/question/answer-options', $options, $this->get_id() );
302 }
303
304
305 public function get_editor_settings() {
306 $blanks = $this->get_data( 'answer_options' );
307
308 global $post;
309
310 return array_merge(
311 parent::get_editor_settings(),
312 array(
313 'id' => $post->ID,
314 'instantParseBlanks' => true,
315 'blankOptions' => $blanks ? array_values( $blanks ) : array(),
316 'blankFillsStyle' => get_post_meta( $post->ID, '_lp_blank_fills_style', true ),
317 'blanksStyle' => get_post_meta( $post->ID, '_lp_blanks_style', true ),
318 )
319 );
320 }
321
322 /**
323 * Get input name.
324 *
325 * @param $fill
326 *
327 * @return string
328 */
329 public function get_input_name( $fill ) {
330 return '_' . md5( wp_create_nonce( $fill ) );
331 }
332
333 /**
334 * Set text format.
335 *
336 * @param $text
337 *
338 * @return string
339 */
340 private function _format_text( $text ) {
341 return trim( preg_replace( '!\s+!', ' ', $text ) );
342 }
343
344 public function get_default_answers() {
345 $default = array(
346 array(
347 'is_true' => 'yes',
348 'value' => '',
349 'title' => '',
350 ),
351 );
352
353 return $default;
354 }
355
356 /**
357 * Check user answer.
358 *
359 * @param null $user_answer
360 *
361 * @return array
362 */
363 public function check( $user_answer = null ) {
364 $return = parent::check();
365 settype( $user_answer, 'array' );
366 $answers = $this->get_answers();
367
368 if ( $answers ) {
369 foreach ( $answers as $key => $option ) {
370 $blanks = $option->get_meta( '_blanks' );
371 $return['blanks'] = array();
372 $return['answered'] = array();
373
374 if ( ! empty( $blanks ) ) {
375 $total_field_input = count( $blanks );
376 $total_answer_correct = 0;
377
378 foreach ( $user_answer as $answer_id => $answer_value ) {
379 $answer_id = trim( $answer_id );
380
381 foreach ( $blanks as $blank ) {
382 if ( $answer_id === $blank['id'] ) {
383 $user_fill = trim( $answer_value );
384 $blank_correct = $this->check_answer( $blank, $answer_value );
385
386 $return['blanks'][ $answer_id ] = $blank_correct;
387 $return['answered'][ $answer_id ] = $user_fill;
388
389 if ( $blank_correct ) {
390 $total_answer_correct++;
391 }
392 }
393 }
394 }
395
396 if ( $total_answer_correct === $total_field_input ) {
397 $return['correct'] = true;
398 $return['mark'] = $this->get_mark();
399 }
400 }
401 }
402 }
403
404 $question = $this;
405 $data = compact( 'user_answer', 'answers', 'question' );
406
407 return apply_filters( 'learn-press/question/fill-in-blank/check', $return, $data );
408 }
409
410 /**
411 * Check answer fill in blank
412 *
413 * @param array $blank
414 * @param $user_fill
415 *
416 * @return bool
417 */
418 public function check_answer( array $blank, $user_fill ): bool {
419 $fill = trim( $blank['fill'] ?? '' );
420 $comparison = ! empty( $blank['comparison'] ) ? $blank['comparison'] : false;
421 $match_case = ! empty( $blank['match_case'] );
422 $user_fill = trim( $user_fill );
423
424 $blank_correct = false;
425
426 switch ( $comparison ) {
427 case 'range':
428 if ( is_numeric( $user_fill ) ) {
429 $fill = explode( ',', $fill );
430 $words = array_map( 'trim', $fill );
431 $words = array_map( 'floatval', $fill );
432 $user_fill = floatval( $user_fill );
433
434 if ( count( $words ) == 2 ) {
435 $blank_correct = $words[0] <= $user_fill && $user_fill <= $words[1];
436 }
437 }
438 break;
439
440 case 'any':
441 $fill = explode( ',', $fill );
442 $words = array_map( 'trim', $fill );
443
444 if ( ! $match_case ) {
445 $words = array_map( 'strtolower', $words );
446 $user_fill = strtolower( $user_fill );
447 }
448
449 $blank_correct = in_array( $user_fill, $words );
450 break;
451
452 default:
453 if ( $match_case ) {
454 $blank_correct = strcmp( $user_fill, $fill ) == 0;
455 } else {
456 $blank_correct = strcasecmp( mb_strtolower( $user_fill, 'UTF-8' ), mb_strtolower( $fill, 'UTF-8' ) ) == 0;
457 }
458 }
459
460 $data = compact( 'blank', 'user_fill' );
461
462 return apply_filters( 'learn-press/question/fill-in-blank/check_answer', $blank_correct, $data );
463 }
464 }
465 }
466
467