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 / AdminListStudentsEnrolled.php

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

713 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\TemplateHooks\Admin;
4
5 use Exception;
6 use LearnPress\Databases\UserItemsDB;
7 use LearnPress\Filters\UserItemsFilter;
8 use LearnPress\Helpers\Singleton;
9 use LearnPress\Helpers\Template;
10 use LearnPress\Models\CourseModel;
11 use LearnPress\Models\UserItems\UserCourseModel;
12 use LearnPress\Models\UserItems\UserItemModel;
13 use LearnPress\Models\UserModel;
14 use LearnPress\TemplateHooks\Instructor\SingleInstructorTemplate;
15 use LearnPress\TemplateHooks\Table\TableListTemplate;
16 use LearnPress\TemplateHooks\TemplateAJAX;
17 use LearnPress\TemplateHooks\UserItem\UserCourseTemplate;
18 use LP_Debug;
19 use LP_Helper;
20 use LP_Page_Controller;
21 use LP_Request;
22 use stdClass;
23 use Throwable;
24
25 /**
26 * Template Admin List Students Enrolled.
27 *
28 * Displays enrolled students for Admin (all courses) and Instructor (own courses only).
29 * Provides WP Admin submenu + Frontend profile tab.
30 *
31 * @since 4.3.3
32 * @version 1.0.1
33 */
34 class AdminListStudentsEnrolled {
35 use Singleton;
36
37 const PER_PAGE = 10;
38
39 public function init(): void {
40 // 2. Whitelist AJAX callback.
41 add_filter( 'lp/rest/ajax/allow_callback', array( $this, 'allow_callback' ) );
42 // 4. Render a modal toolbar template from PHP (used by JS modal).
43 add_action( 'admin_footer', array( $this, 'print_modal_toolbar_template' ) );
44 add_action( 'wp_footer', array( $this, 'print_modal_toolbar_template' ) );
45 }
46
47 /**
48 * Admin page output callback.
49 */
50 public function admin_page_output() {
51 ob_start();
52 $this->enrolled_students_layout();
53 $content = ob_get_clean();
54
55 echo AdminTemplate::html_on_wp_admin_screen(
56 array(
57 'content' => $content,
58 'title' => __( 'Students', 'learnpress' ),
59 'id' => 'lp-enrolled-students',
60 )
61 );
62 }
63
64 /**
65 * Allow callback for AJAX.
66 *
67 * @param array $callbacks
68 *
69 * @return array
70 */
71 public function allow_callback( array $callbacks ): array {
72 $callbacks[] = get_class( $this ) . ':render_enrolled_students';
73
74 return $callbacks;
75 }
76
77 /**
78 * Render initial layout with TemplateAJAX::load_content_via_ajax().
79 */
80 public function enrolled_students_layout() {
81 try {
82 $page_current = '';
83 if ( function_exists( 'get_current_screen' ) ) {
84 $wp_screen = get_current_screen();
85 if ( $wp_screen ) {
86 // Page on the Admin screen.
87 if ( $wp_screen->id === 'learnpress_page_learn-press-students-enrolled' ) {
88 $page_current = 'learnpress_page_learn-press-students-enrolled';
89 }
90 }
91 }
92
93 $args = array(
94 'id_url' => 'lp-enrolled-students',
95 'course_id' => LP_Request::get_param( 'course_id', 0 ),
96 'course_name' => LP_Request::get_param( 'course_name' ),
97 'paged' => 1,
98 'search' => lp_request::get_param( 'search' ),
99 'start_date' => LP_Request::get_param( 'start_date' ),
100 'end_date' => LP_Request::get_param( 'end_date' ),
101 'enableUpdateParamsUrl' => false,
102 );
103
104 $call_back = array(
105 'class' => self::class,
106 'method' => 'render_enrolled_students',
107 );
108
109 $section = [
110 'wrap' => sprintf(
111 '<div class="lp-students-enrolled-layout %s">',
112 $page_current
113 ),
114 'toolbar' => $this->html_toolbar(),
115 'table' => TemplateAJAX::load_content_via_ajax( $args, $call_back ),
116 'wrap-end' => '</div>',
117 ];
118
119 echo Template::combine_components( $section );
120 } catch ( Throwable $e ) {
121 Template::print_message( $e->getMessage(), 'error' );
122 }
123 }
124
125 /**
126 * Static render method called by AJAX — returns stdClass{ content }.
127 *
128 * Permission check: Admin=full, Instructor=own courses only.
129 *
130 * @param array $data
131 *
132 * @return stdClass
133 */
134 public static function render_enrolled_students( array $data ): stdClass {
135 $content = new stdClass();
136 $content->content = '';
137
138 try {
139 // Check permission
140 if ( ! current_user_can( UserModel::ROLE_ADMINISTRATOR )
141 && ! current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
142 throw new Exception( esc_html__( 'You do not have permission to view enrolled students.', 'learnpress' ) );
143 }
144
145 $course_id = abs( LP_Helper::sanitize_params_submitted( $data['course_id'] ?? 0, 'int' ) );
146 $paged = max( 1, abs( LP_Helper::sanitize_params_submitted( $data['paged'] ?? 1, 'int' ) ) );
147 $course_name = LP_Helper::sanitize_params_submitted( $data['course_name'] ?? '' );
148 $search = LP_Helper::sanitize_params_submitted( $data['search'] ?? '' );
149 $start_date = lp_helper::sanitize_params_submitted( $data['start_date'] ?? '' );
150 $end_date = lp_helper::sanitize_params_submitted( $data['end_date'] ?? '' );
151 $per_page = self::PER_PAGE;
152
153 // Normalize date range if request is reversed.
154 if ( $start_date && $end_date && strtotime( $start_date ) > strtotime( $end_date ) ) {
155 $tmp = $start_date;
156 $start_date = $end_date;
157 $end_date = $tmp;
158 }
159
160 $lp_db_user_items = UserItemsDB::getInstance();
161 $filter = new UserItemsFilter();
162 $filter->item_type = LP_COURSE_CPT;
163 $filter->statues = array( 'enrolled', 'finished' );
164 $filter->limit = $per_page;
165 $filter->page = $paged;
166 $filter->order_by = 'ui.start_time';
167 $filter->order = 'DESC';
168 $filter->field_count = 'ui.user_item_id';
169 $filter->only_fields = array(
170 'ui.user_item_id',
171 'ui.user_id',
172 'ui.item_id',
173 'ui.start_time',
174 'ui.status',
175 'ui.graduation',
176 'u.display_name',
177 'u.user_email',
178 'p.post_title AS course_title',
179 );
180 $filter->join[] = "JOIN {$lp_db_user_items->wpdb->posts} p ON ui.item_id = p.ID";
181 $filter->join[] = "JOIN {$lp_db_user_items->wpdb->users} u ON ui.user_id = u.ID";
182
183 $instructor_id = get_current_user_id();
184 if ( $instructor_id > 0 && current_user_can( UserModel::ROLE_INSTRUCTOR ) ) {
185 $filter->where[] = $lp_db_user_items->wpdb->prepare( 'AND p.post_author = %d', $instructor_id );
186 }
187
188 if ( $course_id > 0 ) {
189 $filter->item_id = $course_id;
190 } elseif ( ! empty( $course_name ) ) {
191 $course_name_like = '%' . $lp_db_user_items->wpdb->esc_like( $course_name ) . '%';
192 $filter->where[] = $lp_db_user_items->wpdb->prepare(
193 'AND p.post_title LIKE %s',
194 $course_name_like
195 );
196 }
197
198 if ( ! empty( $search ) ) {
199 $search_like = '%' . $lp_db_user_items->wpdb->esc_like( $search ) . '%';
200 $filter->where[] = $lp_db_user_items->wpdb->prepare(
201 'AND ( u.display_name LIKE %s OR u.user_email LIKE %s )',
202 $search_like,
203 $search_like
204 );
205 }
206
207 if ( ! empty( $start_date ) ) {
208 $filter->where[] = $lp_db_user_items->wpdb->prepare(
209 'AND ui.start_time >= %s',
210 $start_date . ' 00:00:00'
211 );
212 }
213
214 if ( ! empty( $end_date ) ) {
215 $filter->where[] = $lp_db_user_items->wpdb->prepare(
216 'AND ui.start_time <= %s',
217 $end_date . ' 23:59:59'
218 );
219 }
220
221 $filter = apply_filters(
222 'learn-press/filter-enrolled-students',
223 $filter
224 );
225 $total_rows = 0;
226 $rows = $lp_db_user_items->get_user_items( $filter, $total_rows );
227 if ( ! is_array( $rows ) ) {
228 $rows = array();
229 }
230
231 // Build HTML.
232 $html = self::instance()->html_table(
233 $rows,
234 array(
235 'total' => $total_rows,
236 'paged' => $paged,
237 'per_page' => $per_page,
238 'students-of-course' => $course_id,
239 )
240 );
241
242 $content->content = $html;
243 } catch ( Throwable $e ) {
244 $content->content = Template::print_message( $e->getMessage(), 'error', false );
245 LP_Debug::error_log( $e );
246 }
247
248 return $content;
249 }
250
251 /**
252 * HTML builder: toolbar (course filter, search).
253 *
254 * @return string
255 */
256 public function html_toolbar(): string {
257 $courses = array();
258
259 $data_get = LP_Helper::sanitize_params_submitted( $_GET );
260 $selected_course = abs( LP_Helper::sanitize_params_submitted( $data_get['course_id'] ?? 0, 'int' ) );
261 $search_course = LP_Helper::sanitize_params_submitted( $data_get['course_name'] ?? '' );
262 $search_student = LP_Helper::sanitize_params_submitted( $data_get['search'] ?? '' );
263 $search_start = lp_helper::sanitize_params_submitted( $data_get['start_date'] ?? '' );
264 $search_end = lp_helper::sanitize_params_submitted( $data_get['end_date'] ?? '' );
265
266 $html_fields = sprintf(
267 '<div class="filter-field">
268 <label for="lp-enrolled-filter-course-name">%s</label>
269 <input id="lp-enrolled-filter-course-name"
270 class="lp-enrolled-filter-course-name"
271 type="text"
272 name="course_name"
273 list="lp-enrolled-course-list"
274 value="%s"
275 placeholder="%s">
276 </div>
277 <div class="filter-field">
278 <label for="lp-enrolled-search-input">%s</label>
279 <input id="lp-enrolled-search-input"
280 class="lp-enrolled-search-input"
281 type="text"
282 name="search" value="%s" placeholder="%s">
283 </div>
284 <div class="filter-field">
285 <label for="lp-enrolled-filter-start-date">%s</label>
286 <input id="lp-enrolled-filter-start-date"
287 class="lp-enrolled-filter-start-date"
288 type="date" name="start_date"
289 value="%s"
290 placeholder="mm/dd/yyyy">
291 </div>
292 <div class="filter-field">
293 <label for="lp-enrolled-filter-end-date">%s</label>
294 <input id="lp-enrolled-filter-end-date" class="lp-enrolled-filter-end-date" type="date" name="end_date" value="%s" placeholder="mm/dd/yyyy">
295 </div>
296 <datalist id="lp-enrolled-course-list">%s</datalist>',
297 esc_html__( 'Course Filter', 'learnpress' ),
298 esc_attr( $search_course ),
299 esc_attr__( 'Search course...', 'learnpress' ),
300 esc_html__( 'Student', 'learnpress' ),
301 esc_attr( $search_student ),
302 esc_attr__( 'Enter student name or email', 'learnpress' ),
303 esc_html__( 'Start Date', 'learnpress' ),
304 esc_attr( $search_start ),
305 esc_html__( 'End date', 'learnpress' ),
306 esc_attr( $search_end ),
307 ''
308 );
309
310 $html_btn_actions = sprintf(
311 '<button type="button" class="lp-button lp-enrolled-btn-search">%s</button>
312 <button type="button" class="lp-button lp-enrolled-btn-clear">%s</button>',
313 esc_html__( 'Search', 'learnpress' ),
314 esc_html__( 'Clear Filter', 'learnpress' )
315 );
316
317 $html_toolbar = AdminTemplate::html_form_filter(
318 array(
319 'form_classes' => 'lp-enrolled-students-form',
320 'fields' => $html_fields,
321 'btn_actions' => $html_btn_actions,
322 )
323 );
324
325 return apply_filters(
326 'learn-press/admin/enrolled-students/toolbar/section',
327 $html_toolbar,
328 $courses,
329 $selected_course
330 );
331 }
332
333 /**
334 * Render toolbar used inside View Students modal.
335 *
336 * @return string
337 */
338 public function html_toolbar_modal(): string {
339 $html_fields = sprintf(
340 '<div class="filter-field">
341 <label for="lp-modal-enrolled-search-input">%s</label>
342 <input id="lp-modal-enrolled-search-input"
343 class="lp-enrolled-search-input"
344 type="text" name="search" placeholder="%s">
345 </div>
346 <div class="filter-field">
347 <label for="lp-modal-enrolled-filter-start-date">%s</label>
348 <input id="lp-modal-enrolled-filter-start-date"
349 class="lp-enrolled-filter-start-date"
350 type="date" name="start_date" placeholder="mm/dd/yyyy">
351 </div>
352 <div class="filter-field">
353 <label for="lp-modal-enrolled-filter-end-date">%s</label>
354 <input id="lp-modal-enrolled-filter-end-date"
355 class="lp-enrolled-filter-end-date"
356 type="date" name="end_date" placeholder="mm/dd/yyyy">
357 </div>',
358 esc_html__( 'Student', 'learnpress' ),
359 esc_attr__( 'Enter student name or email', 'learnpress' ),
360 esc_html__( 'Start Date', 'learnpress' ),
361 esc_html__( 'End Date', 'learnpress' )
362 );
363
364 $html_btn_actions = sprintf(
365 '<button type="button" class="lp-button lp-enrolled-btn-search-modal">%s</button>
366 <button type="button" class="lp-button lp-enrolled-btn-clear-modal">%s</button>',
367 esc_html__( 'Search', 'learnpress' ),
368 esc_html__( 'Clear Filter', 'learnpress' )
369 );
370
371 return AdminTemplate::html_form_filter(
372 array(
373 'id' => 'lp-modal-enrolled-form',
374 'form_classes' => 'lp-enrolled-students-form lp-enrolled-students-form--modal lp-enrolled-students-table-toolbar--modal',
375 'fields' => $html_fields,
376 'btn_actions' => $html_btn_actions,
377 )
378 );
379 }
380
381 /**
382 * Render lp-target layout used in View Students modal.
383 *
384 * @return string
385 */
386 public function html_modal_students_target(): string {
387 $args = array(
388 'id_url' => 'lp-modal-enrolled-students',
389 'course_id' => 0,
390 'paged' => 1,
391 'enableScrollToView' => false,
392 'enableUpdateParamsUrl' => false,
393 'html_no_load_ajax_first' => sprintf(
394 '<div class="learn-press-message" style="%s">%s</div>',
395 'width: 95%;',
396 esc_html__( 'Loading', 'learnpress' )
397 ),
398 );
399
400 $call_back = array(
401 'class' => self::class,
402 'method' => 'render_enrolled_students',
403 );
404
405 $section = array(
406 'wrap' => '<div id="lp-modal-enrolled-wrap">',
407 'target' => TemplateAJAX::load_content_via_ajax( $args, $call_back ),
408 'wrap-end' => '</div>',
409 );
410
411 return Template::combine_components( $section );
412 }
413
414 /**
415 * Print HTML template for modal toolbar.
416 *
417 * @return void
418 */
419 public function print_modal_toolbar_template() {
420
421 $should_print = false;
422
423 if ( is_admin() ) {
424 $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
425 if ( $screen && isset( $screen->id ) && $screen->id === 'edit-' . LP_COURSE_CPT ) {
426 $should_print = true;
427 }
428 } elseif ( class_exists( 'LP_Page_Controller' ) && defined( 'LP_PAGE_PROFILE' ) ) {
429 $should_print = LP_Page_Controller::page_current() === LP_PAGE_PROFILE;
430 }
431
432 if ( ! $should_print ) {
433 return;
434 }
435
436 echo '<script type="text/html" id="lp-tmpl-enrolled-students-toolbar-modal">';
437 echo $this->html_toolbar_modal();
438 echo '</script>';
439
440 echo '<script type="text/html" id="lp-tmpl-enrolled-students-target-modal">';
441 echo $this->html_modal_students_target();
442 echo '</script>';
443 }
444
445 /**
446 * HTML builder: table wrapper.
447 *
448 * @param array $rows DB result rows.
449 * @param array $meta [ total, paged, per_page ].
450 *
451 * @return string
452 */
453 private function html_table( array $rows, array $meta ): string {
454 if ( empty( $rows ) ) {
455 $section_empty = array(
456 'wrap' => '<div class="lp-enrolled-students-table-wrap">',
457 'empty' => sprintf(
458 '<div class="lp-enrolled-empty"><p>%s</p></div>',
459 esc_html__( 'No students found.', 'learnpress' )
460 ),
461 'wrap-end' => '</div>',
462 );
463 $section_empty = apply_filters(
464 'learn-press/admin/enrolled-students/table/empty/section',
465 $section_empty,
466 $rows,
467 $meta
468 );
469
470 return Template::combine_components( $section_empty );
471 }
472
473 $rows_html = array();
474
475 $results_map = array();
476 foreach ( $rows as $item ) {
477 $userCourseModel = new UserCourseModel( $item );
478 $rows_html[] = $this->html_student_row( $userCourseModel, $meta );
479 }
480 $rows_html = apply_filters(
481 'learn-press/admin/enrolled-students/table/rows-html',
482 $rows_html,
483 $rows,
484 $results_map,
485 $meta
486 );
487
488 $table_args = array(
489 'class_table' => 'lp-enrolled-students-table',
490 'header' => array(
491 'student' => array(
492 'class' => 'lp-col-student',
493 'title' => esc_html__( 'Student', 'learnpress' ),
494 ),
495 'course' => array(
496 'class' => 'lp-col-course',
497 'title' => esc_html__( 'Course', 'learnpress' ),
498 ),
499 'date' => array(
500 'class' => 'lp-col-date',
501 'title' => esc_html__( 'Enrolled Date', 'learnpress' ),
502 ),
503 'progress' => array(
504 'class' => 'lp-col-progress',
505 'title' => esc_html__( 'Progress', 'learnpress' ),
506 ),
507 'status' => array(
508 'class' => 'lp-col-status',
509 'title' => esc_html__( 'Status', 'learnpress' ),
510 ),
511 ),
512 'body' => array(
513 'rows_html' => Template::combine_components( $rows_html ),
514 ),
515 );
516 $section_footer = array(
517 'wrap' => '<div class="lp-enrolled-students-table-footer">',
518 'page_result' => sprintf(
519 '<span class="lp-enrolled-students-table-footer__count">%s</span>',
520 TableListTemplate::instance()->html_page_result(
521 array(
522 'paged' => $meta['paged'],
523 'per_page' => $meta['per_page'],
524 'total_rows' => $meta['total'],
525 'item_name' => _n( 'student', 'students', $meta['total'], 'learnpress' ),
526 )
527 )
528 ),
529 'pagination' => $this->html_pagination( $meta['total'], $meta['paged'], $meta['per_page'] ),
530 'wrap-end' => '</div>',
531 );
532 $section_footer = apply_filters(
533 'learn-press/admin/enrolled-students/table/footer/section',
534 $section_footer,
535 $rows,
536 $results_map,
537 $meta
538 );
539 $table_args['footer'] = Template::combine_components( $section_footer );
540 $table_args = apply_filters(
541 'learn-press/admin/enrolled-students/table/args',
542 $table_args,
543 $rows,
544 $results_map,
545 $meta
546 );
547
548 if ( ! empty( $meta['students-of-course'] ) ) {
549 unset( $table_args['header']['course'] ); // Remove Course column if filtering by course, as it's redundant.
550 }
551
552 $section = array(
553 'wrap' => '<div class="lp-enrolled-students-table-wrap">',
554 'table' => TableListTemplate::instance()->html_table( $table_args ),
555 'wrap-end' => '</div>',
556 );
557 $section = apply_filters(
558 'learn-press/admin/enrolled-students/table/section',
559 $section,
560 $rows,
561 $results_map,
562 $meta
563 );
564
565 return Template::combine_components( $section );
566 }
567
568 /**
569 * HTML builder: single student row.
570 *
571 * @param UserCourseModel $userCourseModel
572 *
573 * @return string
574 */
575 private function html_student_row( UserCourseModel $userCourseModel, array $data = [] ): string {
576 // Avatar initials.
577 $userModel = $userCourseModel->get_user_model();
578 if ( ! $userModel instanceof UserModel ) {
579 return '';
580 }
581
582 $courseModel = $userCourseModel->get_course_model();
583 if ( ! $courseModel instanceof CourseModel ) {
584 return '';
585 }
586
587 // Progress.
588 $course_result = $userCourseModel->calculate_course_results();
589 $progress = (float) ( $course_result['result'] ?? 0 );
590
591 // Status badge.
592 $graduation = $userCourseModel->get_graduation();
593 $status_raw = $graduation !== UserItemModel::GRADUATION_IN_PROGRESS
594 ? $userCourseModel->get_graduation()
595 : $userCourseModel->get_status();
596 $status_label = ucfirst( str_replace( array( '-', '_' ), ' ', $status_raw ) );
597 $badge_class = 'lp-badge--' . sanitize_html_class( $status_raw );
598
599 // Date.
600 $date = UserCourseTemplate::instance()->html_start_date_time( $userCourseModel, false );
601
602 $user_display_name = $userModel->get_display_name();
603 if ( empty( $user_display_name ) ) {
604 $user_display_name = $userModel->get_username();
605 }
606
607 $section = array(
608 'row' => '<tr>',
609 'student-cell-open' => '<td><div class="lp-cell-student">',
610 'avatar' => SingleInstructorTemplate::instance()->html_avatar( $userModel ),
611 'meta-open' => '<div class="lp-meta">',
612 'name' => sprintf(
613 '<span class="lp-name">%s</span>',
614 esc_html( $user_display_name )
615 ),
616 'email' => sprintf(
617 '<span class="lp-email">%s</span>',
618 esc_html( $userModel->get_email() )
619 ),
620 'meta-close' => '</div>',
621 'student-cell-close' => '</div></td>',
622 'course-cell' => sprintf(
623 '<td class="lp-cell-course"><a href="%s">%s</a></td>',
624 esc_url_raw( $courseModel->get_permalink() ),
625 $courseModel->get_title()
626 ),
627 'date-cell' => sprintf(
628 '<td class="lp-cell-date">%s</td>',
629 wp_kses_post( $date )
630 ),
631 'progress-cell-open' => '<td class="lp-cell-progress">',
632 'progress-bar' => sprintf(
633 '<div class="lp-progress-bar"><span class="" style="width: %d%%;"></span></div>',
634 $progress
635 ),
636 'progress-text' => sprintf(
637 '<span class="lp-progress-text">%d%%</span>',
638 $progress
639 ),
640 'progress-cell-close' => '</td>',
641 'status-cell-open' => '<td class="lp-cell-status">',
642 'status-badge' => sprintf(
643 '<span class="lp-badge %s">%s</span>',
644 esc_attr( $badge_class ),
645 esc_html( $status_label )
646 ),
647 'status-cell-close' => '</td>',
648 'row-end' => '</tr>',
649 );
650
651 if ( ! empty( $data['students-of-course'] ) ) {
652 unset( $section['course-cell'] ); // Remove Course cell if filtering by course, as it's redundant.
653 }
654
655 $section = apply_filters(
656 'learn-press/admin/enrolled-students/row/section',
657 $section,
658 $userCourseModel
659 );
660
661 return Template::combine_components( $section );
662 }
663
664 /**
665 * HTML builder: pagination.
666 *
667 * Uses .page-numbers class for loadAJAX.js compatibility.
668 *
669 * @param int $total
670 * @param int $paged
671 * @param int $per_page
672 *
673 * @return string
674 */
675 private function html_pagination( int $total, int $paged, int $per_page ): string {
676 $total_pages = max( 1, ceil( $total / $per_page ) );
677
678 $pagination_items = Template::instance()->html_pagination(
679 array(
680 'total_pages' => $total_pages,
681 'paged' => $paged,
682 'wrapper' => array(
683 '<nav class="learn-press-pagination navigation pagination lp-pagination">' => '</nav>',
684 ),
685 )
686 );
687 $pagination_items = apply_filters(
688 'learn-press/admin/enrolled-students/pagination/items',
689 $pagination_items,
690 $total,
691 $paged,
692 $per_page,
693 $total_pages
694 );
695
696 $section = array(
697 'wrap' => '<div class="lp-enrolled-students-table-footer__pagination">',
698 'pagination' => $pagination_items,
699 'wrap-end' => '</div>',
700 );
701 $section = apply_filters(
702 'learn-press/admin/enrolled-students/pagination/section',
703 $section,
704 $total,
705 $paged,
706 $per_page,
707 $total_pages
708 );
709
710 return Template::combine_components( $section );
711 }
712 }
713