| 1 |
<?php |
| 2 |
/** |
| 3 |
* Common functions to manipulate with the quiz. |
| 4 |
* |
| 5 |
* @since 3.0.0 |
| 6 |
*/ |
| 7 |
|
| 8 |
/** |
| 9 |
* Prevent loading this file directly |
| 10 |
*/ |
| 11 |
defined( 'ABSPATH' ) || exit(); |
| 12 |
|
| 13 |
/** |
| 14 |
* Get quiz from anything is passed |
| 15 |
* |
| 16 |
* @param mixed $the_quiz |
| 17 |
* |
| 18 |
* @return bool|LP_Quiz |
| 19 |
*/ |
| 20 |
function learn_press_get_quiz( $the_quiz ) { |
| 21 |
return LP_Quiz::get_quiz( $the_quiz ); |
| 22 |
} |
| 23 |
|
| 24 |
/** |
| 25 |
* Get question from anything is passed |
| 26 |
* |
| 27 |
* @param mixed $the_question |
| 28 |
* |
| 29 |
* @return bool|LP_Question |
| 30 |
*/ |
| 31 |
function learn_press_get_question( $the_question ) { |
| 32 |
return LP_Question::get_question( $the_question ); |
| 33 |
} |
| 34 |
|
| 35 |
function learn_press_add_question_answer_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) { |
| 36 |
return add_metadata( 'learnpress_question_answer', $item_id, $meta_key, $meta_value, $prev_value ); |
| 37 |
} |
| 38 |
|
| 39 |
function learn_press_update_question_answer_meta( $item_id, $meta_key, $meta_value, $prev_value = '' ) { |
| 40 |
return update_metadata( 'learnpress_question_answer', $item_id, $meta_key, $meta_value, $prev_value ); |
| 41 |
} |
| 42 |
|
| 43 |
function learn_press_delete_question_answer_meta( $item_id, $meta_key, $meta_value, $delete_all = false ) { |
| 44 |
return delete_metadata( 'learnpress_question_answer', $item_id, $meta_key, $meta_value, $delete_all ); |
| 45 |
} |
| 46 |
|
| 47 |
function learn_press_get_question_answer_meta( $item_id, $meta_key, $single = true ) { |
| 48 |
return get_metadata( 'learnpress_question_answer', $item_id, $meta_key, $single ); |
| 49 |
} |
| 50 |
|
| 51 |
|
| 52 |
/** |
| 53 |
* Get all questions of a quiz |
| 54 |
* |
| 55 |
* @author TuNN |
| 56 |
* |
| 57 |
* @param int $quiz_id The ID of a quiz to get all questions |
| 58 |
* @param boolean $only_ids return an array of questions with IDs only or as post objects |
| 59 |
* |
| 60 |
* @return array|null |
| 61 |
* @deprecated 4.1.7.3 |
| 62 |
*/ |
| 63 |
function learn_press_get_quiz_questions( $quiz_id = null, $only_ids = true ) { |
| 64 |
_deprecated_function( __FUNCTION__, '4.1.7.3' ); |
| 65 |
if ( ! $quiz_id ) { |
| 66 |
$quiz_id = get_the_ID(); |
| 67 |
} |
| 68 |
|
| 69 |
return ( $quiz = LP_Quiz::get_quiz( $quiz_id ) ) ? $quiz->get_question_ids() : false; |
| 70 |
} |
| 71 |
|
| 72 |
/** |
| 73 |
* Check to see if user not passed the ID of quiz try to get it from global |
| 74 |
* Only works in single quiz page |
| 75 |
* |
| 76 |
* @param $id |
| 77 |
* |
| 78 |
* @return mixed |
| 79 |
*/ |
| 80 |
function learn_press_get_quiz_id( $id ) { |
| 81 |
if ( ! $id ) { |
| 82 |
global $quiz; |
| 83 |
$id = $quiz->id; |
| 84 |
} |
| 85 |
|
| 86 |
return $id; |
| 87 |
} |
| 88 |
|
| 89 |
/** |
| 90 |
* Check if user has completed a quiz or not |
| 91 |
* |
| 92 |
* @author TuNN |
| 93 |
* |
| 94 |
* @param int $user_id The ID of user need to check |
| 95 |
* @param int $quiz_id The ID of quiz need to check |
| 96 |
* |
| 97 |
* @return boolean |
| 98 |
* @deprecated 4.1.6.9 |
| 99 |
*/ |
| 100 |
/*function learn_press_user_has_completed_quiz( $user_id = null, $quiz_id = null ) { |
| 101 |
$user = learn_press_get_user( $user_id ); |
| 102 |
|
| 103 |
if ( $user ) { |
| 104 |
return $user->has_completed_quiz( $quiz_id ); |
| 105 |
} |
| 106 |
|
| 107 |
return false; |
| 108 |
}*/ |
| 109 |
|
| 110 |
/** |
| 111 |
* get the time remaining of a quiz has started by an user |
| 112 |
* |
| 113 |
* @param null $user_id |
| 114 |
* @param null $quiz_id |
| 115 |
* |
| 116 |
* @return int |
| 117 |
*/ |
| 118 |
function learn_press_get_quiz_time_remaining( $user_id = null, $quiz_id = null ) { |
| 119 |
global $quiz; |
| 120 |
if ( ! $user_id ) { |
| 121 |
$user_id = get_current_user_id(); |
| 122 |
} |
| 123 |
$quiz_id = $quiz_id ? $quiz_id : ( $quiz ? $quiz->id : 0 ); |
| 124 |
if ( ! $quiz_id ) { |
| 125 |
return 0; |
| 126 |
} |
| 127 |
$meta = get_user_meta( $user_id, '_lpr_quiz_start_time', true ); |
| 128 |
$quiz_duration = get_post_meta( $quiz_id, '_lpr_duration', true ); |
| 129 |
$time_remaining = $quiz_duration * 60; |
| 130 |
$quiz_start_time = ! empty( $meta[ $quiz_id ] ) ? $meta[ $quiz_id ] : 0; |
| 131 |
$quiz_start_time = apply_filters( 'learn_press_user_quiz_start_time', $quiz_start_time, $quiz_id, $user_id ); |
| 132 |
|
| 133 |
if ( $quiz_duration && learn_press_user_has_started_quiz( $user_id, $quiz_id ) ) { |
| 134 |
$quiz_duration *= 60; |
| 135 |
$now = current_time( 'timestamp' ); |
| 136 |
|
| 137 |
if ( $now < $quiz_start_time + $quiz_duration ) { |
| 138 |
$time_remaining = $quiz_start_time + $quiz_duration - $now; |
| 139 |
} else { |
| 140 |
$time_remaining = 0; |
| 141 |
} |
| 142 |
} |
| 143 |
|
| 144 |
return apply_filters( 'learn_press_get_quiz_time_remaining', $time_remaining, $user_id, $quiz_id ); |
| 145 |
} |
| 146 |
|
| 147 |
|
| 148 |
/** |
| 149 |
* Check if user has started a quiz or not. |
| 150 |
* |
| 151 |
* @param null $user_id |
| 152 |
* @param null $quiz_id |
| 153 |
* |
| 154 |
* @return bool|mixed |
| 155 |
* @throws Exception |
| 156 |
*/ |
| 157 |
function learn_press_user_has_started_quiz( $user_id = null, $quiz_id = null ) { |
| 158 |
$user = $user_id ? learn_press_get_user( $user_id ) : learn_press_get_current_user(); |
| 159 |
|
| 160 |
return $user ? $user->has_started_quiz( $quiz_id ) : false; |
| 161 |
} |
| 162 |
|
| 163 |
/** |
| 164 |
* Get current status of a quiz for user |
| 165 |
* Status: |
| 166 |
* - null => User does not start quiz |
| 167 |
* - Started => User has started quiz |
| 168 |
* - Completed => User has finished quiz |
| 169 |
* |
| 170 |
* @param $quiz_id |
| 171 |
* @param bool|false $user_id |
| 172 |
* |
| 173 |
* @return string |
| 174 |
*/ |
| 175 |
function learn_press_get_user_quiz_status( $quiz_id, $user_id = false ) { |
| 176 |
$user = $user_id ? learn_press_get_user( $user_id ) : learn_press_get_current_user(); |
| 177 |
|
| 178 |
return $user ? $user->get_quiz_status( $quiz_id ) : ''; |
| 179 |
} |
| 180 |
|
| 181 |
function learn_press_get_quizzes( $user_id = 0, &$args = array() ) { |
| 182 |
// TODO: get all quizzes by user |
| 183 |
} |
| 184 |
|
| 185 |
/** |
| 186 |
* Add new type that LP question can support |
| 187 |
* |
| 188 |
* @param string|array $types |
| 189 |
* @param string|array $supports |
| 190 |
*/ |
| 191 |
function learn_press_add_question_type_support( $types, $supports ) { |
| 192 |
if ( empty( $GLOBALS['learn_press_question_type_support'] ) ) { |
| 193 |
$GLOBALS['learn_press_question_type_support'] = array(); |
| 194 |
} |
| 195 |
$_supports = $GLOBALS['learn_press_question_type_support']; |
| 196 |
settype( $types, 'array' ); |
| 197 |
settype( $supports, 'array' ); |
| 198 |
|
| 199 |
$types = array_filter( $types ); |
| 200 |
$supports = array_filter( $supports ); |
| 201 |
|
| 202 |
if ( $types ) { |
| 203 |
foreach ( $types as $type ) { |
| 204 |
if ( ! $type ) { |
| 205 |
continue; |
| 206 |
} |
| 207 |
if ( empty( $_supports[ $type ] ) ) { |
| 208 |
$_supports[ $type ] = array(); |
| 209 |
} |
| 210 |
if ( $supports ) { |
| 211 |
foreach ( $supports as $s ) { |
| 212 |
$_supports[ $type ][] = $s; |
| 213 |
} |
| 214 |
} |
| 215 |
$_supports[ $type ] = array_filter( $_supports[ $type ] ); |
| 216 |
} |
| 217 |
} |
| 218 |
$GLOBALS['learn_press_question_type_support'] = $_supports; |
| 219 |
} |
| 220 |
|
| 221 |
/** |
| 222 |
* @param string $type |
| 223 |
* |
| 224 |
* @return array|mixed |
| 225 |
*/ |
| 226 |
function learn_press_get_question_type_support( $type = '' ) { |
| 227 |
$supports = ! empty( $GLOBALS['learn_press_question_type_support'] ) ? $GLOBALS['learn_press_question_type_support'] : array(); |
| 228 |
|
| 229 |
return $type && ! empty( $supports[ $type ] ) ? $supports[ $type ] : $supports; |
| 230 |
} |
| 231 |
|
| 232 |
/** |
| 233 |
* Check if a type question is supported. |
| 234 |
* |
| 235 |
* @param string $type |
| 236 |
* |
| 237 |
* @return bool |
| 238 |
*/ |
| 239 |
function learn_press_is_support_question_type( $type ) { |
| 240 |
|
| 241 |
if ( is_array( $type ) ) { |
| 242 |
$type = reset( $type ); |
| 243 |
} |
| 244 |
|
| 245 |
$supports = learn_press_get_question_type_support(); |
| 246 |
|
| 247 |
// New type is supported? |
| 248 |
if ( $supports && ! array_key_exists( $type, $supports ) ) { |
| 249 |
return false; |
| 250 |
} |
| 251 |
|
| 252 |
return true; |
| 253 |
} |
| 254 |
|
| 255 |
function learn_press_question_type_support( $type, $features ) { |
| 256 |
settype( $features, 'array' ); |
| 257 |
$features = array_filter( $features ); |
| 258 |
$supports = learn_press_get_question_type_support( $type ); |
| 259 |
$has_support = true; |
| 260 |
|
| 261 |
if ( $features ) { |
| 262 |
foreach ( $features as $feature ) { |
| 263 |
$has_support = $has_support && in_array( $feature, $supports ); |
| 264 |
} |
| 265 |
} |
| 266 |
|
| 267 |
return $has_support; |
| 268 |
} |
| 269 |
|
| 270 |
function learn_press_default_question_type_support() { |
| 271 |
learn_press_add_question_type_support( |
| 272 |
array( |
| 273 |
'multi_choice', |
| 274 |
'single_choice', |
| 275 |
'true_or_false', |
| 276 |
'fill_in_blanks', |
| 277 |
), |
| 278 |
'check-answer' |
| 279 |
); |
| 280 |
} |
| 281 |
|
| 282 |
add_action( 'plugins_loaded', 'learn_press_default_question_type_support' ); |
| 283 |
|
| 284 |
|
| 285 |
if ( ! function_exists( 'learn_press_quiz_get_questions_order' ) ) { |
| 286 |
/** |
| 287 |
* Get question order in quiz. |
| 288 |
* |
| 289 |
* @since 3.0.0 |
| 290 |
* |
| 291 |
* @param array $questions |
| 292 |
* |
| 293 |
* @return array |
| 294 |
*/ |
| 295 |
function learn_press_quiz_get_questions_order( $questions = array() ) { |
| 296 |
if ( ! $questions ) { |
| 297 |
return array(); |
| 298 |
} |
| 299 |
|
| 300 |
global $wpdb; |
| 301 |
|
| 302 |
$ids = $orders = array(); |
| 303 |
|
| 304 |
foreach ( $questions as $id => $question ) { |
| 305 |
$ids[] = $id; |
| 306 |
} |
| 307 |
|
| 308 |
$order = $wpdb->get_results( "SELECT q.question_id AS q_id, q.question_order AS q_order FROM $wpdb->learnpress_quiz_questions AS q", ARRAY_A ); |
| 309 |
|
| 310 |
if ( $order ) { |
| 311 |
foreach ( $order as $id => $_order ) { |
| 312 |
$orders[ $_order['q_id'] ] = $_order['q_order']; |
| 313 |
} |
| 314 |
} |
| 315 |
|
| 316 |
return $orders; |
| 317 |
} |
| 318 |
} |
| 319 |
|
| 320 |
/** |
| 321 |
* @return bool |
| 322 |
* @deprecated 4.1.6.1 |
| 323 |
* We will remove on version 4.1.7, you can use "get_status" function on the class LP_User_Item_Quiz to replace |
| 324 |
*/ |
| 325 |
function learn_press_is_review_questions() { |
| 326 |
_deprecated_function( __FUNCTION__, '4.1.6.1' ); |
| 327 |
|
| 328 |
$item = LP_Global::course_item(); |
| 329 |
$user = learn_press_get_current_user(); |
| 330 |
|
| 331 |
if ( $item && $user ) { |
| 332 |
$course = learn_press_get_course(); |
| 333 |
|
| 334 |
if ( ! $course ) { |
| 335 |
return false; |
| 336 |
} |
| 337 |
|
| 338 |
$quiz_data = $user->get_item_data( $item->get_id(), $course->get_id() ); |
| 339 |
|
| 340 |
return $quiz_data && $quiz_data->is_review_questions(); |
| 341 |
} |
| 342 |
|
| 343 |
return false; |
| 344 |
} |
| 345 |
|
| 346 |
|
| 347 |
|
| 348 |
|