PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / trunk
Tutor LMS – eLearning and online course solution vtrunk
4.0.0 3.9.15 3.9.14 3.9.13 3.9.12 3.9.11 trunk 1.0.0 1.0.0-alpha 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.2.0 1.2.1 1.2.11 1.2.12 1.2.13 1.2.20 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9 1.8.0 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.14 1.9.15 1.9.16 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.1 2.0.10 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.3.0 2.4.0 2.5.0 2.6.0 2.6.1 2.6.2 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 3.0.0 3.0.1 3.0.2 3.1.0 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.7.0 3.7.1 3.7.2 3.7.3 3.7.4 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 3.9.1 3.9.10 3.9.2 3.9.3 3.9.4 3.9.5 3.9.6 3.9.7 3.9.8 3.9.9
tutor / classes / UserPreference.php
tutor / classes Last commit date
Addons.php 7 hours ago Admin.php 7 hours ago Ajax.php 7 hours ago Announcements.php 7 hours ago Assets.php 7 hours ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 7 hours ago Container.php 11 months ago Course.php 7 hours ago Course_Embed.php 3 years ago Course_Filter.php 7 hours ago Course_List.php 7 hours ago Course_Settings_Tabs.php 7 hours ago Course_Widget.php 1 year ago Custom_Validation.php 7 hours ago Dashboard.php 7 hours ago Earnings.php 9 months ago FormHandler.php 7 hours ago Frontend.php 7 hours ago Gutenberg.php 1 year ago Icon.php 7 hours ago Input.php 7 hours ago Instructor.php 7 hours ago Instructors_List.php 7 hours ago Lesson.php 7 hours ago Options_V2.php 7 hours ago Permalink.php 7 hours ago Post_types.php 1 day ago Private_Course_Access.php 7 hours ago Q_And_A.php 7 hours ago Question_Answers_List.php 11 months ago Quiz.php 7 hours ago QuizBuilder.php 7 hours ago Quiz_Attempts_List.php 7 hours ago RestAPI.php 2 years ago Reviews.php 7 hours ago Rewrite_Rules.php 2 years ago SampleCourse.php 7 hours ago Shortcode.php 7 hours ago Singleton.php 1 year ago Student.php 7 hours ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 7 hours ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 4 weeks ago Tutor.php 7 hours ago TutorEDD.php 7 hours ago Tutor_Base.php 2 years ago Tutor_Setup.php 7 hours ago Upgrader.php 7 hours ago User.php 7 hours ago UserPreference.php 7 hours ago Utils.php 7 hours ago Video_Stream.php 3 years ago WhatsNew.php 10 months ago Withdraw.php 7 hours ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 7 hours ago
UserPreference.php
704 lines
1 <?php
2 /**
3 * User preference manager
4 *
5 * Handles storing and retrieving per–user preferences (e.g. theme, playback, font scale)
6 * in a reusable and extensible way using WordPress user meta.
7 *
8 * @package Tutor\UserPreference
9 * @author Themeum <support@themeum.com>
10 * @link https://www.themeum.com/
11 * @since 4.0.0
12 */
13
14 namespace TUTOR;
15
16 defined( 'ABSPATH' ) || exit;
17
18 use Tutor\Cache\TutorCache;
19 use Tutor\Helpers\HttpHelper;
20 use Tutor\Options_V2;
21 use Tutor\Traits\JsonResponse;
22
23 /**
24 * Class UserPreference
25 *
26 * @since 4.0.0
27 */
28 class UserPreference {
29
30 use JsonResponse;
31
32 /**
33 * User meta key for storing all Tutor user preferences.
34 *
35 * @since 4.0.0
36 *
37 * @var string
38 */
39 const META_KEY = 'tutor_user_preferences';
40
41 /**
42 * Theme option: light.
43 *
44 * @since 4.0.0
45 *
46 * @var string
47 */
48 const THEME_LIGHT = 'light';
49
50 /**
51 * Theme option: dark.
52 *
53 * @since 4.0.0
54 *
55 * @var string
56 */
57 const THEME_DARK = 'dark';
58
59 /**
60 * Theme option: system.
61 *
62 * @since 4.0.0
63 *
64 * @var string
65 */
66 const THEME_SYSTEM = 'system';
67
68 /**
69 * Vision option: normal.
70 *
71 * @since 4.0.0
72 *
73 * @var string
74 */
75 const VISION_NORMAL = 'normal';
76
77 /**
78 * Vision option: protanopia.
79 *
80 * @since 4.0.0
81 *
82 * @var string
83 */
84 const VISION_PROTANOPIA = 'protanopia';
85
86 /**
87 * Vision option: deuteranopia.
88 *
89 * @since 4.0.0
90 *
91 * @var string
92 */
93 const VISION_DEUTERANOPIA = 'deuteranopia';
94
95 /**
96 * Vision option: deuteranomaly.
97 *
98 * @since 4.0.0
99 *
100 * @var string
101 */
102 const VISION_DEUTERANOMALY = 'deuteranomaly';
103
104 /**
105 * Available vision options.
106 *
107 * @since 4.0.0
108 *
109 * @var array<string>
110 */
111 const VISIONS = array(
112 self::VISION_NORMAL,
113 self::VISION_PROTANOPIA,
114 self::VISION_DEUTERANOPIA,
115 self::VISION_DEUTERANOMALY,
116 );
117
118 /**
119 * Contrast option: high.
120 *
121 * @since 4.0.0
122 *
123 * @var string
124 */
125 const CONTRAST_HIGH = 'high';
126
127 /**
128 * Motion effects option: auto (follow system).
129 *
130 * @since 4.0.0
131 *
132 * @var string
133 */
134 const MOTION_EFFECTS_AUTO = 'auto';
135
136 /**
137 * Motion effects option: reduce.
138 *
139 * @since 4.0.0
140 *
141 * @var string
142 */
143 const MOTION_EFFECTS_REDUCE = 'reduce';
144
145 /**
146 * Motion effects option: standard (no reduction).
147 *
148 * @since 4.0.0
149 *
150 * @var string
151 */
152 const MOTION_EFFECTS_STANDARD = 'standard';
153
154 /**
155 * Available motion effects options.
156 *
157 * @since 4.0.0
158 *
159 * @var array<string>
160 */
161 const MOTION_EFFECTS_OPTIONS = array(
162 self::MOTION_EFFECTS_AUTO,
163 self::MOTION_EFFECTS_REDUCE,
164 self::MOTION_EFFECTS_STANDARD,
165 );
166
167 /**
168 * Default theme value.
169 *
170 * @since 4.0.0
171 *
172 * @var string
173 */
174 const DEFAULT_THEME = self::THEME_SYSTEM;
175
176 /**
177 * Available theme options.
178 *
179 * @since 4.0.0
180 *
181 * @var array<string>
182 */
183 const THEMES = array( self::THEME_LIGHT, self::THEME_DARK, self::THEME_SYSTEM );
184
185 /**
186 * Default font scale value.
187 *
188 * @since 4.0.0
189 *
190 * @var int
191 */
192 const DEFAULT_FONT_SCALE = 100;
193
194 /**
195 * Available font scale options.
196 *
197 * @since 4.0.0
198 *
199 * @var array<int>
200 */
201 const FONT_SCALE_OPTIONS = array( 60, 80, 100, 120, 140, 160, 180, 200 );
202
203 /**
204 * Register hooks.
205 *
206 * @since 4.0.0
207 *
208 * @param bool $register_hooks Whether to register WordPress hooks.
209 */
210 public function __construct( $register_hooks = true ) {
211 if ( ! $register_hooks ) {
212 return;
213 }
214
215 add_action( 'wp_ajax_tutor_save_user_preferences', array( $this, 'ajax_save_user_preferences' ) );
216 add_action( 'wp_ajax_tutor_reset_user_preferences', array( $this, 'ajax_reset_user_preferences' ) );
217 add_filter( 'language_attributes', array( $this, 'add_theme_attribute' ) );
218 add_action( 'wp_head', array( $this, 'apply_inline_styles' ) );
219 }
220
221 /**
222 * Apply user preference inline styles (font scale, background color).
223 *
224 * @since 4.0.0
225 *
226 * @return void
227 */
228 public function apply_inline_styles() {
229 if ( ! tutor_utils()->is_dashboard_page() && ! tutor_utils()->is_learning_area() ) {
230 return;
231 }
232 $prefs = $this->get_preferences();
233 $font_scale = isset( $prefs['font_scale'] ) ? (int) $prefs['font_scale'] : self::DEFAULT_FONT_SCALE;
234 $base_font_size = 16;
235 $font_size = ( $base_font_size * $font_scale ) / self::DEFAULT_FONT_SCALE;
236 echo '<style>html { background-color: var(--tutor-surface-base); } :root { font-size: ' . esc_attr( $font_size ) . 'px; }</style>';
237 }
238
239 /**
240 * Add a theme attribute to the <html> tag.
241 *
242 * @since 4.0.0
243 *
244 * @param string $output Language attributes.
245 *
246 * @return string
247 */
248 public function add_theme_attribute( $output ) {
249 $is_logged_in = is_user_logged_in();
250 $is_tutor_page = tutor_utils()->is_dashboard_page() || tutor_utils()->is_learning_area();
251
252 if ( ! $is_logged_in || ! $is_tutor_page ) {
253 return $output;
254 }
255
256 $prefs = $this->get_preferences();
257 $theme = isset( $prefs['theme'] ) ? (string) $prefs['theme'] : self::DEFAULT_THEME;
258 if ( ! in_array( $theme, self::THEMES, true ) ) {
259 $theme = self::DEFAULT_THEME;
260 }
261
262 $vision = isset( $prefs['vision'] ) ? (string) $prefs['vision'] : self::VISION_NORMAL;
263 if ( ! in_array( $vision, self::VISIONS, true ) ) {
264 $vision = self::VISION_NORMAL;
265 }
266
267 $contrast = isset( $prefs['contrast'] ) ? (string) $prefs['contrast'] : '';
268 $contrast_attr = '';
269 if ( self::CONTRAST_HIGH === $contrast ) {
270 $contrast_attr = ' data-tutor-contrast="' . esc_attr( self::CONTRAST_HIGH ) . '"';
271 }
272
273 $motion_effects = isset( $prefs['motion_effects'] ) ? (string) $prefs['motion_effects'] : self::MOTION_EFFECTS_AUTO;
274 if ( ! in_array( $motion_effects, self::MOTION_EFFECTS_OPTIONS, true ) ) {
275 $motion_effects = self::MOTION_EFFECTS_AUTO;
276 }
277
278 $motion_effects_attr = '';
279 if ( self::MOTION_EFFECTS_REDUCE === $motion_effects ) {
280 $motion_effects_attr = ' data-tutor-motion="reduce"';
281 } elseif ( self::MOTION_EFFECTS_AUTO === $motion_effects ) {
282 $motion_effects_attr = ' data-tutor-motion="auto"';
283 }
284
285 $vision_attr = self::VISION_NORMAL !== $vision
286 ? ' data-tutor-vision="' . esc_attr( $vision ) . '"'
287 : '';
288
289 return $output . ' data-tutor-theme="' . esc_attr( $theme ) . '"' . $vision_attr . $contrast_attr . $motion_effects_attr;
290 }
291
292 /**
293 * Get merged preferences for a user.
294 *
295 * Stored values override defaults; unknown keys are ignored.
296 *
297 * @since 4.0.0
298 *
299 * @param int $user_id Optional. User ID. Defaults to current user.
300 *
301 * @return array
302 */
303 public static function get_preferences( $user_id = 0 ) {
304 $user_id = tutor_utils()->get_user_id( $user_id );
305 if ( ! $user_id ) {
306 return array();
307 }
308
309 // Check cache first.
310 $cache_key = 'get_preferences_' . $user_id;
311 $cached = TutorCache::get( $cache_key );
312 if ( false !== $cached ) {
313 return $cached;
314 }
315
316 // Get from database.
317 $preferences = get_user_meta( $user_id, self::META_KEY, true );
318 if ( ! is_array( $preferences ) ) {
319 $preferences = array();
320 }
321 $result = array_merge( self::get_default_preferences(), $preferences );
322
323 // Store in cache.
324 TutorCache::set( $cache_key, $result );
325
326 return $result;
327 }
328
329 /**
330 * Get a single preference value with default support.
331 *
332 * @since 4.0.0
333 *
334 * @param string $key Preference key.
335 * @param mixed $fallback Default value if not set. If false, use internal defaults.
336 * @param int|string $user_id Optional user id.
337 *
338 * @return mixed
339 */
340 public static function get( $key, $fallback = false, $user_id = 0 ) {
341 $prefs = self::get_preferences( $user_id );
342 return isset( $prefs[ $key ] ) ? $prefs[ $key ] : $fallback;
343 }
344
345 /**
346 * Persist preferences to user meta.
347 *
348 * @since 4.0.0
349 *
350 * @param array<string,mixed> $prefs Raw preferences to save.
351 * @param int $user_id Optional. User ID. Defaults to current user.
352 *
353 * @return array|false Final saved preferences.
354 */
355 public function save_preferences( array $prefs, $user_id = 0 ) {
356 $user_id = tutor_utils()->get_user_id( $user_id );
357
358 if ( ! $user_id ) {
359 return false;
360 }
361
362 // Get from database.
363 $current_preferences = get_user_meta( $user_id, self::META_KEY, true );
364 if ( ! is_array( $current_preferences ) ) {
365 $current_preferences = array();
366 }
367
368 $combined_preferences = array_merge( $current_preferences, $prefs );
369
370 $preferences = apply_filters( 'tutor_user_preference_data', $combined_preferences, $user_id );
371
372 update_user_meta( $user_id, self::META_KEY, $preferences );
373
374 do_action( 'tutor_user_preference_after_saved', $user_id, $preferences );
375
376 return $preferences;
377 }
378
379 /**
380 * AJAX handler: save current user's preferences.
381 *
382 * @since 4.0.0
383 *
384 * @return void
385 */
386 public function ajax_save_user_preferences() {
387 tutor_utils()->check_nonce();
388
389 $auto_play_next = Input::post( 'auto_play_next', null );
390 $theme = Input::post( 'theme', null );
391 $vision = Input::post( 'vision', null );
392 $contrast = Input::post( 'contrast', null );
393 $motion_effects = Input::post( 'motion_effects', null );
394 $font_scale = Input::post( 'font_scale', null );
395 $learning_mood = Input::post( 'learning_mood', null );
396
397 $preferences_settings = array();
398
399 if ( null !== $auto_play_next ) {
400 $auto_play_next = 'true' === $auto_play_next ? true : false;
401 $default_auto_play_next = (bool) tutor_utils()->get_option( 'autoload_next_course_content' );
402 $preferences_settings = array_merge( $preferences_settings, self::prepare_preference_setting( 'auto_play_next', $auto_play_next, $default_auto_play_next ) );
403 }
404
405 if ( null !== $theme ) {
406 if ( ! in_array( $theme, self::THEMES, true ) ) {
407 $theme = self::DEFAULT_THEME;
408 }
409 $preferences_settings['theme'] = $theme;
410 }
411
412 if ( null !== $vision ) {
413 $vision = (string) $vision;
414 if ( ! in_array( $vision, self::VISIONS, true ) ) {
415 $vision = self::VISION_NORMAL;
416 }
417 $preferences_settings = array_merge( $preferences_settings, self::prepare_preference_setting( 'vision', $vision, self::VISION_NORMAL ) );
418 }
419
420 if ( null !== $contrast ) {
421 $contrast = (string) $contrast;
422 // Switch inputs often post "true" when checked.
423 if ( 'true' === $contrast ) {
424 $contrast = self::CONTRAST_HIGH;
425 }
426 if ( self::CONTRAST_HIGH !== $contrast ) {
427 $contrast = '';
428 }
429 $preferences_settings = array_merge( $preferences_settings, self::prepare_preference_setting( 'contrast', $contrast, '' ) );
430 }
431
432 if ( null !== $motion_effects ) {
433 $motion_effects = (string) $motion_effects;
434 if ( ! in_array( $motion_effects, self::MOTION_EFFECTS_OPTIONS, true ) ) {
435 $motion_effects = self::MOTION_EFFECTS_AUTO;
436 }
437 $preferences_settings = array_merge( $preferences_settings, self::prepare_preference_setting( 'motion_effects', $motion_effects, self::MOTION_EFFECTS_AUTO ) );
438 }
439
440 if ( null !== $font_scale ) {
441 $preferences_settings['font_scale'] = (int) $font_scale;
442 }
443
444 if ( null !== $learning_mood ) {
445 // Validate learning_mood against allowed values.
446 $allowed_moods = array( Options_V2::LEARNING_MODE_MODERN, Options_V2::LEARNING_MODE_KIDS );
447 if ( ! in_array( $learning_mood, $allowed_moods, true ) ) {
448 $learning_mood = Options_V2::LEARNING_MODE_MODERN;
449 }
450
451 $default_learning_mood = tutor_utils()->get_option( 'learning_mode', Options_V2::LEARNING_MODE_MODERN );
452 $preferences_settings = array_merge( $preferences_settings, self::prepare_preference_setting( 'learning_mood', $learning_mood, $default_learning_mood ) );
453 }
454
455 if ( empty( $preferences_settings ) ) {
456 $this->json_response(
457 __( 'No changes detected', 'tutor' ),
458 null,
459 HttpHelper::STATUS_OK
460 );
461 }
462
463 $preference_data = $this->save_preferences( $preferences_settings, get_current_user_id() );
464
465 if ( false === $preference_data ) {
466 $this->json_response(
467 __( 'Failed to save preferences', 'tutor' ),
468 null,
469 HttpHelper::STATUS_NOT_FOUND
470 );
471 }
472
473 $this->json_response(
474 __( 'Preferences saved successfully', 'tutor' ),
475 $preference_data
476 );
477 }
478
479 /**
480 * AJAX handler: reset current user's preferences back to defaults.
481 *
482 * @since 4.0.0
483 *
484 * @return void
485 */
486 public function ajax_reset_user_preferences() {
487 tutor_utils()->check_nonce();
488
489 $user_id = get_current_user_id();
490 if ( ! $user_id ) {
491 $this->json_response(
492 __( 'Failed to reset preferences', 'tutor' ),
493 null,
494 HttpHelper::STATUS_NOT_FOUND
495 );
496 }
497
498 // Delete user meta.
499 delete_user_meta( $user_id, self::META_KEY );
500
501 $this->json_response(
502 __( 'Preferences reset successfully', 'tutor' ),
503 null
504 );
505 }
506
507 /**
508 * Prepare a single preference setting for saving.
509 *
510 * Only includes the setting if it already exists in user meta OR if it differs from the default.
511 *
512 * @since 4.0.0
513 *
514 * @param string $key Preference key.
515 * @param mixed $value New value to save.
516 * @param mixed $default_value Global default value for this setting.
517 *
518 * @return array<string,mixed> Key-value pair if it should be saved, empty array otherwise.
519 */
520 private static function prepare_preference_setting( $key, $value, $default_value ) {
521 if ( self::has_preference( $key ) || $value !== $default_value ) {
522 return array( $key => $value );
523 }
524 return array();
525 }
526
527 /**
528 * Check if a preference key exists for a user.
529 *
530 * @since 4.0.0
531 *
532 * @param string $key Preference key.
533 * @param int $user_id Optional user ID.
534 *
535 * @return bool
536 */
537 public static function has_preference( $key, $user_id = 0 ) {
538 $user_id = tutor_utils()->get_user_id( $user_id );
539 if ( ! $user_id ) {
540 return false;
541 }
542
543 $preferences = get_user_meta( $user_id, self::META_KEY, true );
544 if ( ! is_array( $preferences ) ) {
545 return false;
546 }
547
548 return array_key_exists( $key, $preferences );
549 }
550
551 /**
552 * Get default preferences.
553 *
554 * @since 4.0.0
555 *
556 * @return array
557 */
558 private static function get_default_preferences() {
559 // Get defaults with filter.
560 $defaults = apply_filters(
561 'tutor_user_preference_defaults',
562 array(
563 'auto_play_next' => (bool) tutor_utils()->get_option( 'autoload_next_course_content' ),
564 'theme' => tutor_utils()->get_option( 'default_theme', Options_V2::DEFAULT_THEME_SYSTEM ),
565 'vision' => self::VISION_NORMAL,
566 'contrast' => '',
567 'motion_effects' => self::MOTION_EFFECTS_AUTO,
568 'font_scale' => self::DEFAULT_FONT_SCALE,
569 'learning_mood' => tutor_utils()->get_option( 'learning_mode', Options_V2::LEARNING_MODE_MODERN ),
570 )
571 );
572
573 return $defaults;
574 }
575
576 /**
577 * Get theme options for UI selects.
578 *
579 * @since 4.0.0
580 *
581 * @return array<int,array{label:string,value:string}>
582 */
583 public static function get_theme_options() {
584 return array(
585 array(
586 'label' => __( 'Light', 'tutor' ),
587 'value' => self::THEME_LIGHT,
588 ),
589 array(
590 'label' => __( 'Dark', 'tutor' ),
591 'value' => self::THEME_DARK,
592 ),
593 array(
594 'label' => __( 'Auto (System Default)', 'tutor' ),
595 'value' => self::THEME_SYSTEM,
596 ),
597 );
598 }
599
600 /**
601 * Get vision options for UI selects.
602 *
603 * @since 4.0.0
604 *
605 * @return array<int,array{label:string,value:string}>
606 */
607 public static function get_vision_options() {
608 return array(
609 array(
610 'label' => __( 'Normal', 'tutor' ),
611 'value' => self::VISION_NORMAL,
612 ),
613 array(
614 'label' => __( 'Protanopia', 'tutor' ),
615 'value' => self::VISION_PROTANOPIA,
616 ),
617 array(
618 'label' => __( 'Deuteranopia', 'tutor' ),
619 'value' => self::VISION_DEUTERANOPIA,
620 ),
621 array(
622 'label' => __( 'Deuteranomaly', 'tutor' ),
623 'value' => self::VISION_DEUTERANOMALY,
624 ),
625 );
626 }
627
628 /**
629 * Get learning mood options for UI selects.
630 *
631 * @since 4.0.0
632 *
633 * @return array<int,array{label:string,value:string}>
634 */
635 public static function get_learning_mood_options() {
636 return array(
637 array(
638 'label' => __( 'Modern', 'tutor' ),
639 'value' => Options_V2::LEARNING_MODE_MODERN,
640 ),
641 array(
642 'label' => __( 'Kids', 'tutor' ),
643 'value' => Options_V2::LEARNING_MODE_KIDS,
644 ),
645 );
646 }
647
648 /**
649 * Get motion effects options for UI selects.
650 *
651 * @since 4.0.0
652 *
653 * @return array<int,array{label:string,value:string}>
654 */
655 public static function get_motion_effects_options() {
656 return array(
657 array(
658 'label' => __( 'Reduced Motion', 'tutor' ),
659 'value' => self::MOTION_EFFECTS_REDUCE,
660 ),
661 array(
662 'label' => __( 'Standard Motion', 'tutor' ),
663 'value' => self::MOTION_EFFECTS_STANDARD,
664 ),
665 array(
666 'label' => __( 'Auto (System Default)', 'tutor' ),
667 'value' => self::MOTION_EFFECTS_AUTO,
668 ),
669 );
670 }
671
672 /**
673 * Get font scale options for UI selects.
674 *
675 * Uses a filter to allow customization of available values.
676 *
677 * @since 4.0.0
678 *
679 * @return array<int,array{label:string,value:int}>
680 */
681 public static function get_font_scale_options() {
682 $values = apply_filters( 'tutor_user_preference_font_scale_values', self::FONT_SCALE_OPTIONS );
683 $options = array();
684 foreach ( $values as $value ) {
685 $value = (int) $value;
686 $option = array(
687 'label' => $value . '%',
688 'value' => $value,
689 );
690
691 if ( self::DEFAULT_FONT_SCALE === $value ) {
692 $option['html_label'] = $value . '% <span class="tutor-badge tutor-ml-4">' . esc_html__( 'Default', 'tutor' ) . '</span>';
693 $option['display_label'] = __( 'Default', 'tutor' );
694 } elseif ( 140 === $value ) {
695 $option['html_label'] = $value . '% <span class="tutor-badge tutor-ml-4">' . esc_html__( 'Large', 'tutor' ) . '</span>';
696 $option['display_label'] = __( 'Large', 'tutor' );
697 }
698
699 $options[] = $option;
700 }
701 return $options;
702 }
703 }
704