PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.0
Tutor LMS – eLearning and online course solution v4.0.0
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 17 hours ago Admin.php 17 hours ago Ajax.php 17 hours ago Announcements.php 17 hours ago Assets.php 17 hours ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 17 hours ago Container.php 11 months ago Course.php 17 hours ago Course_Embed.php 3 years ago Course_Filter.php 17 hours ago Course_List.php 17 hours ago Course_Settings_Tabs.php 17 hours ago Course_Widget.php 1 year ago Custom_Validation.php 17 hours ago Dashboard.php 17 hours ago Earnings.php 9 months ago FormHandler.php 17 hours ago Frontend.php 17 hours ago Gutenberg.php 1 year ago Icon.php 17 hours ago Input.php 17 hours ago Instructor.php 17 hours ago Instructors_List.php 17 hours ago Lesson.php 17 hours ago Options_V2.php 17 hours ago Permalink.php 17 hours ago Post_types.php 1 day ago Private_Course_Access.php 17 hours ago Q_And_A.php 17 hours ago Question_Answers_List.php 11 months ago Quiz.php 17 hours ago QuizBuilder.php 17 hours ago Quiz_Attempts_List.php 17 hours ago RestAPI.php 2 years ago Reviews.php 17 hours ago Rewrite_Rules.php 2 years ago SampleCourse.php 17 hours ago Shortcode.php 17 hours ago Singleton.php 1 year ago Student.php 17 hours ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 17 hours ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 4 weeks ago Tutor.php 17 hours ago TutorEDD.php 17 hours ago Tutor_Base.php 2 years ago Tutor_Setup.php 17 hours ago Upgrader.php 17 hours ago User.php 17 hours ago UserPreference.php 17 hours ago Utils.php 17 hours ago Video_Stream.php 3 years ago WhatsNew.php 10 months ago Withdraw.php 17 hours ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 17 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