PluginProbe
Jetpack – WP Security, Backup, Speed, & Growth / 10.1.2
Jetpack – WP Security, Backup, Speed, & Growth v10.1.2
16.2-beta 12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 All 501 releases
jetpack / modules / shortcodes / quiz.php

quiz.php in Jetpack – WP Security, Backup, Speed, & Growth 10.1.2, at modules/shortcodes/quiz.php

365 lines 9.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php //phpcs:ignore WordPress.Files.FileName.InvalidClassFileNam
2
3 use Automattic\Jetpack\Assets;
4
5 /**
6 * Quiz shortcode.
7 *
8 * Usage:
9 *
10 * [quiz]
11 * [question]What's the right answer?[/question]
12 * [wrong]This one?[explanation]Nope[/explanation][/wrong]
13 * [answer]Yes, this is the one![explanation]Yay![/explanation][/answer]
14 * [wrong]Maybe this one[explanation]Keep trying[/explanation][/wrong]
15 * [wrong]How about this one?[explanation]Try again[/explanation][/wrong]
16 * [/quiz]
17 *
18 * Can also be wrapped in [quiz-wrapper] to display all quizzes together.
19 */
20 class Quiz_Shortcode {
21
22 /**
23 * Parameters admitted by [quiz] shortcode.
24 *
25 * @since 4.5.0
26 *
27 * @var array
28 */
29 private static $quiz_params = array();
30
31 /**
32 * Whether the [quiz-wrapper] shortcode is used.
33 *
34 * @since 10.1
35 *
36 * @var bool
37 */
38 private static $quiz_wrapper = false;
39
40 /**
41 * Whether the scripts were enqueued.
42 *
43 * @since 4.5.0
44 *
45 * @var bool
46 */
47 private static $scripts_enqueued = false;
48
49 /**
50 * In a8c training, store user currently logged in.
51 *
52 * @since 4.5.0
53 *
54 * @var null
55 */
56 private static $username = null;
57
58 /**
59 * Whether the noscript tag was already printed.
60 *
61 * @since 4.5.0
62 *
63 * @var bool
64 */
65 private static $noscript_info_printed = false;
66
67 /**
68 * Whether JavaScript is available.
69 *
70 * @since 4.5.0
71 *
72 * @var null
73 */
74 private static $javascript_unavailable = null;
75
76 /**
77 * Register all shortcodes.
78 *
79 * @since 4.5.0
80 */
81 public static function init() {
82 add_shortcode( 'quiz-wrapper', array( __CLASS__, 'shortcode_wrapper' ) );
83 add_shortcode( 'quiz', array( __CLASS__, 'shortcode' ) );
84 add_shortcode( 'question', array( __CLASS__, 'question_shortcode' ) );
85 add_shortcode( 'answer', array( __CLASS__, 'answer_shortcode' ) );
86 add_shortcode( 'wrong', array( __CLASS__, 'wrong_shortcode' ) );
87 add_shortcode( 'explanation', array( __CLASS__, 'explanation_shortcode' ) );
88 }
89
90 /**
91 * Enqueue assets needed by the quiz,
92 *
93 * @since 4.5.0
94 */
95 private static function enqueue_scripts() {
96 wp_enqueue_style( 'quiz', plugins_url( 'css/quiz.css', __FILE__ ), array(), JETPACK__VERSION );
97 wp_enqueue_script(
98 'quiz',
99 Assets::get_file_url_for_environment( '_inc/build/shortcodes/js/quiz.min.js', 'modules/shortcodes/js/quiz.js' ),
100 array( 'jquery' ),
101 JETPACK__VERSION,
102 true
103 );
104 }
105
106 /**
107 * Check if this is a feed and thus JS is unavailable.
108 *
109 * @since 4.5.0
110 *
111 * @return bool|null
112 */
113 private static function is_javascript_unavailable() {
114 if ( ! is_null( self::$javascript_unavailable ) ) {
115 return self::$javascript_unavailable;
116 }
117
118 if ( is_feed() ) {
119 self::$javascript_unavailable = true;
120 return self::$javascript_unavailable;
121 }
122
123 self::$javascript_unavailable = false;
124 return self::$javascript_unavailable;
125 }
126
127 /**
128 * Display message when JS is not available.
129 *
130 * @since 4.5.0
131 *
132 * @return string
133 */
134 private static function noscript_info() {
135 if ( self::$noscript_info_printed ) {
136 return '';
137 }
138 self::$noscript_info_printed = true;
139 return '<noscript><div><i>' . esc_html__( 'Please view this post in your web browser to complete the quiz.', 'jetpack' ) . '</i></div></noscript>';
140 }
141
142 /**
143 * Check if we're in WordPress.com.
144 *
145 * @since 4.5.0
146 *
147 * @return bool
148 */
149 public static function is_wpcom() {
150 return defined( 'IS_WPCOM' ) && IS_WPCOM;
151 }
152
153 /**
154 * Parse shortcode arguments and render its output.
155 *
156 * @since 4.5.0
157 *
158 * @param array $atts Shortcode parameters.
159 * @param string $content Content enclosed by shortcode tags.
160 *
161 * @return string
162 */
163 public static function shortcode( $atts, $content = null ) {
164
165 // There's nothing to do if there's nothing enclosed.
166 if ( empty( $content ) ) {
167 return '';
168 }
169
170 $id = '';
171
172 if ( self::is_javascript_unavailable() ) {
173 // in an e-mail print the question and the info sentence once per question, too.
174 self::$noscript_info_printed = false;
175 } else {
176
177 if ( ! self::$scripts_enqueued ) {
178 // lazy enqueue cannot use the wp_enqueue_scripts action anymore.
179 self::enqueue_scripts();
180 self::$scripts_enqueued = true;
181 }
182
183 $default_atts = self::is_wpcom()
184 ? array(
185 'trackid' => '',
186 'a8ctraining' => '',
187 )
188 : array(
189 'trackid' => '',
190 );
191
192 self::$quiz_params = shortcode_atts( $default_atts, $atts );
193
194 if ( ! empty( self::$quiz_params['trackid'] ) ) {
195 $id .= ' data-trackid="' . esc_attr( self::$quiz_params['trackid'] ) . '"';
196 }
197 if ( self::is_wpcom() && ! empty( self::$quiz_params['a8ctraining'] ) ) {
198 if ( is_null( self::$username ) ) {
199 self::$username = wp_get_current_user()->user_login;
200 }
201 $id .= ' data-a8ctraining="' . esc_attr( self::$quiz_params['a8ctraining'] ) . '" data-username="' . esc_attr( self::$username ) . '"';
202 }
203 }
204
205 $quiz = self::do_shortcode( $content );
206 $quiz_options = '';
207
208 if ( self::$quiz_wrapper ) {
209 $quiz_options = '<div class="jetpack-quiz-options">
210 <span class="jetpack-quiz-count"></span>
211 <a class="jetpack-quiz-option-button" data-quiz-option="previous" role="button" aria-label="' . esc_attr__( 'Previous quiz', 'jetpack' ) . '">
212 <svg viewBox="0 0 24 24" class="quiz-gridicon">
213 <g><path d="M14 20l-8-8 8-8 1.414 1.414L8.828 12l6.586 6.586"></path></g></svg></a>
214 <a class="jetpack-quiz-option-button" data-quiz-option="next" role="button" aria-label="' . esc_attr__( 'Next quiz', 'jetpack' ) . '">
215 <svg viewBox="0 0 24 24" class="quiz-gridicon">
216 <g><path d="M10 20l8-8-8-8-1.414 1.414L15.172 12l-6.586 6.586"></path></g></svg></a>
217 </div>';
218 }
219
220 return '<div class="jetpack-quiz quiz"' . $id . '>' . $quiz . $quiz_options . '</div>';
221 }
222
223 /**
224 * Wrap shortcode contents.
225 *
226 * @since 10.1
227 *
228 * @param array $atts Shortcode parameters.
229 * @param string $content Content enclosed by shortcode tags.
230 *
231 * @return string
232 */
233 public static function shortcode_wrapper( $atts, $content = null ) {
234 self::$quiz_wrapper = true;
235 return '<div class="jetpack-quiz-wrapper">' . self::do_shortcode( $content ) . '</div>';
236 }
237
238 /**
239 * Strip line breaks, restrict allowed HTML to a few allowed tags and execute nested shortcodes.
240 *
241 * @since 4.5.0
242 *
243 * @param string $content Post content.
244 *
245 * @return mixed|string
246 */
247 private static function do_shortcode( $content ) {
248 // strip autoinserted line breaks.
249 $content = preg_replace( '#(<(?:br /|/?p)>\n?)*(\[/?[a-z]+\])(<(?:br /|/?p)>\n?)*#', '$2', $content );
250
251 // Add internal parameter so it's only rendered when it has it.
252 $content = preg_replace( '/\[(question|answer|wrong|explanation)\]/i', '[$1 quiz_item="true"]', $content );
253 $content = do_shortcode( $content );
254 $content = wp_kses(
255 $content,
256 array(
257 'tt' => array(),
258 'a' => array(
259 'href' => true,
260 'class' => true,
261 'data-quiz-option' => true,
262 'aria-label' => true,
263 'role' => 'button',
264 ),
265 'pre' => array(),
266 'strong' => array(),
267 'i' => array(),
268 'svg' => array(),
269 'g' => array(),
270 'path' => array( 'd' => true ),
271 'br' => array(),
272 'span' => array( 'class' => true ),
273 'img' => array( 'src' => true ),
274 'div' => array(
275 'class' => true,
276 'data-correct' => 1,
277 'data-track-id' => 1,
278 'data-a8ctraining' => 1,
279 'data-username' => 1,
280 'tabindex' => false,
281 ),
282 )
283 );
284 return $content;
285 }
286
287 /**
288 * Render question.
289 *
290 * @since 4.5.0
291 *
292 * @param array $atts Shortcode attributes.
293 * @param null $content Post content.
294 *
295 * @return string
296 */
297 public static function question_shortcode( $atts, $content = null ) {
298 return isset( $atts['quiz_item'] )
299 ? '<div class="jetpack-quiz-question question" tabindex="-1">' . self::do_shortcode( $content ) . '</div>'
300 : '';
301 }
302
303 /**
304 * Render correct answer.
305 *
306 * @since 4.5.0
307 *
308 * @param array $atts Shortcode attributes.
309 * @param null $content Post content.
310 *
311 * @return string
312 */
313 public static function answer_shortcode( $atts, $content = null ) {
314 if ( self::is_javascript_unavailable() ) {
315 return self::noscript_info();
316 }
317
318 return isset( $atts['quiz_item'] )
319 ? '<div class="jetpack-quiz-answer answer" data-correct="1">' . self::do_shortcode( $content ) . '</div>'
320 : '';
321 }
322
323 /**
324 * Render wrong response.
325 *
326 * @since 4.5.0
327 *
328 * @param array $atts Shortcode attributes.
329 * @param null $content Post content.
330 *
331 * @return string
332 */
333 public static function wrong_shortcode( $atts, $content = null ) {
334 if ( self::is_javascript_unavailable() ) {
335 return self::noscript_info();
336 }
337
338 return isset( $atts['quiz_item'] )
339 ? '<div class="jetpack-quiz-answer answer">' . self::do_shortcode( $content ) . '</div>'
340 : '';
341 }
342
343 /**
344 * Render explanation for wrong or right answer.
345 *
346 * @since 4.5.0
347 *
348 * @param array $atts Shortcode attributes.
349 * @param null $content Post content.
350 *
351 * @return string
352 */
353 public static function explanation_shortcode( $atts, $content = null ) {
354 if ( self::is_javascript_unavailable() ) {
355 return self::noscript_info();
356 }
357
358 return isset( $atts['quiz_item'] )
359 ? '<div class="jetpack-quiz-explanation explanation">' . self::do_shortcode( $content ) . '</div>'
360 : '';
361 }
362 }
363
364 Quiz_Shortcode::init();
365