1/**
2 * ChatGPT Chatbot Integration for WordPress Admin
3 *
4 * Author: Mark Harris
5 * URI: https://www.christchurchwebsolutions.co.uk
6 *
7 * This code snippet enables a ChatGPT chatbot within the WordPress admin area, allowing for interactive
8 * conversations directly from the dashboard. Before using this integration, please ensure you complete
9 * the following steps to ensure smooth operation:
10 *
11 * 1. Installation:
12 * - Add this code to the Code Snippets plugin or your theme's functions.php file.
13 *
14 * 2. Dependencies:
15 * - Ensure jQuery is available in your WordPress admin. This script relies on jQuery for DOM manipulation
16 * and AJAX requests.
17 *
18 * 3. OpenAI API Key:
19 * - Obtain an OpenAI API key by creating an account at https://openai.com/.
20 * - Replace the placeholder API key in the `handle_chatgpt_request` function with your actual OpenAI API key.
21 *
22 * 4. Model Selection:
23 * - The default model used is "gpt-4-0125-preview". You may change this to any available model that suits
24 * your needs better. Keep in mind that different models may incur different costs and have different
25 * performance characteristics.
26 *
27 * 5. Credits and Billing:
28 * - OpenAI usage is not covered by any ChatGPT Plus subscription. Ensure your OpenAI account is topped up
29 * with credits to avoid interruptions. API usage costs depend on the model chosen and the volume of requests.
30 *
31 * 6. Timeout Configuration:
32 * - A default timeout of 60 seconds is set for API requests. Adjust this value in the `wp_remote_post` options
33 * if you experience timeouts, but be cautious of setting it too high to avoid long blocking requests.
34 *
35 * 7. Adding to WordPress:
36 * - Once the setup is complete, the chatbot icon will appear in the bottom right corner of your WordPress admin.
37 * Clicking on it will open the chat interface.
38 *
39 * 8. Security Note:
40 * - Keep your API key secure and avoid exposing it in client-side scripts or to unauthorized users.
41 *
42 * By following these setup instructions and considering the noted points, you'll have a functional ChatGPT chatbot
43 * integrated into your WordPress admin area, enhancing your site management experience with AI-powered assistance.
44 */
45
46// Enqueue the necessary scripts and styles
47add_action("admin_enqueue_scripts", function () {
48 wp_enqueue_script("jquery");
49 // Enqueue Showdown from a CDN
50 wp_enqueue_script(
51 "showdown",
52 "https://cdn.jsdelivr.net/npm/showdown@1.9.1/dist/showdown.min.js",
53 [],
54 null,
55 true
56 );
57
58 wp_add_inline_script(
59 "jquery",
60 <<<JS
61jQuery(document).ready(function($) {
62 var converter = new showdown.Converter(); // Initialize the Showdown converter
63 var conversation = JSON.parse(localStorage.getItem('chatgpt_conversation')) || [];
64 updateChatWindow(conversation);
65
66 // Initially hide the chatbot window
67 $('#chatgpt-chatbot').hide();
68
69 $('#chatgpt-chatbot-send').on('click', function() {
70 var message = $('#chatgpt-chatbot-input').val();
71 if(message.trim() !== '') {
72 $('#chatgpt-chatbot-messages').append('<div class="user-message">' + message + '</div>');
73 conversation.push({ role: 'user', content: message });
74 localStorage.setItem('chatgpt_conversation', JSON.stringify(conversation));
75 $('#chatgpt-chatbot-input').val('');
76 //scrollToBottom();
77
78 $.ajax({
79 url: chatgptAjax.ajaxurl,
80 method: 'POST',
81 data: {
82 action: 'chatgpt_request',
83 conversation: conversation
84 },
85success: function(response) {
86 if(response.success) {
87 // Assuming the content is directly under response.data.message
88 var markdownContent = response.data.message; // Adjusted access to data
89 var htmlContent = converter.makeHtml(markdownContent); // Convert Markdown to HTML
90
91 // Now insert htmlContent into your chat window
92 $('#chatgpt-chatbot-messages').append('<div class="chatgpt-message">' + htmlContent + '</div>');
93 conversation.push({ role: 'assistant', content: htmlContent });
94 localStorage.setItem('chatgpt_conversation', JSON.stringify(conversation));
95 updateChatWindow(conversation);
96 } else {
97 $('#chatgpt-chatbot-messages').append('<div class="chatgpt-message">Error: ' + response.data.message + '</div>');
98 }
99},
100
101
102
103
104 error: function() {
105 $('#chatgpt-chatbot-messages').append('<div class="chatgpt-message">Error: Could not reach the server.</div>');
106 }
107 });
108 }
109 });
110
111 // Add the new event listener for the input box to handle Enter and Shift+Enter
112 $('#chatgpt-chatbot-input').on('keydown', function(e) {
113 // Check if the Enter key is pressed without the Shift key
114 if (e.key === 'Enter' && !e.shiftKey) {
115 e.preventDefault(); // Prevent the default action (new line)
116 $('#chatgpt-chatbot-send').click(); // Trigger the send button click
117 }
118 });
119
120 $('#chatgpt-chatbot-toggle-size').on('click', function() {
121 $('#chatgpt-chatbot').toggleClass('expanded');
122 $(this).text($('#chatgpt-chatbot').hasClass('expanded') ? '[Collapse]' : '[Expand]');
123 scrollToBottom();
124 });
125
126 $('#chatgpt-chatbot-icon').on('click', function() {
127 $('#chatgpt-chatbot').toggle();
128 scrollToBottom();
129 });
130
131 // Event handler for the close button
132 $('#chatgpt-chatbot-close').on('click', function() {
133 $('#chatgpt-chatbot').hide();
134 });
135
136 // Event handler for the clear chat button
137 $('#chatgpt-chatbot-clear').on('click', function() {
138 localStorage.removeItem('chatgpt_conversation');
139 $('#chatgpt-chatbot-messages').html('');
140 conversation = [];
141 });
142
143 function updateChatWindow(conversation) {
144 $('#chatgpt-chatbot-messages').html('');
145 conversation.forEach(function(message) {
146 var messageClass = message.role === 'user' ? 'user-message' : 'chatgpt-message';
147 $('#chatgpt-chatbot-messages').append('<div class="' + messageClass + '">' + message.content + '</div>');
148 });
149 scrollToBottom();
150 }
151
152 function scrollToBottom() {
153 var chatWindow = $('#chatgpt-chatbot-messages')[0];
154 //chatWindow.scrollTop = chatWindow.scrollHeight;
155 //new code added here
156 jQuery('#chatgpt-chatbot-content').animate({
157 scrollTop: chatWindow.scrollHeight//jQuery(".user-message:last").offset().bottom
158 }, 'fast');
159 }
160});
161JS
162 );
163
164 wp_add_inline_style(
165 "wp-admin",
166 <<<CSS
167 #chatgpt-chatbot-icon {
168 position: fixed;
169 bottom: 10px;
170 right: 10px;
171 background-color: #0073aa;
172 color: white;
173 width: 50px;
174 height: 50px;
175 border-radius: 25px;
176 text-align: center;
177 line-height: 50px;
178 font-size: 30px;
179 cursor: pointer;
180 box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
181 z-index: 10001;
182}
183
184#chatgpt-chatbot-header {
185 display: flex;
186 justify-content: space-between;
187 align-items: center;
188 padding: 10px;
189 background-color: #0073aa;
190 color: white;
191 font-size: 16px;
192 border-top-left-radius: 10px;
193 border-top-right-radius: 10px;
194}
195
196#chatgpt-chatbot {
197 display: flex;
198 flex-direction: column;
199 position: fixed;
200 bottom: 10px;
201 right: 65px;
202 background-color: #f1f1f1;
203 border-radius: 10px;
204 width: 350px;
205 height: calc(400px + 150px);
206 max-height: 80vh;
207 box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
208 z-index: 10000;
209}
210
211#chatgpt-chatbot.expanded {
212 width: 600px;
213 height: 800px;
214}
215
216#chatgpt-chatbot-content {
217 overflow-y: auto;
218 flex-grow: 1;
219 padding: 10px;
220}
221
222#chatgpt-chatbot-messages {
223 overflow-y: auto;
224 padding: 10px;
225 margin-bottom: 70px;
226}
227
228#chatgpt-chatbot-footer {
229 display: flex;
230 flex-direction: column;
231 align-items: stretch;
232 padding: 10px;
233 box-sizing: border-box;
234}
235
236#chatgpt-chatbot-input {
237 border: 2px solid #0073aa;
238 border-radius: 5px;
239 padding: 10px;
240 margin-bottom: 5px; /* Adjusted for consistency */
241 width: calc(100% - 20px); /* Adjust width to account for padding */
242 box-sizing: border-box;
243}
244
245#chatgpt-chatbot-send,
246#chatgpt-chatbot-clear {
247 background-color: #0073aa;
248 color: white;
249 border: none;
250 border-radius: 5px;
251 padding: 10px;
252 margin-bottom: 5px; /* Adjusted for consistency */
253 width: calc(100% - 20px); /* Adjust width to account for padding */
254 box-sizing: border-box;
255}
256
257#chatgpt-chatbot-toggle-size,
258#chatgpt-chatbot-close {
259 background: none;
260 border: none;
261 color: white;
262 cursor: pointer;
263 font-size: 12px;
264}
265
266.user-message, .chatgpt-message {
267 margin-bottom: 10px;
268 padding: 10px;
269 border-radius: 5px;
270 box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
271}
272
273.user-message {
274 background-color: #0073aa;
275 color: white;
276 border-radius: 5px;
277}
278
279.chatgpt-message {
280 background-color: #f0f0f0;
281 color: black; /* Ensured text color for readability */
282 border-radius: 5px;
283}
284
285pre {
286 background-color: #f8f8f8;
287 border: 1px solid #ddd;
288 border-left: 3px solid #f36d33;
289 color: #666;
290 page-break-inside: avoid;
291 font-family: monospace;
292 font-size: 15px;
293 line-height: 1.6;
294 margin-bottom: 1.6em;
295 max-width: 100%;
296 overflow: auto;
297 padding: 1em 1.5em;
298 display: block;
299 word-wrap: break-word;
300}
301
302code {
303 font-family: monospace;
304 line-height: 1.6;
305}
306
307CSS
308 );
309
310 wp_localize_script("jquery", "chatgptAjax", [
311 "ajaxurl" => admin_url("admin-ajax.php"),
312 ]);
313});
314
315// Handle the AJAX request
316add_action("wp_ajax_chatgpt_request", "handle_chatgpt_request");
317function handle_chatgpt_request()
318{
319 if (!isset($_POST["conversation"])) {
320 wp_send_json_error("Conversation parameter is missing.");
321 wp_die();
322 }
323
324 $conversation = $_POST["conversation"];
325 $api_key = "YOUR_API_KEY_HERE"; // Replace with your actual OpenAI API key
326 $model = "gpt-4-0125-preview"; // Use the desired model
327
328 $response = wp_remote_post("https://api.openai.com/v1/chat/completions", [
329 "headers" => [
330 "Authorization" => "Bearer " . $api_key,
331 "Content-Type" => "application/json",
332 ],
333 "body" => json_encode([
334 "model" => $model,
335 "messages" => $conversation,
336 ]),
337 "timeout" => 60, // Set timeout, default is 60 seconds
338 ]);
339
340 if (is_wp_error($response)) {
341 error_log("API Request Error: " . $response->get_error_message());
342 wp_send_json_error("Failed to connect to ChatGPT API.");
343 wp_die();
344 }
345
346 $body = json_decode(wp_remote_retrieve_body($response), true);
347
348 if (isset($body["choices"][0]["message"]["content"])) {
349 $chat_response = $body["choices"][0]["message"]["content"];
350 wp_send_json_success(["message" => $chat_response]);
351 } else {
352 wp_send_json_error("No response received from ChatGPT API.");
353 wp_die();
354 }
355}
356
357// Add the chatbot icon and window to the admin footer
358add_action("admin_footer", function () {
359 echo <<<HTML
360 <div id="chatgpt-chatbot-icon">🤖</div>
361 <div id="chatgpt-chatbot" class="closed">
362 <div id="chatgpt-chatbot-header">
363 <button id="chatgpt-chatbot-toggle-size">[Expand]</button>
364 WordPress Co-Pilot
365 <button id="chatgpt-chatbot-close">[X]</button>
366 </div>
367 <div id="chatgpt-chatbot-content">
368 <div id="chatgpt-chatbot-messages"></div>
369 </div>
370 <div id="chatgpt-chatbot-footer">
371 <div id="chatgpt-chatbot-input-container">
372 <textarea id="chatgpt-chatbot-input" placeholder="How can I help you today?"></textarea>
373 </div>
374 <div id="chatgpt-chatbot-buttons">
375 <button id="chatgpt-chatbot-send">Send</button>
376 <button id="chatgpt-chatbot-clear">Clear Chat</button>
377 </div>
378 </div>
379 </div>
380HTML;
381});