PluginProbe
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot / 4.2.0
BetterDocs – AI Documentation, Knowledge Base, MCP Server, Docs, Wikis, FAQ & Chatbot v4.2.0
4.9.1 4.9.0 4.8.2 4.8.1 4.8.0 4.7.0 4.6.2 4.6.1 4.6.0 4.5.6 4.5.5 4.5.4 4.5.3 4.5.2 4.5.1 4.5.0 4.4.1 4.4.0 3.3.4 3.4.0 3.4.1 3.4.2 3.5.0 3.5.1 3.5.2 All 199 releases
← All changes | includes/Core/WriteWithAI.php +160 -354 4.5.14.2.0 View file →
@@ -1,295 +1,172 @@
1 1 <?php
2 2
3 - namespace WPDeveloper\BetterDocs\Core;
3 +namespace WPDeveloper\BetterDocs\Core;
4 4
5 - use WPDeveloper\BetterDocs\Utils\Base;
6 - use WPDeveloper\BetterDocs\Core\Settings;
7 - use WPDeveloper\BetterDocs\Core\PostType;
5 +use WPDeveloper\BetterDocs\Utils\Base;
6 +use WPDeveloper\BetterDocs\Core\Settings;
7 +use WPDeveloper\BetterDocs\Core\PostType;
8 8
9 - use WPDeveloper\BetterDocs\Utils\Helper;
9 +use WPDeveloper\BetterDocs\Utils\Helper;
10 10
11 - class WriteWithAI extends Base {
11 +class WriteWithAI extends Base {
12 12
13 - public $settings;
13 + public $settings;
14 14
15 - public function __construct( Settings $settings ) {
16 - $this->settings = $settings;
17 - // Get the post ID from the URL
18 - $post_id = isset( $_GET[ 'post' ] ) ? intval( $_GET[ 'post' ] ) : 0; // phpcs:ignore
15 + public function __construct( Settings $settings ) {
16 + $this->settings = $settings;
17 + // Get the post ID from the URL
18 + $post_id = isset($_GET['post']) ? intval($_GET['post']) : 0; // phpcs:ignore
19 19
20 - if ( ! empty( $_GET[ 'post_type' ] ) ) { // phpcs:ignore
21 - $post_type = $_GET[ 'post_type' ]; // phpcs:ignore
22 - } elseif ( $post_id > 0 ) {
23 - $post_type = get_post_type( $post_id );
24 - } else {
25 - $post_type = '';
26 - }
20 + if (!empty($_GET['post_type'])) { // phpcs:ignore
21 + $post_type = $_GET['post_type']; // phpcs:ignore
22 + } elseif ( $post_id > 0 ) {
23 + $post_type = get_post_type( $post_id );
24 + } else {
25 + $post_type = '';
26 + }
27 27
28 - if ( ! empty( $this->isEnabledWriteWithAI() ) && 'docs' == $post_type ) {
29 - add_action( 'admin_footer', array( $this, 'ai_autowrite_button' ) );
30 - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_ai_edit_assets' ) );
31 - }
32 - add_action( 'wp_ajax_generate_openai_content', array( $this, 'generate_openai_content_callback' ) );
33 - }
28 + if ( ! empty( $this->isEnabledWriteWithAI() ) && $post_type == 'docs' ) {
29 + add_action( 'admin_footer', [ $this, 'ai_autowrite_button' ] );
30 + }
31 + add_action( 'wp_ajax_generate_openai_content', [ $this, 'generate_openai_content_callback' ] );
34 32
35 - public function enqueue_ai_edit_assets( $hook ) {
36 - if ( $hook !== 'post.php' && $hook !== 'post-new.php' ) {
37 - return;
38 - }
33 + }
39 34
40 - global $post_type;
41 - if ( $post_type !== 'docs' ) {
42 - return;
43 - }
35 + public function isEnabledWriteWithAI() {
36 + $isEnableAutoWrite = $this->settings->get( 'enable_write_with_ai', true );
37 + return $isEnableAutoWrite;
38 + }
44 39
45 - if ( empty( $this->get_api_key() ) ) {
46 - return;
47 - }
40 + public function isValidAPIKey( $apiKey ) {
41 + if ( empty( $apiKey ) ) {
42 + $api_response['valid'] = false;
43 + $api_response['message'] = 'Please Insert your <a href="/admin.php?page=betterdocs-settings">OpenAI API Key</a> to use this Write with AI feature.';
48 44
49 - betterdocs()->assets->enqueue( 'betterdocs-ai-edit', 'blocks/ai-edit.js' );
50 - betterdocs()->assets->enqueue( 'betterdocs-ai-edit-style', 'blocks/ai-edit-style.css' );
45 + return $api_response;
46 + }
51 47
52 - wp_localize_script(
53 - 'betterdocs-ai-edit',
54 - 'betterdocsAIEdit',
55 - array(
56 - 'rest_url' => esc_url_raw( rest_url( 'betterdocs/v1/ai-edit' ) ),
57 - 'rest_nonce' => wp_create_nonce( 'wp_rest' ),
58 - 'post_id' => get_the_ID(),
59 - )
60 - );
61 - }
48 + $ch = curl_init( 'https://api.openai.com/v1/engines' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init
49 + curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
50 + curl_setopt(
51 + $ch,
52 + CURLOPT_HTTPHEADER,
53 + [ //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
54 + 'Content-Type: application/json',
55 + 'Authorization: Bearer ' . $apiKey,
56 + ]
57 + );
62 58
63 - public function isEnabledWriteWithAI() {
64 - $isEnableAutoWrite = $this->settings->get( 'enable_write_with_ai', true );
65 - return $isEnableAutoWrite;
66 - }
59 + $api_response = [];
67 60
68 - public function isValidAPIKey( $apiKey ) {
69 - if ( empty( $apiKey ) ) {
70 - $api_response[ 'valid' ] = false;
71 - $api_response[ 'message' ] = 'Please Insert your <a href="/admin.php?page=betterdocs-settings#betterdocs-ai">OpenAI API Key</a> to use this Write with AI feature.';
61 + $response = curl_exec( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_exec
62 + $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_getinfo
72 63
73 - return $api_response;
74 - }
64 + curl_close( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close
75 65
76 - $ch = curl_init( 'https://api.openai.com/v1/engines' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_init
77 - curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
78 - curl_setopt(
79 - $ch,
80 - CURLOPT_HTTPHEADER,
81 - array( //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_setopt
82 - 'Content-Type: application/json',
83 - 'Authorization: Bearer ' . $apiKey
84 - )
85 - );
66 + if ( $httpCode == 200 ) {
67 + $api_response['valid'] = true;
68 + $api_response['message'] = 'Valid API Key';
69 + } else {
70 + $responseData = json_decode( $response, true );
71 + // Access the message data (replace 'data' with the actual key used in the response)
72 + $messageData = $responseData['error'] ? $responseData['error'] : '';
73 + $api_response['valid'] = false;
74 + $api_response['message'] = $messageData['message'] ? $messageData['message'] : 'Invalid API Key';
75 + }
86 76
87 - $api_response = array();
77 + // print_r($response);
88 78
89 - $response = curl_exec( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_exec
90 - $httpCode = curl_getinfo( $ch, CURLINFO_HTTP_CODE ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_getinfo
79 + return $api_response;
80 + }
91 81
92 - curl_close( $ch ); //phpcs:ignore WordPress.WP.AlternativeFunctions.curl_curl_close
82 + public function get_api_key() {
83 + $api_key = $this->settings->get( 'ai_autowrite_api_key', '' );
84 + return $api_key;
85 + }
93 86
94 - if ( 200 == $httpCode ) {
95 - $api_response[ 'valid' ] = true;
96 - $api_response[ 'message' ] = 'Valid API Key';
97 - } else {
98 - $responseData = json_decode( $response, true );
99 - // Access the message data (replace 'data' with the actual key used in the response)
100 - $messageData = $responseData[ 'error' ] ? $responseData[ 'error' ] : '';
101 - $api_response[ 'valid' ] = false;
102 - $api_response[ 'message' ] = $messageData[ 'message' ] ? $messageData[ 'message' ] : 'Invalid API Key';
103 - }
104 87
105 - // print_r($response);
88 + public function generate_openai_response( $prompt, $keywords ) {
89 + try {
90 + $api_key = $this->settings->get( 'ai_autowrite_api_key', '' );
91 + $max_tokens = $this->settings->get( 'ai_autowrite_max_token', 1500 );
92 + $model = $this->settings->get( 'write_with_ai_model', 'gpt-4o-mini' );
106 93
107 - return $api_response;
108 - }
94 + $api_endpoint = 'https://api.openai.com/v1/chat/completions'; // Update the endpoint based on OpenAI API version
109 95
110 - public function get_api_key() {
111 - $api_key = $this->settings->get( 'ai_autowrite_api_key', '' );
112 - return $api_key;
113 - }
96 + $request_options = array(
97 + 'headers' => array(
98 + 'Content-Type' => 'application/json',
99 + 'Authorization' => 'Bearer ' . $api_key,
100 + ),
101 + 'body' => json_encode(
102 + array( //phpcs:ignore WordPress.WP.AlternativeFunctions.json_encode_json_encode
103 + 'model' => $model, // Add the model parameter here
104 + 'messages' => array(
105 + array(
106 + 'role' => 'system',
107 + 'content' => 'You are a helpful assistant who writes documentation for users.'
108 + ),
109 + array(
110 + 'role' => 'user',
111 + 'content' => $prompt
112 + ),
113 + ),
114 + 'max_tokens' => $max_tokens,
114 115
115 - public function get_system_prompt() {
116 - $prompt = <<<'PROMPT'
117 -You are a Senior Technical Writer specializing in comprehensive, high-quality documentation. Your goal is to produce documentation that scores 100/100 on clarity, completeness, and structure.
116 + )
117 + ),
118 + 'timeout' => 50,
119 + );
118 120
119 -## Output format
121 + $response = wp_remote_post( $api_endpoint, $request_options );
120 122
121 -Return only HTML body content. Never wrap output in `<!doctype>`, `<html>`, `<head>`, `<body>`, or markdown code fences (no ```html ... ```).
123 + if ( is_wp_error( $response ) ) {
124 + return 'Error: ' . $response->get_error_message();
125 + } else {
126 + $body = wp_remote_retrieve_body( $response );
122 127
123 -Use semantic, Gutenberg-friendly tags only:
124 -- Headings: `<h2>`, `<h3>`, `<h4>` (do not emit `<h1>` — it is reserved for the document title)
125 -- Paragraphs: `<p>` for prose
126 -- Lists: `<ul>`/`<ol>` with `<li>` for any list of items, steps, or bullet points — never fake a list with paragraphs or `<br>`
127 -- Links: `<a href="https://...">link text</a>` with absolute URLs
128 -- Inline emphasis: `<strong>`, `<em>`, `<code>`
129 -- Code blocks: `<pre><code>...</code></pre>` for multi-line code or commands
130 -- Quotes: `<blockquote>`
131 -- Tables: `<table>` with `<thead>`, `<tbody>`, `<tr>`, `<th>`, `<td>`
132 -- Images: `<img src="..." alt="...">`
128 + $data = json_decode( $body, true );
133 129
134 -Apply `<span class="highlight">key term</span>` to important topic terms inside headings and to the first occurrence of each keyword in body text. Use it sparingly — never wrap whole sentences or wrap text inside `href`, `src`, `alt`, or other attributes.
130 + if ( ! empty( $data['error'] ) ) {
131 + return $data['error']['message'];
132 + }
135 133
136 -Do not emit `<style>`, `<script>`, `<iframe>`, `<form>`, or inline `style=""` / `class=""` attributes (other than the `highlight` class above).
134 + return $data['choices'][0]['message']['content']; // Update this line to get the assistant's message
135 + }
136 + } catch ( Exception $error ) {
137 + return 'Error: ' . $error->getMessage();
138 + }
139 + }
137 140
138 -If — and only if — the user's prompt explicitly asks for raw/custom HTML, embed code, or a non-standard structure, follow that request instead of these defaults.
139 -PROMPT;
140 141
141 - return apply_filters( 'betterdocs_write_with_ai_system_prompt', $prompt );
142 - }
143 142
144 - public function generate_openai_response( $prompt, $keywords ) {
145 - try {
146 - $api_key = $this->settings->get( 'ai_autowrite_api_key', '' );
147 - $max_tokens = $this->settings->get( 'ai_autowrite_max_token', 1500 );
148 - $model = $this->settings->get( 'write_with_ai_model', 'gpt-4o-mini' );
143 + public function generate_openai_content_callback() {
144 + // Verify the nonce
145 + if (!isset($_POST['ai_nonce']) || !wp_verify_nonce($_POST['ai_nonce'], 'generate_openai_content_nonce')) { //phpcs:ignore
146 + wp_send_json_error( 'Invalid nonce' );
147 + wp_die();
148 + }
149 149
150 - $api_endpoint = 'https://api.openai.com/v1/chat/completions'; // Update the endpoint based on OpenAI API version
150 + $prompt = sanitize_text_field($_POST['prompt']); //phpcs:ignore
151 + // $num_of_sections = sanitize_text_field($_POST['numOfSections']);
152 + // $num_of_paragraphs = sanitize_text_field($_POST['numOfParagraphs']);
153 + $keywords = sanitize_text_field($_POST['keywords']); //phpcs:ignore
151 154
152 - $request_body = array(
153 - 'model' => $model,
154 - 'messages' => array(
155 - array(
156 - 'role' => 'system',
157 - 'content' => $this->get_system_prompt()
158 - ),
159 - array(
160 - 'role' => 'user',
161 - 'content' => $prompt
162 - )
163 - ),
164 - 'max_tokens' => $max_tokens
165 - );
155 + $ai_instance = new WriteWithAI( $this->settings );
166 156
167 - $request_options = array(
168 - 'headers' => array(
169 - 'Content-Type' => 'application/json',
170 - 'Authorization' => 'Bearer ' . $api_key
171 - ),
172 - 'body' => json_encode( $request_body ),
173 - 'timeout' => 50
174 - );
157 + $generated_content = $ai_instance->generate_openai_response( $prompt, $keywords );
175 158
176 - $response = wp_remote_post( $api_endpoint, $request_options );
159 + // Send the generated content as the AJAX response
160 + wp_send_json_success( $generated_content );
161 + wp_die();
162 + }
177 163
178 - if ( is_wp_error( $response ) ) {
179 - return 'Error: ' . $response->get_error_message();
180 - } else {
181 - $body = wp_remote_retrieve_body( $response );
182 164
183 - $data = json_decode( $body, true );
184 165
185 - if ( ! empty( $data[ 'error' ] ) ) {
186 - return $data[ 'error' ][ 'message' ];
187 - }
166 + public function ai_autowrite_button() {
188 167
189 - return $data[ 'choices' ][ 0 ][ 'message' ][ 'content' ]; // Update this line to get the assistant's message
190 - }
191 - } catch ( Exception $error ) {
192 - return 'Error: ' . $error->getMessage();
193 - }
194 - }
195 -
196 - public function generate_openai_response_full( $prompt ) {
197 - $api_key = $this->settings->get( 'ai_autowrite_api_key', '' );
198 - $max_tokens = $this->settings->get( 'ai_autowrite_max_token', 1500 );
199 - $model = $this->settings->get( 'write_with_ai_model', 'gpt-4o-mini' );
200 -
201 - $api_endpoint = 'https://api.openai.com/v1/chat/completions';
202 -
203 - $payload = array(
204 - 'model' => $model,
205 - 'messages' => array(
206 - array(
207 - 'role' => 'system',
208 - 'content' => $this->get_system_prompt()
209 - ),
210 - array(
211 - 'role' => 'user',
212 - 'content' => $prompt
213 - )
214 - ),
215 - 'max_tokens' => $max_tokens
216 - );
217 -
218 - $request_options = array(
219 - 'headers' => array(
220 - 'Content-Type' => 'application/json',
221 - 'Authorization' => 'Bearer ' . $api_key
222 - ),
223 - 'body' => wp_json_encode( $payload ),
224 - 'timeout' => 50
225 - );
226 -
227 - $response = wp_remote_post( $api_endpoint, $request_options );
228 -
229 - if ( is_wp_error( $response ) ) {
230 - return array(
231 - 'success' => false,
232 - 'error' => $response->get_error_message(),
233 - 'model' => $model,
234 - );
235 - }
236 -
237 - $body = wp_remote_retrieve_body( $response );
238 - $data = json_decode( $body, true );
239 -
240 - if ( ! empty( $data['error'] ) ) {
241 - return array(
242 - 'success' => false,
243 - 'error' => isset( $data['error']['message'] ) ? $data['error']['message'] : 'OpenAI error',
244 - 'model' => $model,
245 - 'raw' => $data,
246 - );
247 - }
248 -
249 - $content = isset( $data['choices'][0]['message']['content'] ) ? $data['choices'][0]['message']['content'] : '';
250 - $usage = isset( $data['usage'] ) && is_array( $data['usage'] ) ? $data['usage'] : array();
251 -
252 - return array(
253 - 'success' => true,
254 - 'content' => $content,
255 - 'model' => $model,
256 - 'prompt_tokens' => isset( $usage['prompt_tokens'] ) ? (int) $usage['prompt_tokens'] : null,
257 - 'completion_tokens' => isset( $usage['completion_tokens'] ) ? (int) $usage['completion_tokens'] : null,
258 - 'total_tokens' => isset( $usage['total_tokens'] ) ? (int) $usage['total_tokens'] : null,
259 - 'finish_reason' => isset( $data['choices'][0]['finish_reason'] ) ? $data['choices'][0]['finish_reason'] : null,
260 - );
261 - }
262 -
263 - public function generate_openai_content_callback() {
264 - // Verify the nonce
265 - if ( ! isset( $_POST[ 'ai_nonce' ] ) || ! wp_verify_nonce( $_POST[ 'ai_nonce' ], 'generate_openai_content_nonce' ) ) { //phpcs:ignore
266 - wp_send_json_error( 'Invalid nonce' );
267 - wp_die();
268 - }
269 -
270 - if ( ! current_user_can( 'edit_posts' ) ) {
271 - wp_send_json_error( 'Insufficient permissions' );
272 - wp_die();
273 - }
274 -
275 - $prompt = sanitize_text_field( $_POST[ 'prompt' ] ); //phpcs:ignore
276 - // $num_of_sections = sanitize_text_field($_POST['numOfSections']);
277 - // $num_of_paragraphs = sanitize_text_field($_POST['numOfParagraphs']);
278 - $keywords = sanitize_text_field( $_POST[ 'keywords' ] ); //phpcs:ignore
279 -
280 - $ai_instance = new WriteWithAI( $this->settings );
281 -
282 - $generated_content = $ai_instance->generate_openai_response( $prompt, $keywords );
283 -
284 - // Send the generated content as the AJAX response
285 - wp_send_json_success( $generated_content );
286 - wp_die();
287 - }
288 -
289 - public function ai_autowrite_button() {
290 -
291 - ?>
168 + ?>
292 169 <script>
293 170 var docsTitle;
294 171
295 172 function responseMessage(message) {
@@ -355,8 +232,14 @@
355 232 setTimeout(() => {
356 233 insertContentToEditor(title, response.data, isOverwrite, keywords);
357 234 docGenerateBtnTxt.innerHTML = reGenerateDocLabel;
358 235 jQuery('.generate-btn').removeAttr('disabled');
236 +
237 + // console.log(jQuery('.betterdocs-ai-autowrite-form-container').data('new-doc-page'));
238 +
239 + // if(jQuery('.betterdocs-ai-autowrite-form-container')?.data('new-doc-page')) {
240 + // docGenerateBtnTxt.innerHTML = reGenerateDocLabel;
241 + // }
359 242 }, 2000);
360 243 } else {
361 244 // alert(response.data.message);
362 245 jQuery('#betterdocs-ai-error-message').parent().removeClass('hidden');
@@ -392,9 +275,9 @@
392 275 if (!jQuery('#betterdocs-ai-error-message').parent().hasClass('hidden')) {
393 276 jQuery('#betterdocs-ai-error-message').parent().addClass('hidden');
394 277 }
395 278
396 - contentTextArea.value = `Write documentation for '${title}'. Cover these topics in depth: ${keywords}. Use headings, paragraphs, lists, links, code blocks, and tables wherever they help the reader. Follow the output-format rules in the system instructions.`;
279 + contentTextArea.value = `Generate a documentation using HTML heading tags for '${title}'. Include relevant details on ${keywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
397 280 }
398 281
399 282 function convertMarkdownToHTML(markdownContent) {
400 283 // Simple Markdown to HTML conversion (you may need to enhance this based on your needs)
@@ -424,107 +307,30 @@
424 307 return newDiv.innerHTML;
425 308 }
426 309
427 310
428 - function escapeHtml(str) {
429 - return String(str).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
430 - }
431 -
432 - function escapeRegex(str) {
433 - return String(str).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
434 - }
435 -
436 - function stripCodeFences(htmlString) {
437 - if (!htmlString) {
438 - return '';
439 - }
440 - return htmlString
441 - .replace(/^\s*```(?:html|HTML)?\s*\n?/, '')
442 - .replace(/\n?\s*```\s*$/, '');
443 - }
444 -
445 311 function wrapwithHeighlight(inputString, keywords) {
446 - if (!inputString) {
447 - return '';
448 - }
312 + let modifiedString = inputString.replace(/<(h\d)(.*?)>(.*?)<\/\1>/g, '<$1$2><span class="highlight">$3</span></$1>');
449 313
450 - const container = document.createElement('div');
451 - container.innerHTML = inputString;
314 + const keywordArray = keywords.split(',').map(keyword => keyword.trim());
452 315
453 - // Wrap each heading's visible text with the highlight span (skip if already present)
454 - container.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(function (heading) {
455 - if (heading.querySelector('.highlight')) {
456 - return;
457 - }
458 - const text = heading.textContent;
459 - if (!text || !text.trim()) {
460 - return;
461 - }
462 - heading.innerHTML = '<span class="highlight">' + escapeHtml(text) + '</span>';
316 + keywordArray.forEach(keyword => {
317 + modifiedString = modifiedString.replace(new RegExp(`\\b(${keyword})\\b`, 'gi'), '<span class="highlight">$1</span>');
463 318 });
464 319
465 - // Wrap keywords only inside text nodes — never inside attributes, code, or existing highlights
466 - const keywordList = (keywords || '')
467 - .split(',')
468 - .map(function (k) { return k.trim(); })
469 - .filter(Boolean);
470 -
471 - if (keywordList.length) {
472 - const pattern = new RegExp('\\b(' + keywordList.map(escapeRegex).join('|') + ')\\b', 'gi');
473 - const walker = document.createTreeWalker(container, NodeFilter.SHOW_TEXT, {
474 - acceptNode: function (node) {
475 - let parent = node.parentNode;
476 - while (parent && parent !== container) {
477 - if (parent.nodeType === 1) {
478 - const tag = parent.tagName.toLowerCase();
479 - if (tag === 'code' || tag === 'pre') {
480 - return NodeFilter.FILTER_REJECT;
481 - }
482 - if (parent.classList && parent.classList.contains('highlight')) {
483 - return NodeFilter.FILTER_REJECT;
484 - }
485 - }
486 - parent = parent.parentNode;
487 - }
488 - return NodeFilter.FILTER_ACCEPT;
489 - }
490 - });
491 -
492 - const textNodes = [];
493 - let current;
494 - while ((current = walker.nextNode())) {
495 - textNodes.push(current);
496 - }
497 -
498 - textNodes.forEach(function (textNode) {
499 - pattern.lastIndex = 0;
500 - if (!pattern.test(textNode.nodeValue)) {
501 - return;
502 - }
503 - pattern.lastIndex = 0;
504 - const fragmentHost = document.createElement('span');
505 - fragmentHost.innerHTML = escapeHtml(textNode.nodeValue).replace(pattern, '<span class="highlight">$1</span>');
506 - const parent = textNode.parentNode;
507 - while (fragmentHost.firstChild) {
508 - parent.insertBefore(fragmentHost.firstChild, textNode);
509 - }
510 - parent.removeChild(textNode);
511 - });
512 - }
513 -
514 - return container.innerHTML;
320 + return modifiedString;
515 321 }
516 322
517 323 function getBodyContent(htmlString) {
518 - if (!htmlString) {
519 - return '';
520 - }
521 - const cleaned = stripCodeFences(htmlString);
522 - const match = cleaned.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
324 + var match = htmlString.match(/<body[^>]*>([\s\S]*?)<\/body>/i);
325 +
326 + // Check if match is null before accessing match[1]
523 327 if (match) {
328 + console.log(match[1].replace(/<p>\s+/g, '<p>'));
524 329 return match[1].replace(/<p>\s+/g, '<p>');
330 + } else {
331 + return '';
525 332 }
526 - return cleaned;
527 333 }
528 334
529 335
530 336
@@ -537,9 +343,9 @@
537 343
538 344 htmlContent = getBodyContent(htmlContent);
539 345 htmlContent = removeFirstHeading(htmlContent);
540 346 htmlContent = wrapwithHeighlight(htmlContent, keywords);
541 - const isPostContent = `<?php echo isset( $_GET[ 'post' ] ) ? esc_html( get_the_content( $_GET[ 'post' ] ) ) : ''; // phpcs:ignore ?>`;
347 + const isPostContent = `<?php echo isset($_GET['post']) ? esc_html(get_the_content($_GET['post'])) : ''; // phpcs:ignore ?>`;
542 348
543 349 const blocks = wp.blocks.rawHandler({
544 350 HTML: htmlContent
545 351 });
@@ -592,9 +398,9 @@
592 398 let currentKeywords = jQuery('#betterdocs-ai-keyword').val();
593 399 if (!currentKeywords) {
594 400 currentKeywords = '{Documentation Keywords}';
595 401 }
596 - const currentPrompt = `Write documentation for '${docsTitle?docsTitle:'{Documentation title}'}'. Cover these topics in depth: ${currentKeywords}. Use headings, paragraphs, lists, links, code blocks, and tables wherever they help the reader. Follow the output-format rules in the system instructions.`;
402 + const currentPrompt = `Generate documentation using HTML heading tags for '${docsTitle?docsTitle:'{Documentation title}'}'. Include relevant details on ${currentKeywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
597 403 jQuery('#betterdocs-ai-content').val(currentPrompt);
598 404
599 405 jQuery('#betterdocs-ai-title').val(docsTitle);
600 406
@@ -611,14 +417,14 @@
611 417
612 418
613 419 function writeWithAIForm() {
614 420
615 - let title = `<?php echo isset( $_GET[ 'post' ] ) ? esc_html( get_the_title( $_GET[ 'post' ] ) ) : ''; // phpcs:ignore ?>`;
421 + let title = `<?php echo isset($_GET['post']) ? esc_html(get_the_title($_GET['post'])) : ''; // phpcs:ignore ?>`;
616 422 if (docsTitle) {
617 423 title = docsTitle;
618 424 }
619 425
620 - const promtTitle = `<?php echo isset( $_GET[ 'post' ] ) ? esc_html( get_the_title( $_GET[ 'post' ] ) ) : '{Documentation Title}'; // phpcs:ignore ?>`;
426 + const promtTitle = `<?php echo isset($_GET['post']) ? esc_html(get_the_title($_GET['post'])) : '{Documentation Title}'; // phpcs:ignore ?>`;
621 427 const titlePlaceholder = "<?php echo esc_attr__( 'Enter a descriptive title for your documentation.', 'betterdocs' ); ?>";
622 428 const keywords = "<?php echo esc_attr( '{Documentation Keywords}' ); ?>";
623 429 const keywordsPlaceholder = "<?php echo esc_attr__( 'Add keywords to generate precise & relevant documentation (comma-separated).', 'betterdocs' ); ?>";
624 430 const language = "<?php echo esc_attr( 'English' ); ?>";
@@ -633,18 +439,18 @@
633 439 const checkboxLabel = "<?php echo esc_html__( 'Overwrite your existing Doc:', 'betterdocs' ); ?>";
634 440 const nonce = "<?php echo esc_attr( wp_create_nonce( 'generate_openai_content_nonce' ) ); ?>";
635 441
636 442 <?php
637 - $is_valid = $this->get_api_key();
638 - $disable_field = 'disabled-input-field';
639 - if ( $this->get_api_key() ) {
640 - $disable_field = '';
641 - }
642 - ?>
443 + $is_valid = $this->get_api_key();
444 + $disable_field = 'disabled-input-field';
445 + if ( $this->get_api_key() ) {
446 + $disable_field = '';
447 + }
448 + ?>
643 449
644 450 let hiddenClass = 'hidden';
645 451 let newDocPageAtt = 'data-new-doc-page="true"';
646 - const isPostContent = `<?php echo isset( $_GET[ 'post' ] ) ? esc_html( get_the_content( $_GET[ 'post' ] ) ) : ''; // phpcs:ignore ?>`;
452 + const isPostContent = `<?php echo isset($_GET['post']) ? esc_html(get_the_content($_GET['post'])) : ''; // phpcs:ignore ?>`;
647 453
648 454 if (isPostContent !== '') {
649 455 hiddenClass = '';
650 456 newDocPageAtt = '';
@@ -654,9 +460,9 @@
654 460 // const prompt = `Make a knowledge base article with html heading tags about [${title}] in [${language}]. Here is some topic to describe the article: [${keywords}]. and wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
655 461
656 462 // const prompt = `Create a details knowledge base article in [${language}] about [${title}] with html heading tags. Here is some topic to describe the article: [${keywords}]. And wrap the content with p tag also add a span tag with a class named 'highlight' to all the heading and topic tags in the article.`;
657 463
658 - const prompt = `Write documentation for '${promtTitle}'. Cover these topics in depth: ${keywords}. Use headings, paragraphs, lists, links, code blocks, and tables wherever they help the reader. Follow the output-format rules in the system instructions.`;
464 + const prompt = `Generate a documentation using HTML heading tags for '${promtTitle}'. Include relevant details on ${keywords} in the documentation. Ensure all content is enclosed with <p> tags and apply a <span> tag with the class 'highlight' to headings and topic tags for emphasis.`;
659 465
660 466 const aiIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="21" height="20" viewBox="0 0 21 20" fill="none">
661 467 <g clip-path="url(#clip0_2460_1729)">
662 468 <path d="M10.3956 18.8608L6.10991 19.2322L6.48134 14.9465L15.3956 6.08936C15.5287 5.95329 15.6876 5.84518 15.863 5.77137C16.0384 5.69756 16.2268 5.65954 16.4171 5.65954C16.6074 5.65954 16.7957 5.69756 16.9711 5.77137C17.1466 5.84518 17.3054 5.95329 17.4385 6.08936L19.2528 7.91793C19.3865 8.05083 19.4926 8.20886 19.565 8.38293C19.6375 8.55701 19.6747 8.74368 19.6747 8.93221C19.6747 9.12075 19.6375 9.30742 19.565 9.48149C19.4926 9.65557 19.3865 9.8136 19.2528 9.9465L10.3956 18.8608ZM1.7042 5.67507C1.20277 5.58793 1.20277 4.86793 1.7042 4.78079C2.59203 4.62626 3.41374 4.21085 4.06456 3.58751C4.71538 2.96417 5.16583 2.16113 5.35848 1.28079L5.38848 1.14221C5.49705 0.647929 6.20277 0.643643 6.31705 1.13936L6.35277 1.29936C6.55248 2.17579 7.0067 2.97367 7.65837 3.59281C8.31005 4.21195 9.13013 4.62475 10.0156 4.77936C10.5199 4.86507 10.5199 5.58936 10.0156 5.67793C9.13005 5.83218 8.3098 6.24465 7.65787 6.86354C7.00594 7.48243 6.5514 8.28014 6.35134 9.1565L6.3142 9.31793C6.20134 9.81221 5.49563 9.80936 5.38705 9.31364L5.35848 9.17507C5.16564 8.29433 4.71476 7.49102 4.06339 6.86764C3.41202 6.24426 2.58969 5.82908 1.70134 5.67507H1.7042Z" stroke="white" stroke-width="1.42857" stroke-linecap="round" stroke-linejoin="round"/>
@@ -693,14 +499,14 @@
693 499 <div class="autowrite-subheadding">
694 500 <p><?php echo esc_html__( 'Generate documentation effortlessly with BetterDocs AI. Simply input your doc title, keywords, prompt and let the system automatically generate comprehensive documentation tailored to your needs.', 'betterdocs' ); ?></p>
695 501 </div>
696 502
697 - <?php if ( empty( $this->get_api_key() ) ): ?>
503 + <?php if ( empty( $this->get_api_key() ) ) : ?>
698 504 <div id="betterdocs-ai-message">
699 505 <div class="warning-message">
700 506 <span class="dashicons dashicons-warning"></span>
701 507 <div>
702 - <?php echo wp_kses_post( 'Please Insert your <a target="_blank" href="' . esc_url( admin_url( 'admin.php?page=betterdocs-settings#betterdocs-ai' ) ) . '">OpenAI API Key</a> to use this Write with AI feature.', 'betterdocs' ); ?>
508 + <?php echo wp_kses_post( 'Please Insert your <a target="_blank" href="' . esc_url( admin_url( 'admin.php?page=betterdocs-settings&tab=tab-ai-autowrite' ) ) . '">OpenAI API Key</a> to use this Write with AI feature.', 'betterdocs' ); ?>
703 509 </div>
704 510 </div>
705 511
706 512 </div>
@@ -1312,6 +1118,6 @@
1312 1118
1313 1119 }
1314 1120 </style>
1315 1121 <?php
1316 - }
1317 - }
1122 + }
1123 +}