PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.10
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.10
4.4.10 4.4.9.1 4.4.9 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 All 142 releases
← All changes | inc/TemplateHooks/CourseBuilder/Quiz/BuilderEditQuizTemplate.php +615 -604 4.3.8 → 4.4.10 View file →
@@ -1,604 +1,615 @@
1 -<?php
2 -/**
3 - * Template hooks Course Builder.
4 - *
5 - * @since 4.3.0
6 - * @version 1.0.0
7 - */
8 -
9 -namespace LearnPress\TemplateHooks\CourseBuilder\Quiz;
10 -
11 -use Exception;
12 -use LearnPress\CourseBuilder\CourseBuilderAccessPolicy;
13 -use LearnPress\Models\UserModel;
14 -use LearnPress\TemplateHooks\CourseBuilder\Course\BuilderCourseTemplate;
15 -use LearnPress\CourseBuilder\CourseBuilder;
16 -use LearnPress\Helpers\Singleton;
17 -use LearnPress\Helpers\Template;
18 -use LearnPress\Models\PostModel;
19 -use LearnPress\Models\QuizPostModel;
20 -use LearnPress\TemplateHooks\Admin\AdminEditQizTemplate;
21 -use LearnPress\TemplateHooks\Admin\AdminTemplate;
22 -use LearnPress\TemplateHooks\Course\AdminEditCurriculumTemplate;
23 -use LearnPress\TemplateHooks\TemplateAJAX;
24 -use LP_Settings;
25 -use LP_WP_Filesystem;
26 -use Throwable;
27 -use WP_User;
28 -
29 -class BuilderEditQuizTemplate {
30 - use Singleton;
31 -
32 - public function init() {
33 - add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
34 - }
35 -
36 - /**
37 - * Display layout edit/create quiz.
38 - *
39 - * @param array $data [ 'userModel' => UserModel, 'item_id' => int|string ]
40 - *
41 - * @throws Exception
42 - */
43 - public function layout( array $data = [] ) {
44 - try {
45 - $userModel = $data['userModel'] ?? false;
46 - if ( ! $userModel || ! $userModel->is_instructor() ) {
47 - throw new Exception( __( 'You do not have permission to create or edit quizzes', 'learnpress' ) );
48 - }
49 -
50 - $item_id = $data['item_id'] ?? '';
51 - if ( empty( $item_id ) ) {
52 - throw new Exception( __( 'Invalid quiz ID', 'learnpress' ) );
53 - }
54 -
55 - if ( ! CourseBuilderAccessPolicy::can_access_tab_post( 'quizzes', $item_id ) ) {
56 - throw new Exception( __( "Sorry, you don't have permission to access this content", 'learnpress' ) );
57 - }
58 -
59 - $is_create_new = $item_id === CourseBuilder::POST_NEW;
60 - $quizModel = false;
61 -
62 - if ( ! $is_create_new ) {
63 - $quizModel = QuizPostModel::find( (int) $item_id, true );
64 - if ( ! $quizModel ) {
65 - throw new Exception( __( 'Quiz not found', 'learnpress' ) );
66 - }
67 -
68 - if ( $quizModel->post_status === PostModel::STATUS_TRASH ) {
69 - throw new Exception(
70 - __(
71 - 'You cannot edit this item because it is in the Trash. Please restore it and try again.',
72 - 'learnpress'
73 - )
74 - );
75 - }
76 - }
77 -
78 - $data['quizModel'] = $quizModel;
79 -
80 - $section = [
81 - 'wrap' => sprintf(
82 - '<div class="lp-cb-content" data-post-id="%1$s">',
83 - esc_attr( $item_id )
84 - ),
85 - 'header' => $this->html_header( $data ),
86 - 'tabs' => $this->html_tabs( $data ),
87 - 'wrap_end' => '</div>',
88 - ];
89 -
90 - echo Template::combine_components( $section );
91 -
92 - } catch ( Throwable $e ) {
93 - Template::print_message( $e->getMessage(), 'error' );
94 - }
95 - }
96 -
97 - public function html_header( array $data = [] ): string {
98 - $userModel = $data['userModel'] ?? false;
99 - if ( ! $userModel instanceof UserModel ) {
100 - return '';
101 - }
102 -
103 - $quizModel = $data['quizModel'] ?? false;
104 - $hide_instructor_access_admin_screen = LP_Settings::is_hide_instructor_access_admin_screen();
105 - $more_actions_icon = LP_WP_Filesystem::get_icon_svg( 'ico-cb-more.svg' );
106 - $title = $quizModel ? $quizModel->get_the_title() : __( 'Add New Quiz', 'learnpress' );
107 - $status = $quizModel ? $quizModel->post_status : '';
108 - $status_label = 'future' === $status ? __( 'scheduled', 'learnpress' ) : $status;
109 - $main_action_status = in_array( $status, [ 'publish', 'draft', 'pending', 'future', 'private' ], true ) ? $status : 'publish';
110 - $wp_user = new WP_User( $userModel );
111 - $hide_wp_edit_link = $hide_instructor_access_admin_screen && user_can( $wp_user, UserModel::ROLE_INSTRUCTOR );
112 -
113 - $section = [
114 - 'header_wrap' => '<div class="lp-cb-header">',
115 - 'header_left' => '<div class="lp-cb-header__left">',
116 - 'title' => sprintf(
117 - '<h1 class="lp-cb-header__title">%s</h1>',
118 - esc_html( $title )
119 - ),
120 - 'status_badge' => $quizModel && $status ? sprintf(
121 - '<span class="quiz-status %1$s">%2$s</span>',
122 - esc_attr( $status ),
123 - esc_html( $status_label )
124 - ) : '',
125 - 'link_edit_on_wp' => $quizModel && ! $hide_wp_edit_link ? sprintf(
126 - '<a href="%1$s" class="lp-cb-admin-link" target="_blank" title="%2$s"%3$s>
127 - <span class="dashicons dashicons-wordpress"></span>
128 - <span>%2$s</span>
129 - </a>',
130 - esc_url( admin_url( 'post.php?post=' . $quizModel->get_id() . '&action=edit' ) ),
131 - esc_attr__( 'Edit with WordPress', 'learnpress' ),
132 - 'trash' === $status ? ' style="display:none"' : ''
133 - ) : '',
134 - 'header_left_end' => '</div>',
135 - 'header_actions' => '<div class="lp-cb-header__actions">',
136 - 'dropdown_wrap' => '<div class="cb-header-actions-dropdown cb-header-actions-dropdown--single">',
137 - 'update_btn' => sprintf(
138 - '<div class="cb-btn-update lp-button cb-btn-primary cb-btn-main-action"
139 - data-status="%1$s"
140 - data-title-update="%2$s"
141 - data-title-publish="%3$s"
142 - data-title-draft="%4$s">%5$s</div>',
143 - esc_attr( $main_action_status ),
144 - esc_attr__( 'Update', 'learnpress' ),
145 - esc_attr__( 'Publish', 'learnpress' ),
146 - esc_attr__( 'Save Draft', 'learnpress' ),
147 - esc_html__( 'Update', 'learnpress' )
148 - ),
149 - 'dropdown_wrap_end' => '</div>',
150 - 'expanded_actions' => $quizModel ? sprintf(
151 - '<div class="cb-header-action-expanded">
152 - <button type="button" class="lp-button course-action-expanded" aria-haspopup="true" aria-expanded="false" aria-label="%1$s">
153 - %2$s
154 - </button>
155 - <div class="cb-header-action-expanded__items">
156 - <div class="cb-header-action-expanded__duplicate lp-button cb-btn-duplicate-quiz"
157 - data-title="%3$s"
158 - data-content="%4$s">
159 - <span class="dashicons dashicons-admin-page"></span>
160 - %5$s
161 - </div>
162 - <div class="cb-header-action-expanded__trash lp-button cb-btn-trash">
163 - <span class="dashicons dashicons-trash"></span>
164 - %6$s
165 - </div>
166 - </div>
167 - </div>',
168 - esc_attr__( 'More actions', 'learnpress' ),
169 - $more_actions_icon,
170 - esc_attr__( 'Are you sure?', 'learnpress' ),
171 - esc_attr__( 'Are you sure you want to duplicate this quiz?', 'learnpress' ),
172 - esc_html__( 'Duplicate', 'learnpress' ),
173 - esc_html__( 'Move to Trash', 'learnpress' )
174 - ) : '',
175 - 'header_actions_end' => '</div>',
176 - 'header_end' => '</div>',
177 - ];
178 -
179 - return Template::combine_components( $section );
180 - }
181 -
182 - public function html_tabs( array $data = [] ): string {
183 - $section_tab = [
184 - 'tabs_wrap' => '<div class="lp-cb-tabs">',
185 - 'tabs' => '',
186 - 'tabs_end' => '</div>',
187 - ];
188 -
189 - $section_content = [
190 - 'wrap' => '<div class="lp-cb-tab-content">',
191 - 'content' => '',
192 - 'wrap-end' => '</div>',
193 - ];
194 -
195 - $tabs = apply_filters(
196 - 'learn-press/course-builder/quizzes/edit/tabs',
197 - [
198 - 'overview' => [
199 - 'title' => esc_html__( 'Overview', 'learnpress' ),
200 - 'html' => $this->html_tab_overview( $data ),
201 - ],
202 - 'question' => [
203 - 'title' => esc_html__( 'Question', 'learnpress' ),
204 - 'html' => $this->html_tab_question( $data ),
205 - ],
206 - 'settings' => [
207 - 'title' => esc_html__( 'Settings', 'learnpress' ),
208 - 'html' => $this->html_tab_settings( $data ),
209 - ],
210 - ],
211 - $data
212 - );
213 -
214 - $tab_sections = [];
215 - foreach ( $tabs as $key => $tab ) {
216 - $tab_sections[ $key ] = $tab['slug'] ?? $key;
217 - }
218 -
219 - $tab_active = (string) reset( $tab_sections );
220 - if ( isset( $_GET['tab'] ) ) {
221 - $requested_tab = sanitize_key( wp_unslash( $_GET['tab'] ) );
222 - if ( in_array( $requested_tab, $tab_sections, true ) ) {
223 - $tab_active = $requested_tab;
224 - }
225 - }
226 -
227 - foreach ( $tabs as $key => $tab ) {
228 - $tab_section = $tab_sections[ $key ];
229 - $is_active = $tab_section === $tab_active;
230 -
231 - $section_tab['tabs'] .= sprintf(
232 - '<a href="#" class="lp-cb-tabs__item %s" data-tab-section="%s">%s</a>',
233 - $is_active ? 'is-active' : '',
234 - esc_attr( $tab_section ),
235 - esc_html( $tab['title'] ?? '' )
236 - );
237 -
238 - /**
239 - * @uses html_tab_overview
240 - * @uses html_tab_question
241 - * @uses html_tab_settings
242 - */
243 - $section_content['content'] .= sprintf(
244 - '<div class="lp-cb-tab-panel %s" data-section="%s">%s</div>',
245 - $is_active ? '' : 'lp-hidden',
246 - esc_attr( $tab_section ),
247 - $tab['html'] ?? ''
248 - );
249 - }
250 -
251 - return Template::combine_components(
252 - [
253 - 'tabs' => Template::combine_components( $section_tab ),
254 - 'contents' => Template::combine_components( $section_content ),
255 - ]
256 - );
257 - }
258 -
259 - public function html_tab_overview( array $data = [] ): string {
260 - wp_enqueue_script( 'lp-course-builder' );
261 -
262 - $quiz_model = $data['quizModel'] ?? false;
263 - $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
264 -
265 - if ( absint( $quiz_id ) && ! $quiz_model ) {
266 - $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
267 - if ( empty( $quiz_model ) ) {
268 - return '';
269 - }
270 - }
271 -
272 - $html_assigned = $this->assigned_course( $quiz_model );
273 - $html_edit_title = $this->edit_title( $quiz_model );
274 - $html_permalink = $this->edit_permalink( $quiz_model );
275 - $html_publish = $this->edit_publish( $quiz_model );
276 - $html_edit_desc = $this->edit_desc( $quiz_model );
277 - $section = [
278 - 'wrapper' => sprintf( '<div class="cb-section__quiz-edit" data-quiz-id="%s">', $quiz_id ),
279 - 'content_wrapper' => '<div class="cb-item-edit-content">',
280 - 'left_column' => '<div class="cb-item-edit-column cb-item-edit-column--left">',
281 - 'edit_title' => $html_edit_title,
282 - 'assigned_course' => $html_assigned,
283 - 'edit_permalink' => $html_permalink,
284 - 'edit_publish' => $html_publish,
285 - 'left_column_end' => '</div>',
286 - 'right_column' => '<div class="cb-item-edit-column cb-item-edit-column--right">',
287 - 'edit_desc' => $html_edit_desc,
288 - 'right_column_end' => '</div>',
289 - 'content_wrapper_end' => '</div>',
290 - 'wrapper_end' => '</div>',
291 - ];
292 -
293 - return Template::combine_components( $section );
294 - }
295 -
296 - public function html_tab_question( array $data = [] ): string {
297 - wp_enqueue_style( 'lp-edit-quiz' );
298 -
299 - $quiz_model = $data['quizModel'] ?? false;
300 - $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
301 -
302 - if ( $quiz_id === CourseBuilder::POST_NEW || absint( $quiz_id ) <= 0 ) {
303 - return sprintf( '<span class="lp-message lp-message--info">%s</span>', __( 'Please save Quiz before add question', 'learnpress' ) );
304 - }
305 -
306 - if ( ! $quiz_model ) {
307 - $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
308 - if ( empty( $quiz_model ) ) {
309 - return '';
310 - }
311 - }
312 -
313 - $args = [
314 - 'id_url' => 'edit-quiz',
315 - 'quiz_id' => $quiz_model->ID,
316 - ];
317 - $call_back = [
318 - 'class' => AdminEditQizTemplate::class,
319 - 'method' => 'render_edit_quiz',
320 - ];
321 -
322 - return TemplateAJAX::load_content_via_ajax( $args, $call_back );
323 - }
324 -
325 - public function html_tab_settings( array $data = [] ): string {
326 - wp_enqueue_script( 'lp-cb-edit-curriculum' );
327 - wp_enqueue_script( 'lp-tom-select' );
328 - wp_enqueue_style( 'lp-cb-edit-curriculum' );
329 - wp_enqueue_script( 'lp-cb-learnpress' );
330 -
331 - $quiz_model = $data['quizModel'] ?? false;
332 - $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
333 -
334 - if ( $quiz_id === CourseBuilder::POST_NEW || absint( $quiz_id ) <= 0 ) {
335 - return sprintf( '<span class="lp-message lp-message--info">%s</span>', __( 'Please save Quiz before setting quiz', 'learnpress' ) );
336 - }
337 -
338 - if ( ! $quiz_model ) {
339 - $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
340 - if ( empty( $quiz_model ) ) {
341 - return '';
342 - }
343 - }
344 -
345 - if ( ! class_exists( 'LP_Meta_Box_Quiz' ) ) {
346 - require_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/quiz/settings.php';
347 - }
348 -
349 - $metabox = new \LP_Meta_Box_Quiz();
350 - ob_start();
351 - $metabox->output( $quiz_model );
352 - $settings = ob_get_clean();
353 -
354 - $output = [
355 - 'wrapper' => sprintf( '<div class="cb-section__quiz-edit" data-quiz-id="%s">', $quiz_id ),
356 - 'form_setting' => '<form name="lp-form-setting-quiz" class="lp-form-setting-quiz" method="post" enctype="multipart/form-data">',
357 - 'settings' => $settings,
358 - 'form_setting_end' => '</form>',
359 - 'wrapper_end' => '</div>',
360 - ];
361 -
362 - return Template::combine_components( $output );
363 - }
364 -
365 - /**
366 - * Allow callback for AJAX.
367 - * @use self::render_edit_course_curriculum
368 - * @use self::render_html
369 - *
370 - * @param array $callbacks
371 - *
372 - * @return array
373 - */
374 - public function allow_callback( array $callbacks ): array {
375 - $callbacks[] = AdminEditCurriculumTemplate::class . ':render_edit_course_curriculum';
376 -
377 - return $callbacks;
378 - }
379 -
380 - public function assigned_course( $quiz_model ) {
381 - $assign_course = ! empty( $quiz_model ) ? $this->get_assigned( $quiz_model->get_id() ) : '';
382 - $html_courses = '';
383 - $assigned = sprintf( '<span class="quiz-not-assigned">%s</span>', __( 'Not assigned yet', 'learnpress' ) );
384 - if ( ! empty( $assign_course ) ) {
385 - $courses = is_array( $assign_course ) && isset( $assign_course['id'] )
386 - ? array( $assign_course )
387 - : $assign_course;
388 -
389 - $course_htmls = array();
390 - foreach ( $courses as $course ) {
391 - $course_id = $course['id'] ?? 0;
392 - $course_title = $course['title'] ?? '';
393 -
394 - if ( $course_id && $course_title ) {
395 - $course_link = BuilderCourseTemplate::instance()->get_link_edit( $course_id );
396 - $course_htmls[] = sprintf(
397 - '<a href="%s" target="_blank">%s</a>',
398 - esc_url( $course_link ),
399 - esc_html( $course_title )
400 - );
401 - }
402 - }
403 -
404 - if ( ! empty( $course_htmls ) ) {
405 - $assigned = implode( ', ', $course_htmls );
406 - }
407 - }
408 -
409 - $html_courses = sprintf(
410 - '<div class="cb-item-edit-assigned quiz-assigned-courses"><span class="label">%s</span> %s</div>',
411 - __( 'Assigned', 'learnpress' ),
412 - $assigned
413 - );
414 -
415 - return $html_courses;
416 - }
417 -
418 -
419 - public function edit_title( $quiz_model ) {
420 - $title = ! empty( $quiz_model ) ? $quiz_model->get_the_title() : '';
421 - $edit = [
422 - 'wrapper' => '<div class="cb-quiz-edit-title">',
423 - 'label' => sprintf( '<label for="title" class="cb-quiz-edit-title__label">%s</label>', __( 'Title', 'learnpress' ) ),
424 - 'input' => sprintf( '<input type="text" name="quiz_title" size="30" value="%s" id="title" class="cb-quiz-edit-title__input">', $title ),
425 - 'wrapper_end' => '</div>',
426 - ];
427 -
428 - return Template::combine_components( $edit );
429 - }
430 -
431 - public function edit_desc( $quiz_model ) {
432 - $desc = ! empty( $quiz_model ) ? $quiz_model->get_the_content() : '';
433 - $editor_id = 'quiz_description_editor';
434 - $editor_settings = array(
435 - 'textarea_name' => 'quiz_description',
436 - 'textarea_rows' => 10,
437 - 'teeny' => false,
438 - 'media_buttons' => true,
439 - 'tinymce' => array(
440 - 'content_style' => "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 1.6; color: #1e1e1e; }",
441 - 'toolbar1' => 'formatselect,bold,italic,underline,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,spellchecker,wp_adv',
442 - 'toolbar2' => 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
443 - ),
444 - 'quicktags' => true,
445 - );
446 -
447 - $edit = [
448 - 'wrapper' => '<div class="cb-quiz-edit-desc">',
449 - 'label' => sprintf( '<label for="quiz_description" class="cb-quiz-edit-desc__label">%s</label>', __( 'Description', 'learnpress' ) ),
450 - 'edit' => AdminTemplate::editor_tinymce(
451 - $desc,
452 - $editor_id,
453 - $editor_settings
454 - ),
455 - 'wrapper_end' => '</div>',
456 - ];
457 -
458 - return Template::combine_components( $edit );
459 - }
460 -
461 - public function edit_permalink( $quiz_model ): string {
462 - $post_id = ! empty( $quiz_model ) ? absint( $quiz_model->get_id() ) : 0;
463 - $post = $post_id ? get_post( $post_id ) : null;
464 - $post_name = $post && ! empty( $post->post_name ) ? (string) $post->post_name : '';
465 - $full_url = '';
466 - $base_url = '';
467 - $display_classes = 'cb-permalink-display';
468 - $placeholder_class = 'cb-item-edit-permalink__placeholder';
469 - $notice_no_link = __(
470 - 'Permalink is only available if the item is already assigned to a course.',
471 - 'learnpress'
472 - );
473 - $placeholder_text = __( 'Permalink will be available after saving.', 'learnpress' );
474 - $show_unavailable = true;
475 -
476 - if ( $post_id ) {
477 - $current_status = $post && ! empty( $post->post_status ) ? sanitize_key( $post->post_status ) : '';
478 - if ( 'draft' !== $current_status ) {
479 - $course_id_of_item = \LP_Course_DB::getInstance()->get_course_by_item_id( $post_id );
480 - if ( $course_id_of_item ) {
481 - $course = learn_press_get_course( $course_id_of_item );
482 - if ( $course ) {
483 - $full_url = urldecode( $course->get_item_link( $post_id ) );
484 - $base_url = $full_url;
485 - $show_unavailable = false;
486 -
487 - if ( ! empty( $post_name ) ) {
488 - $base_url = trailingslashit( preg_replace( '/' . preg_quote( $post_name, '/' ) . '\/?$/', '', $full_url ) );
489 - }
490 - }
491 - }
492 - }
493 - }
494 -
495 - if ( $show_unavailable && $post_id ) {
496 - $placeholder_text = $notice_no_link;
497 - }
498 -
499 - if ( $show_unavailable ) {
500 - $display_classes .= ' lp-hidden';
501 - } else {
502 - $placeholder_class .= ' lp-hidden';
503 - }
504 -
505 - $state_a = sprintf(
506 - '<span class="cb-item-edit-permalink__label">%s</span>
507 - <div class="%s">
508 - <a href="%s" target="_blank" class="cb-permalink-url">%s</a>
509 - <button type="button" class="cb-permalink-edit-btn" title="%s">
510 - <span class="dashicons dashicons-edit"></span>
511 - </button>
512 - </div>',
513 - __( 'Permalink', 'learnpress' ),
514 - esc_attr( $display_classes ),
515 - esc_url( $full_url ),
516 - esc_html( $full_url ),
517 - __( 'Edit', 'learnpress' )
518 - );
519 -
520 - $state_b = sprintf(
521 - '<div class="cb-permalink-editor lp-hidden">
522 - <span class="cb-permalink-prefix">%s</span>
523 - <div class="cb-permalink-input-row">
524 - <input type="text" name="quiz_permalink" id="quiz_permalink" value="%s" class="cb-permalink-slug-input" placeholder="%s">
525 - <div class="cb-permalink-actions">
526 - <button type="button" class="cb-permalink-ok-btn">%s</button>
527 - <button type="button" class="cb-permalink-cancel-btn">%s</button>
528 - </div>
529 - </div>
530 - </div>',
531 - esc_html( $base_url ),
532 - esc_attr( $post_name ),
533 - esc_attr__( 'your-slug', 'learnpress' ),
534 - __( 'OK', 'learnpress' ),
535 - __( 'Cancel', 'learnpress' )
536 - );
537 -
538 - $hidden_base = sprintf(
539 - '<input type="hidden" id="cb-permalink-base-url" value="%s">',
540 - esc_attr( $base_url )
541 - );
542 -
543 - $placeholder = sprintf(
544 - '<span class="%s">%s</span>',
545 - esc_attr( $placeholder_class ),
546 - esc_html( $placeholder_text )
547 - );
548 -
549 - $view = [
550 - 'wrapper' => '<div class="cb-item-edit-permalink cb-course-edit-permalink">',
551 - 'state_a' => $state_a,
552 - 'state_b' => $state_b,
553 - 'hidden_base' => $hidden_base,
554 - 'placeholder' => $placeholder,
555 - 'wrapper_end' => '</div>',
556 - ];
557 -
558 - return Template::combine_components( $view );
559 - }
560 -
561 - public function edit_publish( $quiz_model ): string {
562 - $post_id = ! empty( $quiz_model ) ? absint( $quiz_model->get_id() ) : 0;
563 - $post = $post_id ? get_post( $post_id ) : null;
564 - $current_status = $post && ! empty( $post->post_status ) ? sanitize_key( $post->post_status ) : 'draft';
565 - $status_value = 'draft' === $current_status ? 'draft' : 'publish';
566 -
567 - $status_options_html = sprintf(
568 - '<option value="publish" %1$s>%2$s</option><option value="draft" %3$s>%4$s</option>',
569 - selected( $status_value, 'publish', false ),
570 - esc_html__( 'Published', 'learnpress' ),
571 - selected( $status_value, 'draft', false ),
572 - esc_html__( 'Draft', 'learnpress' )
573 - );
574 -
575 - $publish = [
576 - 'wrapper' => '<div class="cb-item-edit-publish">',
577 - 'title' => sprintf( '<h3 class="cb-item-edit-publish__title">%s</h3>', esc_html__( 'Publish', 'learnpress' ) ),
578 - 'status_row' => sprintf(
579 - '<div class="cb-item-edit-publish__row">
580 - <label for="cb-quiz-publish-status" class="cb-item-edit-publish__label">%1$s</label>
581 - <select id="cb-quiz-publish-status" name="cb_quiz_publish_status" class="cb-item-edit-publish__control">%2$s</select>
582 - </div>',
583 - esc_html__( 'Status', 'learnpress' ),
584 - $status_options_html
585 - ),
586 - 'wrapper_end' => '</div>',
587 - ];
588 -
589 - return Template::combine_components( $publish );
590 - }
591 -
592 - public function get_assigned( $id ) {
593 - $courses = learn_press_get_item_courses( $id );
594 -
595 - if ( empty( $courses ) ) {
596 - return array();
597 - }
598 -
599 - return array(
600 - 'id' => $courses[0]->ID,
601 - 'title' => $courses[0]->post_title ?? '',
602 - );
603 - }
604 -}
1 +<?php
2 +/**
3 + * Template hooks Course Builder.
4 + *
5 + * @since 4.3.0
6 + * @version 1.0.0
7 + */
8 +
9 +namespace LearnPress\TemplateHooks\CourseBuilder\Quiz;
10 +
11 +use Exception;
12 +use LearnPress\CourseBuilder\CourseBuilderAccessPolicy;
13 +use LearnPress\Models\UserModel;
14 +use LearnPress\TemplateHooks\CourseBuilder\Course\BuilderCourseTemplate;
15 +use LearnPress\CourseBuilder\CourseBuilder;
16 +use LearnPress\Helpers\Singleton;
17 +use LearnPress\Helpers\Template;
18 +use LearnPress\Models\PostModel;
19 +use LearnPress\Models\QuizPostModel;
20 +use LearnPress\TemplateHooks\Admin\AdminEditQizTemplate;
21 +use LearnPress\TemplateHooks\Admin\AdminTemplate;
22 +use LearnPress\TemplateHooks\Course\AdminEditCurriculumTemplate;
23 +use LearnPress\TemplateHooks\TemplateAJAX;
24 +use LP_Settings;
25 +use LP_WP_Filesystem;
26 +use Throwable;
27 +use WP_User;
28 +
29 +class BuilderEditQuizTemplate {
30 + use Singleton;
31 +
32 + public function init() {
33 + add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
34 + }
35 +
36 + /**
37 + * Display layout edit/create quiz.
38 + *
39 + * @param array $data [ 'userModel' => UserModel, 'item_id' => int|string ]
40 + *
41 + * @throws Exception
42 + */
43 + public function layout( array $data = [] ) {
44 + try {
45 + $userModel = $data['userModel'] ?? false;
46 + if ( ! $userModel || ! $userModel->is_instructor() ) {
47 + throw new Exception( __( 'You do not have permission to create or edit quizzes', 'learnpress' ) );
48 + }
49 +
50 + $item_id = $data['item_id'] ?? '';
51 + if ( empty( $item_id ) ) {
52 + throw new Exception( __( 'Invalid quiz ID', 'learnpress' ) );
53 + }
54 +
55 + /*if ( ! CourseBuilderAccessPolicy::can_access_tab_post( 'quizzes', $item_id ) ) {
56 + throw new Exception( __( "Sorry, you don't have permission to access this content", 'learnpress' ) );
57 + }*/
58 +
59 + $is_create_new = $item_id === CourseBuilder::POST_NEW;
60 + $quizModel = false;
61 +
62 + if ( ! $is_create_new ) {
63 + $quizModel = QuizPostModel::find( (int) $item_id, true );
64 + if ( ! $quizModel ) {
65 + throw new Exception( __( 'Quiz not found', 'learnpress' ) );
66 + }
67 +
68 + $quizModel->check_capabilities_update_item_course();
69 +
70 + if ( $quizModel->post_status === PostModel::STATUS_TRASH ) {
71 + throw new Exception(
72 + __(
73 + 'You cannot edit this item because it is in the Trash. Please restore it and try again.',
74 + 'learnpress'
75 + )
76 + );
77 + }
78 + } else {
79 + $quizModelNew = new QuizPostModel();
80 + $quizModelNew->check_capabilities_create_item_course();
81 + }
82 +
83 + $data['quizModel'] = $quizModel;
84 +
85 + $section = [
86 + 'wrap' => sprintf(
87 + '<div class="lp-cb-content" data-post-id="%1$s">',
88 + esc_attr( $item_id )
89 + ),
90 + 'header' => $this->html_header( $data ),
91 + 'tabs' => $this->html_tabs( $data ),
92 + 'wrap_end' => '</div>',
93 + ];
94 +
95 + echo Template::combine_components( $section );
96 +
97 + } catch ( Throwable $e ) {
98 + Template::print_message( $e->getMessage(), 'error' );
99 + }
100 + }
101 +
102 + public function html_header( array $data = [] ): string {
103 + $userModel = $data['userModel'] ?? false;
104 + if ( ! $userModel instanceof UserModel ) {
105 + return '';
106 + }
107 +
108 + $quizModel = $data['quizModel'] ?? false;
109 + $hide_instructor_access_admin_screen = LP_Settings::is_hide_instructor_access_admin_screen();
110 + $more_actions_icon = LP_WP_Filesystem::get_icon_svg( 'ico-cb-more.svg' );
111 + $title = $quizModel ? $quizModel->get_the_title() : __( 'Add New Quiz', 'learnpress' );
112 + $status = $quizModel ? $quizModel->post_status : '';
113 + $status_label = 'future' === $status ? __( 'scheduled', 'learnpress' ) : $status;
114 + $main_action_status = in_array( $status, [ 'publish', 'draft', 'pending', 'future', 'private' ], true ) ? $status : 'publish';
115 + $wp_user = new WP_User( $userModel );
116 + $hide_wp_edit_link = $hide_instructor_access_admin_screen && user_can( $wp_user, UserModel::ROLE_INSTRUCTOR );
117 +
118 + $section = [
119 + 'header_wrap' => '<div class="lp-cb-header">',
120 + 'header_left' => '<div class="lp-cb-header__left">',
121 + 'title' => sprintf(
122 + '<h1 class="lp-cb-header__title">%s</h1>',
123 + esc_html( $title )
124 + ),
125 + 'status_badge' => $quizModel && $status ? sprintf(
126 + '<span class="quiz-status %1$s">%2$s</span>',
127 + esc_attr( $status ),
128 + esc_html( $status_label )
129 + ) : '',
130 + 'link_edit_on_wp' => $quizModel && ! $hide_wp_edit_link ? sprintf(
131 + '<a href="%1$s" class="lp-cb-admin-link" target="_blank" title="%2$s"%3$s>
132 + <span class="dashicons dashicons-wordpress"></span>
133 + <span>%2$s</span>
134 + </a>',
135 + esc_url( admin_url( 'post.php?post=' . $quizModel->get_id() . '&action=edit' ) ),
136 + esc_attr__( 'Edit with WordPress', 'learnpress' ),
137 + 'trash' === $status ? ' style="display:none"' : ''
138 + ) : '',
139 + 'header_left_end' => '</div>',
140 + 'header_actions' => '<div class="lp-cb-header__actions">',
141 + 'dropdown_wrap' => '<div class="cb-header-actions-dropdown cb-header-actions-dropdown--single">',
142 + 'update_btn' => sprintf(
143 + '<div class="cb-btn-update lp-button cb-btn-primary cb-btn-main-action"
144 + data-status="%1$s"
145 + data-title-update="%2$s"
146 + data-title-publish="%3$s"
147 + data-title-draft="%4$s">%5$s</div>',
148 + esc_attr( $main_action_status ),
149 + esc_attr__( 'Update', 'learnpress' ),
150 + esc_attr__( 'Publish', 'learnpress' ),
151 + esc_attr__( 'Save Draft', 'learnpress' ),
152 + esc_html__( 'Update', 'learnpress' )
153 + ),
154 + 'dropdown_wrap_end' => '</div>',
155 + 'expanded_actions' => $quizModel ? sprintf(
156 + '<div class="cb-header-action-expanded">
157 + <button type="button" class="lp-button course-action-expanded" aria-haspopup="true" aria-expanded="false" aria-label="%1$s">
158 + %2$s
159 + </button>
160 + <div class="cb-header-action-expanded__items">
161 + <div class="cb-header-action-expanded__duplicate lp-button cb-btn-duplicate-quiz"
162 + data-title="%3$s"
163 + data-content="%4$s">
164 + <span class="dashicons dashicons-admin-page"></span>
165 + %5$s
166 + </div>
167 + <div class="cb-header-action-expanded__trash lp-button cb-btn-trash">
168 + <span class="dashicons dashicons-trash"></span>
169 + %6$s
170 + </div>
171 + </div>
172 + </div>',
173 + esc_attr__( 'More actions', 'learnpress' ),
174 + $more_actions_icon,
175 + esc_attr__( 'Are you sure?', 'learnpress' ),
176 + esc_attr__( 'Are you sure you want to duplicate this quiz?', 'learnpress' ),
177 + esc_html__( 'Duplicate', 'learnpress' ),
178 + esc_html__( 'Move to Trash', 'learnpress' )
179 + ) : '',
180 + 'header_actions_end' => '</div>',
181 + 'header_end' => '</div>',
182 + ];
183 +
184 + return Template::combine_components( $section );
185 + }
186 +
187 + public function html_tabs( array $data = [] ): string {
188 + $section_tab = [
189 + 'tabs_wrap' => '<div class="lp-cb-tabs">',
190 + 'tabs' => '',
191 + 'tabs_end' => '</div>',
192 + ];
193 +
194 + $section_content = [
195 + 'wrap' => '<div class="lp-cb-tab-content">',
196 + 'content' => '',
197 + 'wrap-end' => '</div>',
198 + ];
199 +
200 + $tabs = apply_filters(
201 + 'learn-press/course-builder/quizzes/edit/tabs',
202 + [
203 + 'overview' => [
204 + 'title' => esc_html__( 'Overview', 'learnpress' ),
205 + 'html' => $this->html_tab_overview( $data ),
206 + ],
207 + 'question' => [
208 + 'title' => esc_html__( 'Question', 'learnpress' ),
209 + 'html' => $this->html_tab_question( $data ),
210 + ],
211 + 'settings' => [
212 + 'title' => esc_html__( 'Settings', 'learnpress' ),
213 + 'html' => $this->html_tab_settings( $data ),
214 + ],
215 + ],
216 + $data
217 + );
218 +
219 + $tab_sections = [];
220 + foreach ( $tabs as $key => $tab ) {
221 + $tab_sections[ $key ] = $tab['slug'] ?? $key;
222 + }
223 +
224 + $tab_active = (string) reset( $tab_sections );
225 + if ( isset( $_GET['tab'] ) ) {
226 + $requested_tab = sanitize_key( wp_unslash( $_GET['tab'] ) );
227 + if ( in_array( $requested_tab, $tab_sections, true ) ) {
228 + $tab_active = $requested_tab;
229 + }
230 + }
231 +
232 + foreach ( $tabs as $key => $tab ) {
233 + $tab_section = $tab_sections[ $key ];
234 + $is_active = $tab_section === $tab_active;
235 +
236 + $section_tab['tabs'] .= sprintf(
237 + '<a href="#" class="lp-cb-tabs__item %s" data-tab-section="%s">%s</a>',
238 + $is_active ? 'is-active' : '',
239 + esc_attr( $tab_section ),
240 + esc_html( $tab['title'] ?? '' )
241 + );
242 +
243 + /**
244 + * @uses html_tab_overview
245 + * @uses html_tab_question
246 + * @uses html_tab_settings
247 + */
248 + $section_content['content'] .= sprintf(
249 + '<div class="lp-cb-tab-panel %s" data-section="%s">%s</div>',
250 + $is_active ? '' : 'lp-hidden',
251 + esc_attr( $tab_section ),
252 + $tab['html'] ?? ''
253 + );
254 + }
255 +
256 + return Template::combine_components(
257 + [
258 + 'tabs' => Template::combine_components( $section_tab ),
259 + 'contents' => Template::combine_components( $section_content ),
260 + ]
261 + );
262 + }
263 +
264 + public function html_tab_overview( array $data = [] ): string {
265 + wp_enqueue_script( 'lp-course-builder' );
266 +
267 + $quiz_model = $data['quizModel'] ?? false;
268 + $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
269 +
270 + if ( absint( $quiz_id ) && ! $quiz_model ) {
271 + $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
272 + if ( empty( $quiz_model ) ) {
273 + return '';
274 + }
275 + }
276 +
277 + $html_assigned = $this->assigned_course( $quiz_model );
278 + $html_edit_title = $this->edit_title( $quiz_model );
279 + $html_permalink = $this->edit_permalink( $quiz_model );
280 + $html_publish = $this->edit_publish( $quiz_model );
281 + $html_edit_desc = $this->edit_desc( $quiz_model );
282 + $section = [
283 + 'wrapper' => sprintf( '<div class="cb-section__quiz-edit" data-quiz-id="%s">', $quiz_id ),
284 + 'content_wrapper' => '<div class="cb-item-edit-content">',
285 + 'left_column' => '<div class="cb-item-edit-column cb-item-edit-column--left">',
286 + 'edit_title' => $html_edit_title,
287 + 'assigned_course' => $html_assigned,
288 + 'edit_permalink' => $html_permalink,
289 + 'edit_publish' => $html_publish,
290 + 'left_column_end' => '</div>',
291 + 'right_column' => '<div class="cb-item-edit-column cb-item-edit-column--right">',
292 + 'edit_desc' => $html_edit_desc,
293 + 'right_column_end' => '</div>',
294 + 'content_wrapper_end' => '</div>',
295 + 'wrapper_end' => '</div>',
296 + ];
297 +
298 + return Template::combine_components( $section );
299 + }
300 +
301 + public function html_tab_question( array $data = [] ): string {
302 + wp_enqueue_style( 'lp-edit-quiz' );
303 +
304 + $quiz_model = $data['quizModel'] ?? false;
305 + $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
306 +
307 + if ( $quiz_id === CourseBuilder::POST_NEW || absint( $quiz_id ) <= 0 ) {
308 + return sprintf( '<span class="lp-message lp-message--info">%s</span>', __( 'Please save Quiz before add question', 'learnpress' ) );
309 + }
310 +
311 + if ( ! $quiz_model ) {
312 + $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
313 + if ( empty( $quiz_model ) ) {
314 + return '';
315 + }
316 + }
317 +
318 + $args = [
319 + 'id_url' => 'edit-quiz',
320 + 'quiz_id' => $quiz_model->ID,
321 + ];
322 + $call_back = [
323 + 'class' => AdminEditQizTemplate::class,
324 + 'method' => 'render_edit_quiz',
325 + ];
326 +
327 + return TemplateAJAX::load_content_via_ajax( $args, $call_back );
328 + }
329 +
330 + public function html_tab_settings( array $data = [] ): string {
331 + wp_enqueue_script( 'lp-cb-edit-curriculum' );
332 + wp_enqueue_script( 'lp-tom-select' );
333 + wp_enqueue_style( 'lp-cb-edit-curriculum' );
334 + wp_enqueue_script( 'lp-cb-learnpress' );
335 +
336 + $quiz_model = $data['quizModel'] ?? false;
337 + $quiz_id = $data['item_id'] ?? ( $quiz_model ? $quiz_model->get_id() : CourseBuilder::POST_NEW );
338 +
339 + if ( $quiz_id === CourseBuilder::POST_NEW || absint( $quiz_id ) <= 0 ) {
340 + return sprintf( '<span class="lp-message lp-message--info">%s</span>', __( 'Please save Quiz before setting quiz', 'learnpress' ) );
341 + }
342 +
343 + if ( ! $quiz_model ) {
344 + $quiz_model = QuizPostModel::find( absint( $quiz_id ), true );
345 + if ( empty( $quiz_model ) ) {
346 + return '';
347 + }
348 + }
349 +
350 + if ( ! class_exists( 'LP_Meta_Box_Quiz' ) ) {
351 + require_once LP_PLUGIN_PATH . 'inc/admin/views/meta-boxes/quiz/settings.php';
352 + }
353 +
354 + $metabox = new \LP_Meta_Box_Quiz();
355 + ob_start();
356 + $metabox->output( $quiz_model );
357 + $settings = ob_get_clean();
358 +
359 + $output = [
360 + 'wrapper' => sprintf( '<div class="cb-section__quiz-edit" data-quiz-id="%s">', $quiz_id ),
361 + 'form_setting' => '<form name="lp-form-setting-quiz" class="lp-form-setting-quiz" method="post" enctype="multipart/form-data">',
362 + 'settings' => $settings,
363 + 'form_setting_end' => '</form>',
364 + 'wrapper_end' => '</div>',
365 + ];
366 +
367 + return Template::combine_components( $output );
368 + }
369 +
370 + /**
371 + * Allow callback for AJAX.
372 + * @use self::render_edit_course_curriculum
373 + * @use self::render_html
374 + *
375 + * @param array $callbacks
376 + *
377 + * @return array
378 + */
379 + public function allow_callback( array $callbacks ): array {
380 + $callbacks[] = AdminEditCurriculumTemplate::class . ':render_edit_course_curriculum';
381 +
382 + return $callbacks;
383 + }
384 +
385 + public function assigned_course( $quiz_model ) {
386 + $assign_course = ! empty( $quiz_model ) ? $this->get_assigned( $quiz_model->get_id() ) : '';
387 + $html_courses = '';
388 + $assigned = sprintf( '<span class="quiz-not-assigned">%s</span>', __( 'Not assigned yet', 'learnpress' ) );
389 + if ( ! empty( $assign_course ) ) {
390 + $courses = is_array( $assign_course ) && isset( $assign_course['id'] )
391 + ? array( $assign_course )
392 + : $assign_course;
393 +
394 + $course_htmls = array();
395 + foreach ( $courses as $course ) {
396 + $course_id = $course['id'] ?? 0;
397 + $course_title = $course['title'] ?? '';
398 +
399 + if ( $course_id && $course_title ) {
400 + $course_link = BuilderCourseTemplate::instance()->get_link_edit( $course_id );
401 + $course_htmls[] = sprintf(
402 + '<a href="%s" target="_blank">%s</a>',
403 + esc_url( $course_link ),
404 + esc_html( $course_title )
405 + );
406 + }
407 + }
408 +
409 + if ( ! empty( $course_htmls ) ) {
410 + $assigned = implode( ', ', $course_htmls );
411 + }
412 + }
413 +
414 + $html_courses = sprintf(
415 + '<div class="cb-item-edit-assigned quiz-assigned-courses"><span class="label">%s</span> %s</div>',
416 + __( 'Assigned', 'learnpress' ),
417 + $assigned
418 + );
419 +
420 + return $html_courses;
421 + }
422 +
423 +
424 + public function edit_title( $quiz_model ) {
425 + $title = ! empty( $quiz_model ) ? $quiz_model->get_the_title() : '';
426 + $edit = [
427 + 'wrapper' => '<div class="cb-quiz-edit-title">',
428 + 'label' => sprintf( '<label for="title" class="cb-quiz-edit-title__label">%s</label>', __( 'Title', 'learnpress' ) ),
429 + 'input' => sprintf( '<input type="text" name="quiz_title" size="30" value="%s" id="title" class="cb-quiz-edit-title__input">', esc_attr( $title ) ),
430 + 'wrapper_end' => '</div>',
431 + ];
432 +
433 + return Template::combine_components( $edit );
434 + }
435 +
436 + /**
437 + * Edit description
438 + *
439 + * @param QuizPostModel|false $quiz_model
440 + * @return string
441 + */
442 + public function edit_desc( $quiz_model ) {
443 + $desc = ! empty( $quiz_model ) ? $quiz_model->post_content : '';
444 + $editor_id = 'quiz_description_editor';
445 + $editor_settings = array(
446 + 'textarea_name' => 'quiz_description',
447 + 'textarea_rows' => 10,
448 + 'teeny' => false,
449 + 'media_buttons' => true,
450 + 'tinymce' => array(
451 + 'content_style' => "body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; font-size: 14px; line-height: 1.6; color: #1e1e1e; }",
452 + 'toolbar1' => 'formatselect,bold,italic,underline,bullist,numlist,blockquote,alignleft,aligncenter,alignright,link,unlink,spellchecker,wp_adv',
453 + 'toolbar2' => 'strikethrough,hr,forecolor,pastetext,removeformat,charmap,outdent,indent,undo,redo,wp_help',
454 + ),
455 + 'quicktags' => true,
456 + );
457 +
458 + $edit = [
459 + 'wrapper' => '<div class="cb-quiz-edit-desc">',
460 + 'label' => sprintf( '<label for="quiz_description" class="cb-quiz-edit-desc__label">%s</label>', __( 'Description', 'learnpress' ) ),
461 + 'edit' => AdminTemplate::editor_tinymce(
462 + $desc,
463 + $editor_id,
464 + $editor_settings
465 + ),
466 + 'wrapper_end' => '</div>',
467 + ];
468 +
469 + return Template::combine_components( $edit );
470 + }
471 +
472 + public function edit_permalink( $quiz_model ): string {
473 + $post_id = ! empty( $quiz_model ) ? absint( $quiz_model->get_id() ) : 0;
474 + $post = $post_id ? get_post( $post_id ) : null;
475 + $post_name = $post && ! empty( $post->post_name ) ? (string) $post->post_name : '';
476 + $full_url = '';
477 + $base_url = '';
478 + $display_classes = 'cb-permalink-display';
479 + $placeholder_class = 'cb-item-edit-permalink__placeholder';
480 + $notice_no_link = __(
481 + 'Permalink is only available if the item is already assigned to a course.',
482 + 'learnpress'
483 + );
484 + $placeholder_text = __( 'Permalink will be available after saving.', 'learnpress' );
485 + $show_unavailable = true;
486 +
487 + if ( $post_id ) {
488 + $current_status = $post && ! empty( $post->post_status ) ? sanitize_key( $post->post_status ) : '';
489 + if ( 'draft' !== $current_status ) {
490 + $course_id_of_item = \LP_Course_DB::getInstance()->get_course_by_item_id( $post_id );
491 + if ( $course_id_of_item ) {
492 + $course = learn_press_get_course( $course_id_of_item );
493 + if ( $course ) {
494 + $full_url = urldecode( $course->get_item_link( $post_id ) );
495 + $base_url = $full_url;
496 + $show_unavailable = false;
497 +
498 + if ( ! empty( $post_name ) ) {
499 + $base_url = trailingslashit( preg_replace( '/' . preg_quote( $post_name, '/' ) . '\/?$/', '', $full_url ) );
500 + }
501 + }
502 + }
503 + }
504 + }
505 +
506 + if ( $show_unavailable && $post_id ) {
507 + $placeholder_text = $notice_no_link;
508 + }
509 +
510 + if ( $show_unavailable ) {
511 + $display_classes .= ' lp-hidden';
512 + } else {
513 + $placeholder_class .= ' lp-hidden';
514 + }
515 +
516 + $state_a = sprintf(
517 + '<span class="cb-item-edit-permalink__label">%s</span>
518 + <div class="%s">
519 + <a href="%s" target="_blank" class="cb-permalink-url">%s</a>
520 + <button type="button" class="cb-permalink-edit-btn" title="%s">
521 + <span class="dashicons dashicons-edit"></span>
522 + </button>
523 + </div>',
524 + __( 'Permalink', 'learnpress' ),
525 + esc_attr( $display_classes ),
526 + esc_url( $full_url ),
527 + esc_html( $full_url ),
528 + __( 'Edit', 'learnpress' )
529 + );
530 +
531 + $state_b = sprintf(
532 + '<div class="cb-permalink-editor lp-hidden">
533 + <span class="cb-permalink-prefix">%s</span>
534 + <div class="cb-permalink-input-row">
535 + <input type="text" name="quiz_permalink" id="quiz_permalink" value="%s" class="cb-permalink-slug-input" placeholder="%s">
536 + <div class="cb-permalink-actions">
537 + <button type="button" class="cb-permalink-ok-btn">%s</button>
538 + <button type="button" class="cb-permalink-cancel-btn">%s</button>
539 + </div>
540 + </div>
541 + </div>',
542 + esc_html( $base_url ),
543 + esc_attr( $post_name ),
544 + esc_attr__( 'your-slug', 'learnpress' ),
545 + __( 'OK', 'learnpress' ),
546 + __( 'Cancel', 'learnpress' )
547 + );
548 +
549 + $hidden_base = sprintf(
550 + '<input type="hidden" id="cb-permalink-base-url" value="%s">',
551 + esc_attr( $base_url )
552 + );
553 +
554 + $placeholder = sprintf(
555 + '<span class="%s">%s</span>',
556 + esc_attr( $placeholder_class ),
557 + esc_html( $placeholder_text )
558 + );
559 +
560 + $view = [
561 + 'wrapper' => '<div class="cb-item-edit-permalink cb-course-edit-permalink">',
562 + 'state_a' => $state_a,
563 + 'state_b' => $state_b,
564 + 'hidden_base' => $hidden_base,
565 + 'placeholder' => $placeholder,
566 + 'wrapper_end' => '</div>',
567 + ];
568 +
569 + return Template::combine_components( $view );
570 + }
571 +
572 + public function edit_publish( $quiz_model ): string {
573 + $post_id = ! empty( $quiz_model ) ? absint( $quiz_model->get_id() ) : 0;
574 + $post = $post_id ? get_post( $post_id ) : null;
575 + $current_status = $post && ! empty( $post->post_status ) ? sanitize_key( $post->post_status ) : 'draft';
576 + $status_value = 'draft' === $current_status ? 'draft' : 'publish';
577 +
578 + $status_options_html = sprintf(
579 + '<option value="publish" %1$s>%2$s</option><option value="draft" %3$s>%4$s</option>',
580 + selected( $status_value, 'publish', false ),
581 + esc_html__( 'Published', 'learnpress' ),
582 + selected( $status_value, 'draft', false ),
583 + esc_html__( 'Draft', 'learnpress' )
584 + );
585 +
586 + $publish = [
587 + 'wrapper' => '<div class="cb-item-edit-publish">',
588 + 'title' => sprintf( '<h3 class="cb-item-edit-publish__title">%s</h3>', esc_html__( 'Publish', 'learnpress' ) ),
589 + 'status_row' => sprintf(
590 + '<div class="cb-item-edit-publish__row">
591 + <label for="cb-quiz-publish-status" class="cb-item-edit-publish__label">%1$s</label>
592 + <select id="cb-quiz-publish-status" name="cb_quiz_publish_status" class="cb-item-edit-publish__control">%2$s</select>
593 + </div>',
594 + esc_html__( 'Status', 'learnpress' ),
595 + $status_options_html
596 + ),
597 + 'wrapper_end' => '</div>',
598 + ];
599 +
600 + return Template::combine_components( $publish );
601 + }
602 +
603 + public function get_assigned( $id ) {
604 + $courses = learn_press_get_item_courses( $id );
605 +
606 + if ( empty( $courses ) ) {
607 + return array();
608 + }
609 +
610 + return array(
611 + 'id' => $courses[0]->ID,
612 + 'title' => $courses[0]->post_title ?? '',
613 + );
614 + }
615 +}