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 / CourseBuilder / BuilderPopupTemplate.php

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

378 lines 13.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Template hooks for Course Builder Popup.
4 * Handles AJAX popup loading for lesson, quiz, and question builders.
5 *
6 * @since 4.3.0
7 * @version 1.0.0
8 */
9
10 namespace LearnPress\TemplateHooks\CourseBuilder;
11
12 use Exception;
13 use LearnPress\CourseBuilder\CourseBuilder;
14 use LearnPress\CourseBuilder\CourseBuilderAccessPolicy;
15 use LearnPress\Helpers\Singleton;
16 use LearnPress\Helpers\Template;
17 use LearnPress\Models\LessonPostModel;
18 use LearnPress\Models\PostModel;
19 use LearnPress\Models\QuizPostModel;
20 use LearnPress\Models\Question\QuestionPostModel;
21 use LearnPress\TemplateHooks\CourseBuilder\Lesson\BuilderEditLessonTemplate;
22 use LearnPress\TemplateHooks\CourseBuilder\Question\BuilderEditQuestionTemplate;
23 use LearnPress\TemplateHooks\CourseBuilder\Quiz\BuilderEditQuizTemplate;
24 use stdClass;
25
26 class BuilderPopupTemplate {
27 use Singleton;
28
29 public function init() {
30 add_filter( 'lp/rest/ajax/allow_callback', [ $this, 'allow_callback' ] );
31 }
32
33 /**
34 * Allow callback for AJAX.
35 *
36 * @param array $callbacks
37 * @return array
38 */
39 public function allow_callback( array $callbacks ): array {
40 $callbacks[] = self::class . ':render_lesson_popup';
41 $callbacks[] = self::class . ':render_quiz_popup';
42 $callbacks[] = self::class . ':render_question_popup';
43
44 return $callbacks;
45 }
46
47 /**
48 * Validate object-level permission before rendering popup content.
49 *
50 * @param string $item_type
51 * @param int $item_id
52 *
53 * @throws Exception
54 */
55 /*private static function ensure_popup_access( string $item_type, int $item_id ) {
56 if ( $item_id > 0 ) {
57 if ( ! CourseBuilderAccessPolicy::can_edit_item( $item_type, $item_id ) ) {
58 throw new Exception( __( "Sorry, you don't have permission to access this content", 'learnpress' ) );
59 }
60
61 return;
62 }
63
64 if ( ! CourseBuilderAccessPolicy::can_create_item_type( $item_type ) ) {
65 throw new Exception( __( "Sorry, you don't have permission to create this item", 'learnpress' ) );
66 }
67 }*/
68
69 /**
70 * Get popup wrapper HTML structure.
71 */
72 public function get_popup_wrapper( string $type, int $post_id, string $title, string $status = '' ): array {
73 $status_html = '';
74 if ( ! empty( $status ) ) {
75 $status_html = sprintf( '<span class="%s-status %s">%s</span>', $type, esc_attr( $status ), esc_html( $status ) );
76 }
77
78 return [
79 'overlay' => '<div class="lp-builder-popup-overlay"></div>',
80 'wrapper' => sprintf( '<div class="lp-builder-popup lp-builder-popup--%s" data-%s-id="%d">', $type, $type, $post_id ),
81 'header' => '<div class="lp-builder-popup__header">',
82 'header_left' => '<div class="lp-builder-popup__header-left">',
83 'title' => sprintf( '<h3 class="lp-builder-popup__title">%s</h3>', esc_html( $title ) ),
84 'status' => $status_html,
85 'header_left_end' => '</div>',
86 'header_actions' => '<div class="lp-builder-popup__header-actions">',
87 'resize_btn' => '<button type="button" class="lp-builder-popup__resize" aria-label="' . esc_attr__( 'Toggle fullscreen', 'learnpress' ) . '" title="' . esc_attr__( 'Toggle fullscreen', 'learnpress' ) . '"><i class="lp-icon-expand"></i></button>',
88 'close_btn' => '<button type="button" class="lp-builder-popup__close" aria-label="' . esc_attr__( 'Close', 'learnpress' ) . '">&times;</button>',
89 'header_actions_end' => '</div>',
90 'header_end' => '</div>',
91 'body' => '<div class="lp-builder-popup__body">',
92 ];
93 }
94
95 /**
96 * Get popup footer HTML structure with Trash and Update/Publish buttons.
97 * Same style as edit lesson/question/quiz pages.
98 */
99 public function get_popup_footer( string $type, int $post_id, string $status = '' ): array {
100 $btn_save_text = $status === 'publish' ? __( 'Update', 'learnpress' ) : __( 'Publish', 'learnpress' );
101
102 // Trash button - only show if item exists (post_id > 0)
103 $btn_trash = '';
104 // Save Draft button
105 $btn_draft = '';
106 $btn_save = '';
107 if ( $status !== 'trash' ) {
108 $btn_draft = sprintf(
109 '<button type="button" class="cb-button lp-button cb-button--secondary cb-btn-draft__%s lp-builder-popup__btn lp-builder-popup__btn--draft" data-confirm-unpublish="%s">%s</button>',
110 $type,
111 esc_attr__( 'Saving as draft will unpublish this item from the course. Are you sure?', 'learnpress' ),
112 __( 'Save Draft', 'learnpress' )
113 );
114
115 $btn_save = sprintf(
116 '<button type="button" class="cb-button lp-button cb-btn-update__%s lp-builder-popup__btn lp-builder-popup__btn--save" data-title-update="%s" data-title-publish="%s">%s</button>',
117 $type,
118 __( 'Update', 'learnpress' ),
119 __( 'Publish', 'learnpress' ),
120 $btn_save_text
121 );
122
123 if ( $post_id > 0 ) {
124 $btn_trash = sprintf(
125 '<button type="button" class="cb-button lp-button cb-btn-trash__%s lp-builder-popup__btn lp-builder-popup__btn--trash">%s</button>',
126 $type,
127 __( 'Move to trash', 'learnpress' )
128 );
129 }
130 }
131
132 return [
133 'body_end' => '</div>',
134 'footer' => '<div class="lp-builder-popup__footer">',
135 'footer_left' => '<div class="lp-builder-popup__footer-left">',
136 'btn_trash' => $btn_trash,
137 'footer_left_end' => '</div>',
138 'footer_right' => '<div class="lp-builder-popup__footer-right">',
139 'btn_cancel' => sprintf(
140 '<button type="button" class="cb-button lp-builder-popup__btn lp-builder-popup__btn--cancel">%s</button>',
141 __( 'Cancel', 'learnpress' )
142 ),
143 'btn_draft' => $btn_draft,
144 'btn_save' => $btn_save,
145 'footer_right_end' => '</div>',
146 'footer_end' => '</div>',
147 'wrapper_end' => '</div>',
148 ];
149 }
150
151 /**
152 * Render Lesson Popup
153 * @throws Exception
154 */
155 public static function render_lesson_popup( array $args = [] ): stdClass {
156 $response = new stdClass();
157 $lesson_id = absint( $args['lesson_id'] ?? 0 );
158 //self::ensure_popup_access( LP_LESSON_CPT, $lesson_id );
159
160 $lesson_model = $lesson_id ? LessonPostModel::find( $lesson_id, true ) : null;
161
162 if ( $lesson_model instanceof LessonPostModel ) {
163 $lesson_model->check_capabilities_update_item_course();
164 } else {
165 $lessonPostModelNew = new LessonPostModel();
166 $lessonPostModelNew->check_capabilities_create_item_course();
167 }
168
169 $title = $lesson_model ? __( 'Edit Lesson', 'learnpress' ) : __( 'New Lesson', 'learnpress' );
170 $status = $lesson_model ? $lesson_model->post_status : '';
171
172 $instance = self::instance();
173 $content = $instance->build_lesson_content( $lesson_id, $lesson_model );
174
175 $html = array_merge(
176 $instance->get_popup_wrapper( 'lesson', $lesson_id, $title, $status ),
177 [ 'content' => $content ],
178 $instance->get_popup_footer( 'lesson', $lesson_id, $status )
179 );
180
181 $response->content = Template::combine_components( $html );
182
183 return $response;
184 }
185
186 /**
187 * Build lesson content
188 * @throws Exception
189 */
190 private function build_lesson_content( int $lesson_id, $lesson_model ): string {
191 if ( $lesson_model && $lesson_model->post_status === PostModel::STATUS_TRASH ) {
192 $message = __(
193 'You cannot edit this item because it is in the Trash. Please restore it and try again.',
194 'learnpress'
195 );
196
197 return Template::print_message( $message, 'error', false );
198 }
199
200 $template = BuilderEditLessonTemplate::instance();
201 $lesson_context_id = $lesson_id > 0 ? $lesson_id : CourseBuilder::POST_NEW;
202 $lesson_data = [
203 'item_id' => $lesson_context_id,
204 'lessonModel' => $lesson_model ?? false,
205 ];
206 $overview_html = $template->html_tab_overview( $lesson_data );
207 $settings_html = $template->html_tab_settings( $lesson_data );
208
209 $sections = [
210 'wrapper' => sprintf( '<div class="cb-section__lesson-edit" data-lesson-id="%d">', $lesson_id ),
211 'tabs' => $this->build_tabs( 'lesson', [ 'overview', 'settings' ] ),
212 'tab_content_start' => '<div class="lp-builder-popup__tab-content">',
213 'overview' => sprintf( '<div class="lp-builder-popup__tab-pane active" data-tab="overview">%s</div>', $overview_html ),
214 'settings' => sprintf( '<div class="lp-builder-popup__tab-pane" data-tab="settings">%s</div>', $settings_html ),
215 'tab_content_end' => '</div>',
216 'wrapper_end' => '</div>',
217 ];
218
219 return Template::combine_components( $sections );
220 }
221
222 /**
223 * Render Quiz Popup
224 * @throws Exception
225 */
226 public static function render_quiz_popup( array $args = [] ): stdClass {
227 $response = new stdClass();
228 $quiz_id = absint( $args['quiz_id'] ?? 0 );
229 //self::ensure_popup_access( LP_QUIZ_CPT, $quiz_id );
230
231 $quiz_model = $quiz_id ? QuizPostModel::find( $quiz_id, true ) : null;
232
233 if ( $quiz_model instanceof QuizPostModel ) {
234 $quiz_model->check_capabilities_update_item_course();
235 } else {
236 $quizPostModelNew = new QuizPostModel();
237 $quizPostModelNew->check_capabilities_create_item_course();
238 }
239
240 $title = $quiz_model ? __( 'Edit Quiz', 'learnpress' ) : __( 'New Quiz', 'learnpress' );
241 $status = $quiz_model ? $quiz_model->post_status : '';
242
243 $instance = self::instance();
244 $content = $instance->build_quiz_content( $quiz_id, $quiz_model );
245
246 $html = array_merge(
247 $instance->get_popup_wrapper( 'quiz', $quiz_id, $title, $status ),
248 [ 'content' => $content ],
249 $instance->get_popup_footer( 'quiz', $quiz_id, $status )
250 );
251
252 $response->content = Template::combine_components( $html );
253
254 return $response;
255 }
256
257 /**
258 * Build quiz content
259 */
260 private function build_quiz_content( int $quiz_id, $quiz_model = false ): string {
261 $template = BuilderEditQuizTemplate::instance();
262 $quiz_context_id = $quiz_id > 0 ? $quiz_id : CourseBuilder::POST_NEW;
263 $quiz_data = [
264 'item_id' => $quiz_context_id,
265 'quizModel' => $quiz_model,
266 ];
267 $overview_html = $template->html_tab_overview( $quiz_data );
268 $question_html = $template->html_tab_question( $quiz_data );
269 $settings_html = $template->html_tab_settings( $quiz_data );
270
271 $sections = [
272 'wrapper' => sprintf( '<div class="cb-section__quiz-edit" data-quiz-id="%d">', $quiz_id ),
273 'tabs' => $this->build_tabs( 'quiz', [ 'overview', 'questions', 'settings' ] ),
274 'tab_content_start' => '<div class="lp-builder-popup__tab-content">',
275 'overview' => sprintf( '<div class="lp-builder-popup__tab-pane active" data-tab="overview">%s</div>', $overview_html ),
276 'questions' => sprintf( '<div class="lp-builder-popup__tab-pane" data-tab="questions" data-require-js="quiz-questions">%s</div>', $question_html ),
277 'settings' => sprintf( '<div class="lp-builder-popup__tab-pane" data-tab="settings">%s</div>', $settings_html ),
278 'tab_content_end' => '</div>',
279 'wrapper_end' => '</div>',
280 ];
281
282 return Template::combine_components( $sections );
283 }
284
285 /**
286 * Render Question Popup
287 * @throws Exception
288 */
289 public static function render_question_popup( array $args = [] ): stdClass {
290 $response = new stdClass();
291 $question_id = absint( $args['question_id'] ?? 0 );
292 //self::ensure_popup_access( LP_QUESTION_CPT, $question_id );
293
294 $question_model = $question_id ? QuestionPostModel::find( $question_id, true ) : null;
295
296 if ( $question_model instanceof QuestionPostModel ) {
297 $question_model->check_capabilities_update_item_course();
298 } else {
299 $questionPostModelNew = new QuestionPostModel();
300 $questionPostModelNew->check_capabilities_create_item_course();
301 }
302
303 $title = $question_model ? __( 'Edit Question', 'learnpress' ) : __( 'New Question', 'learnpress' );
304 $status = $question_model ? $question_model->post_status : '';
305
306 $instance = self::instance();
307 $content = $instance->build_question_content( $question_id, $question_model );
308
309 $html = array_merge(
310 $instance->get_popup_wrapper( 'question', $question_id, $title, $status ),
311 [ 'content' => $content ],
312 $instance->get_popup_footer( 'question', $question_id, $status )
313 );
314
315 $response->content = Template::combine_components( $html );
316
317 return $response;
318 }
319
320 /**
321 * Build question content
322 */
323 private function build_question_content( int $question_id, $question_model = false ): string {
324 $template = BuilderEditQuestionTemplate::instance();
325 $question_context_id = $question_id > 0 ? $question_id : CourseBuilder::POST_NEW;
326 $question_data = [
327 'item_id' => $question_context_id,
328 'questionModel' => $question_model,
329 ];
330 $overview_html = $template->html_tab_overview( $question_data );
331 $settings_html = $template->html_tab_settings( $question_data );
332
333 $sections = [
334 'wrapper' => sprintf( '<div class="cb-section__question-edit" data-question-id="%d">', $question_id ),
335 'tabs' => $this->build_tabs( 'question', [ 'overview', 'settings' ] ),
336 'tab_content_start' => '<div class="lp-builder-popup__tab-content">',
337 'overview' => sprintf( '<div class="lp-builder-popup__tab-pane active" data-tab="overview">%s</div>', $overview_html ),
338 'settings' => sprintf( '<div class="lp-builder-popup__tab-pane" data-tab="settings">%s</div>', $settings_html ),
339 'tab_content_end' => '</div>',
340 'wrapper_end' => '</div>',
341 ];
342
343 return Template::combine_components( $sections );
344 }
345
346 /**
347 * Build tabs navigation.
348 */
349 public function build_tabs( string $type, array $tabs ): string {
350 $tab_labels = apply_filters(
351 "learn-press/course-builder/popup/{$type}/tab-labels",
352 [
353 'overview' => __( 'Overview', 'learnpress' ),
354 'settings' => __( 'Settings', 'learnpress' ),
355 'questions' => __( 'Questions', 'learnpress' ),
356 'answers' => __( 'Answers', 'learnpress' ),
357 ],
358 $type,
359 $tabs
360 );
361
362 $tabs_html = '<ul class="lp-builder-popup__tabs">';
363 foreach ( $tabs as $index => $tab ) {
364 $active = $index === 0 ? ' active' : '';
365 $label = $tab_labels[ $tab ] ?? ucfirst( $tab );
366 $tabs_html .= sprintf(
367 '<li class="lp-builder-popup__tab%s" data-tab="%s">%s</li>',
368 $active,
369 esc_attr( $tab ),
370 esc_html( $label )
371 );
372 }
373 $tabs_html .= '</ul>';
374
375 return $tabs_html;
376 }
377 }
378