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 / Admin.php
tutor / classes Last commit date
Addons.php 17 hours ago Admin.php 17 hours ago Ajax.php 17 hours ago Announcements.php 17 hours ago Assets.php 17 hours ago Backend_Page_Trait.php 1 year ago BaseController.php 1 year ago Config.php 17 hours ago Container.php 11 months ago Course.php 17 hours ago Course_Embed.php 3 years ago Course_Filter.php 17 hours ago Course_List.php 17 hours ago Course_Settings_Tabs.php 17 hours ago Course_Widget.php 1 year ago Custom_Validation.php 17 hours ago Dashboard.php 17 hours ago Earnings.php 9 months ago FormHandler.php 17 hours ago Frontend.php 17 hours ago Gutenberg.php 1 year ago Icon.php 17 hours ago Input.php 17 hours ago Instructor.php 17 hours ago Instructors_List.php 17 hours ago Lesson.php 17 hours ago Options_V2.php 17 hours ago Permalink.php 17 hours ago Post_types.php 1 day ago Private_Course_Access.php 17 hours ago Q_And_A.php 17 hours ago Question_Answers_List.php 11 months ago Quiz.php 17 hours ago QuizBuilder.php 17 hours ago Quiz_Attempts_List.php 17 hours ago RestAPI.php 2 years ago Reviews.php 17 hours ago Rewrite_Rules.php 2 years ago SampleCourse.php 17 hours ago Shortcode.php 17 hours ago Singleton.php 1 year ago Student.php 17 hours ago Students_List.php 1 year ago Taxonomies.php 1 year ago Template.php 17 hours ago Theme_Compatibility.php 3 years ago Tools.php 1 year ago Tools_V2.php 4 weeks ago Tutor.php 17 hours ago TutorEDD.php 17 hours ago Tutor_Base.php 2 years ago Tutor_Setup.php 17 hours ago Upgrader.php 17 hours ago User.php 17 hours ago UserPreference.php 17 hours ago Utils.php 17 hours ago Video_Stream.php 3 years ago WhatsNew.php 10 months ago Withdraw.php 17 hours ago Withdraw_Requests_List.php 11 months ago WooCommerce.php 17 hours ago
Admin.php
989 lines
1 <?php
2 /**
3 * Manage admin menu and plugin related logic
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 defined( 'ABSPATH' ) || exit;
14
15 use Tutor\Ecommerce\OrderController;
16 use Tutor\Helpers\HttpHelper;
17 use TUTOR\Input;
18 use Tutor\Models\CourseModel;
19 use Tutor\Traits\JsonResponse;
20
21 /**
22 * Admin Class
23 *
24 * @since 1.0.0
25 */
26 class Admin {
27 use JsonResponse;
28
29 /**
30 * Constructor
31 *
32 * @since 1.0.0
33 *
34 * @return void
35 */
36 public function __construct() {
37 add_action( 'admin_notices', array( $this, 'show_unstable_version_admin_notice' ) );
38
39 add_action( 'admin_menu', array( $this, 'register_menu' ) );
40 // Force activate menu for necessary.
41 add_filter( 'parent_file', array( $this, 'parent_menu_active' ) );
42 add_filter( 'submenu_file', array( $this, 'submenu_file_active' ), 10, 2 );
43
44 add_action( 'admin_init', array( $this, 'filter_posts_for_instructors' ) );
45 add_action( 'admin_init', array( $this, 'redirect_to_welcome_page' ) );
46 add_action( 'load-post.php', array( $this, 'check_if_current_users_post' ) );
47
48 add_filter( 'plugin_action_links_' . plugin_basename( TUTOR_FILE ), array( $this, 'plugin_action_links' ) );
49
50 // Plugin Row Meta.
51 add_filter( 'plugin_row_meta', array( $this, 'plugin_row_meta' ), 10, 2 );
52
53 // Admin Footer Text.
54 add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ), 1 );
55 // Register Course Widget.
56 add_action( 'widgets_init', array( $this, 'register_course_widget' ) );
57
58 // Handle flash toast message for redirect_to util helper.
59 add_action( 'admin_head', array( new Utils(), 'handle_flash_message' ), 999 );
60
61 add_action( 'admin_bar_menu', array( $this, 'add_toolbar_items' ), 100 );
62
63 add_action( 'wp_ajax_tutor_do_not_show_feature_page', array( $this, 'handle_do_not_show_feature_page' ) );
64
65 add_action( 'upgrader_process_complete', array( $this, 'set_permalink_flag_on_upgrade' ), 10, 2 );
66
67 add_action( 'admin_notices', array( $this, 'show_offer_notice' ) );
68 add_action( 'wp_ajax_tutor_dismiss_offer_notice', array( $this, 'ajax_dismiss_offer_notice' ) );
69 }
70
71 /**
72 * Flush Tutor permalink rewrite rules after updates.
73 *
74 * @since 4.0.0
75 *
76 * @param mixed $upgrader_object Upgrader instance.
77 * @param array $options Extra arguments passed to the hook.
78 *
79 * @return void
80 */
81 public function set_permalink_flag_on_upgrade( $upgrader_object, $options ) {
82 Permalink::set_permalink_reset_flag( $upgrader_object, $options );
83 }
84
85 /**
86 * Check offer notice is dismissed.
87 *
88 * @since 4.0.0
89 *
90 * @return bool
91 */
92 private function is_offer_notice_dismissed() {
93 return '4.0.0' === get_transient( 'tutor_offer_notice_dismissed' );
94 }
95
96 /**
97 * Show offer notice
98 *
99 * @since 4.0.0
100 *
101 * @return void
102 */
103 public function show_offer_notice() {
104 if ( ! User::is_admin() || Input::has( 'welcome', Input::GET_REQUEST ) ) {
105 return;
106 }
107
108 $is_free_user = ! tutor()->has_pro;
109 $cta_label = __( 'Claim 30% OFF', 'tutor' );
110 $cta_link = 'https://tutorlms.com/pricing/?utm_source=tutor-plugin&utm_medium=notice&utm_campaign=tutor-lms-pro-offer';
111
112 $now = new \DateTimeImmutable( 'now', wp_timezone() );
113 $expiration_dt = '2026-07-15 23:59:59';
114 $expiration = new \DateTimeImmutable( $expiration_dt, wp_timezone() );
115
116 $remaining = max( 0, $expiration->getTimestamp() - $now->getTimestamp() );
117
118 $days = floor( $remaining / DAY_IN_SECONDS );
119 $hours = floor( ( $remaining % DAY_IN_SECONDS ) / HOUR_IN_SECONDS );
120 $minutes = floor( ( $remaining % HOUR_IN_SECONDS ) / MINUTE_IN_SECONDS );
121 $seconds = $remaining % MINUTE_IN_SECONDS;
122
123 $expire_in = sprintf(
124 '%dd:%02dh:%02d:%02d',
125 $days,
126 $hours,
127 $minutes,
128 $seconds
129 );
130
131 if ( $is_free_user && $remaining > 0 && ! self::is_offer_notice_dismissed() ) {
132 ?>
133 <div class="tutor-offer-notice">
134 <div class="tutor-offer-notice-wrapper">
135 <div class="tutor-offer-notice-left">
136 <div data-subheader><?php esc_html_e( '4.0 launch offer', 'tutor' ); ?></div>
137 <div data-header><?php esc_html_e( '30% OFF', 'tutor' ); ?></div>
138 <div data-subtext><?php esc_html_e( 'on all annual plans', 'tutor' ); ?></div>
139 </div>
140 <div class="tutor-offer-notice-right">
141 <div class="tutor-offer-notice-text"><?php esc_html_e( 'Offer ends by', 'tutor' ); ?> <span class="tutor-offer-notice-timer" data-expiry="<?php echo esc_attr( $expiration->getTimestamp() ); ?>"><?php echo esc_html( $expire_in ); ?></span></div>
142 <a class="tutor-offer-notice-cta" href="<?php echo esc_url( $cta_link ); ?>" target="_blank">
143 <?php echo esc_html( $cta_label ); ?>
144 <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="none" viewBox="0 0 24 24"><path fill="#fff" d="M13.938 6.937a.55.55 0 0 0-.786 0 .555.555 0 0 0 0 .778l3.338 3.34H5.243a.55.55 0 0 0-.55.551c0 .305.242.558.55.558h11.246l-3.337 3.334a.563.563 0 0 0 0 .785.55.55 0 0 0 .786 0L18.217 12a.543.543 0 0 0 0-.78z"/></svg>
145 </a>
146 </div>
147 </div>
148 <button type="button" class="tutor-offer-notice-dismiss"><span class="tutor-icon-times"></span></button>
149 </div>
150 <?php
151 }
152 }
153
154 /**
155 * Dismiss offer notice.
156 *
157 * @since 4.0.0
158 *
159 * @return void JSON response.
160 */
161 public function ajax_dismiss_offer_notice() {
162 if ( ! User::is_admin() ) {
163 $this->response_bad_request( tutor_utils()->error_message() );
164 }
165
166 if ( self::is_offer_notice_dismissed() ) {
167 $this->response_bad_request( __( 'You have already dismissed the offer notice.', 'tutor' ) );
168 }
169
170 // Set expiry until next day.
171 $expiration = strtotime( 'tomorrow' ) - time();
172 set_transient( 'tutor_offer_notice_dismissed', '4.0.0', $expiration );
173 $this->json_response( __( 'Notice dismissed', 'tutor' ) );
174 }
175
176 /**
177 * Show unstable version notice.
178 *
179 * @since 3.0.0
180 *
181 * @return void
182 */
183 public function show_unstable_version_admin_notice() {
184 $version = tutor_utils()->extract_version_details( TUTOR_VERSION );
185 if ( ! $version->is_stable ) {
186 /* translators: %s: version name */
187 $message = sprintf( __( 'You\'re currently using Tutor LMS %s. To ensure stability, please do not use it on a live site.', 'tutor' ), '<strong>' . $version->version . '</strong>' );
188 ?>
189 <div class="notice notice-warning">
190 <p><strong><?php esc_html_e( 'Warning!', 'tutor' ); ?></strong></p>
191 <p><?php echo wp_kses_post( $message ); ?></p>
192 </div>
193 <?php
194 }
195 }
196
197 /**
198 * Register admin menus
199 *
200 * @since 1.0.0
201 * @since 3.8.0 re-organize admin menu.
202 *
203 * @return void
204 */
205 public function register_menu() {
206 $has_pro = tutor()->has_pro;
207
208 $unanswered_questions = tutor_utils()->unanswered_question_count();
209 $unanswered_bubble = '';
210 if ( $unanswered_questions ) {
211 $unanswered_bubble = '<span class="update-plugins count-' . $unanswered_questions . '"><span class="plugin-count">' . $unanswered_questions . '</span></span>';
212 }
213
214 $course_post_type = tutor()->course_post_type;
215
216 $pro_text = '';
217 if ( $has_pro ) {
218 $pro_text = ' ' . apply_filters( 'tutor_pro_flag', __( 'Pro', 'tutor' ) );
219 }
220
221 $enable_course_marketplace = (bool) tutor_utils()->get_option( 'enable_course_marketplace' );
222
223 $welcome = Tutor_Setup::is_welcome_page_visited();
224
225 $root_page = array( $this, 'tutor_course_list' );
226 if ( false === $welcome && Input::has( 'page' ) && 'tutor' === Input::get( 'page' ) && Input::has( 'welcome' ) ) {
227 $root_page = array( $this, 'welcome_page' );
228 }
229
230 $icon_base64_uri = 'data:image/svg+xml;base64,' . base64_encode( '<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1139"><defs/><path fill-rule="evenodd" clip-rule="evenodd" d="M341.652 622.4c-23.412 0-43.222-19.8-43.222-43.2v-99c0-23.4 19.81-43.2 43.222-43.2 23.412 0 43.222 19.8 43.222 43.2v99c0 23.4-18.009 43.2-43.222 43.2 1.801 0 1.801 0 0 0zM655.01 622.4c-23.412 0-43.222-18-43.222-43.2v-99c0-23.4 19.81-43.2 43.222-43.2 23.412 0 43.222 19.8 43.222 43.2v99c0 25.2-19.81 43.2-43.222 43.2z" fill="#9DA2A8"/><path fill-rule="evenodd" clip-rule="evenodd" d="M255.204 406.4c18.009-37.8 54.028-63 95.449-63 61.231 1.8 108.055 52.2 106.254 113.4v203.4c3.602 21.6 23.412 37.8 45.023 34.2 18.009-1.8 32.416-16.2 34.217-34.2V455c-1.801-61.2 46.824-111.6 106.254-113.4 39.621 0 75.639 21.6 93.648 59.4 68.435 133.2 14.407 295.2-117.06 363.6C487.523 833 325.44 779 258.806 647.6c-39.62-75.6-39.62-165.6-3.602-241.2zM426.291 140h151.277v59.4c-25.212-5.4-52.226-9-77.439-9-25.213 0-50.426 3.6-75.639 7.2l1.801-57.6zm414.211 388.8c0-122.4-66.634-235.8-172.888-295.2V140h64.833c25.213 0 45.023-19.8 45.023-45s-21.611-45-45.023-45H271.413C246.2 51.8 226.39 71.6 226.39 96.8c0 25.2 19.81 45 45.023 45h66.633v91.8c-163.883 90-230.517 298.8-135.068 459 3.602 5.4-3.602-5.4 0 0C338.046 930.2 687.424 948.2 802.683 950c10.805 0 19.81-3.6 27.014-10.8 7.203-7.2 10.805-18 10.805-27V528.8z" fill="#9DA2A8"/></svg>' );
231 $menu_position = 2;
232
233 add_menu_page(
234 __( 'Tutor LMS', 'tutor' ) . $pro_text,
235 __( 'Tutor LMS', 'tutor' ) . $pro_text,
236 'manage_tutor_instructor',
237 'tutor',
238 $root_page,
239 $icon_base64_uri,
240 $menu_position
241 );
242
243 new WhatsNew();
244
245 $admin_menu = apply_filters(
246 'tutor_admin_menu',
247 array(
248 'group_one' => array(
249 'courses' => array(
250 'parent_slug' => 'tutor',
251 'page_title' => __( 'Courses', 'tutor' ),
252 'menu_title' => __( 'Courses', 'tutor' ),
253 'capability' => 'manage_tutor_instructor',
254 'menu_slug' => 'tutor',
255 'callback' => array( $this, 'tutor_course_list' ),
256 ),
257 'content_bank' => null,
258 'course_builder' => array(
259 'parent_slug' => 'tutor',
260 'page_title' => __( 'Course Builder', 'tutor' ),
261 'menu_title' => '<span class="tutor-create-course">Create Course</span>',
262 'capability' => 'manage_tutor_instructor',
263 'menu_slug' => 'create-course',
264 'callback' => array( new Course( false ), 'load_course_builder' ),
265 ),
266 'categories' => array(
267 'parent_slug' => 'tutor',
268 'page_title' => __( 'Categories', 'tutor' ),
269 'menu_title' => __( 'Categories', 'tutor' ),
270 'capability' => 'manage_tutor',
271 'menu_slug' => 'edit-tags.php?taxonomy=course-category&post_type=' . $course_post_type,
272 ),
273 'tags' => array(
274 'parent_slug' => 'tutor',
275 'page_title' => __( 'Tags', 'tutor' ),
276 'menu_title' => __( 'Tags', 'tutor' ),
277 'capability' => 'manage_tutor',
278 'menu_slug' => 'edit-tags.php?taxonomy=course-tag&post_type=' . $course_post_type,
279 ),
280 ),
281 'group_two' => array(
282 'orders' => null,
283 'subscriptions' => null,
284 'coupons' => null,
285 'students' => array(
286 'parent_slug' => 'tutor',
287 'page_title' => __( 'Students', 'tutor' ),
288 'menu_title' => __( 'Students', 'tutor' ),
289 'capability' => 'manage_tutor',
290 'menu_slug' => Students_List::STUDENTS_LIST_PAGE,
291 'callback' => array( $this, 'tutor_students' ),
292
293 ),
294 'announcements' => array(
295 'parent_slug' => 'tutor',
296 'page_title' => __( 'Announcements', 'tutor' ),
297 'menu_title' => __( 'Announcements', 'tutor' ),
298 'capability' => 'manage_tutor_instructor',
299 'menu_slug' => 'tutor_announcements',
300 'callback' => array( $this, 'tutor_announcements' ),
301
302 ),
303 'assignments' => null,
304 'quiz_attempts' => array(
305 'parent_slug' => 'tutor',
306 'page_title' => __( 'Quiz Attempts', 'tutor' ),
307 'menu_title' => __( 'Quiz Attempts', 'tutor' ),
308 'capability' => 'manage_tutor_instructor',
309 'menu_slug' => Quiz_Attempts_List::QUIZ_ATTEMPT_PAGE,
310 'callback' => array( $this, 'quiz_attempts' ),
311 ),
312 'q_and_a' => array(
313 'parent_slug' => 'tutor',
314 'page_title' => __( 'Q&A', 'tutor' ),
315 'menu_title' => __( 'Q&A ', 'tutor' ) . $unanswered_bubble,
316 'capability' => 'manage_tutor_instructor',
317 'menu_slug' => Question_Answers_List::QUESTION_ANSWER_PAGE,
318 'callback' => array( $this, 'question_answer' ),
319 ),
320 'enrollments' => null,
321 'reports' => null,
322 'gradebook' => null,
323 'instructors' => $enable_course_marketplace ? array(
324 'parent_slug' => 'tutor',
325 'page_title' => __( 'Instructors', 'tutor' ),
326 'menu_title' => __( 'Instructors', 'tutor' ),
327 'capability' => 'manage_tutor',
328 'menu_slug' => Instructors_List::INSTRUCTOR_LIST_PAGE,
329 'callback' => array( $this, 'tutor_instructors' ),
330 ) : null,
331 'withdraw_requests' => $enable_course_marketplace ? array(
332 'parent_slug' => 'tutor',
333 'page_title' => __( 'Withdraw Requests', 'tutor' ),
334 'menu_title' => __( 'Withdraw Requests', 'tutor' ),
335 'capability' => 'manage_tutor',
336 'menu_slug' => Withdraw_Requests_List::WITHDRAW_REQUEST_LIST_PAGE,
337 'callback' => array( $this, 'withdraw_requests' ),
338 ) : null,
339 ),
340 'group_three' => array(
341 'google_classroom' => null,
342 'zoom' => null,
343 'google_meet' => null,
344 'h5p' => null,
345 'addons' => array(
346 'parent_slug' => 'tutor',
347 'page_title' => __( 'Addons', 'tutor' ),
348 'menu_title' => __( 'Addons', 'tutor' ),
349 'capability' => 'manage_tutor',
350 'menu_slug' => 'tutor-addons',
351 'callback' => array( $this, 'enable_disable_addons' ),
352 ),
353 'tools' => array(
354 'parent_slug' => 'tutor',
355 'page_title' => __( 'Tools', 'tutor' ),
356 'menu_title' => __( 'Tools', 'tutor' ),
357 'capability' => 'manage_tutor',
358 'menu_slug' => 'tutor-tools',
359 'callback' => array( new Tools_V2(), 'load_tools_page' ),
360 ),
361 'settings' => array(
362 'parent_slug' => 'tutor',
363 'page_title' => __( 'Settings', 'tutor' ),
364 'menu_title' => __( 'Settings', 'tutor' ),
365 'capability' => 'manage_tutor',
366 'menu_slug' => 'tutor_settings',
367 'callback' => array( new Options_V2(), 'load_settings_page' ),
368 ),
369 'license' => null,
370 'whats_new' => null,
371 'upgrade_to_pro' => $has_pro ? null : array(
372 'parent_slug' => 'tutor',
373 'page_title' => __( 'Upgrade to Pro', 'tutor' ),
374 'menu_title' => sprintf( '<span class="tutor-get-pro-text">%s</span>', __( 'Upgrade to Pro', 'tutor' ) ),
375 'capability' => 'manage_options',
376 'menu_slug' => 'tutor-get-pro',
377 'callback' => array( $this, 'tutor_get_pro' ),
378 ),
379 ),
380 )
381 );
382
383 foreach ( $admin_menu as $group => $menu ) {
384 foreach ( $menu as $name => $args ) {
385 if ( empty( $args ) ) {
386 continue;
387 }
388
389 // Backward compatibility hook.
390 if ( 'addons' === $name ) {
391 do_action( 'tutor_admin_register' );
392 }
393
394 // Backward compatibility hook.
395 do_action( "tutor_before_{$name}_admin_menu" );
396
397 do_action( "tutor_before_{$name}_menu" );
398 add_submenu_page( $args['parent_slug'], $args['page_title'], $args['menu_title'], $args['capability'], $args['menu_slug'], $args['callback'] ?? '', $args['position'] ?? null );
399
400 // Backward compatibility hook.
401 do_action( "tutor_after_{$name}_menu" );
402
403 do_action( "tutor_after_{$name}_admin_menu" );
404 }
405
406 if ( 'group_three' !== $group ) {
407 if ( 'group_two' === $group && ! current_user_can( 'manage_options' ) ) {
408 continue;
409 }
410
411 add_submenu_page( 'tutor', '', '<span class="tutor-admin-menu-separator"></span>', 'manage_tutor_instructor', '#' );
412 }
413 }
414 }
415
416 /**
417 * Welcome page opt-out
418 *
419 * @since 3.0.0
420 */
421 public function handle_do_not_show_feature_page() {
422 tutor_utils()->check_nonce();
423
424 if ( ! User::is_admin() ) {
425 $this->json_response(
426 tutor_utils()->error_message(),
427 null,
428 HttpHelper::STATUS_BAD_REQUEST
429 );
430 }
431
432 update_option( 'tutor-new-feature', '3.0.0' );
433 $this->json_response( __( 'Success', 'tutor' ) );
434 }
435
436 /**
437 * Show Feature Promotion Page for Free User.
438 *
439 * @since 2.2.0
440 *
441 * @return void
442 */
443 public function feature_promotion_page() {
444 include tutor()->path . 'views/pages/welcome.php';
445 }
446
447 /**
448 * Show students page
449 *
450 * @since 1.0.0
451 *
452 * @return void
453 */
454 public function tutor_students() {
455 include tutor()->path . 'views/pages/students.php';
456 }
457
458 /**
459 * Show instructor page
460 *
461 * @since 1.0.0
462 *
463 * @return void
464 */
465 public function tutor_instructors() {
466 include tutor()->path . 'views/pages/instructors.php';
467 }
468
469 /**
470 * Show announcements page
471 *
472 * @since 1.0.0
473 *
474 * @return void
475 */
476 public function tutor_announcements() {
477 include tutor()->path . 'views/pages/announcements.php';
478 }
479
480 /**
481 * Show Q&A page
482 *
483 * @since 1.0.0
484 *
485 * @return void
486 */
487 public function question_answer() {
488 include tutor()->path . 'views/pages/question_answer.php';
489 }
490
491 /**
492 * Show quiz attempts page
493 *
494 * @since 1.0.0
495 *
496 * @return void
497 */
498 public function quiz_attempts() {
499 include tutor()->path . 'views/pages/quiz_attempts.php';
500 }
501
502 /**
503 * Show the withdraw requests table
504 *
505 * @since 1.2.0
506 *
507 * @return void
508 */
509 public function withdraw_requests() {
510 include tutor()->path . 'views/pages/withdraw_requests.php';
511 }
512
513 /**
514 * Enable or disable addons
515 *
516 * @since 1.0.0
517 *
518 * @return void
519 */
520 public function enable_disable_addons() {
521 include tutor()->path . 'views/pages/enable_disable_addons.php';
522 }
523
524 /**
525 * Tutor tools page (OLD)
526 *
527 * @since 1.0.0
528 *
529 * @return void
530 */
531 public function tutor_tools_old() {
532 $tutor_admin_tools_page = Input::get( 'tutor_admin_tools_page' );
533 if ( $tutor_admin_tools_page ) {
534 include apply_filters( 'tutor_admin_tools_page', tutor()->path . "views/pages/{$tutor_admin_tools_page}.php", $tutor_admin_tools_page );
535 } else {
536 $pages = apply_filters(
537 'tutor_tool_pages',
538 array(
539 'tutor_pages' => array( 'title' => __( 'Tutor Pages', 'tutor' ) ),
540 'status' => __( 'Status', 'tutor' ),
541 )
542 );
543
544 $current_page = 'tutor_pages';
545 $requested_page = Input::get( 'sub_page' );
546 if ( $requested_page ) {
547 $current_page = $requested_page;
548 }
549
550 $current_page = str_replace( '/', '', $current_page );
551 $current_page = str_replace( '.', '', $current_page );
552 $current_page = str_replace( '\\', '', $current_page );
553 $current_page = trim( $current_page );
554
555 include tutor()->path . 'views/pages/tools.php';
556 }
557 }
558
559 /**
560 * Show pro upgrade page
561 *
562 * @since 1.0.0
563 *
564 * @return void
565 */
566 public function tutor_get_pro() {
567 include tutor()->path . 'views/pages/get-pro.php';
568 }
569
570 /**
571 * Parent menu active
572 *
573 * @since 1.0.0
574 *
575 * @param string $parent_file parent file.
576 *
577 * @return string
578 */
579 public function parent_menu_active( $parent_file ) {
580 $taxonomy = Input::get( 'taxonomy' );
581 if ( CourseModel::COURSE_CATEGORY === $taxonomy || CourseModel::COURSE_TAG === $taxonomy ) {
582 return 'tutor';
583 }
584
585 return $parent_file;
586 }
587
588 /**
589 * Sub-menu active
590 *
591 * @since 1.0.0
592 *
593 * @param string $submenu_file submenu file.
594 * @param string $parent_file parent file.
595 *
596 * @return string
597 */
598 public function submenu_file_active( $submenu_file, $parent_file ) {
599 $taxonomy = Input::get( 'taxonomy' );
600 $course_post_type = tutor()->course_post_type;
601
602 if ( CourseModel::COURSE_CATEGORY === $taxonomy ) {
603 return 'edit-tags.php?taxonomy=course-category&post_type=' . $course_post_type;
604 }
605 if ( CourseModel::COURSE_TAG === $taxonomy ) {
606 return 'edit-tags.php?taxonomy=course-tag&post_type=' . $course_post_type;
607 }
608
609 return $submenu_file;
610 }
611
612 /**
613 * Filter posts for instructor
614 *
615 * @since 1.0.0
616 *
617 * @return void
618 */
619 public function filter_posts_for_instructors() {
620 if ( ! current_user_can( 'administrator' ) && current_user_can( tutor()->instructor_role ) ) {
621 @remove_menu_page( 'edit-comments.php' ); // Comments.
622 add_filter( 'posts_clauses_request', array( $this, 'posts_clauses_request' ) );
623 }
624 }
625
626 /**
627 * Request for posts clauses
628 *
629 * @since 1.0.0
630 *
631 * @param mixed $clauses clauses.
632 *
633 * @return mixed
634 */
635 public function posts_clauses_request( $clauses ) {
636
637 if ( ! is_admin() || ( ! Input::has( 'post_type' ) || Input::get( 'post_type' ) != tutor()->course_post_type ) || tutor_utils()->has_user_role( array( 'administrator', 'editor' ) ) ) {
638 return $clauses;
639 }
640
641 // Need multi instructor check.
642 global $wpdb;
643
644 $user_id = get_current_user_id();
645
646 $get_assigned_courses_ids = $wpdb->get_col( $wpdb->prepare( "SELECT meta_value from {$wpdb->usermeta} WHERE meta_key = '_tutor_instructor_course_id' AND user_id = %d", $user_id ) );
647 $own_courses = is_array( $get_assigned_courses_ids ) ? $get_assigned_courses_ids : array();
648
649 $in_query_pre = count( $own_courses ) ? implode( ',', $own_courses ) : null;
650 $in_query_where = $in_query_pre ? " OR {$wpdb->posts}.ID IN({$in_query_pre})" : '';
651
652 $course_post_type = tutor()->course_post_type;
653 $custom_author_query = " AND ({$wpdb->posts}.post_type!='{$course_post_type}' OR {$wpdb->posts}.post_author = {$user_id}) {$in_query_where}";
654
655 $clauses['where'] .= $custom_author_query;
656
657 return $clauses;
658 }
659
660 /**
661 * Prevent unauthorised course/lesson edit page by direct URL
662 *
663 * @since 1.0.0
664 *
665 * @return void
666 */
667 public function check_if_current_users_post() {
668 if ( current_user_can( 'administrator' ) || ! current_user_can( tutor()->instructor_role ) ) {
669 return;
670 }
671
672 if ( ! empty( Input::get( 'post' ) ) ) {
673 $get_post_id = Input::get( 'post', Input::TYPE_INT );
674 $get_post = get_post( $get_post_id );
675 $tutor_post_types = array( tutor()->course_post_type, tutor()->lesson_post_type );
676
677 $current_user = get_current_user_id();
678
679 if ( in_array( $get_post->post_type, $tutor_post_types ) && $get_post->post_author != $current_user ) {
680 global $wpdb;
681
682 $get_assigned_courses_ids = (int) $wpdb->get_var(
683 $wpdb->prepare(
684 "SELECT user_id
685 from {$wpdb->usermeta}
686 WHERE user_id = %d AND meta_key = '_tutor_instructor_course_id' AND meta_value = %d ",
687 $current_user,
688 $get_post_id
689 )
690 );
691
692 if ( ! $get_assigned_courses_ids ) {
693 wp_die( esc_html__( 'Permission Denied', 'tutor' ) );
694 }
695 }
696 }
697 }
698
699 /**
700 * Scan template files
701 *
702 * @since 1.0.0
703 *
704 * @param string $template_path template file path.
705 *
706 * @return array
707 */
708 public static function scan_template_files( $template_path = null ) {
709 if ( ! $template_path ) {
710 $template_path = tutor()->path . 'templates/';
711 }
712
713 $files = @scandir($template_path); // @codingStandardsIgnoreLine.
714 $result = array();
715
716 if ( ! empty( $files ) ) {
717 foreach ( $files as $key => $value ) {
718 if ( ! in_array( $value, array( '.', '..', '.DS_Store' ), true ) ) {
719 if ( is_dir( $template_path . DIRECTORY_SEPARATOR . $value ) ) {
720 $sub_files = self::scan_template_files( $template_path . DIRECTORY_SEPARATOR . $value );
721 foreach ( $sub_files as $sub_file ) {
722 $result[] = $value . DIRECTORY_SEPARATOR . $sub_file;
723 }
724 } else {
725 $result[] = $value;
726 }
727 }
728 }
729 }
730 return $result;
731 }
732
733 /**
734 * Get Template overridden files
735 *
736 * @since 1.0.0
737 *
738 * @return array
739 */
740 public static function template_overridden_files() {
741 $template_files = self::scan_template_files();
742
743 $override_files = array();
744 foreach ( $template_files as $file ) {
745 $file_path = null;
746 if ( file_exists( trailingslashit( get_stylesheet_directory() ) . tutor()->template_path . $file ) ) {
747 $file_path = $file;
748 } elseif ( file_exists( trailingslashit( get_template_directory() ) . tutor()->template_path . $file ) ) {
749 $file_path = $file;
750 }
751
752 if ( $file_path ) {
753 $override_files[] = str_replace( WP_CONTENT_DIR . '/themes/', '', $file_path );
754 }
755 }
756
757 return $override_files;
758 }
759
760 /**
761 * Plugin activation link
762 *
763 * @since 1.0.0
764 *
765 * @param array $actions action list.
766 *
767 * @return array
768 */
769 public function plugin_action_links( $actions ) {
770 $has_pro = tutor()->has_pro;
771
772 if ( ! $has_pro ) {
773 $actions['tutor_pro_link'] =
774 '<a href="https://tutorlms.com/pricing?utm_source=tutor_plugin_action_link&utm_medium=wordpress_dashboard&utm_campaign=go_premium" target="_blank">
775 <span style="color: #ff7742; font-weight: bold;">' .
776 __( 'Upgrade to Pro', 'tutor' ) .
777 '</span>
778 </a>';
779 }
780
781 $actions['settings'] = '<a href="admin.php?page=tutor_settings">' . __( 'Settings', 'tutor' ) . '</a>';
782
783 return $actions;
784 }
785
786 /**
787 * Add plugin meta data in WP plugins list page
788 *
789 * @since 1.0.0
790 *
791 * @param array $plugin_meta plugin meta data.
792 * @param string $plugin_file plugin file.
793 *
794 * @return array
795 */
796 public function plugin_row_meta( $plugin_meta, $plugin_file ) {
797
798 if ( tutor()->basename === $plugin_file ) {
799 $plugin_meta[] = sprintf(
800 '<a href="%s"><strong style="color: #03bd24">%s</strong></a>',
801 esc_url( 'https://docs.themeum.com/tutor-lms/?utm_source=tutor&utm_medium=plugins_installation_list&utm_campaign=plugin_docs_link' ),
802 esc_html__( 'Documentation', 'tutor' )
803 );
804 $plugin_meta[] = sprintf(
805 '<a href="%s"><strong style="color: #03bd24">%s</strong></a>',
806 esc_url( 'https://tutorlms.com/support/?utm_source=tutor&utm_medium=plugins_installation_list&utm_campaign=plugin_support_link' ),
807 esc_html__( 'Get Support', 'tutor' )
808 );
809 }
810
811 return $plugin_meta;
812 }
813
814 /**
815 * Add footer text only on tutor pages
816 *
817 * @since 1.0.0
818 *
819 * @param string $footer_text footer text.
820 *
821 * @return string
822 */
823 public function admin_footer_text( $footer_text ) {
824 $current_screen = get_current_screen();
825
826 /**
827 * We are making sure that this message will be only on Tutor Admin page
828 */
829 if ( apply_filters( 'tutor_display_admin_footer_text', ( tutor_utils()->array_get( 'parent_base', $current_screen ) === 'tutor' ) ) ) {
830 $footer_text = sprintf(
831 /* translators: %s: plugin name */
832 __( 'If you like %1$s please leave us a %2$s rating. A huge thanks in advance!', 'tutor' ),
833 sprintf( '<strong>%s</strong>', esc_html__( 'Tutor LMS', 'tutor' ) ),
834 '<a href="https://wordpress.org/support/plugin/tutor/reviews?rate=5#new-post" target="_blank" class="tutor-rating-link">&#9733;&#9733;&#9733;&#9733;&#9733;</a>'
835 );
836 }
837
838 return $footer_text;
839 }
840
841 /**
842 * Register course widget
843 *
844 * @since 1.0.0
845 * @return void
846 */
847 public function register_course_widget() {
848 register_widget( Course_Widget::class );
849 }
850
851 /**
852 * Tutor Course List
853 *
854 * @since 2.0.0
855 *
856 * @return void
857 */
858 public function tutor_course_list() {
859 include tutor()->path . 'views/pages/course-list.php';
860 }
861
862 /**
863 * Orders view page
864 *
865 * @since 3.0.0
866 *
867 * @return void
868 */
869 public function orders_view() {
870 $current_page = Input::get( 'page' );
871 $action = Input::get( 'action' );
872
873 if ( OrderController::PAGE_SLUG === $current_page && 'edit' === $action ) {
874 ?>
875 <div class="tutor-admin-wrap tutor-order-details-wrapper">
876 <div id="tutor-order-details-root">
877 </div>
878 </div>
879 <?php
880 return;
881 }
882
883 include tutor()->path . 'views/pages/ecommerce/order-list.php';
884 }
885
886 /**
887 * Coupons view page
888 *
889 * @since 3.0.0
890 *
891 * @return void
892 */
893 public function coupons_view() {
894 $action = Input::get( 'action' );
895 if ( in_array( $action, array( 'add_new', 'edit' ) ) ) {
896 ?>
897 <div class="tutor-admin-wrap">
898 <div id="tutor-coupon-root">
899 </div>
900 </div>
901 <?php
902 return;
903 }
904 include tutor()->path . 'views/pages/ecommerce/coupon-list.php';
905 }
906
907 /**
908 * Show welcome page
909 *
910 * @since 1.0.0
911 *
912 * @return void
913 */
914 public function welcome_page() {
915 Tutor_Setup::mark_as_visited();
916 include tutor()->path . 'views/pages/welcome.php';
917 exit;
918 }
919
920 /**
921 * Add toolbar items
922 *
923 * @since 1.4.6
924 *
925 * @param \WP_Admin_Bar $admin_bar admin bar object.
926 *
927 * @return mixed
928 */
929 public function add_toolbar_items( \WP_Admin_Bar $admin_bar ) {
930 global $post;
931
932 $course_id = Input::get( 'post', 0, Input::TYPE_INT );
933 $course_post_type = tutor()->course_post_type;
934
935 if ( $admin_bar->get_node( 'new-courses' ) ) {
936 $args = $admin_bar->get_node( 'new-courses' );
937 $args->href = '#';
938 $args->meta['class'] = 'tutor-create-new-course';
939 $admin_bar->add_node( $args );
940 }
941
942 if ( ! tutor_utils()->can_user_edit_course( get_current_user_id(), $course_id ) ) {
943 return $admin_bar;
944 }
945
946 if (
947 ( is_admin() && $post && $course_id && $post->post_type === $course_post_type ) ||
948 ( ! is_admin() && is_single() && $post && $course_post_type === $post->post_type )
949 ) {
950
951 $admin_bar->add_menu(
952 array(
953 'id' => 'edit',
954 'title' => __( 'Edit with Course Builder', 'tutor' ),
955 'href' => tutor_utils()->course_edit_link( $post->ID ),
956 'meta' => array(
957 'title' => __( 'Edit with Course Builder', 'tutor' ),
958 'target' => '_blank',
959 ),
960 )
961 );
962 }
963
964 return $admin_bar;
965 }
966
967 /**
968 * Redirect to welcome page if user is not logged in.
969 *
970 * @since 4.0.0
971 *
972 * @return void
973 */
974 public function redirect_to_welcome_page() {
975 // Skip for fresh installs, during the setup wizard, or during AJAX.
976 if ( ! get_option( 'tutor_wizard' ) || 'tutor-setup' === Input::get( 'page' ) || wp_doing_ajax() ) {
977 return;
978 }
979
980 $tutor_new_feature = get_option( 'tutor-new-feature' );
981 if ( version_compare( $tutor_new_feature, '4.0.0-rc.2', '>=' ) ) {
982 return;
983 }
984
985 wp_safe_redirect( admin_url( 'admin.php?page=tutor&welcome=1' ) );
986 update_option( 'tutor-new-feature', TUTOR_VERSION );
987 }
988 }
989