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