easily add chatgpt to wordpress theme

Below is the full code with relatively complete instructions for adding an instance of OpenAI’s ChatGPT to a WordPress theme. There are no complex steps or challenging dependencies to navigate. You should essentially be able to cut and paste the code and have it work right away.

Skill level

These instructions are best suited for those who are familiar with the structure of a WordPress theme and have spent some time working with theme files.

Deploying this code does not require any significant knowledge of front-end coding, however you will need to look at the code and change elements indicated in the instructions to fit your needs.

Security

This solution stores the API key on the client-side using PHP instead of on the server-side. This method is both less secure and a LOT easier to implement. The API key is obscured but could be found if someone were to hack your website.

However, the API is so cheap to use that there isn’t a lot of incentive to steal it. OpenAI lets you set a maximum to spend per month capping any potential loss. And you can change your key on a regular basis.

This implementation should not open up your website to any greater likelihood of being hacked.

Getting Started

You’ll need to go to OpenAI and sign up for an account or sign in to your existing account.

Once you have the account you will need to create a new secret key. Be sure to copy the key to a safe place before navigating away from the page.

You will need to have a bank or credit card on file so you can be charged for your use of the API. It’s surprisingly affordable.

HTML

<?php /* Template Name: GPTpage */ ?>
<?php get_header(); ?>
	<div id="gptOutput"></div>
	<div id="inputWrapper">
		<input type="text" id="gptInput" placeholder="Ask a question...">
		<button id="gptSubmit">Ask</button>
	</div>
<?php get_footer(); ?>

How to use the HTML

  • Create a file called ‘template-somename.php’ in your theme folder. Change ‘somename’ to whatever you like.
  • Once you’ve made that file paste in the code above and save it.
  • Change the ‘Template Name’ at the top of the code from ‘GPTpage’ to what ever you prefer.
  • In the WordPress Admin create a new page and assign it the template you created above. This setting is in the page ‘Summery’ in the right sidebar. This may be hidden. Click the sidebar icon in the top right to see it.
  • In the code you can change the input placeholder which is the text that displays in the input before anything is added.
  • You can change the text of the button.
  • The code above may not include all wrappers, containers, or sidebars in use on your theme. Look at the page.php file to see what might be missing.

CSS

#gptOutput {width:100%;font-size:1.25rem;}
#gptOutput * {line-height:1.8em;}
#gptOutput div {background:#eeeeee;padding:1rem;border:1px solid #000000;margin-bottom:1.5rem;}
#gptOutput div p {margin-bottom:1.875rem;}
#gptOutput div ul, #gptOutput div ol {margin-bottom:1.875rem;padding-left:1.5rem;}
#gptOutput div li {list-style-type:disc;}
#gptOutput div pre {margin-bottom:1.875rem;background: #dddddd;padding:1rem 1.25rem;border:1px solid #000000;overflow:auto;tab-size:4;}
#gptOutput div *:last-child {margin-bottom: 0.375rem;}
#inputWrapper {display:grid;grid-template-columns:10fr auto;}
#gptInput {padding:1rem;background:#eeeeee;font-size:1.125rem;line-height:1.2em;color:#000;height:auto;border:1px solid #000000;-webkit-border-radius:0;border-radius:0;}
#gptInput::placeholder {color:#bbb;height:100%;}
#gptSubmit {background:#000000;border:none;padding:0 1rem 0.25rem 1rem;line-height:0;display:inline-block;height:100%;font-size:1rem;font-weight:300;font-size:1.125em;color:white;}
#gptSubmit:hover {background:#333333;}

How to use the CSS

  • Paste this code into your style.css file.
  • ‘#gptOutput div’ is the wrapper for both your questions and the answers that display.
  • Nothing you change here will break the functionality of the page, but could make it hard to understand.

Javascript

if (window.location.href.indexOf("https://your-domain.com/page") > -1) {
	let openaiApiKey;
	const xhr = new XMLHttpRequest();
	xhr.open('POST', '/wp-admin/admin-ajax.php?action=get_openai_api_key');
	xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	xhr.onload = function() {
		openaiApiKey = xhr.responseText;
		const submitButton = document.querySelector('#gptSubmit');
		const outputElement = document.querySelector('#gptOutput');
		const inputElement = document.querySelector('#gptInput');
		let loadInterval;
		function startLoader() {
			inputElement.value = '';
			inputElement.setAttribute('placeholder', '');
			inputElement.blur();
			loadInterval = setInterval(() => {
				const text = inputElement.getAttribute('placeholder');
				if (text.endsWith('...')) {
					inputElement.setAttribute('placeholder', text.slice(0, -3));
				} else {
					inputElement.setAttribute('placeholder', text + '.');
				}
			}, 300);
		}
		function stopLoader() {
			clearInterval(loadInterval);
			inputElement.setAttribute('placeholder', '');
			inputElement.focus();
		}
		async function getMessage() {
			const options = {
				method: 'POST',
				headers: {
					'Authorization': `Bearer ${openaiApiKey}`,
					'Content-Type' : 'application/json',
				},
				body: JSON.stringify({
					model: "gpt-3.5-turbo",
					messages: [
						{role: "system", content: "Act as an expert."},
						{role: "user", content: inputElement.value}
					]
				})
			}
			try {
				const inputText = document.createElement('div');
				inputText.textContent = inputElement.value;
				inputElement.value = '';
				startLoader();
				outputElement.append(inputText);
				const response = await fetch('https://api.openai.com/v1/chat/completions', options);
				stopLoader();
				if (!response.ok) {
					throw new Error(`API request failed with status ${response.status}`);
				}
				const data = await response.json();
				const outputText = document.createElement('div');
				outputText.innerHTML = DOMPurify.sanitize(marked.parse(data.choices[0].message.content));
				outputElement.append(outputText);
			} catch (error){
				console.error(error);
				stopLoader();
				const outputError = document.createElement('div');
				outputError.innerHTML = '<p>There was a problem with the GPT service. Try again later.</p>';
				outputElement.append(outputError);
			}
		}
		submitButton.addEventListener('click', getMessage);
		inputElement.addEventListener('keydown', function(e) {
			if (e.key === 'Enter') {
				e.preventDefault();
				getMessage();
			}
		});
	}
	xhr.send();
}

How to use the Javascript

  • Paste this code into your scripts.js file.
  • The first line is an ‘if statement’ that only allows the script to run when the GPT page displays. Put the url of that page where it says “https://your-domain.com/page.”
  • If you search for ‘messages’ in the code you will find a ‘system’ role where you can add ‘content.’ This content allows you to customize how your instance functions. It is important to change this or leave it blank.
  • The outputError variable holds text that will display if there is a problem like an OpenAI outage.
  • Portions of this script are credited to Ania Kubów.

PHP

function get_openai_api_key() {
	$allowed_domains = array('your-domain.com');
	$referer = $_SERVER['HTTP_REFERER'];
	$referer_parts = parse_url($referer);
	$referer_host = $referer_parts['host'];
	if (in_array($referer_host, $allowed_domains)) {
		$api_key = "your-api-key-here";
	} else {
		http_response_code(403);
		die("Access denied");
	}
	echo $api_key;
	wp_die();
}
add_action('wp_ajax_get_openai_api_key', 'get_openai_api_key');
add_action('wp_ajax_nopriv_get_openai_api_key', 'get_openai_api_key');

How to use the PHP

  • Paste this code into the functions.php file of your theme.
  • Paste in your domain where it says “your-domain.com.”
  • Paste in your OpenAI API key where it says “your-api-key-here” and save the file.
  • If there is no functions.php file, create one and paste this in with opening and closing php tags at the beginning and end. <?php code ?>

Dependencies

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>

<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.2/purify.min.js"></script>

How to use the dependencies

  • Marked.js adds html tags to the GPT output. This allows you to style that output. The most common output will be paragraphs, lists, and code.
  • DOMpurify strips that output of any malicious code providing a measure of security.
  • The scripts above should be placed in the footer of your theme before <?php wp_footer(); ?>.
  • For better performance you can copy the Marked and DOMpurify code and add them to your scripts.js file. Place the Marked code at the bottom as it has a quirk that may cancel code below it.

Notes

  • An example of this code in use can be found on this site here.
  • This article was written because I couldn’t find anything similar when trying to accomplish this goal.
  • ChatGPT was very helpful putting this together.