PluginProbe ʕ •ᴥ•ʔ
Tutor LMS – eLearning and online course solution / 4.0.1
Tutor LMS – eLearning and online course solution v4.0.1
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 4 days ago Admin.php 4 days ago Ajax.php 4 days ago Announcements.php 4 days ago Assets.php 1 day ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 4 days ago Container.php 11 months ago Course.php 4 days ago Course_Embed.php 3 years ago Course_Filter.php 4 days ago Course_List.php 4 days ago Course_Settings_Tabs.php 4 days ago Course_Widget.php 1 year ago Custom_Validation.php 4 days ago Dashboard.php 4 days ago Earnings.php 9 months ago FormHandler.php 4 days ago Frontend.php 4 days ago Gutenberg.php 1 year ago Icon.php 4 days ago Input.php 4 days ago Instructor.php 4 days ago Instructors_List.php 4 days ago Lesson.php 4 days ago Options_V2.php 4 days ago Permalink.php 4 days ago Post_types.php 5 days ago Private_Course_Access.php 4 days ago Q_And_A.php 4 days ago Question_Answers_List.php 11 months ago Quiz.php 1 day ago QuizBuilder.php 4 days ago Quiz_Attempts_List.php 1 day ago RestAPI.php 1 day ago Reviews.php 4 days ago Rewrite_Rules.php 2 years ago SampleCourse.php 4 days ago Shortcode.php 4 days ago Singleton.php 1 year ago Student.php 4 days ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 4 days ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 1 month ago Tutor.php 4 days ago TutorEDD.php 4 days ago Tutor_Base.php 2 years ago Tutor_Setup.php 4 days ago Upgrader.php 4 days ago User.php 4 days ago UserPreference.php 4 days ago Utils.php 1 day ago Video_Stream.php 3 years ago WhatsNew.php 1 day ago Withdraw.php 4 days ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 4 days ago
Assets.php
1016 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
378 // Assign quiz option.
379 if ( ! empty( $post->post_type ) && 'tutor_quiz' === $post->post_type ) {
380 $single_quiz_options = (array) tutor_utils()->get_quiz_option( $post->ID );
381 $saved_quiz_options = array(
382 'quiz_when_time_expires' => tutor_utils()->get_option( 'quiz_when_time_expires' ),
383 );
384
385 $quiz_options = array_merge( $single_quiz_options, $saved_quiz_options );
386
387 $previous_attempts = tutor_utils()->quiz_attempts();
388
389 if ( $previous_attempts && count( $previous_attempts ) ) {
390 $quiz_options['quiz_auto_start'] = 0;
391 }
392
393 $localize_data['quiz_options'] = $quiz_options;
394 }
395
396 // Including player assets if video exists.
397 if ( tutor_utils()->has_video_in_single() ) {
398 $localize_data['post_id'] = get_the_ID();
399 $localize_data['best_watch_time'] = 0;
400
401 $best_watch_time = tutor_utils()->get_lesson_reading_info( get_the_ID(), 0, 'video_best_watched_time' );
402 if ( $best_watch_time > 0 ) {
403 $localize_data['best_watch_time'] = $best_watch_time;
404 }
405 }
406 }
407
408 return $localize_data;
409 }
410
411 /**
412 * Load common scripts for frontend and backend
413 *
414 * @since 1.0.0
415 *
416 * @since 4.0.0 Legacy scripts loading check added.
417 *
418 * @param string $slug The page slug.
419 *
420 * @return void
421 */
422 public function common_scripts( $slug ) {
423 if ( ! self::should_load_legacy_scripts() ) {
424 return;
425 }
426
427 /**
428 * Load TinyMCE for tutor settings page if tutor pro is not available.
429 *
430 * @since v2.0.8
431 */
432 $baseurl = includes_url( 'js/tinymce' );
433 $current_page = Input::get( 'page' );
434
435 // If it is settings page & tutor pro not activated.
436 if ( 'tutor_settings' === $current_page && ! wp_script_is( 'wp-tinymce-root' ) ) {
437 wp_enqueue_script( 'tutor-tiny', $baseurl . '/tinymce.min.js', array( 'jquery' ), TUTOR_VERSION, true );
438 }
439 wp_enqueue_style( 'tutor-icon', tutor()->url . 'assets/css/tutor-icon.min.css', array(), TUTOR_VERSION );
440
441 // Common css library.
442 if ( is_rtl() ) {
443 wp_enqueue_style( 'tutor', tutor()->url . 'assets/css/tutor-rtl.min.css', array(), TUTOR_VERSION );
444 } else {
445 wp_enqueue_style( 'tutor', tutor()->url . 'assets/css/tutor.min.css', array(), TUTOR_VERSION );
446 }
447
448 /**
449 * Load tutor common scripts both backend and frontend
450 *
451 * @since v2.0.0
452 */
453 wp_enqueue_script( 'tutor-script', tutor()->url . 'assets/js/tutor.js', array( 'jquery', 'wp-i18n', 'wp-element' ), TUTOR_VERSION, true );
454
455 /**
456 * Enqueue datetime countdown scripts & styles
457 *
458 * Add filter to enqueue countdown scripts & styles
459 * don't return false if it is true to prevent conflict
460 * with other filters
461 *
462 * @since v2.1.0
463 */
464 $should_enqueue = apply_filters( 'tutor_should_enqueue_countdown_scripts', false );
465 if ( $should_enqueue ) {
466 wp_enqueue_script( 'tutor-moment', tutor()->url . 'assets/lib/countdown/moment.min.js', array(), TUTOR_VERSION, true );
467
468 wp_enqueue_script( 'tutor-moment-timezone', tutor()->url . 'assets/lib/countdown/moment-timezone-with-data.min.js', array(), TUTOR_VERSION, true );
469
470 wp_enqueue_script( 'tutor-jquery-countdown', tutor()->url . 'assets/lib/countdown/jquery.countdown.min.js', array( 'jquery' ), TUTOR_VERSION, true );
471
472 wp_enqueue_script( 'tutor-countdown', tutor()->url . 'assets/lib/countdown/tutor-countdown.min.js', array( 'jquery' ), TUTOR_VERSION, true );
473
474 wp_enqueue_style( 'tutor-countdown', tutor()->url . 'assets/lib/countdown/tutor-countdown.min.css', '', TUTOR_VERSION );
475 }
476 }
477
478 /**
479 * Load meta data
480 *
481 * @since 1.0.0
482 * @return void
483 */
484 public function load_meta_data() {
485 // Localize scripts.
486 $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
487 wp_localize_script( 'tutor-frontend', '_tutorobject', $localize_data );
488 wp_localize_script( 'tutor-admin', '_tutorobject', $localize_data );
489 wp_localize_script( 'tutor-script', '_tutorobject', $localize_data );
490 wp_localize_script( 'tutor-order-details', '_tutorobject', $localize_data );
491 wp_localize_script( 'tutor-tax-settings', '_tutorobject', $localize_data );
492 wp_localize_script( 'tutor-coupon', '_tutorobject', $localize_data );
493 wp_localize_script( 'tutor-course-builder', '_tutorobject', $localize_data );
494
495 // Inline styles.
496 wp_add_inline_style( 'tutor-frontend', $this->load_color_palette() );
497 wp_add_inline_style( 'tutor-admin', $this->load_color_palette() );
498 }
499
500 /**
501 * Load color palette
502 *
503 * @since 1.0.0
504 * @return string
505 */
506 private function load_color_palette() {
507 $colors = array(
508 'tutor_primary_color' => '--tutor-color-primary',
509 'tutor_primary_hover_color' => '--tutor-color-primary-hover',
510 'tutor_text_color' => '--tutor-body-color',
511 'tutor_border_color' => '--tutor-border-color',
512 'tutor_gray_color' => '--tutor-color-gray',
513 );
514
515 // Admin colors.
516 $admin_colors = array();
517 if ( is_admin() ) {
518 $admin_colors = array(
519 '--tutor-color-primary' => '#3E64DE',
520 '--tutor-color-primary-hover' => '#3A5CCC',
521 '--tutor-body-color' => '#212327',
522 '--tutor-border-color' => '#CDCFD5',
523 '--tutor-color-gray' => '#CDCFD5',
524 );
525 }
526
527 $fallback_colors = array(
528 'tutor_primary_color' => '#3E64DE',
529 'tutor_primary_hover_color' => '#3A5CCC',
530 'tutor_text_color' => '#212327',
531 'tutor_border_color' => '#E3E5EB',
532 'tutor_gray_color' => '#CDCFD5',
533 );
534
535 $brand_color = tutor_utils()->get_brand_color();
536
537 $color_string = '';
538 foreach ( $colors as $key => $property ) {
539 $fallback_color = isset( $fallback_colors[ $key ] ) ? $fallback_colors[ $key ] : '#212327';
540 $color = $fallback_color;
541
542 if ( Options_V2::DEFAULT_BRAND_COLOR !== $brand_color ) {
543 if ( 'tutor_primary_color' === $key ) {
544 $color = $brand_color;
545 }
546
547 if ( 'tutor_primary_hover_color' === $key ) {
548 $palette = $this->generate_color_palette( $brand_color );
549 $color = $palette[700];
550 }
551 }
552
553 $color_rgb = tutor_utils()->hex2rgb( $color );
554
555 if ( is_admin() && isset( $admin_colors[ $property ] ) ) {
556 $color = $admin_colors[ $property ];
557 $color_rgb = tutor_utils()->hex2rgb( $admin_colors[ $property ] );
558 }
559
560 if ( $color ) {
561 $color_string .= $property . ':' . $color . ';';
562 }
563
564 if ( $color_rgb ) {
565 $color_string .= $property . '-rgb:' . $color_rgb . ';';
566 }
567 }
568
569 return ':root{' . $color_string . '}';
570 }
571
572 /**
573 * Generate color palette
574 *
575 * @since 4.0.0
576 *
577 * @param string $base_hex HEX color code.
578 *
579 * @return array
580 */
581 private function generate_color_palette( $base_hex ) {
582 $base = tutor_utils()->hex_to_hsl( $base_hex );
583
584 // Mapping of [Hue-Shift, Saturation-Shift, Target-Lightness].
585 $rules = array(
586 100 => array( -1, 3, 97.5 ),
587 200 => array( -3, 1, 94.1 ),
588 300 => array( -3, -2, 92.2 ),
589 400 => array( -4, 0, 79.6 ),
590 450 => array( -2, -3, 76.7 ),
591 500 => array( -4, 5, 59.8 ),
592 600 => array( 0, 0, $base['l'] ),
593 700 => array( 3, -7, 48.0 ),
594 800 => array( 4, -12, 40.2 ),
595 900 => array( 5, -17, 33.1 ),
596 950 => array( 6, -24, 20.8 ),
597 );
598
599 $palette = array();
600 foreach ( $rules as $weight => $modifier ) {
601 if ( 600 === $weight ) {
602 $palette[ $weight ] = strtolower( $base_hex );
603 continue;
604 }
605
606 $new_h = fmod( ( $base['h'] + $modifier[0] + 360 ), 360 );
607 $new_s = max( 0, min( 100, $base['s'] + $modifier[1] ) );
608 $new_l = max( 0, min( 100, $modifier[2] ) );
609
610 $palette[ $weight ] = tutor_utils()->hsl_to_hex( $new_h, $new_s, $new_l );
611 }
612
613 return $palette;
614 }
615
616 /**
617 * Load core color palette
618 *
619 * @since 4.0.0
620 *
621 * @param string $brand_color Base color code.
622 *
623 * @return string
624 */
625 private function load_core_color_palette( $brand_color ) {
626 if ( empty( $brand_color ) ) {
627 return '';
628 }
629
630 $palette = $this->generate_color_palette( $brand_color );
631
632 return "
633 :root {
634 --tutor-brand-100: {$palette[100]};
635 --tutor-brand-200: {$palette[200]};
636 --tutor-brand-300: {$palette[300]};
637 --tutor-brand-400: {$palette[400]};
638 --tutor-brand-450: {$palette[450]};
639 --tutor-brand-500: {$palette[500]};
640 --tutor-brand-600: {$palette[600]};
641 --tutor-brand-700: {$palette[700]};
642 --tutor-brand-800: {$palette[800]};
643 --tutor-brand-900: {$palette[900]};
644 --tutor-brand-950: {$palette[950]};
645 }
646 ";
647 }
648
649 /**
650 * Add Tinymce button for placing shortcode
651 *
652 * @since 1.0.0
653 * @return void|null
654 */
655 public function tutor_add_mce_button() {
656 // Check user permissions.
657 if ( ! current_user_can( 'edit_posts' ) && ! current_user_can( 'edit_pages' ) ) {
658 return;
659 }
660 // Check if WYSIWYG is enabled.
661 if ( 'true' == get_user_option( 'rich_editing' ) ) {
662 add_filter( 'mce_external_plugins', array( $this, 'tutor_add_tinymce_js' ) );
663 add_filter( 'mce_buttons', array( $this, 'tutor_register_mce_button' ) );
664 }
665 }
666
667 /**
668 * Add tinymce button
669 *
670 * @since 1.0.0
671 *
672 * @param array $plugin_array plugin array.
673 * @return array
674 */
675 public function tutor_add_tinymce_js( $plugin_array ) {
676 $plugin_array['tutor_button'] = tutor()->url . 'assets/lib/mce-button.js';
677 return $plugin_array;
678 }
679
680 /**
681 * Register new button in the editor
682 *
683 * @since 1.0.0
684 *
685 * @param array $buttons buttons.
686 * @return array
687 */
688 public function tutor_register_mce_button( $buttons ) {
689 array_push( $buttons, 'tutor_button' );
690 return $buttons;
691 }
692
693 /**
694 * Output generator tag to aid debugging.
695 *
696 * @since 1.0.0
697 *
698 * @param string $gen Generator.
699 * @param string $type Type.
700 *
701 * @return string
702 */
703 public function tutor_generator_tag( $gen, $type ) {
704 switch ( $type ) {
705 case 'html':
706 $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '">';
707 break;
708 case 'xhtml':
709 $gen .= "\n" . '<meta name="generator" content="TutorLMS ' . TUTOR_VERSION . '" />';
710 break;
711 }
712 return $gen;
713 }
714
715 /**
716 * Load text domain handled script after all enqueue_scripts
717 * registered functions
718 *
719 * @since 1.9.0
720 * @since 3.9.2 Refactored to dynamically detect scripts instead of hardcoded list.
721 *
722 * @return void
723 */
724 public function tutor_script_text_domain() {
725 global $wp_scripts;
726
727 if ( empty( $wp_scripts->registered ) ) {
728 return;
729 }
730
731 foreach ( $wp_scripts->registered as $handle => $data ) {
732 $src = $data->src ?? '';
733 $is_from_tutor = str_contains( $src, 'tutor/assets/js' );
734
735 if ( ! $is_from_tutor ) {
736 continue;
737 }
738
739 wp_set_script_translations( $handle, 'tutor', tutor()->path . 'languages/' );
740 }
741 }
742
743 /**
744 * Add translation support for external tinyMCE button
745 *
746 * @since 1.9.7
747 * @return array
748 */
749 public function tutor_tinymce_translate() {
750 $locales['tutor_button'] = tutor()->path . 'includes/tinymce_translate.php';
751 return $locales;
752 }
753
754 /**
755 * Add an identifier class to body
756 *
757 * @since 1.0.0
758 *
759 * @param mixed $classes classes.
760 * @return mixed
761 */
762 public function add_identifier_class_to_body( $classes ) {
763 $course_builder_screen = tutor_utils()->get_course_builder_screen();
764 $to_add = array( 'tutor-lms' );
765
766 // Add backend course editor identifier class to body.
767 if ( $course_builder_screen ) {
768 $to_add[] = is_admin() ? 'tutor-backend' : 'tutor-frontend';
769 $to_add[] = ' tutor-screen-course-builder tutor-screen-course-builder-' . $course_builder_screen . ' ';
770 }
771
772 // Add frontend course builder identifier class.
773 if ( ! $course_builder_screen && tutor_utils()->is_tutor_frontend_dashboard() ) {
774 $to_add[] = 'tutor-screen-frontend-dashboard';
775 }
776
777 if ( is_post_type_archive( tutor()->course_post_type ) ) {
778 $to_add[] = 'tutor-frontend';
779 }
780
781 if ( tutor_utils()->is_tutor_frontend_dashboard() ) {
782 $to_add[] = 'tutor-frontend';
783 }
784
785 if ( is_single() ) {
786 global $post;
787
788 $post_types = array(
789 tutor()->course_post_type,
790 tutor()->lesson_post_type,
791 tutor()->quiz_post_type,
792 tutor()->assignment_post_type,
793 tutor()->zoom_post_type,
794 tutor()->meet_post_type,
795 );
796
797 if ( isset( $post->post_type ) && in_array( $post->post_type, $post_types, true ) ) {
798 $to_add[] = 'tutor-frontend';
799 }
800 }
801
802 if ( is_admin() ) {
803 $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
804 $base = ( $screen && is_object( $screen ) && property_exists( $screen, 'base' ) ) ? $screen->base : '';
805 $index = strpos( $base, 'tutor' );
806
807 if ( 0 === $index || $index > 0 ) {
808 $to_add[] = 'tutor-backend';
809
810 $page = Input::get( 'page' );
811 if ( 'tutor_settings' === $page ) {
812 $to_add[] = 'tutor-screen-backend-settings ';
813 }
814 if ( ! empty( $page ) ) {
815 $to_add[] = 'tutor-backend-' . $page;
816 }
817 }
818 }
819
820 // Remove duplicate classes if any.
821 $to_add = array_unique( $to_add );
822
823 if ( is_array( $classes ) ) {
824 $classes = array_merge( $classes, $to_add );
825 } else {
826 $classes .= implode( ' ', $to_add );
827 }
828
829 return $classes;
830 }
831
832 /**
833 * Enqueue script for adding edit with frontend course builder button
834 * on the Gutenberg editor
835 *
836 * @since 2.0.5
837 * @return void
838 */
839 public static function add_frontend_editor_button() {
840 $wp_screen = get_current_screen();
841
842 if ( is_a( $wp_screen, 'WP_Screen' ) && tutor()->course_post_type === $wp_screen->post_type ) {
843 wp_enqueue_script( 'tutor-gutenberg', tutor()->url . 'assets/js/tutor-gutenberg.js', array(), TUTOR_VERSION, true );
844 $data = array(
845 'frontend_dashboard_url' => esc_url( trailingslashit( tutor_utils()->tutor_dashboard_url( 'create-course' ) ) ) . '?course_id=' . get_the_ID(),
846 );
847
848 wp_add_inline_script(
849 'tutor-gutenberg',
850 'const tutorInlineData =' . json_encode( $data ),
851 'before'
852 );
853 }
854 }
855
856 /**
857 * Enqueue styles & scripts for latest design system
858 *
859 * @since 4.0.0
860 *
861 * @return void
862 */
863 public function enqueue_scripts() {
864 if ( self::should_load_legacy_scripts() ) {
865 return;
866 }
867
868 $is_dashboard = tutor_utils()->is_dashboard_page();
869 $is_learning_area = tutor_utils()->is_learning_area();
870 $is_kids_mode = tutor_utils()->is_kids_mode();
871 $is_legacy_learning = Options_V2::LEARNING_MODE_LEGACY === tutor_utils()->get_option( 'learning_mode' );
872
873 $core_css_url = tutor()->assets_url . 'css/tutor-core.min.css';
874 $kids_css_url = tutor()->assets_url . 'css/tutor-kids.min.css';
875 $dashboard_css_url = tutor()->assets_url . 'css/tutor-dashboard.min.css';
876 $learning_area_css_url = tutor()->assets_url . 'css/tutor-learning-area.min.css';
877 $google_font_url = 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap';
878
879 $core_js_url = tutor()->assets_url . 'js/tutor-core.js';
880 $dashboard_js_url = tutor()->assets_url . 'js/tutor-dashboard.js';
881 $learning_area_js_url = tutor()->assets_url . 'js/tutor-learning-area.js';
882
883 $version = TUTOR_ENV === 'DEV' ? time() : TUTOR_VERSION;
884
885 $is_course_list_page = tutor_utils()->is_course_list_page();
886 $is_course_details_page = tutor_utils()->is_course_details_page();
887
888 $localize_data = apply_filters( 'tutor_localize_data', $this->get_default_localized_data() );
889 if ( $is_kids_mode ) {
890 $google_font_url = 'https://fonts.googleapis.com/css2?family=Nunito:wght@300;400;500;600;700&display=swap';
891 wp_enqueue_style( 'tutor-kids', $kids_css_url, array( 'tutor-core' ), $version );
892 }
893
894 // Core.
895 wp_enqueue_style( 'tutor-google-fonts', $google_font_url, array(), $version );
896
897 wp_enqueue_style( 'tutor-core', $core_css_url, array( 'tutor-google-fonts' ), $version );
898 wp_enqueue_script( 'tutor-core', $core_js_url, array( 'wp-i18n' ), $version, true );
899
900 wp_localize_script( 'tutor-core', '_tutorobject', $localize_data );
901
902 // Generate color palette from user selected brand color and add to the root.
903 $brand_color = tutor_utils()->get_brand_color();
904 if ( Options_V2::DEFAULT_BRAND_COLOR !== $brand_color ) {
905 wp_add_inline_style( 'tutor-core', $this->load_core_color_palette( $brand_color ) );
906 }
907
908 if ( $is_dashboard ) {
909 wp_enqueue_style( 'tutor-dashboard', $dashboard_css_url, array(), $version );
910 wp_enqueue_script( 'tutor-dashboard', $dashboard_js_url, array( 'tutor-core', 'wp-i18n' ), $version, true );
911 }
912
913 if ( $is_learning_area ) {
914 wp_enqueue_style( 'tutor-learning', $learning_area_css_url, array(), $version );
915 wp_enqueue_script( 'tutor-learning', $learning_area_js_url, array( 'tutor-core', 'wp-i18n' ), $version, true );
916
917 if ( is_single_course( true ) ) {
918 wp_enqueue_style( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.css', array(), $version );
919 wp_enqueue_script( 'tutor-plyr', tutor()->url . 'assets/lib/plyr/plyr.polyfilled.min.js', array( 'jquery' ), $version, true );
920 }
921 }
922 }
923
924 /**
925 * Check if need to load legacy scripts
926 *
927 * If the current screen is dashboard or new learning area
928 * then this method will return false to avoid loading legacy css & js files
929 *
930 * @since 4.0.0
931 *
932 * @return boolean
933 */
934 public static function should_load_legacy_scripts(): bool {
935 $load = true;
936
937 $post_id = get_the_ID();
938
939 $is_learning_area = tutor_utils()->is_learning_area();
940 $is_legacy_learning = tutor_utils()->is_legacy_learning_mode();
941 $is_dashboard = tutor_utils()->is_dashboard_page();
942
943 $page_ids = array(
944 (int) tutor_utils()->get_option( 'student_register_page' ),
945 (int) tutor_utils()->get_option( 'instructor_register_page' ),
946 );
947
948 // Ignore loading legacy scripts on specific case.
949 if ( $is_learning_area && ! $is_legacy_learning ) {
950 $load = false;
951 } elseif ( $is_dashboard ) {
952 $load = false;
953 } elseif ( in_array( $post_id, $page_ids, true ) ) {
954 $load = false;
955 } else {
956 // Ignore loading legacy scripts for these shortcodes.
957 $has_shortcode = false;
958
959 $shortcdes = array(
960 'tutor_student_registration_form',
961 'tutor_instructor_registration_form',
962 'tutor_dashboard',
963 'tutor_login',
964 );
965
966 $post_content = get_the_content();
967
968 foreach ( $shortcdes as $shortcde ) {
969 $has_shortcode = has_shortcode( $post_content, $shortcde );
970 if ( $has_shortcode ) {
971 $load = false;
972 break;
973 }
974 }
975 }
976
977 return apply_filters( 'tutor_should_load_legacy_scripts', $load );
978 }
979
980 /**
981 * Add custom meta data to the head section.
982 *
983 * Outputs a viewport meta tag to improve mobile responsiveness.
984 *
985 * @since 4.0.0
986 *
987 * @return void
988 */
989 public function add_custom_data() {
990 if ( tutor_utils()->is_dashboard_page() || tutor_utils()->is_learning_area() ) {
991 echo '<meta name="viewport" content="width=device-width, initial-scale=1" />' . "\n";
992 }
993 }
994
995 /**
996 * Add preload to CSS
997 *
998 * @param string $html HTML.
999 * @param string $handle Handle.
1000 *
1001 * @since 4.0.0
1002 *
1003 * @return string
1004 */
1005 public function add_preload_to_css( $html, $handle ) {
1006 if ( 'tutor-google-fonts' === $handle ) {
1007 $html = str_replace(
1008 "rel='stylesheet'",
1009 "rel='preload' as='style' onload=\"this.onload=null;this.rel='stylesheet'\"",
1010 $html
1011 );
1012 }
1013 return $html;
1014 }
1015 }
1016