PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / TemplateHooks / Admin / Tools / AdminCourseTools.php

AdminCourseTools.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.8, at inc/TemplateHooks/Admin/Tools/AdminCourseTools.php

401 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Admin templates for LearnPress tools.
4 *
5 * @package LearnPress\TemplateHooks\Admin\Tools
6 * @since 4.4.6
7 * @version 1.0.0
8 */
9
10 namespace LearnPress\TemplateHooks\Admin\Tools;
11
12 use Exception;
13 use LearnPress\Databases\DataBase;
14 use LearnPress\Databases\UserItemsDB;
15 use LearnPress\Filters\UserItemsFilter;
16 use LearnPress\Helpers\Response;
17 use LearnPress\Helpers\Singleton;
18 use LearnPress\Helpers\Template;
19 use LearnPress\Models\CourseModel;
20 use LearnPress\Models\UserItems\UserCourseModel;
21 use LearnPress\Models\UserModel;
22 use LP_Helper;
23 use stdClass;
24 use Throwable;
25
26 defined( 'ABSPATH' ) || exit;
27
28 /**
29 * Class AdminCourseTools
30 *
31 * @since 4.4.6
32 * @version 1.0.1
33 */
34 class AdminCourseTools {
35 use Singleton;
36
37 /**
38 * Hooks initialization.
39 */
40 public function init(): void {
41 add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
42 }
43
44 /**
45 * Register AJAX callbacks allowed for loading content via AJAX.
46 *
47 * @param array $callbacks List of allowed callbacks.
48 *
49 * @return array
50 */
51 public function allow_callback( array $callbacks ): array {
52 $callbacks[] = self::class . ':render_courses_to_reset_progress';
53 $callbacks[] = self::class . ':render_items_to_reset_progress';
54
55 return $callbacks;
56 }
57
58 /**
59 * Render paginated list of course items (lesson, quiz, etc.) for reset progress.
60 *
61 * @param array $data Request arguments.
62 *
63 * @return stdClass
64 * @since 4.4.6
65 * @version 1.0.0
66 */
67 public static function render_items_to_reset_progress( array $data ): stdClass {
68 $content = new stdClass();
69
70 try {
71 // Check permission
72 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR ) ) {
73 throw new Exception( __( 'You do not have permission to perform this action.', 'learnpress' ) );
74 }
75
76 $item_selecting = $data['item_selecting'] ?? [];
77 $search_item = trim( $data['lp-search-item'] ?? '' );
78 $search_course = trim( $data['lp-search-course'] ?? '' );
79 $search_user = trim( $data['lp-search-user'] ?? '' );
80 $item_type = trim( $data['lp-item-type'] ?? '' );
81 $paged = max( 1, intval( $data['paged'] ?? 1 ) );
82
83 $selected_compare = new stdClass();
84 if ( ! empty( $item_selecting ) && is_array( $item_selecting ) ) {
85 foreach ( $item_selecting as $item ) {
86 if ( ! isset( $item['id'] ) ) {
87 continue;
88 }
89 $selected_compare->{$item['id']} = true;
90 }
91 }
92
93 $limit = 10;
94
95 $db = UserItemsDB::getInstance();
96 $total_rows = 0;
97 $filter = new UserItemsFilter();
98 $filter->limit = $limit;
99 $filter->page = $paged;
100 $filter->only_fields = [
101 'DISTINCT(ui.user_item_id)',
102 'ui.item_id',
103 'ui.user_id',
104 'ui.item_type',
105 'ui.ref_id',
106 ];
107
108 // Filter by ref_type = course (items belong to a course)
109 $filter->ref_type = LP_COURSE_CPT;
110
111 // Get only user_id > 0
112 $filter->where[] = 'AND ui.user_id > 0';
113
114 // Filter by item type
115 if ( ! empty( $item_type ) ) {
116 $filter->item_type = $item_type;
117 } else {
118 $item_types = CourseModel::item_types_support();
119 $types_format = LP_Helper::db_format_array( $item_types, '%s' );
120 // phpcs:disable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
121 $filter->where[] = $db->wpdb->prepare(
122 'AND ui.item_type IN (' . $types_format . ')',
123 ...$item_types
124 );
125 // phpcs:enable WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
126 }
127
128 // Search item by title
129 if ( ! empty( $search_item ) ) {
130 $filter->join[] = "INNER JOIN {$db->tb_posts} AS p ON ui.item_id = p.ID";
131 $filter->where[] = $db->wpdb->prepare(
132 'AND p.post_title LIKE %s',
133 '%' . $db->wpdb->esc_like( $search_item ) . '%'
134 );
135 }
136
137 // Search course by title
138 if ( ! empty( $search_course ) ) {
139 $filter->join[] = "INNER JOIN {$db->tb_posts} AS pc ON ui.ref_id = pc.ID";
140 $filter->where[] = $db->wpdb->prepare(
141 'AND pc.post_title LIKE %s',
142 '%' . $db->wpdb->esc_like( $search_course ) . '%'
143 );
144 }
145
146 // Search user
147 if ( ! empty( $search_user ) ) {
148 $filter->join[] = "INNER JOIN {$db->tb_users} AS u ON ui.user_id = u.ID";
149 $esc_search_user = '%' . $db->wpdb->esc_like( $search_user ) . '%';
150 $filter->where[] = $db->wpdb->prepare(
151 'AND (u.display_name LIKE %s OR u.user_login LIKE %s OR u.user_email LIKE %s)',
152 $esc_search_user,
153 $esc_search_user,
154 $esc_search_user
155 );
156 }
157
158 $userItems = $db->get_user_items( $filter, $total_rows );
159 $total_pages = DataBase::get_total_pages( $limit, $total_rows );
160
161 $html_lis = '';
162 if ( empty( $userItems ) ) {
163 $html_lis = Template::print_message(
164 esc_html__( 'No data found', 'learnpress' ),
165 'info',
166 false
167 );
168 } else {
169 foreach ( $userItems as $userItem ) {
170 $user_item_id = intval( $userItem->user_item_id ?? 0 );
171 if ( empty( $user_item_id ) ) {
172 continue;
173 }
174
175 $checked = '';
176 if ( isset( $selected_compare->{$user_item_id} ) ) {
177 $checked = ' checked="checked"';
178 }
179
180 $item_title_raw = get_the_title( $userItem->item_id );
181 $item_title = $item_title_raw ? $item_title_raw : __( 'Unknown', 'learnpress' );
182 $course_title_raw = get_the_title( $userItem->ref_id );
183 $course_title = $course_title_raw ? $course_title_raw : __( 'Unknown', 'learnpress' );
184 $userModel = UserModel::find( $userItem->user_id, true );
185 $user_name = $userModel ? $userModel->get_display_name() : __( 'Unknown', 'learnpress' );
186
187 $title_display = sprintf(
188 '<span class="title">%s <strong>(#%d)</strong> - %s - %s (#%d)</span>',
189 esc_html( $item_title ),
190 esc_html( $userItem->item_id ),
191 esc_html( $course_title ),
192 esc_html( $user_name ),
193 esc_html( $userItem->user_id )
194 );
195
196 $html_lis .= sprintf(
197 '<li class="lp-select-item">%s%s</li>',
198 sprintf(
199 '<input name="lp-select-item"
200 value="%1$s"
201 data-id="%1$d"
202 data-title="%2$s"
203 %3$s
204 type="checkbox" />',
205 esc_attr( $user_item_id ),
206 esc_attr( $title_display ),
207 esc_attr( $checked )
208 ),
209 $title_display,
210 );
211 }
212 }
213
214 $section = [
215 'ul' => '<ul class="list-items">',
216 'items' => $html_lis,
217 'ul_end' => '</ul>',
218 'pagination' => Template::instance()->html_pagination(
219 [
220 'total_pages' => $total_pages,
221 'paged' => $paged,
222 ]
223 ),
224 ];
225
226 $content->content = Template::combine_components( $section );
227 } catch ( Throwable $exception ) {
228 $content->content = Template::print_message(
229 $exception->getMessage(),
230 Response::STATUS_ERROR,
231 false
232 );
233 }
234
235 return $content;
236 }
237
238 /**
239 * Render paginated list of courses that have enrolled users.
240 *
241 * @param array $data Request arguments.
242 *
243 * @return stdClass
244 * @since 4.4.6
245 * @version 1.0.1
246 */
247 public static function render_courses_to_reset_progress( array $data ): stdClass {
248 $content = new stdClass();
249
250 try {
251 // Check permission
252 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR ) ) {
253 throw new Exception( 'Access denied.' );
254 }
255
256 $item_selecting = $data['item_selecting'] ?? [];
257 $search_course = trim( $data['lp-search-course'] ?? '' );
258 $search_user = trim( $data['lp-search-user'] ?? '' );
259 $paged = max( 1, intval( $data['paged'] ?? 1 ) );
260
261 $selected_compare = new stdClass();
262 if ( ! empty( $item_selecting ) && is_array( $item_selecting ) ) {
263 foreach ( $item_selecting as $item ) {
264 if ( ! isset( $item['id'] ) ) {
265 continue;
266 }
267 $selected_compare->{$item['id']} = true;
268 }
269 }
270
271 $limit = 10;
272
273 $db = UserItemsDB::getInstance();
274 $total_rows = 0;
275 $filter = new UserItemsFilter();
276 $filter->limit = $limit;
277 $filter->page = $paged;
278 $filter->item_type = LP_COURSE_CPT;
279 $filter->only_fields = [ 'DISTINCT(ui.user_item_id)', 'ui.item_id', 'ui.user_id' ];
280
281 // Get only courses has items attendance
282 $filter_course_attendance = new UserItemsFilter();
283 $filter_course_attendance->only_fields = [ 'parent_id' ];
284 $filter_course_attendance->ref_type = LP_COURSE_CPT;
285 $filter_course_attendance->return_string_query = 1;
286 $filter_course_attendance->limit = -1;
287 $query_course_attendance = $db->get_user_items( $filter_course_attendance );
288 $filter->where[] = sprintf(
289 'AND ui.user_item_id IN (%s)',
290 $query_course_attendance
291 );
292 // End get only courses has items attendance
293
294 // Get only user_id > 0
295 $filter->where[] = 'AND ui.user_id > 0';
296
297 // Search course
298 if ( ! empty( $search_course ) ) {
299 $filter->only_fields[] = 'post_title';
300 $filter->join[] = "INNER JOIN {$db->tb_lp_courses} AS c ON ui.item_id = c.ID";
301 $filter->where[] = $db->wpdb->prepare(
302 'AND c.post_title LIKE %s',
303 '%' . $db->wpdb->esc_like( $search_course ) . '%'
304 );
305 }
306
307 // Search user
308 if ( ! empty( $search_user ) ) {
309 $filter->join[] = "INNER JOIN {$db->tb_users} AS u ON ui.user_id = u.ID";
310 $esc_search_user = '%' . $db->wpdb->esc_like( $search_user ) . '%';
311 $filter->where[] = $db->wpdb->prepare(
312 'AND (u.display_name LIKE %s OR u.user_login LIKE %s OR u.user_email LIKE %s)',
313 $esc_search_user,
314 $esc_search_user,
315 $esc_search_user
316 );
317 }
318
319 $userCourses = $db->get_user_items( $filter, $total_rows );
320 $total_pages = DataBase::get_total_pages( $limit, $total_rows );
321
322 $html_lis = '';
323 if ( empty( $userCourses ) ) {
324 $html_lis = Template::print_message(
325 esc_html__( 'No data found', 'learnpress' ),
326 'info',
327 false
328 );
329 } else {
330 foreach ( $userCourses as $userCourse ) {
331 $userCourseModel = UserCourseModel::find( $userCourse->user_id, $userCourse->item_id, true );
332 if ( ! $userCourseModel ) {
333 continue;
334 }
335
336 $courseModel = $userCourseModel->get_course_model();
337 $checked = '';
338 if ( isset( $selected_compare->{$userCourseModel->get_user_item_id()} ) ) {
339 $checked = ' checked="checked"';
340 }
341
342 $userModel = $userCourseModel->get_user_model();
343 $user_id = $userModel ? $userModel->get_id() : 0;
344
345 $students_text = sprintf(
346 /* translators: %d: number of enrolled students */
347 __( '%1$s (#%2$d)', 'learnpress' ),
348 $user_id ? $userModel->get_display_name() : esc_html__( 'Unknown', 'learnpress' ),
349 $user_id
350 );
351
352 $title_display = sprintf(
353 '<span class="title">%s<strong>(#%d - %s)</strong></span>',
354 esc_html( $courseModel ? $courseModel->get_title() : __( 'Unknown', 'learnpress' ) ),
355 esc_html( $courseModel ? $courseModel->get_id() : 0 ),
356 esc_html( $students_text )
357 );
358
359 $html_lis .= sprintf(
360 '<li class="lp-select-item">%s%s</li>',
361 sprintf(
362 '<input name="lp-select-item"
363 value="%1$s"
364 data-id="%1$d"
365 data-title="%2$s"
366 %3$s
367 type="checkbox" />',
368 esc_attr( $userCourseModel->get_user_item_id() ),
369 esc_attr( $title_display ),
370 esc_attr( $checked )
371 ),
372 $title_display,
373 );
374 }
375 }
376
377 $section = [
378 'ul' => '<ul class="list-items">',
379 'items' => $html_lis,
380 'ul_end' => '</ul>',
381 'pagination' => Template::instance()->html_pagination(
382 [
383 'total_pages' => $total_pages,
384 'paged' => $paged,
385 ]
386 ),
387 ];
388
389 $content->content = Template::combine_components( $section );
390 } catch ( Throwable $exception ) {
391 $content->content = Template::print_message(
392 $exception->getMessage(),
393 Response::STATUS_ERROR,
394 false
395 );
396 }
397
398 return $content;
399 }
400 }
401