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 / Assets.php
tutor / classes Last commit date
Addons.php 1 day ago Admin.php 1 day ago Ajax.php 1 day ago Announcements.php 1 day ago Assets.php 1 day ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 1 day ago Container.php 11 months ago Course.php 1 day ago Course_Embed.php 3 years ago Course_Filter.php 1 day ago Course_List.php 1 day ago Course_Settings_Tabs.php 1 day ago Course_Widget.php 1 year ago Custom_Validation.php 1 day ago Dashboard.php 1 day ago Earnings.php 9 months ago FormHandler.php 1 day ago Frontend.php 1 day ago Gutenberg.php 1 year ago Icon.php 1 day ago Input.php 1 day ago Instructor.php 1 day ago Instructors_List.php 1 day ago Lesson.php 1 day ago Options_V2.php 1 day ago Permalink.php 1 day ago Post_types.php 2 days ago Private_Course_Access.php 1 day ago Q_And_A.php 1 day ago Question_Answers_List.php 11 months ago Quiz.php 1 day ago QuizBuilder.php 1 day ago Quiz_Attempts_List.php 1 day ago RestAPI.php 2 years ago Reviews.php 1 day ago Rewrite_Rules.php 2 years ago SampleCourse.php 1 day ago Shortcode.php 1 day ago Singleton.php 1 year ago Student.php 1 day ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 1 day ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 4 weeks ago Tutor.php 1 day ago TutorEDD.php 1 day ago Tutor_Base.php 2 years ago Tutor_Setup.php 1 day ago Upgrader.php 1 day ago User.php 1 day ago UserPreference.php 1 day ago Utils.php 1 day ago Video_Stream.php 3 years ago WhatsNew.php 10 months ago Withdraw.php 1 day ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 1 day ago
Assets.php
1015 lines
1 <?php
2 /**
3 * Manage Assets
4 *
5 * @package Tutor
6 * @author Themeum <support@themeum.com>
7 * @link https://themeum.com
8 * @since 1.0.0
9 */
10
11 namespace TUTOR;
12
13 use Tutor\Ecommerce\CartController;
14 use Tutor\Ecommerce\CheckoutController;
15 use Tutor\Ecommerce\CouponController;
16 use Tutor\Ecommerce\OptionKeys;
17 use Tutor\Ecommerce\OrderController;
18 use Tutor\Ecommerce\Settings;
19 use Tutor\Models\CourseModel;
20 use Tutor\Options_V2;
21
22 if ( ! defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 /**
27 * Assets class
28 *
29 * @since 1.0.0
30 */
31 class Assets {
32
33
34 /**
35 * Constructor
36 *
37 * @since 1.0.0
38 *
39 * @since 3.0.0 register hook param added
40 *
41 * @param bool $register_hooks param added to enable or disable registering hooks.
42 *
43 * @return void
44 */
45 public function __construct( $register_hooks = true ) {
46 if ( ! $register_hooks ) {
47 return;
48 }
49
50 /**
51 * Common scripts loading
52 */
53 add_action( 'admin_enqueue_scripts', array( $this, 'common_scripts' ) );
54 add_action( 'wp_enqueue_scripts', array( $this, 'common_scripts' ) );
55 /**
56 * Front and backend script enqueue
57 */
58 add_action( 'admin_enqueue_scripts', array( $this, 'admin_scripts' ) );
59 add_action( 'wp_enqueue_scripts', array( $this, 'frontend_scripts' ) );
60
61 add_action( 'admin_enqueue_scripts', array( $this, 'load_meta_data' ) );
62 add_action( 'wp_enqueue_scripts', array( $this, 'load_meta_data' ) );
63
64 /**
65 * Text domain loading
66 */
67 add_action( 'admin_enqueue_scripts', array( $this, 'tutor_script_text_domain' ), 100 );
68 add_action( 'wp_enqueue_scripts', array( $this, 'tutor_script_text_domain' ), 100 );
69 add_filter( 'tutor_localize_data', array( $this, 'modify_localize_data' ) );
70
71 /**
72 * Register translatable function to load
73 * Handled script with text domain attached to
74 *
75 * @since 1.9.0
76 */
77 add_action( 'admin_head', array( $this, 'tutor_add_mce_button' ) );
78 add_filter( 'get_the_generator_html', array( $this, 'tutor_generator_tag' ), 10, 2 );
79 add_filter( 'get_the_generator_xhtml', array( $this, 'tutor_generator_tag' ), 10, 2 );
80
81 /**
82 * Add translation support for external tinyMCE button
83 *
84 * @since 1.9.7
85 */
86 add_filter( 'mce_external_languages', array( $this, 'tutor_tinymce_translate' ) );
87
88 /**
89 * Identifier class to body tag
90 *
91 * @since v1.9.9
92 */
93 add_filter( 'body_class', array( $this, 'add_identifier_class_to_body' ) );
94 add_filter( 'admin_body_class', array( $this, 'add_identifier_class_to_body' ) );
95
96 /**
97 * Add edit with front end builder button on Gutenberg editor
98 *
99 * @since v2.0.5
100 */
101 add_action( 'enqueue_block_editor_assets', __CLASS__ . '::add_frontend_editor_button' );
102
103 /**
104 * Enqueue styles & scripts
105 *
106 * @since 4.0.0
107 */
108 add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
109
110 // Add custom meta.
111 add_action( 'wp_head', array( $this, 'add_custom_data' ) );
112
113 /**
114 * Add preload to CSS
115 *
116 * @since 4.0.0
117 */
118 add_filter( 'style_loader_tag', array( $this, 'add_preload_to_css' ), 10, 2 );
119 }
120
121 /**
122 * Load default localized data
123 *
124 * @since 1.0.0
125 * @return array
126 */
127 public function get_default_localized_data() {
128 $home_url = get_home_url();
129 $parsed = parse_url( $home_url );
130
131 $base_path = ( is_array( $parsed ) && isset( $parsed['path'] ) ) ? $parsed['path'] : '/';
132 $base_path = rtrim( $base_path, '/' ) . '/';
133
134 $post_id = get_the_ID();
135 $post_type = get_post_type( $post_id );
136
137 $current_page = tutor_utils()->get_current_page_slug();
138
139 /**
140 * Only required current user data.
141 *
142 * @since 2.6.2
143 */
144 $current_user = array();
145 $userdata = get_userdata( get_current_user_id() );
146
147 if ( $userdata ) {
148 $current_user = array(
149 'roles' => array_values( $userdata->roles ),
150 'data' => array(
151 'id' => $userdata->ID,
152 'display_name' => $userdata->display_name,
153 ),
154 );
155 }
156
157 $tutor_currency = array(
158 'symbol' => Settings::get_currency_symbol_by_code( tutor_utils()->get_option( OptionKeys::CURRENCY_CODE, 'USD' ) ),
159 'currency' => tutor_utils()->get_option( OptionKeys::CURRENCY_CODE ),
160 'position' => tutor_utils()->get_option( OptionKeys::CURRENCY_POSITION, 'left' ),
161 'thousand_separator' => tutor_utils()->get_option( OptionKeys::THOUSAND_SEPARATOR, ',' ),
162 'decimal_separator' => tutor_utils()->get_option( OptionKeys::DECIMAL_SEPARATOR, '.' ),
163 'no_of_decimal' => tutor_utils()->get_option( OptionKeys::NUMBER_OF_DECIMALS, '2' ),
164 );
165
166 /**
167 * Get only required options.
168 *
169 * @since 3.0.0
170 */
171 $required_options = array(
172 'monetize_by',
173 );
174
175 $tutor_settings = Options_V2::get_only( $required_options );
176
177 // Load available kids mode icons to avoid frontend 404s if kids mode is active.
178 $kids_icons = array();
179 if ( tutor_utils()->is_kids_mode() ) {
180 $kids_icons = array_map(
181 function ( $file ) {
182 return basename( $file, '.svg' );
183 },
184 glob( tutor()->path . 'assets/icons/kids/*.svg' ) ?: array()
185 );
186 }
187
188 return array(
189 'ajaxurl' => admin_url( 'admin-ajax.php' ),
190 'home_url' => rtrim( get_home_url(), '/' ),
191 'site_url' => rtrim( get_site_url(), '/' ),
192 'site_title' => get_bloginfo( 'title' ),
193 'base_path' => tutor()->basepath,
194 'tutor_url' => tutor()->url,
195 'tutor_pro_url' => function_exists( 'tutor_pro' ) ? tutor_pro()->url : null,
196 'nonce_key' => tutor()->nonce,
197 tutor()->nonce => wp_create_nonce( tutor()->nonce_action ),
198 'loading_icon_url' => get_admin_url() . 'images/wpspin_light.gif',
199 'placeholder_img_src' => tutor_placeholder_img_src(),
200 'enable_lesson_classic_editor' => get_tutor_option( 'enable_lesson_classic_editor' ),
201 'tutor_frontend_dashboard_url' => tutor_utils()->get_tutor_dashboard_page_permalink(),
202 'wp_date_format' => tutor_js_date_format_against_wp(),
203 'start_of_week' => get_option( 'start_of_week', 1 ),
204 'is_admin' => is_admin(),
205 'is_admin_bar_showing' => is_admin_bar_showing(),
206 'addons_data' => tutor_utils()->prepare_free_addons_data(),
207 'current_user' => $current_user,
208 'content_change_event' => 'tutor_content_changed_event',
209 'is_tutor_course_edit' => isset( $_GET['action'] ) && 'edit' === $_GET['action'] && tutor()->course_post_type === get_post_type( get_the_ID() ) ? true : false,
210 'current_page' => $current_page,
211 'quiz_answer_display_time' => 1000 * (int) tutor_utils()->get_option( 'quiz_answer_display_time' ),
212 'is_ssl' => is_ssl(),
213 'course_list_page_url' => admin_url( 'admin.php?page=tutor' ),
214 'course_post_type' => tutor()->course_post_type,
215 'tutor_currency' => $tutor_currency,
216 'local' => get_locale(),
217 'settings' => $tutor_settings,
218 'max_upload_size' => wp_max_upload_size(),
219 'monetize_by' => tutor_utils()->get_option( 'monetize_by' ),
220 'kids_icons_registry' => $kids_icons,
221 'is_kids_mode' => tutor_utils()->is_kids_mode(),
222 'user_preferences' => UserPreference::get_preferences( get_current_user_id() ),
223 'is_legacy_learning_mode' => tutor_utils()->is_legacy_learning_mode(),
224 'course_slug' => tutor_utils()->get_option( 'course_permalink_base', 'courses' ),
225 'lesson_slug' => tutor_utils()->get_option( 'lesson_permalink_base', 'lessons' ),
226 'quiz_slug' => tutor_utils()->get_option( 'quiz_permalink_base', 'quizzes' ),
227 'is_tour_completed' => (bool) get_user_meta( get_current_user_id(), User::TOUR_COMPLETED_META, true ),
228 );
229 }
230
231 /**
232 * Enqueue scripts for admin
233 *
234 * @since 1.0.0
235 * @since 3.0.0 Order details & coupon scripts added.
236 *
237 * @param string $slug The page slug.
238 *
239 * @return void
240 */
241 public function admin_scripts( $slug ) {
242 wp_enqueue_style( 'tutor-select2', tutor()->url . 'assets/lib/select2/select2.min.css', array(), TUTOR_VERSION );
243 wp_enqueue_style( 'tutor-admin', tutor()->url . 'assets/css/tutor-admin.min.css', array(), TUTOR_VERSION );
244
245 /**
246 * Scripts
247 */
248 wp_enqueue_media();
249
250 wp_enqueue_script( 'wp-color-picker' );
251 wp_enqueue_style( 'wp-color-picker' );
252
253 wp_enqueue_script( 'jquery-ui-slider' );
254 wp_enqueue_script( 'jquery-ui-datepicker' );
255
256 wp_enqueue_script( 'tutor-select2', tutor()->url . 'assets/lib/select2/select2.full.min.js', array( 'jquery' ), TUTOR_VERSION, true );
257 wp_enqueue_script( 'tutor-admin', tutor()->url . 'assets/js/tutor-admin.js', array( 'jquery', 'tutor-script', 'wp-color-picker', 'wp-i18n', 'wp-data' ), TUTOR_VERSION, true );
258
259 // Tutor order detail & coupon scripts.
260 $page = Input::get( 'page', '' );
261 $action = Input::get( 'action' );
262 $sub_page = Input::get( 'sub_page' );
263
264 $allowed_actions = array( 'add_new', 'edit' );
265
266 if ( tutor_utils()->is_monetize_by_tutor() ) {
267 if ( OrderController::PAGE_SLUG === $page && 'edit' === $action ) {
268 wp_enqueue_script( 'tutor-order-details', tutor()->url . 'assets/js/tutor-order-details.js', array( 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
269 }
270
271 if ( CouponController::PAGE_SLUG === $page && in_array( $action, $allowed_actions, true ) ) {
272 wp_enqueue_script( 'tutor-coupon', tutor()->url . 'assets/js/tutor-coupon.js', array( 'wp-date', 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
273 }
274
275 // @since 3.0.0 add tax react app on the settings page.
276 if ( 'tutor_settings' === $page && ! Input::has( 'edit' ) ) {
277 wp_enqueue_editor();
278 wp_enqueue_script( 'tutor-tax-settings', tutor()->url . 'assets/js/tutor-tax-settings.js', array( 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
279 wp_enqueue_script( 'tutor-payment-settings', tutor()->url . 'assets/js/tutor-payment-settings.js', array( 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
280 }
281 }
282
283 if ( 'tutor-tools' === $page && 'import_export' === $sub_page ) {
284 wp_enqueue_script( 'tutor-import-export', tutor()->url . 'assets/js/tutor-import-export.js', array( 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
285 }
286
287 if ( 'tutor-addons' === $page ) {
288 wp_enqueue_script( 'tutor-coupon', tutor()->url . 'assets/js/tutor-addon-list.js', array( 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
289 }
290 }
291
292 /**
293 * Load frontend scripts
294 *
295 * @since 1.0.0
296 *
297 * @since 4.0.0 Legacy scripts loading check added.
298 *
299 * @return void
300 */
301 public function frontend_scripts() {
302 $load_legacy_scripts = self::should_load_legacy_scripts();
303 if ( ! $load_legacy_scripts ) {
304 return;
305 }
306
307 /**
308 * We checked wp_enqueue_editor() in condition because it conflicting with Divi Builder
309 * condition updated @since v.1.7.4
310 *
311 * @since 2.7.0 is_user_logged_in() check added to remove duplicate H1 tag on each single post.
312 */
313 if ( is_single() && is_user_logged_in() ) {
314 if ( function_exists( 'et_pb_is_pagebuilder_used' ) ) {
315 $is_page_builder_used = et_pb_is_pagebuilder_used( get_the_ID() );
316 if ( ! $is_page_builder_used ) {
317 wp_enqueue_editor();
318 wp_enqueue_script( 'quicktags' );
319 }
320 } else {
321 wp_enqueue_editor();
322 wp_enqueue_script( 'quicktags' );
323 }
324 }
325
326 /**
327 * Enabling Sorting, draggable, droppable...
328 */
329 wp_enqueue_script( 'jquery-ui-sortable' );
330 wp_enqueue_script('jquery-touch-punch', ['jquery-ui-sortable']); //phpcs:ignore
331
332 // Plyr.
333 if ( is_single_course( true ) ) {
334 wp_enqueue_style( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.css', array(), TUTOR_VERSION );
335 wp_enqueue_script( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.polyfilled.min.js', array( 'jquery' ), TUTOR_VERSION, true );
336 }
337
338 // Social Share.
339 wp_enqueue_script( 'tutor-social-share', tutor()->url . 'assets/lib/SocialShare/SocialShare.min.js', array( 'jquery' ), TUTOR_VERSION, true );
340
341 /**
342 * Dependency wp-i18n added for translate js file
343 *
344 * @since 1.9.0
345 */
346 wp_enqueue_style( 'tutor-frontend', tutor()->url . 'assets/css/tutor-front.min.css', array(), TUTOR_VERSION );
347 wp_enqueue_script( 'tutor-frontend', tutor()->url . 'assets/js/tutor-front.js', array( 'jquery', 'wp-i18n', 'wp-date' ), TUTOR_VERSION, true );
348 }
349
350 /**
351 * Modify localize data
352 *
353 * @since 1.0.0
354 *
355 * @param array $localize_data localize data.
356 * @return array
357 */
358 public function modify_localize_data( $localize_data ) {
359 global $post;
360
361 if ( is_admin() ) {
362 $taxonomy = Input::get( 'taxonomy' );
363 if ( CourseModel::COURSE_CATEGORY === $taxonomy || CourseModel::COURSE_TAG === $taxonomy ) {
364 $localize_data['open_tutor_admin_menu'] = true;
365 }
366
367 if ( 'en_US' !== $localize_data['local'] ) {
368 $page = Input::get( 'page', '' );
369 $action = Input::get( 'action' );
370 $allowed_actions = array( 'add_new', 'edit' );
371 if ( CouponController::PAGE_SLUG === $page && in_array( $action, $allowed_actions, true ) ) {
372 $localize_data['coupon_main_content_locales'] = tutils()->get_script_locale_data( 'tutor-coupon-main-content', $localize_data['local'] );
373 }
374 }
375 } else {
376
377 // Assign quiz option.
378 if ( ! empty( $post->post_type ) && 'tutor_quiz' === $post->post_type ) {
379 $single_quiz_options = (array) tutor_utils()->get_quiz_option( $post->ID );
380 $saved_quiz_options = array(
381 'quiz_when_time_expires' => tutor_utils()->get_option( 'quiz_when_time_expires' ),
382 );
383
384 $quiz_options = array_merge( $single_quiz_options, $saved_quiz_options );
385
386 $previous_attempts = tutor_utils()->quiz_attempts();
387
388 if ( $previous_attempts && count( $previous_attempts ) ) {
389 $quiz_options['quiz_auto_start'] = 0;
390 }
391
392 $localize_data['quiz_options'] = $quiz_options;
393 }
394
395 // Including player assets if video exists.
396 if ( tutor_utils()->has_video_in_single() ) {
397 $localize_data['post_id'] = get_the_ID();
398 $localize_data['best_watch_time'] = 0;
399
400 $best_watch_time = tutor_utils()->get_lesson_reading_info( get_the_ID(), 0, 'video_best_watched_time' );
401 if ( $best_watch_time > 0 ) {
402 $localize_data['best_watch_time'] = $best_watch_time;
403 }
404 }
405 }
406
407 return $localize_data;
408 }
409
410 /**
411 * Load common scripts for frontend and backend
412 *
413 * @since 1.0.0
414 *
415 * @since 4.0.0 Legacy scripts loading check added.
416 *
417 * @param string $slug The page slug.
418 *
419 * @return void
420 */
421 public function common_scripts( $slug ) {
422 if ( ! self::should_load_legacy_scripts() ) {
423 return;
424 }
425
426 /**
427 * Load TinyMCE for tutor settings page if tutor pro is not available.
428 *
429 * @since v2.0.8
430 */
431 $baseurl = includes_url( 'js/tinymce' );
432 $current_page = Input::get( 'page' );
433
434 // If it is settings page & tutor pro not activated.
435 if ( 'tutor_settings' === $current_page && ! wp_script_is( 'wp-tinymce-root' ) ) {
436 wp_enqueue_script( 'tutor-tiny', $baseurl . '/tinymce.min.js', array( 'jquery' ), TUTOR_VERSION, true );
437 }
438 wp_enqueue_style( 'tutor-icon', tutor()->url . 'assets/css/tutor-icon.min.css', array(), TUTOR_VERSION );
439
440 // Common css library.
441 if ( is_rtl() ) {
442 wp_enqueue_style( 'tutor', tutor()->url . 'assets/css/tutor-rtl.min.css', array(), TUTOR_VERSION );
443 } else {
444 wp_enqueue_style( 'tutor', tutor()->url . 'assets/css/tutor.min.css', array(), TUTOR_VERSION );
445 }
446
447 /**
448 * Load tutor common scripts both backend and frontend
449 *
450 * @since v2.0.0
451 */
452 wp_enqueue_script( 'tutor-script', tutor()->url . 'assets/js/tutor.js', array( 'jquery', 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
453
454 /**
455 * Enqueue datetime countdown scripts & styles
456 *
457 * Add filter to enqueue countdown scripts & styles
458 * don't return false if it is true to prevent conflict
459 * with other filters
460 *
461 * @since v2.1.0
462 */
463 $should_enqueue = apply_filters( 'tutor_should_enqueue_countdown_scripts', false );
464 if ( $should_enqueue ) {
465 wp_enqueue_script( 'tutor-moment', tutor()->url . 'assets/lib/countdown/moment.min.js', array(), TUTOR_VERSION, true );
466
467 wp_enqueue_script( 'tutor-moment-timezone', tutor()->url . 'assets/lib/countdown/moment-timezone-with-data.min.js', array(), TUTOR_VERSION, true );
468
469 wp_enqueue_script( 'tutor-jquery-countdown', tutor()->url . 'assets/lib/countdown/jquery.countdown.min.js', array( 'jquery' ), TUTOR_VERSION, true );
470
471 wp_enqueue_script( 'tutor-countdown', tutor()->url . 'assets/lib/countdown/tutor-countdown.min.js', array( 'jquery' ), TUTOR_VERSION, true );
472
473 wp_enqueue_style( 'tutor-countdown', tutor()->url . 'assets/lib/countdown/tutor-countdown.min.css', '', TUTOR_VERSION );
474 }
475 }
476
477 /**
478 * Load meta data
479 *
480 * @since 1.0.0
481 * @return void
482 */
483 public function load_meta_data() {
484 // Localize scripts.
485 $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
486 wp_localize_script( 'tutor-frontend', '_tutorobject', $localize_data );
487 wp_localize_script( 'tutor-admin', '_tutorobject', $localize_data );
488 wp_localize_script( 'tutor-script', '_tutorobject', $localize_data );
489 wp_localize_script( 'tutor-order-details', '_tutorobject', $localize_data );
490 wp_localize_script( 'tutor-tax-settings', '_tutorobject', $localize_data );
491 wp_localize_script( 'tutor-coupon', '_tutorobject', $localize_data );
492 wp_localize_script( 'tutor-course-builder', '_tutorobject', $localize_data );
493
494 // Inline styles.
495 wp_add_inline_style( 'tutor-frontend', $this->load_color_palette() );
496 wp_add_inline_style( 'tutor-admin', $this->load_color_palette() );
497 }
498
499 /**
500 * Load color palette
501 *
502 * @since 1.0.0
503 * @return string
504 */
505 private function load_color_palette() {
506 $colors = array(
507 'tutor_primary_color' => '--tutor-color-primary',
508 'tutor_primary_hover_color' => '--tutor-color-primary-hover',
509 'tutor_text_color' => '--tutor-body-color',
510 'tutor_border_color' => '--tutor-border-color',
511 'tutor_gray_color' => '--tutor-color-gray',
512 );
513
514 // Admin colors.
515 $admin_colors = array();
516 if ( is_admin() ) {
517 $admin_colors = array(
518 '--tutor-color-primary' => '#3E64DE',
519 '--tutor-color-primary-hover' => '#3A5CCC',
520 '--tutor-body-color' => '#212327',
521 '--tutor-border-color' => '#CDCFD5',
522 '--tutor-color-gray' => '#CDCFD5',
523 );
524 }
525
526 $fallback_colors = array(
527 'tutor_primary_color' => '#3E64DE',
528 'tutor_primary_hover_color' => '#3A5CCC',
529 'tutor_text_color' => '#212327',
530 'tutor_border_color' => '#E3E5EB',
531 'tutor_gray_color' => '#CDCFD5',
532 );
533
534 $brand_color = tutor_utils()->get_brand_color();
535
536 $color_string = '';
537 foreach ( $colors as $key => $property ) {
538 $fallback_color = isset( $fallback_colors[ $key ] ) ? $fallback_colors[ $key ] : '#212327';
539 $color = $fallback_color;
540
541 if ( Options_V2::DEFAULT_BRAND_COLOR !== $brand_color ) {
542 if ( 'tutor_primary_color' === $key ) {
543 $color = $brand_color;
544 }
545
546 if ( 'tutor_primary_hover_color' === $key ) {
547 $palette = $this->generate_color_palette( $brand_color );
548 $color = $palette[700];
549 }
550 }
551
552 $color_rgb = tutor_utils()->hex2rgb( $color );
553
554 if ( is_admin() && isset( $admin_colors[ $property ] ) ) {
555 $color = $admin_colors[ $property ];
556 $color_rgb = tutor_utils()->hex2rgb( $admin_colors[ $property ] );
557 }
558
559 if ( $color ) {
560 $color_string .= $property . ':' . $color . ';';
561 }
562
563 if ( $color_rgb ) {
564 $color_string .= $property . '-rgb:' . $color_rgb . ';';
565 }
566 }
567
568 return ':root{' . $color_string . '}';
569 }
570
571 /**
572 * Generate color palette
573 *
574 * @since 4.0.0
575 *
576 * @param string $base_hex HEX color code.
577 *
578 * @return array
579 */
580 private function generate_color_palette( $base_hex ) {
581 $base = tutor_utils()->hex_to_hsl( $base_hex );
582
583 // Mapping of [Hue-Shift, Saturation-Shift, Target-Lightness].
584 $rules = array(
585 100 => array( -1, 3, 97.5 ),
586 200 => array( -3, 1, 94.1 ),
587 300 => array( -3, -2, 92.2 ),
588 400 => array( -4, 0, 79.6 ),
589 450 => array( -2, -3, 76.7 ),
590 500 => array( -4, 5, 59.8 ),
591 600 => array( 0, 0, $base['l'] ),
592 700 => array( 3, -7, 48.0 ),
593 800 => array( 4, -12, 40.2 ),
594 900 => array( 5, -17, 33.1 ),
595 950 => array( 6, -24, 20.8 ),
596 );
597
598 $palette = array();
599 foreach ( $rules as $weight => $modifier ) {
600 if ( 600 === $weight ) {
601 $palette[ $weight ] = strtolower( $base_hex );
602 continue;
603 }
604
605 $new_h = fmod( ( $base['h'] + $modifier[0] + 360 ), 360 );
606 $new_s = max( 0, min( 100, $base['s'] + $modifier[1] ) );
607 $new_l = max( 0, min( 100, $modifier[2] ) );
608
609 $palette[ $weight ] = tutor_utils()->hsl_to_hex( $new_h, $new_s, $new_l );
610 }
611
612 return $palette;
613 }
614
615 /**
616 * Load core color palette
617 *
618 * @since 4.0.0
619 *
620 * @param string $brand_color Base color code.
621 *
622 * @return string
623 */
624 private function load_core_color_palette( $brand_color ) {
625 if ( empty( $brand_color ) ) {
626 return '';
627 }
628
629 $palette = $this->generate_color_palette( $brand_color );
630
631 return "
632 :root {
633 --tutor-brand-100: {$palette[100]};
634 --tutor-brand-200: {$palette[200]};
635 --tutor-brand-300: {$palette[300]};
636 --tutor-brand-400: {$palette[400]};
637 --tutor-brand-450: {$palette[450]};
638 --tutor-brand-500: {$palette[500]};
639 --tutor-brand-600: {$palette[600]};
640 --tutor-brand-700: {$palette[700]};
641 --tutor-brand-800: {$palette[800]};
642 --tutor-brand-900: {$palette[900]};
643 --tutor-brand-950: {$palette[950]};
644 }
645 ";
646 }
647
648 /**
649 * Add Tinymce button for placing shortcode
650 *
651 * @since 1.0.0
652 * @return void|null
653 */
654 public function tutor_add_mce_button() {
655 // Check user permissions.
656 if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) ) {
657 return;
658 }
659 // Check if WYSIWYG is enabled.
660 if ( 'true' == get_user_option( 'rich_editing' ) ) {
661 add_filter( 'mce_external_plugins', array( $this, 'tutor_add_tinymce_js' ) );
662 add_filter( 'mce_buttons', array( $this, 'tutor_register_mce_button' ) );
663 }
664 }
665
666 /**
667 * Add tinymce button
668 *
669 * @since 1.0.0
670 *
671 * @param array $plugin_array plugin array.
672 * @return array
673 */
674 public function tutor_add_tinymce_js( $plugin_array ) {
675 $plugin_array['tutor_button'] = tutor()->url . 'assets/lib/mce-button.js';
676 return $plugin_array;
677 }
678
679 /**
680 * Register new button in the editor
681 *
682 * @since 1.0.0
683 *
684 * @param array $buttons buttons.
685 * @return array
686 */
687 public function tutor_register_mce_button( $buttons ) {
688 array_push( $buttons, 'tutor_button' );
689 return $buttons;
690 }
691
692 /**
693 * Output generator tag to aid debugging.
694 *
695 * @since 1.0.0
696 *
697 * @param string $gen Generator.
698 * @param string $type Type.
699 *
700 * @return string
701 */
702 public function tutor_generator_tag( $gen, $type ) {
703 switch ( $type ) {
704 case 'html':
705 $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '">';
706 break;
707 case 'xhtml':
708 $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '" />';
709 break;
710 }
711 return $gen;
712 }
713
714 /**
715 * Load text domain handled script after all enqueue_scripts
716 * registered functions
717 *
718 * @since 1.9.0
719 * @since 3.9.2 Refactored to dynamically detect scripts instead of hardcoded list.
720 *
721 * @return void
722 */
723 public function tutor_script_text_domain() {
724 global $wp_scripts;
725
726 if ( empty( $wp_scripts->registered ) ) {
727 return;
728 }
729
730 foreach ( $wp_scripts->registered as $handle => $data ) {
731 $src = $data->src ?? '';
732 $is_from_tutor = str_contains( $src, 'tutor/assets/js' );
733
734 if ( ! $is_from_tutor ) {
735 continue;
736 }
737
738 wp_set_script_translations( $handle, 'tutor', tutor()->path . 'languages/' );
739 }
740 }
741
742 /**
743 * Add translation support for external tinyMCE button
744 *
745 * @since 1.9.7
746 * @return array
747 */
748 public function tutor_tinymce_translate() {
749 $locales['tutor_button'] = tutor()->path . 'includes/tinymce_translate.php';
750 return $locales;
751 }
752
753 /**
754 * Add an identifier class to body
755 *
756 * @since 1.0.0
757 *
758 * @param mixed $classes classes.
759 * @return mixed
760 */
761 public function add_identifier_class_to_body( $classes ) {
762 $course_builder_screen = tutor_utils()->get_course_builder_screen();
763 $to_add = array( 'tutor-lms' );
764
765 // Add backend course editor identifier class to body.
766 if ( $course_builder_screen ) {
767 $to_add[] = is_admin() ? 'tutor-backend' : 'tutor-frontend';
768 $to_add[] = ' tutor-screen-course-builder tutor-screen-course-builder-' . $course_builder_screen . ' ';
769 }
770
771 // Add frontend course builder identifier class.
772 if ( ! $course_builder_screen && tutor_utils()->is_tutor_frontend_dashboard() ) {
773 $to_add[] = 'tutor-screen-frontend-dashboard';
774 }
775
776 if ( is_post_type_archive( tutor()->course_post_type ) ) {
777 $to_add[] = 'tutor-frontend';
778 }
779
780 if ( tutor_utils()->is_tutor_frontend_dashboard() ) {
781 $to_add[] = 'tutor-frontend';
782 }
783
784 if ( is_single() ) {
785 global $post;
786
787 $post_types = array(
788 tutor()->course_post_type,
789 tutor()->lesson_post_type,
790 tutor()->quiz_post_type,
791 tutor()->assignment_post_type,
792 tutor()->zoom_post_type,
793 tutor()->meet_post_type,
794 );
795
796 if ( isset( $post->post_type ) && in_array( $post->post_type, $post_types, true ) ) {
797 $to_add[] = 'tutor-frontend';
798 }
799 }
800
801 if ( is_admin() ) {
802 $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
803 $base = ( $screen && is_object( $screen ) && property_exists( $screen, 'base' ) ) ? $screen->base : '';
804 $index = strpos( $base, 'tutor' );
805
806 if ( 0 === $index || $index > 0 ) {
807 $to_add[] = 'tutor-backend';
808
809 $page = Input::get( 'page' );
810 if ( 'tutor_settings' === $page ) {
811 $to_add[] = 'tutor-screen-backend-settings ';
812 }
813 if ( ! empty( $page ) ) {
814 $to_add[] = 'tutor-backend-' . $page;
815 }
816 }
817 }
818
819 // Remove duplicate classes if any.
820 $to_add = array_unique( $to_add );
821
822 if ( is_array( $classes ) ) {
823 $classes = array_merge( $classes, $to_add );
824 } else {
825 $classes .= implode( ' ', $to_add );
826 }
827
828 return $classes;
829 }
830
831 /**
832 * Enqueue script for adding edit with frontend course builder button
833 * on the Gutenberg editor
834 *
835 * @since 2.0.5
836 * @return void
837 */
838 public static function add_frontend_editor_button() {
839 $wp_screen = get_current_screen();
840
841 if ( is_a( $wp_screen, 'WP_Screen' ) && tutor()->course_post_type === $wp_screen->post_type ) {
842 wp_enqueue_script( 'tutor-gutenberg', tutor()->url . 'assets/js/tutor-gutenberg.js', array(), TUTOR_VERSION, true );
843 $data = array(
844 'frontend_dashboard_url' => esc_url( trailingslashit( tutor_utils()->tutor_dashboard_url( 'create-course' ) ) ) . '?course_id=' . get_the_ID(),
845 );
846
847 wp_add_inline_script(
848 'tutor-gutenberg',
849 'const tutorInlineData =' . json_encode( $data ),
850 'before'
851 );
852 }
853 }
854
855 /**
856 * Enqueue styles & scripts for latest design system
857 *
858 * @since 4.0.0
859 *
860 * @return void
861 */
862 public function enqueue_scripts() {
863 if ( self::should_load_legacy_scripts() ) {
864 return;
865 }
866
867 $is_dashboard = tutor_utils()->is_dashboard_page();
868 $is_learning_area = tutor_utils()->is_learning_area();
869 $is_kids_mode = tutor_utils()->is_kids_mode();
870 $is_legacy_learning = Options_V2::LEARNING_MODE_LEGACY === tutor_utils()->get_option( 'learning_mode' );
871
872 $core_css_url = tutor()->assets_url . 'css/tutor-core.min.css';
873 $kids_css_url = tutor()->assets_url . 'css/tutor-kids.min.css';
874 $dashboard_css_url = tutor()->assets_url . 'css/tutor-dashboard.min.css';
875 $learning_area_css_url = tutor()->assets_url . 'css/tutor-learning-area.min.css';
876 $google_font_url = 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap';
877
878 $core_js_url = tutor()->assets_url . 'js/tutor-core.js';
879 $dashboard_js_url = tutor()->assets_url . 'js/tutor-dashboard.js';
880 $learning_area_js_url = tutor()->assets_url . 'js/tutor-learning-area.js';
881
882 $version = TUTOR_ENV === 'DEV' ? time() : TUTOR_VERSION;
883
884 $is_course_list_page = tutor_utils()->is_course_list_page();
885 $is_course_details_page = tutor_utils()->is_course_details_page();
886
887 $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
888 if ( $is_kids_mode ) {
889 $google_font_url = 'https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700&display=swap';
890 wp_enqueue_style( 'tutor-kids', $kids_css_url, array( 'tutor-core' ), $version );
891 }
892
893 // Core.
894 wp_enqueue_style( 'tutor-google-fonts', $google_font_url, array(), $version );
895
896 wp_enqueue_style( 'tutor-core', $core_css_url, array( 'tutor-google-fonts' ), $version );
897 wp_enqueue_script( 'tutor-core', $core_js_url, array( 'wp-i18n' ), $version, true );
898
899 wp_localize_script( 'tutor-core', '_tutorobject', $localize_data );
900
901 // Generate color palette from user selected brand color and add to the root.
902 $brand_color = tutor_utils()->get_brand_color();
903 if ( Options_V2::DEFAULT_BRAND_COLOR !== $brand_color ) {
904 wp_add_inline_style( 'tutor-core', $this->load_core_color_palette( $brand_color ) );
905 }
906
907 if ( $is_dashboard ) {
908 wp_enqueue_style( 'tutor-dashboard', $dashboard_css_url, array(), $version );
909 wp_enqueue_script( 'tutor-dashboard', $dashboard_js_url, array( 'tutor-core', 'wp-i18n' ), $version, true );
910 }
911
912 if ( $is_learning_area ) {
913 wp_enqueue_style( 'tutor-learning', $learning_area_css_url, array(), $version );
914 wp_enqueue_script( 'tutor-learning', $learning_area_js_url, array( 'tutor-core', 'wp-i18n' ), $version, true );
915
916 if ( is_single_course( true ) ) {
917 wp_enqueue_style( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.css', array(), $version );
918 wp_enqueue_script( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.polyfilled.min.js', array( 'jquery' ), $version, true );
919 }
920 }
921 }
922
923 /**
924 * Check if need to load legacy scripts
925 *
926 * If the current screen is dashboard or new learning area
927 * then this method will return false to avoid loading legacy css & js files
928 *
929 * @since 4.0.0
930 *
931 * @return boolean
932 */
933 public static function should_load_legacy_scripts(): bool {
934 $load = true;
935
936 $post_id = get_the_ID();
937
938 $is_learning_area = tutor_utils()->is_learning_area();
939 $is_legacy_learning = tutor_utils()->is_legacy_learning_mode();
940 $is_dashboard = tutor_utils()->is_dashboard_page();
941
942 $page_ids = array(
943 (int) tutor_utils()->get_option( 'student_register_page' ),
944 (int) tutor_utils()->get_option( 'instructor_register_page' ),
945 );
946
947 // Ignore loading legacy scripts on specific case.
948 if ( $is_learning_area && ! $is_legacy_learning ) {
949 $load = false;
950 } elseif ( $is_dashboard ) {
951 $load = false;
952 } elseif ( in_array( $post_id, $page_ids, true ) ) {
953 $load = false;
954 } else {
955 // Ignore loading legacy scripts for these shortcodes.
956 $has_shortcode = false;
957
958 $shortcdes = array(
959 'tutor_student_registration_form',
960 'tutor_instructor_registration_form',
961 'tutor_dashboard',
962 'tutor_login',
963 );
964
965 $post_content = get_the_content();
966
967 foreach ( $shortcdes as $shortcde ) {
968 $has_shortcode = has_shortcode( $post_content, $shortcde );
969 if ( $has_shortcode ) {
970 $load = false;
971 break;
972 }
973 }
974 }
975
976 return apply_filters( 'tutor_should_load_legacy_scripts', $load );
977 }
978
979 /**
980 * Add custom meta data to the head section.
981 *
982 * Outputs a viewport meta tag to improve mobile responsiveness.
983 *
984 * @since 4.0.0
985 *
986 * @return void
987 */
988 public function add_custom_data() {
989 if ( tutor_utils()->is_dashboard_page() || tutor_utils()->is_learning_area() ) {
990 echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
991 }
992 }
993
994 /**
995 * Add preload to CSS
996 *
997 * @param string $html HTML.
998 * @param string $handle Handle.
999 *
1000 * @since 4.0.0
1001 *
1002 * @return string
1003 */
1004 public function add_preload_to_css( $html, $handle ) {
1005 if ( 'tutor-google-fonts' === $handle ) {
1006 $html = str_replace(
1007 "rel='stylesheet'",
1008 "rel='preload' as='style' onload=\"this.onload=null;this.rel='stylesheet'\"",
1009 $html
1010 );
1011 }
1012 return $html;
1013 }
1014 }
1015