PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.6
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.6
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 / Course / AdminEditCurriculumTemplate.php

AdminEditCurriculumTemplate.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.6, at inc/TemplateHooks/Course/AdminEditCurriculumTemplate.php

742 lines 21.7 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\Course;
4
5 use Exception;
6 use LearnPress\Databases\DataBase;
7 use LearnPress\Databases\PostDB;
8 use LearnPress\Filters\PostFilter;
9 use LearnPress\Helpers\Singleton;
10 use LearnPress\Helpers\Template;
11 use LearnPress\Models\CourseModel;
12 use LearnPress\Models\CoursePostModel;
13 use LearnPress\Models\PostModel;
14 use LearnPress\Models\UserModel;
15 use LearnPress\TemplateHooks\Admin\AdminTemplate;
16 use LearnPress\TemplateHooks\TemplateAJAX;
17 use stdClass;
18
19 /**
20 * Template hooks Admin Edit Course Curriculum.
21 *
22 * @since 4.2.8.6
23 * @version 1.0.1
24 */
25 class AdminEditCurriculumTemplate {
26 use Singleton;
27
28 /**
29 * Course model.
30 *
31 * @var CourseModel
32 */
33 public $courseModel;
34
35 /**
36 * Context data from AJAX request.
37 * Contains flags like is_course_builder.
38 *
39 * @var array
40 */
41 public $context_data = [];
42
43 public function init(): void {
44 add_action( 'learn-press/admin/edit-curriculum/layout', [ $this, 'edit_course_curriculum_layout' ] );
45 add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
46 }
47
48 /**
49 * Layout for edit course curriculum.
50 *
51 * @since 4.2.8.6
52 * @version 1.0.1
53 *
54 * @param CourseModel $courseModel
55 * @param array $context Additional context merged into AJAX args (e.g. ['is_course_builder' => true]).
56 */
57 public function edit_course_curriculum_layout( CourseModel $courseModel, array $context = [] ) {
58 wp_enqueue_style( 'lp-edit-curriculum' );
59 wp_enqueue_script( 'lp-edit-course' );
60
61 $args = array_merge(
62 [
63 'id_url' => 'edit-course-curriculum',
64 'course_id' => $courseModel->ID,
65 ],
66 $context
67 );
68
69 $call_back = [
70 'class' => self::class,
71 'method' => 'render_edit_course_curriculum',
72 ];
73
74 echo TemplateAJAX::load_content_via_ajax( $args, $call_back );
75 }
76
77 /**
78 * Allow callback for AJAX.
79 * @use self::render_edit_course_curriculum
80 * @use self::render_html
81 *
82 * @param array $callbacks
83 *
84 * @return array
85 */
86 public function allow_callback( array $callbacks ): array {
87 $callbacks[] = get_class( $this ) . ':render_edit_course_curriculum';
88 $callbacks[] = get_class( $this ) . ':render_list_items_not_assign';
89
90 return $callbacks;
91 }
92
93 /**
94 * Render edit course curriculum html.
95 *
96 * @throws Exception
97 */
98 public static function render_edit_course_curriculum( array $data ): stdClass {
99 $course_id = $data['course_id'] ?? 0;
100 $courseModel = CourseModel::find( $course_id, true );
101 if ( ! $courseModel ) {
102 throw new Exception( __( 'Course not found', 'learnpress' ) );
103 }
104
105 self::instance()->courseModel = $courseModel;
106 self::instance()->context_data = $data; // Store context data for filters
107
108 $coursePostModel = new CoursePostModel( $courseModel );
109 if ( ! $coursePostModel->check_capabilities_create() ) {
110 throw new Exception( __( 'You do not have permission to edit this course', 'learnpress' ) );
111 }
112
113 $content = new stdClass();
114 $content->content = self::instance()->html_edit_curriculum( $courseModel );
115
116 return $content;
117 }
118
119 /**
120 * HTML for edit curriculum.
121 *
122 * @param CourseModel $courseModel
123 *
124 * @return string
125 */
126 public function html_edit_curriculum( CourseModel $courseModel ): string {
127 $html_sections = '';
128
129 // Get sections items
130 $sections_items = $courseModel->get_section_items();
131 $count_sections = count( $sections_items );
132
133 foreach ( $sections_items as $section_items ) {
134 $html_sections .= $this->html_edit_section( $courseModel, $section_items );
135 }
136
137 $sections = [
138 'wrap' => '<div class="curriculum-sections">',
139 'list-sections' => $html_sections,
140 'section-clone' => $this->html_edit_section( $courseModel ),
141 'wrap_end' => '</div>',
142 ];
143
144 $section = [
145 'wrap' => '<div id="lp-course-edit-curriculum">',
146 'heading' => '<div class="heading">',
147 'h4' => sprintf(
148 '<h4>%s</h4>',
149 __( 'Details', 'learnpress' )
150 ),
151 'count-sections' => sprintf(
152 '<div class="count-sections" data-count="%s">%s</div>',
153 $count_sections,
154 sprintf(
155 __( '<span class="count">%1$s</span> %2$s', 'learnpress' ),
156 $count_sections,
157 sprintf(
158 '<span class="one">%s</span><span class="plural">%s</span>',
159 __( 'Section', 'learnpress' ),
160 __( 'Sections', 'learnpress' )
161 )
162 )
163 ),
164 'count-items' => sprintf(
165 '<div class="total-items" data-count="%s">%s</div>',
166 $courseModel->count_items(),
167 sprintf(
168 __( '<span class="count">%1$s</span> %2$s', 'learnpress' ),
169 $courseModel->count_items(),
170 sprintf(
171 '<span class="one">%s</span><span class="plural">%s</span>',
172 __( 'Item', 'learnpress' ),
173 __( 'Items', 'learnpress' )
174 )
175 )
176 ),
177 'section-toggle' =>
178 '<div class="course-toggle-all-sections lp-collapse">
179 <span class="lp-icon-angle-down"></span>
180 <span class="lp-icon-angle-up"></span>
181 </div>',
182 'heading_end' => '</div>',
183 'sections' => Template::combine_components( $sections ),
184 'add_new_section' => $this->html_add_new_section(),
185 'select_items' => $this->html_popup_items_to_select_clone( $courseModel ),
186 'wrap_end' => '</div>',
187 ];
188
189 return Template::combine_components( $section );
190 }
191
192 /**
193 * HTML for edit section.
194 *
195 * @param CourseModel $courseModel
196 * @param null|object $section_items
197 *
198 * @return string
199 */
200 public function html_edit_section( CourseModel $courseModel, $section_items = null ): string {
201 $is_clone = is_null( $section_items );
202 $total_items = 0;
203 $items = [];
204 $html_items = '';
205 $section_id = $section_items->section_id ?? 0;
206 $section_name = $section_items->section_name ?? '';
207
208 if ( ! $is_clone ) {
209 $total_items = count( $section_items->items ?? [] );
210 $items = $section_items->items ?? [];
211
212 foreach ( $items as $item ) {
213 $html_items .= $this->html_section_item( $courseModel, $item );
214 }
215 }
216
217 $section_list_items = [
218 'wrap' => '<ul class="section-list-items">',
219 'items' => $html_items,
220 'item_clone' => $this->html_section_item( $courseModel ),
221 'wrap_end' => '</ul>',
222 ];
223
224 $section = [
225 'wrap' => sprintf(
226 '<div data-section-id="%s" class="section lp-collapse %s">',
227 $section_id,
228 $is_clone ? 'clone lp-hidden' : ''
229 ),
230 'head' => '<div class="section-head">',
231 'drag' => sprintf(
232 '<span class="drag lp-icon-drag" title="%s"></span>',
233 __( 'Drag to reorder section', 'learnpress' )
234 ),
235 'loading' => '<span class="lp-icon-spinner"></span>',
236 'title' => $this->html_input_section_title( $section_name ),
237 'btn-edit' => sprintf(
238 '<span class="lp-btn-edit-section-title lp-icon-edit" title="%s"></span>',
239 __( 'Edit section title', 'learnpress' )
240 ),
241 'btn-delete' => sprintf(
242 '<button type="button" class="lp-btn-delete-section button"
243 data-send="%s"
244 data-title="%s" data-content="%s">%s
245 </button>',
246 Template::convert_data_to_json(
247 [
248 'action' => 'course_delete_section',
249 'course_id' => $courseModel->get_id(),
250 'id_url' => 'course-delete-section',
251 ]
252 ),
253 __( 'Are you sure?', 'learnpress' ),
254 __( 'This section will be deleted. The items in this section will no longer be assigned to this course, but will not be permanently deleted.', 'learnpress' ),
255 __( 'Delete Section', 'learnpress' )
256 ),
257 'btn-update' => sprintf(
258 '<button type="button" class="lp-btn-update-section-title button">%s</button>',
259 __( 'Update' )
260 ),
261 'btn-cancel' => sprintf(
262 '<button type="button" class="lp-btn-cancel-update-section-title button">%s</button>',
263 __( 'Cancel' )
264 ),
265 'count-items' => sprintf(
266 '<div class="section-items-counts" data-count="%s">%s</div>',
267 $total_items,
268 sprintf(
269 __( '<span class="count">%1$s</span> %2$s', 'learnpress' ),
270 $total_items,
271 sprintf(
272 '<span class="one">%s</span><span class="plural">%s</span>',
273 __( 'Item', 'learnpress' ),
274 __( 'Items', 'learnpress' )
275 )
276 )
277 ),
278 'toggle' => '<div class="section-toggle"><span class="lp-icon-angle-down"></span><span class="lp-icon-angle-up"></span></div>',
279 'head_end' => '</div>',
280 'wrap_content' => '<div class="section-collapse">',
281 'section-content' => '<div class="section-content">',
282 'section-description' => sprintf(
283 '<div class="section-description">%s%s%s</div>',
284 $this->html_edit_section_description( $section_items->section_description ?? '' ),
285 sprintf(
286 '<button type="button" class="lp-btn-update-section-description button">%s</button>',
287 __( 'Update' )
288 ),
289 sprintf(
290 '<button type="button" class="lp-btn-cancel-update-section-description button">%s</button>',
291 __( 'Cancel' )
292 )
293 ),
294 'section-list-items' => Template::combine_components( $section_list_items ),
295 'section-content-end' => '</div>',
296 'section-item-actions' => $this->html_section_item_actions(),
297 'wrap_content_end' => '</div>',
298 'wrap_end' => '</div>',
299 ];
300
301 return Template::combine_components( $section );
302 }
303
304 /**
305 * HTML input section title.
306 *
307 * @param string $section_name
308 *
309 * @return string
310 */
311 public function html_input_section_title( string $section_name = '' ): string {
312 return sprintf(
313 '<input class="lp-section-title-input"
314 name="lp-section-title-input"
315 type="text"
316 value="%1$s"
317 data-old="%1$s"
318 placeholder="%2$s"
319 data-mess-empty-title="%3$s"
320 data-send="%4$s">',
321 esc_attr( $section_name ),
322 esc_attr__( 'Update section title', 'learnpress' ),
323 esc_attr__( 'Section title is required', 'learnpress' ),
324 Template::convert_data_to_json(
325 [
326 'action' => 'course_update_section',
327 'course_id' => $this->courseModel->get_id(),
328 'id_url' => 'course-update-section-title',
329 ]
330 )
331 );
332 }
333
334 /**
335 * HTML for section description input.
336 *
337 * @param string|null $section_description
338 *
339 * @return string
340 */
341 public function html_edit_section_description( string $section_description = '' ): string {
342 return sprintf(
343 '<textarea class="lp-section-description-input"
344 name="lp-section-description-input"
345 type="text"
346 data-old="%1$s"
347 placeholder="%2$s"
348 data-send="%3$s">%1$s</textarea>',
349 esc_attr( $section_description ),
350 esc_attr__( '+ Add Description', 'learnpress' ),
351 Template::convert_data_to_json(
352 [
353 'action' => 'course_update_section',
354 'course_id' => $this->courseModel->get_id(),
355 'id_url' => 'course-update-section-description',
356 ]
357 )
358 );
359 }
360
361 /**
362 * HTML add new section.
363 *
364 * @return string
365 */
366 public function html_add_new_section(): string {
367 $section = [
368 'wrap' => '<div class="add-new-section">',
369 'icon' => '<span class="lp-icon-plus"></span>',
370 'input' => sprintf(
371 '<input class="lp-section-title-new-input"
372 name="lp-section-title-new-input"
373 type="text"
374 title="%1$s"
375 placeholder="%1$s"
376 data-mess-empty-title="%2$s"
377 data-send="%3$s">',
378 esc_attr__( 'Create a new section', 'learnpress' ),
379 esc_attr__( 'Section title is required', 'learnpress' ),
380 Template::convert_data_to_json(
381 [
382 'action' => 'course_add_section',
383 'course_id' => $this->courseModel->get_id(),
384 'id_url' => 'course-add-section',
385 ]
386 )
387 ),
388 'button' => sprintf(
389 '<button type="button"
390 class="lp-btn-add-section button lp-btn-edit-primary">%s
391 </button>',
392 __( 'Add Section', 'learnpress' )
393 ),
394 'wrap_end' => '</div>',
395 ];
396
397 return Template::combine_components( $section );
398 }
399
400 /**
401 * HTML for section item.
402 * $item is null when clone item new
403 *
404 * @param CourseModel $courseModel
405 * @param null|object $item
406 *
407 * @return string
408 */
409 public function html_section_item( CourseModel $courseModel, $item = null ): string {
410 $is_clone = is_null( $item );
411 $item_id = $item->item_id ?? 0;
412 $item_title = $item->title ?? '';
413 $item_type = $item->item_type ?? '';
414
415 /**
416 * @var $itemModel PostModel
417 */
418 $itemModel = $courseModel->get_item_model( $item_id, $item_type );
419
420 $edit_button = apply_filters(
421 'learn-press/admin/curriculum/section-item/edit-button',
422 sprintf(
423 '<li title="%s"><a href="%s" target="_blank" class="lp-icon-edit-square edit-link"></a></li>',
424 __( 'Edit item detail', 'learnpress' ),
425 $itemModel ? $itemModel->get_edit_link() : ''
426 ),
427 $item,
428 $itemModel,
429 $courseModel
430 );
431
432 $section_action = [
433 'wrap' => '<ul class="item-actions">',
434 'preview' => sprintf(
435 '<li title="%s" class="lp-btn-set-preview-item"><a class="%s"></a></li>',
436 __( 'Enable/Disable Preview', 'learnpress' ),
437 $itemModel && $itemModel->post_type === LP_LESSON_CPT
438 && $itemModel->has_preview() ? 'lp-icon-eye' : 'lp-icon-eye-slash'
439 ),
440 'edit' => $edit_button,
441 'delete' => sprintf(
442 '<li class="action lp-btn-delete-item"
443 data-title="%s" data-content="%s">%s</li>',
444 __( 'Are you sure?', 'learnpress' ),
445 __( 'This item will be removed from this section. This item will no longer be assigned to this course. It will not be permanently deleted from the system.', 'learnpress' ),
446 sprintf( '<a class="lp-icon-trash-o" title="%s"></a>', __( 'Remove item', 'learnpress' ) )
447 ),
448 'wrap_end' => '</ul>',
449 ];
450
451 $section_action = apply_filters(
452 'learn-press/admin/curriculum/section-item/actions',
453 $section_action,
454 $item,
455 $itemModel,
456 $courseModel,
457 $this->context_data
458 );
459
460 $section = [
461 'li' => sprintf(
462 '<li data-item-id="%s" data-item-type="%s" class="section-item %s %s">',
463 $item_id,
464 $item_type,
465 $item_type,
466 $is_clone ? 'clone lp-hidden' : ''
467 ),
468 'drag' => sprintf(
469 '<span class="drag lp-icon-drag" title="%s"></span>',
470 __( 'Drag to reorder item', 'learnpress' )
471 ),
472 'icon' => '<div class="item-ico-type"></div>',
473 'loading' => '<span class="lp-icon-spinner"></span>',
474 'input-title' => sprintf(
475 '<input name="%1$s" class="%1$s" type="text" value="%2$s" data-old="%2$s" data-mess-empty-title="%3$s">',
476 'lp-item-title-input',
477 wp_kses_post( $item_title ),
478 esc_attr__( 'Item title is required', 'learnpress' )
479 ),
480 'btn-update' => sprintf(
481 '<button type="button" class="lp-btn-update-item-title button button-primary">%s</button>',
482 __( 'Update' )
483 ),
484 'btn-cancel' => sprintf(
485 '<button type="button" class="lp-btn-cancel-update-item-title button">%s</button>',
486 __( 'Cancel' )
487 ),
488 'item_actions' => Template::combine_components( $section_action ),
489 'li_end' => '</li>',
490 ];
491
492 return Template::combine_components( $section );
493 }
494
495 public function html_section_item_actions(): string {
496 $course_item_types = CourseModel::item_types_support();
497
498 $html_buttons = '';
499 foreach ( $course_item_types as $type ) {
500 $item_label = CourseModel::item_types_label( $type );
501
502 $html_buttons .= sprintf(
503 '<button class="lp-btn-select-item-type button"
504 data-item-type="%s"
505 data-placeholder="%s"
506 data-button-add-text="%s"
507 type="button">%s</button>',
508 $type,
509 sprintf( __( 'Create a new %s', 'learnpress' ), $item_label ),
510 sprintf( __( 'Add %s', 'learnpress' ), $item_label ),
511 sprintf( __( 'New %s', 'learnpress' ), $item_label )
512 );
513 }
514
515 $section = [
516 'wrap' => '<div class="section-actions">',
517 'buttons' => $html_buttons,
518 'btn-select-items' => sprintf(
519 '<button type="button"
520 data-template="#lp-tmpl-select-course-items-bank"
521 class="button lp-btn-show-popup-items-to-select">
522 %s</button>',
523 __( 'Content Bank', 'learnpress' )
524 ),
525 'add-item-type' => $this->html_add_item_type(),
526 'wrap_end' => '</div>',
527 ];
528
529 return Template::combine_components( $section );
530 }
531
532 /**
533 * HTML for section item new.
534 *
535 * @return string
536 */
537 public function html_add_item_type(): string {
538 $section = [
539 'wrap' => '<div class="lp-add-item-type clone lp-hidden">',
540 'icon-plus' => '<div class="lp-icon-plus"></div>',
541 'item-ico-type' => '<div class="item-ico-type"></div>',
542 'actions' => '<div class="new-item-actions">',
543 'input' => sprintf(
544 '<input class="%1$s" name="%1$s" data-mess-empty-title="%2$s" type="text"/>',
545 'lp-add-item-type-title-input',
546 esc_attr__( 'Item title is required', 'learnpress' )
547 ),
548 'button_add' => '<button class="lp-btn-add-item button button-primary" type="button"></button>',
549 'button_cancel' => sprintf(
550 '<button class="lp-btn-add-item-cancel button" type="button">%s</button>',
551 __( 'Cancel' )
552 ),
553 'actions_end' => '</div>',
554 'wrap_end' => '</div>',
555 ];
556
557 return Template::combine_components( $section );
558 }
559
560 /**
561 * HTML for popup items to select.
562 *
563 * @param CourseModel $course_model
564 *
565 * @return string
566 */
567 public function html_popup_items_to_select_clone( CourseModel $course_model ): string {
568 /**
569 * @uses self::render_list_items_not_assign
570 */
571 $html_items = TemplateAJAX::load_content_via_ajax(
572 [
573 'id_url' => 'list-items-not-assign',
574 'enableScrollToView' => false,
575 'course_id' => $course_model->ID,
576 'item_type' => LP_LESSON_CPT,
577 'paged' => 1,
578 ],
579 [
580 'class' => self::class,
581 'method' => 'render_list_items_not_assign',
582 ]
583 );
584
585 $tabs = [];
586 $course_item_types = CourseModel::item_types_support();
587 foreach ( $course_item_types as $type ) {
588 $item_label = CourseModel::item_types_label( $type );
589 $tabs[ $type ] = $item_label;
590 }
591
592 $section = [
593 'wrap-script-template' => '<script type="text/template" id="lp-tmpl-select-course-items-bank">',
594 'popup' => AdminTemplate::html_popup_items_to_select_clone( $tabs, $html_items ),
595 'wrap-script-template-end' => '</div>',
596 ];
597
598 return Template::combine_components( $section );
599 }
600
601 /**
602 * Render list items not assign to course.
603 * Get all items not assigned to any course, use old logic.
604 * If user current is Admin, get all items.
605 * Else get all items created by user current.
606 *
607 * @throws Exception
608 * @since 4.2.8.6
609 * @version 1.0.5
610 */
611 public static function render_list_items_not_assign( $data ): stdClass {
612 $user = wp_get_current_user();
613 $content = new stdClass();
614 $course_id = $data['course_id'] ?? 0;
615 $item_type = $data['item_type'] ?? LP_LESSON_CPT;
616 $item_selecting = $data['item_selecting'] ?? [];
617 $search_title = $data['search_title'] ?? '';
618 $paged = intval( $data['paged'] ?? 1 );
619 $item_selecting_compare = new stdClass();
620
621 $courseModel = CourseModel::find( $course_id, true );
622 if ( ! $courseModel ) {
623 throw new Exception( __( 'Course not found', 'learnpress' ) );
624 }
625
626 // Check permission
627 $coursePostModel = new CoursePostModel( $courseModel );
628 if ( ! $coursePostModel->check_capabilities_create() ) {
629 throw new Exception( __( 'You do not have permission view list', 'learnpress' ) );
630 }
631
632 $lp_posts_db = PostDB::getInstance();
633 $filter = new PostFilter();
634 $filter->only_fields = [
635 'DISTINCT(p.ID) AS ID',
636 'p.post_title',
637 'p.post_type',
638 ];
639 $filter->post_type = $item_type;
640 $filter->post_status = [ 'publish' ];
641 $filter->order_by = 'p.ID';
642 $filter->page = $paged;
643 if ( ! user_can( $user, UserModel::ROLE_ADMINISTRATOR ) ) {
644 $filter->post_author = $user->ID;
645 }
646
647 if ( ! empty( $search_title ) ) {
648 $filter->post_title = $search_title;
649 }
650
651 // Old logic: Get all items not assigned to any course.
652 $filter->where[] = "AND p.ID NOT IN ( SELECT item_id FROM {$lp_posts_db->tb_lp_section_items} )";
653
654 // New logic: Get all items not assigned to the course.
655 // Code here
656
657 $total_rows = 0;
658 $filter = apply_filters(
659 'learn-press/filter-list-items-not-assign-course',
660 $filter,
661 $data,
662 $courseModel
663 );
664 $posts = $lp_posts_db->get_posts( $filter, $total_rows );
665 $total_pages = DataBase::get_total_pages( $filter->limit, $total_rows );
666
667 $html_lis = '';
668 if ( empty( $posts ) ) {
669 $html_lis = sprintf( '<li>%s</li>', __( 'No items found', 'learnpress' ) );
670 } else {
671 if ( ! empty( $item_selecting ) ) {
672 foreach ( $item_selecting as $item ) {
673 if ( ! isset( $item['id'] ) || ! isset( $item['type'] ) ) {
674 continue;
675 }
676
677 $item_selecting_compare->{$item['id']} = new stdClass();
678 $item_selecting_compare->{$item['id']}->item_type = $item['type'];
679 }
680 }
681
682 foreach ( $posts as $post ) {
683 /**
684 * @var $itemModel PostModel
685 */
686 $itemModel = $courseModel->get_item_model( $post->ID, $post->post_type, false );
687 if ( ! $itemModel ) {
688 continue;
689 }
690
691 $checked = '';
692
693 if ( isset( $item_selecting_compare->{$post->ID} )
694 && $item_selecting_compare->{$post->ID}->item_type === $post->post_type ) {
695 $checked = ' checked="checked"';
696 }
697
698 $title_display = sprintf(
699 '<span class="title">%s<strong>(#%d)</strong></span>',
700 $post->post_title,
701 $post->ID
702 );
703
704 $html_lis .= sprintf(
705 '<li class="lp-select-item">%s%s</li>',
706 sprintf(
707 '<input name="lp-select-item"
708 data-id="%d"
709 data-type="%s"
710 data-title="%s" %s data-edit-link="%s"
711 data-title-selected="%s"
712 type="checkbox" />',
713 esc_attr( $post->ID ?? 0 ),
714 esc_attr( $post->post_type ?? '' ),
715 esc_attr( $title_display ), // For JS display on list selected.
716 esc_attr( $checked ),
717 get_edit_post_link( $post->ID ),
718 esc_attr( get_the_title( $post->ID ) )
719 ),
720 $title_display
721 );
722 }
723 }
724
725 $section = [
726 'ul' => '<ul class="list-items">',
727 'items' => $html_lis,
728 'ul_end' => '</ul>',
729 'pagination' => Template::instance()->html_pagination(
730 [
731 'total_pages' => $total_pages,
732 'paged' => $paged,
733 ]
734 ),
735 ];
736
737 $content->content = Template::combine_components( $section );
738
739 return $content;
740 }
741 }
742