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 / AI / AdminCreateCourseAITemplate.php

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

666 lines 22.0 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\AI;
4
5 use LearnPress\Helpers\Config;
6 use LearnPress\Helpers\Singleton;
7 use LearnPress\Helpers\Template;
8 use LearnPress\TemplateHooks\Admin\AdminTemplate;
9 use LP_Debug;
10 use Throwable;
11
12 /**
13 * Class AdminCreateCourseAITemplate
14 *
15 * @since 4.3.0
16 * @version 1.0.0
17 */
18 class AdminCreateCourseAITemplate {
19 use Singleton;
20
21 /**
22 * @var array|null
23 */
24 private ?array $config;
25
26 /**
27 * Init hooks.
28 */
29 public function init() {
30 add_action( 'admin_footer', [ $this, 'layout_popup' ] );
31 }
32
33 public function layout_popup() {
34 try {
35 if ( ! function_exists( 'get_current_screen' ) ) {
36 return;
37 }
38
39 $screen = get_current_screen();
40 if ( ! $screen || $screen->id != 'edit-' . LP_COURSE_CPT ) {
41 return;
42 }
43
44 $this->config = Config::instance()->get( 'open-ai-modal', 'settings' );
45 echo $this->html_create_course_via_ai();
46 echo $this->html_creating_course();
47 echo $this->html_warning_enable_ai();
48 } catch ( Throwable $e ) {
49 LP_Debug::error_log( $e );
50 }
51 }
52
53 /**
54 * Render AI templates for non-admin contexts (e.g. Course Builder frontend).
55 *
56 * @return string
57 */
58 public function render_for_frontend(): string {
59 $this->config = Config::instance()->get( 'open-ai-modal', 'settings' );
60
61 return $this->html_create_course_via_ai()
62 . $this->html_creating_course()
63 . $this->html_warning_enable_ai();
64 }
65
66 public function html_create_course_via_ai(): string {
67 $components = [
68 'wrap-script-template' => '<script type="text/template" id="lp-tmpl-create-course-ai">',
69 'wrap' => '<div class="lp-generate-data-ai-wrap">',
70 'btn-close' =>
71 '<button type="button" class="lp-btn-close-ai-popup">
72 <i class="lp-icon-remove"></i>
73 </button>',
74 'h2' => sprintf(
75 '<div class="content-title">%s</div>',
76 esc_html__( 'AI Course Builder for LearnPress', 'learnpress' )
77 ),
78 'header' => $this->html_step_header(),
79 'form' => '<form class="lp-form-generate-data-ai">',
80 'step_1' => $this->html_step_1(),
81 'step_2' => $this->html_step_2(),
82 'step_3' => $this->html_step_3(),
83 'step_4' => $this->html_step_4(),
84 'step_5' => $this->html_step_5(),
85 'buttons' => sprintf(
86 '<div class="button-actions" data-step="1" data-step-max="4">
87 <button class="btn btn-secondary lp-btn-step lp-hidden"
88 data-step-show="2,3,4,5"
89 data-action="prev" type="button">&larr; %s
90 </button>
91 <button class="btn btn-primary lp-btn-step"
92 data-step-show="1,2"
93 data-action="next" type="button">%s &rarr;
94 </button>
95 <button class="lp-button btn-primary lp-btn-generate-prompt lp-hidden"
96 data-step-show="3"
97 data-send="%s" type="button">%s
98 </button>
99 <button class="lp-button btn-primary lp-btn-call-open-ai lp-hidden"
100 data-step-show="4"
101 data-send="%s" type="button">%s
102 </button>
103 <button class="lp-button btn-primary lp-btn-create-course lp-hidden"
104 data-step-show="5"
105 data-send="%s"
106 type="button">%s
107 </button>
108 </div>',
109 esc_html__( 'Previous', 'learnpress' ),
110 esc_html__( 'Next', 'learnpress' ),
111 Template::convert_data_to_json(
112 [
113 'action' => 'openai_generate_prompt_course',
114 'id_url' => 'generate_prompt_openai',
115 ]
116 ),
117 esc_html__( 'Generate Prompt', 'learnpress' ),
118 Template::convert_data_to_json(
119 [
120 'action' => 'openai_generate_data_course',
121 'id_url' => 'submit_to_openai',
122 ]
123 ),
124 esc_html__( 'Generate Data Course', 'learnpress' ),
125 Template::convert_data_to_json(
126 [
127 'action' => 'openai_create_course',
128 'id_url' => 'openai_create_course',
129 ]
130 ),
131 esc_html__( 'Create Course', 'learnpress' ),
132 ),
133 'form-end' => '</form>',
134 'wrap-end' => '</div>',
135 'wrap-script-template-end' => '</script>',
136 ];
137
138 return Template::combine_components( $components );
139 }
140
141 public function html_step_header(): string {
142 $components = [
143 'wrap' => '<div class="step-header">',
144 'step_1' => sprintf(
145 '<div class="step-item active" data-step="1"><span class="step-number">1</span><span class="step-text">%s</span></div>',
146 esc_html__( 'Course Goal', 'learnpress' )
147 ),
148 'step_2' => sprintf(
149 '<div class="step-item" data-step="2"><span class="step-number">2</span><span class="step-text">%s</span></div>',
150 esc_html__( 'AI Settings', 'learnpress' )
151 ),
152 'step_3' => sprintf(
153 '<div class="step-item" data-step="3"><span class="step-number">3</span><span class="step-text">%s</span></div>',
154 esc_html__( 'Course Structure', 'learnpress' )
155 ),
156 'step_4' => sprintf(
157 '<div class="step-item" data-step="4"><span class="step-number">4</span><span class="step-text">%s</span></div>',
158 esc_html__( 'Prompt', 'learnpress' )
159 ),
160 'step_5' => sprintf(
161 '<div class="step-item" data-step="5">
162 <span class="step-number">5</span>
163 <span class="step-text">%s</span>
164 </div>',
165 esc_html__( 'Create course', 'learnpress' )
166 ),
167 'wrap-end' => '</div>',
168 ];
169
170 return Template::combine_components( $components );
171 }
172
173 private function html_step_1(): string {
174 $options = $this->config;
175
176 $components = [
177 'step' => '<div class="step-content active" data-step="1">',
178 'title' => sprintf(
179 '<div class="step-title">%s</div>',
180 esc_html__( 'Step 1 — Course Goal', 'learnpress' ),
181 ),
182 'description' => sprintf(
183 '<p class="step-description">%s</p>',
184 ''
185 ),
186 'role' => sprintf(
187 '<div class="form-group">
188 <label>%s</label>
189 <input type="text" name="role_persona" placeholder="">
190 <p class="field-description">%s</p>
191 </div>',
192 esc_html__( 'Role / Persona', 'learnpress' ),
193 esc_html__( 'Defines who is creating the course so AI can tailor tone, expertise, and perspective.', 'learnpress' )
194 ),
195 'audience' => sprintf(
196 '<div class="form-group">
197 <label>%s</label>%s
198 <p class="field-description">%s</p>
199 </div>',
200 esc_html__( 'Target Audience', 'learnpress' ),
201 AdminTemplate::html_tom_select(
202 [
203 'name' => 'target_audience',
204 'class_name' => '',
205 'options' => $options['audience'] ?? [],
206 'default_value' => 'Students',
207 'multiple' => true,
208 ]
209 ),
210 esc_html__( 'Identifies who will take the course so the content matches their background and skill level.', 'learnpress' )
211 ),
212 'objective' => sprintf(
213 '<div class="form-group">
214 <label>%s</label>
215 <textarea name="course_objective" placeholder="%s"></textarea>
216 <p class="field-description">%s</p>
217 </div>',
218 esc_html__( 'Course objective', 'learnpress' ),
219 esc_html__( 'Enter description about course you want AI generate', 'learnpress' ),
220 esc_html__( 'Specifies what learners should achieve after completing the course, guiding AI to generate outcome-aligned content.', 'learnpress' ),
221 ),
222 'step_close' => '</div>',
223 ];
224
225 return Template::combine_components( $components );
226 }
227
228 /**
229 * Step 2 HTML.
230 *
231 * @return string
232 */
233 public function html_step_2(): string {
234 $options = $this->config;
235 $grid_components = [
236 'grid' => '<div class="form-grid">',
237 'language' => sprintf(
238 '<div class="form-group">
239 <label>%s</label>%s
240 <p class="field-description">%s</p>
241 </div>',
242 esc_html__( 'Language', 'learnpress' ),
243 AdminTemplate::html_tom_select(
244 [
245 'name' => 'language',
246 'options' => $options['language'] ?? [],
247 ]
248 ),
249 esc_html__( 'Sets the output language for all generated course content.', 'learnpress' )
250 ),
251 'tone' => sprintf(
252 '<div class="form-group">
253 <label for="swal-tone">%s</label>%s
254 <p class="field-description">%s</p>
255 </div>',
256 esc_html__( 'Tone', 'learnpress' ),
257 AdminTemplate::html_tom_select(
258 [
259 'name' => 'tone',
260 'options' => $options['tone'] ?? [],
261 'multiple' => true,
262 'default_value' => [ 'Analytical' ],
263 ]
264 ),
265 esc_html__( 'Controls the writing style (e.g., friendly, formal, story-telling) so the content matches your brand and audience.', 'learnpress' )
266 ),
267 'reading_level' => sprintf(
268 '<div class="form-group">
269 <label for="swal-levels">%s</label>
270 %s
271 <p class="field-description">%s</p>
272 </div>',
273 esc_html__( 'Reading level', 'learnpress' ),
274 AdminTemplate::html_tom_select(
275 [
276 'name' => 'reading_level',
277 'options' => $options['reading_level'] ?? [],
278 ]
279 ),
280 esc_html__( 'Determines the complexity of language (e.g., foundational, intermediate, advanced) so the AI can generate content appropriate for the learners’ comprehension level.', 'learnpress' )
281 ),
282 'seo_emphasis' => sprintf(
283 '<div class="form-group">
284 <label for="seo-emphasis">%s</label>
285 <input type="text" name="seo_emphasis" value="">
286 <p class="field-description">%s</p>
287 </div>',
288 esc_html__( 'SEO emphasis', 'learnpress' ),
289 esc_html__( 'Determines how strongly AI should optimize content for search engines.', 'learnpress' ),
290 ),
291 'keywords' => sprintf(
292 '<div class="form-group">
293 <label>%s</label>
294 <input type="text" name="target_keywords" value="">
295 <p class="field-description">%s</p>
296 </div>',
297 esc_html__( 'Target keywords (comma-separated)', 'learnpress' ),
298 esc_html__( 'Lists the keywords AI should integrate to improve SEO performance across titles and descriptions.', 'learnpress' )
299 ),
300 'grid-end' => '</div>',
301 ];
302
303 $components = [
304 'step' => '<div class="step-content" data-step="2">',
305 'title' => sprintf(
306 '<div class="step-title">%s</div>',
307 esc_html__( 'Step 2 — AI Settings', 'learnpress' ),
308 ),
309 'description' => sprintf(
310 '<p class="step-description">%s</p>',
311 esc_html__( 'Configure content quality controls for ChatGPT output.', 'learnpress' )
312 ),
313 'form_grid' => Template::combine_components( $grid_components ),
314 'step-end' => '</div>',
315 ];
316
317 return Template::combine_components( $components );
318 }
319
320 public function html_step_3(): string {
321 $grid_components = [
322 'grid' => '<div class="form-grid">',
323 'sections-number' => sprintf(
324 '<div class="form-group">
325 <label>%s</label>
326 <input type="number" name="section_number" value="2" min="0">
327 <p class="field-description">%s</p>
328 </div>',
329 esc_html__( 'Sections number', 'learnpress' ),
330 esc_html__( 'Defines how many main sections/modules the course will include.', 'learnpress' )
331 ),
332 /*'sections-title-length' => sprintf(
333 '<div class="form-group">
334 <label>%s</label>
335 <input type="number" name="section_title_length" value="60" min="0">
336 <p class="field-description">%s</p>
337 </div>',
338 esc_html__( 'Each section title length', 'learnpress' ),
339 esc_html__( 'Specifies the word limit for section titles to maintain consistency and readability.', 'learnpress' )
340 ),
341 'sections-des-length' => sprintf(
342 '<div class="form-group">
343 <label>%s</label>
344 <input type="number" name="section_description_length" value="200" min="0">
345 <p class="field-description">%s</p>
346 </div>',
347 esc_html__( 'Each section description length', 'learnpress' ),
348 esc_html__( 'Sets the word limit for section introductions to control depth and clarity.', 'learnpress' )
349 ),*/
350 'lesson-number' => sprintf(
351 '<div class="form-group">
352 <label>%s</label>
353 <input type="number" name="lessons_per_section" value="2" min="0">
354 </div>',
355 esc_html__( 'Lessons per Section', 'learnpress' )
356 ),
357 /*'lesson-title-length' => sprintf(
358 '<div class="form-group">
359 <label>%s</label>
360 <input type="number" name="lessons_title_length" value="60" min="0">
361 </div>',
362 esc_html__( 'Each lesson title length (words)', 'learnpress' )
363 ),
364 'lesson-des-length' => sprintf(
365 '<div class="form-group">
366 <label>%s</label>
367 <input type="number" name="lessons_description_length" value="1000" min="0">
368 </div>',
369 esc_html__( 'Each lesson description length', 'learnpress' )
370 ),*/
371 'quizzes' => sprintf(
372 '<div class="form-group">
373 <label>%s</label>
374 <input type="number" name="quizzes_per_section" value="2" min="0">
375 </div>',
376 esc_html__( 'Quizzes per Section', 'learnpress' )
377 ),
378 'questions' => sprintf(
379 '<div class="form-group">
380 <label for="questions-per-quiz">%s</label>
381 <input type="number" name="questions_per_quiz" value="2" min="0"></div>',
382 esc_html__( 'Questions per Quiz', 'learnpress' )
383 ),
384 'grid-end' => '</div>',
385 ];
386
387 $components = [
388 'step' => '<div class="step-content" data-step="3">',
389 'title' => sprintf(
390 '<div class="step-title">%s</div>',
391 esc_html__( 'Step 3 — Course Structure', 'learnpress' ),
392 ),
393 'description' => sprintf(
394 '<p class="step-description">%s</p>',
395 esc_html__( 'Define the LearnPress Curriculum structure. The Prompt will be generated based on these controls.', 'learnpress' )
396 ),
397 'form_grid' => Template::combine_components( $grid_components ),
398 'step-end' => '</div>',
399 ];
400
401 return Template::combine_components( $components );
402 }
403
404 /**
405 * Generated prompt to submit OpenAI
406 *
407 * @return string
408 */
409 public function html_step_4(): string {
410 $components = [
411 'step' => '<div class="step-content" data-step="4">',
412 'title' => sprintf(
413 '<div class="step-title">%s</div>',
414 esc_html__( 'Step 4 — Prompt Generated', 'learnpress' ),
415 ),
416 'prompt' => sprintf(
417 '<div class="form-group">
418 <textarea name="lp-openai-prompt-generated-field" rows="20"></textarea>
419 <i>%s</i>
420 </div>',
421 __( 'Shows the auto-generated AI prompt, allowing further adjustments before submission.', 'learnpress' )
422 ),
423 'step-end' => '</div>',
424 ];
425
426 return Template::combine_components( $components );
427 }
428
429 /**
430 * Preview Course and create
431 *
432 * @return string
433 */
434 public function html_step_5(): string {
435 $components = [
436 'step' => '<div class="step-content" data-step="5">',
437 'title' => sprintf(
438 '<div class="step-title">%s</div>',
439 esc_html__( 'Step 5 — Create Course', 'learnpress' ),
440 ),
441 'description' => sprintf(
442 '<p class="step-description">%s</p>',
443 esc_html__( 'Data preview before create course.', 'learnpress' )
444 ),
445 'preview' => '<div class="lp-ai-generated-results lp-ai-course-data-preview-wrap"></div>',
446 'step-end' => '</div>',
447 ];
448
449 return Template::combine_components( $components );
450 }
451
452 /**
453 * HTML preview with data received from OpenAI
454 *
455 * @param array $data_received
456 *
457 * @return string
458 */
459 public static function html_preview_with_data( array $data_received ): string {
460 $course_title = $data_received['course_title'] ?? '';
461 $course_description = $data_received['course_description'] ?? '';
462 $sections = $data_received['sections'] ?? [];
463
464 $html_section = '';
465 foreach ( $sections as $section ) {
466 $section_title = $section['section_title'] ?? '';
467 $section_des = $section['section_description'] ?? '';
468 $lessons = $section['lessons'] ?? [];
469 $quizzes = $section['quizzes'] ?? [];
470
471 $html_lessons = '';
472 foreach ( $lessons as $lesson ) {
473 $lesson_title = $lesson['lesson_title'] ?? '';
474 $lesson_des = $lesson['lesson_description'] ?? '';
475
476 $arr_lesson_components = [
477 'wrap' => '<li class="course-lesson-item">',
478 'title' => sprintf(
479 '<div class="lesson-title">%s: %s</div>',
480 __( 'Lesson', 'learnpress' ),
481 esc_html( $lesson_title )
482 ),
483 'des' => sprintf( '<div class="lesson-description">%s</div>', esc_html( $lesson_des ) ),
484 'wrap-end' => '</li>',
485 ];
486
487 $html_lessons .= Template::combine_components( $arr_lesson_components );
488 }
489
490 // Quizzes
491 $html_quizzes = '';
492 foreach ( $quizzes as $quiz ) {
493 $quiz_title = $quiz['quiz_title'] ?? '';
494 $quiz_des = $quiz['quiz_description'] ?? '';
495 $questions = $quiz['questions'] ?? [];
496
497 $html_questions = '';
498 foreach ( $questions as $question ) {
499 $question_title = $question['question_title'] ?? '';
500 $question_des = $question['question_description'] ?? '';
501 $options = $question['options'] ?? [];
502
503 $html_options = '';
504 foreach ( $options as $option ) {
505 $html_options .= sprintf( '<li class="question-option">%s</li>', esc_html( $option ) );
506 }
507
508 $arr_question_components = [
509 'wrap' => '<li class="quiz-question-item">',
510 'title' => sprintf(
511 '<div class="question-title">%s: %s</div>',
512 __( 'Question', 'learnpress' ),
513 esc_html( $question_title )
514 ),
515 'desc' => sprintf( '<div class="question-desc">%s</div>', esc_html( $question_des ) ),
516 'options' => sprintf( '<ul class="course-question-options">%s</ul>', $html_options ),
517 'wrap-end' => '</li>',
518 ];
519
520 $html_questions .= Template::combine_components( $arr_question_components );
521 }
522
523 $arr_quiz_components = [
524 'wrap' => '<li class="course-quiz-item">',
525 'title' => sprintf(
526 '<div class="quiz-title">%s: %s</div>',
527 __( 'Quiz', 'learnpress' ),
528 esc_html( $quiz_title )
529 ),
530 'des' => sprintf( '<div class="quiz-description">%s</div>', esc_html( $quiz_des ) ),
531 'questions' => sprintf( '<ul class="course-questions">%s</ul>', $html_questions ),
532 'wrap-end' => '</li>',
533 ];
534
535 $html_quizzes .= Template::combine_components( $arr_quiz_components );
536 }
537
538 $arr_section_components = [
539 'wrap' => '<li class="course-section-item">',
540 'title' => sprintf(
541 '<div class="section-title">%s: %s</div>',
542 __( 'Curriculum', 'learnpress' ),
543 esc_html( $section_title )
544 ),
545 'des' => sprintf( '<div class="section-description">%s</div>', esc_html( $section_des ) ),
546 'ul-items' => '<ul class="course-section-items">',
547 'items' => $html_lessons . $html_quizzes,
548 'ul-items-end' => '</ul>',
549 'wrap-end' => '</li>',
550 ];
551
552 $html_section .= Template::combine_components( $arr_section_components );
553 }
554
555 $section = [
556 'wrap' => '<div class="lp-ai-course-data-preview">',
557 'title' => sprintf( '<div class="course-title">%s</div>', esc_html( $course_title ) ),
558 'des' => sprintf( '<div class="course-description">%s</div>', esc_html( $course_description ) ),
559 'sections' => sprintf( '<ul class="course-sections">%s</ul>', $html_section ),
560 'wrap-end' => '</div>',
561 ];
562
563 return Template::combine_components( $section );
564 }
565
566 /**
567 * HTML for Popup Creating course template
568 *
569 * @return string
570 */
571 public function html_creating_course(): string {
572 $components = [
573 'wrap-script-template' => '<script type="text/template" id="lp-tmpl-creating-course-ai">',
574 'wrap' => '<div class="lp-creating-course-ai-wrap">',
575 'head' => sprintf(
576 '<h2><strong>%s</strong></h2>',
577 esc_html__( 'Creating your LearnPress course...', 'learnpress' )
578 ),
579 'desc' => sprintf(
580 '<div class="desc">%s</div>
581 <div>%s</div>',
582 esc_html__( 'Please wait while we prepare sections, lessons...', 'learnpress' ),
583 esc_html__( 'Don\'t reload page when creating', 'learnpress' ),
584 ),
585 'loader' => '<div class="loading-wrap">
586 <span class="lp-loading-circle"></span>
587 </div>',
588 'struct' => sprintf(
589 '<ul>
590 <li>%s</li>
591 <li>%s</li>
592 <li>%s</li>
593 </ul>',
594 esc_html__( 'Creating sections...', 'learnpress' ),
595 esc_html__( 'Creating lessons...', 'learnpress' ),
596 esc_html__( 'Creating quizzes...', 'learnpress' ),
597 ),
598 'wrap-end' => '</div>',
599 'wrap-script-template-end' => '</script>',
600 ];
601
602 return Template::combine_components( $components );
603 }
604
605 /**
606 * HTML for Popup warning enable AI
607 *
608 * @return string
609 */
610 public function html_warning_enable_ai(): string {
611 $components = [
612 'wrap-script-template' => '<script type="text/template" id="lp-tmpl-must-enable-ai">',
613 'wrap' => '<div class="lp-must-enable-ai-wrap">',
614 'head' => sprintf(
615 '<h2><i class="lp-icon-warning"></i><strong>%s</strong></h2>',
616 esc_html__( 'OpenAI API is not connected', 'learnpress' )
617 ),
618 'desc' => sprintf(
619 '<div class="desc">%s</div>',
620 esc_html__( 'Connect the OpenAI API to unlock LearnPress AI features.', 'learnpress' ),
621 ),
622 'paragraph' => sprintf(
623 '<p>%s</p>
624 <p class="p2">%s</p>',
625 sprintf(
626 '%s <a href="%s" target="_blank">%s</a>',
627 __( 'Please enter your <strong>OpenAI Secret Key</strong> and enable the option <strong>Enable OpenAI</strong> option', 'learnpress' ),
628 esc_url( admin_url( 'admin.php?page=learn-press-settings&tab=open-ai' ) ),
629 esc_html__( 'here.', 'learnpress' ),
630 ),
631 esc_html__(
632 'LearnPress AI helps you create courses, lessons, quizzes, and
633 learning content faster with intelligent AI assistance.',
634 'learnpress'
635 ),
636 ),
637 'help-link' => sprintf(
638 '<div class="help-link">%s<br/>%s</div>',
639 sprintf(
640 '%s %s',
641 '<i class="lp-icon-book"></i>',
642 esc_html__( 'Need help using LearnPress AI?', 'learnpress' ),
643 ),
644 sprintf(
645 '<a href="%s" target="_blank">%s</a>',
646 esc_url( 'https://learnpresslms.com/docs/learnpress/guide-to-using-ai-to-create-courses-in-learpress/' ),
647 esc_html__( 'View LearnPress AI documentation.', 'learnpress' ),
648 ),
649 ),
650 'buttons' => sprintf(
651 '<div class="button-actions">
652 <button class="button lp-btn-close-ai-popup" type="button">%s</button>
653 <a class="button button-primary" href="%s" target="_blank">%s</a>
654 </div>',
655 esc_html__( 'Close', 'learnpress' ),
656 esc_url( admin_url( 'admin.php?page=learn-press-settings&tab=open-ai' ) ),
657 esc_html__( 'Go to Settings', 'learnpress' ),
658 ),
659 'wrap-end' => '</div>',
660 'wrap-script-template-end' => '</script>',
661 ];
662
663 return Template::combine_components( $components );
664 }
665 }
666