├── .gitattributes
├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── LICENSE
├── README.md
├── wp-content
└── plugins
│ └── superez-ai-seo
│ ├── _inc.css
│ └── styles.css
│ ├── _inc.htm
│ └── tpl_edit.htm
│ ├── _inc.js
│ ├── script.js
│ ├── superez-gpt-builder.editor.js
│ └── superez-gpt-builder.gptapi.js
│ ├── _inc.php
│ └── sections.php
│ └── superez-ai-seo.php
└── wp-superez-ai-seo-page.png
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2023, g023
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SuperEZ AI SEO Wordpress Plugin
2 |
3 | A Wordpress plugin that utilizes the power of OpenAI GPT-3/GPT-4 API to generate SEO content for your blog or page posts. This Wordpress plugin serves as a personal AI assistant to help you with content ideas and creating content. It also allows you to add Gutenberg blocks to the editor after the assistant generates the content.
4 |
5 | ## Features
6 |
7 | - Early alpha release, use at your own risk.
8 | - Personal AI assistant to assist with content ideas and creation.
9 | - Ability to add Gutenberg blocks to the editor.
10 | - AI-powered revision and update of existing titles.
11 | - Mainly running in JavaScript with PHP handling on page load to eliminate page reloads while using the plugin.
12 | - Utilizes jQuery to access the API and provide functionality.
13 | - Various fields for SEO generation, including meta title, meta description, meta keywords, meta categories, and meta tags.
14 | - Supports the use of short tags in editable prompts, such as {PAGE_TITLE}.
15 | - Easy to add more fields using a simple array, although their interactivity will need to be connected via jQuery.
16 | - Temperature can be adjusted, with 0.0 being very conservative and 1.2 being very creative.
17 | - Max tokens control the limit of tokens for each request.
18 | - Click on the title of the AI assistant to minimize or maximize its window.
19 |
20 | ## Installation
21 |
22 | 1. Download the plugin and place it in the `wp-content/plugins/` folder.
23 | - Create a folder called `superez-ai-seo` inside the `plugins` folder.
24 | - Place the plugin files inside the `superez-ai-seo` folder.
25 | - Example path: `wp-content/plugins/superez-ai-seo/superez-ai-seo.php`
26 | - Write permissions are not required for any of the folders at the moment.
27 | 2. Activate the plugin.
28 | - Go to the WordPress plugins section and activate the plugin.
29 | 3. Access the plugin in a blog post or page.
30 | - You should see a section called "AI SEO and AI Content Generation".
31 | - If the section is collapsed, click on it to show the AI assistants.
32 | 4. Set your API key.
33 | - Get an API key from [https://openai.com/blog/openai-api](https://openai.com/blog/openai-api).
34 | - Add your API key to the API key field and click "Set API Key".
35 | 5. Start using the plugin.
36 | - Choose an assistant and start exploring its features.
37 | - You can start by entering a simple title on your page and then use the AI to generate a different title. Click "AI Revise Main Title" and then "Update Main Title" to update the main title with the revised title.
38 | 6. Enjoy!
39 |
40 | ## Requires
41 | - OpenAI API Key
42 | - Tested on clean install of Wordpress 6.3.2
43 |
44 | [](#screenshot)
45 |
46 |
47 | ## Notes
48 | v1.0.1a
49 | - Code cleanup. Release .zip should install as a wordpress zipped plugin.
50 |
51 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.css/styles.css:
--------------------------------------------------------------------------------
1 |
2 | .ezseo .row {
3 | display:block;
4 | }
5 |
6 | .ezseo .col {
7 | display:inline-block;
8 | }
9 |
10 | .ezseo .button {
11 | margin-left:5px;
12 | margin-right:5px;
13 | }
14 |
15 | .d-footer input,
16 | .ezseo input.output {
17 | margin-bottom:4px;
18 | }
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | .d-ai-assistant {
30 | position:fixed;
31 | border:1px solid #222;
32 | bottom:40px;
33 | right:30px;
34 | text-align:center;
35 | /*
36 | margin:2px;
37 | padding:10px;
38 | */
39 | padding:0px;
40 | z-index:999998999;
41 | background-color:white;
42 | background-color:rgba(255,255,255,0.6);
43 | /* blur effect */
44 | backdrop-filter: blur(5px);
45 | -webkit-backdrop-filter: blur(5px);
46 | border-radius:2px 2px 2px 2px;
47 |
48 | padding:20px;
49 |
50 | min-width:220px;
51 | }
52 |
53 | /* now style interior */
54 |
55 | .d-ai-assistant .row {
56 | position:relative;
57 | width:100%;
58 | padding:2px;
59 | }
60 |
61 | .d-ai-assistant button,
62 | .d-ai-assistant input,
63 | .d-ai-assistant textarea {
64 | position:relative;
65 | width:100%;
66 | padding:2px;margin:0px;
67 | outline:none;
68 | left:0px;right:0px;
69 | /* prevent overlapping */
70 |
71 | border:1px solid #ccc;
72 | border-radius:2px 2px 2px 2px;
73 |
74 |
75 | }
76 |
77 | .d-ai-assistant .title {
78 | cursor:pointer;
79 | /* no select */
80 | user-select:none;
81 | -webkit-user-select:none;
82 | -moz-user-select:none;
83 | -ms-user-select:none;
84 | -o-user-select:none;
85 | /* background-color:#ccc; */
86 | padding:2px;
87 | border-radius:2px 2px 0px 0px;
88 | border-bottom:1px solid #ccc;
89 |
90 | }
91 |
92 | .d-ai-assistant .title:hover {
93 | background-color:#ccc;
94 | }
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 | .config-container {
103 | }
104 | .config-container textarea {
105 | width: 100%;
106 | }
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.htm/tpl_edit.htm:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
47 |
48 |
49 |
50 | max tokens:
51 |
52 |
53 |
output:
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.js/script.js:
--------------------------------------------------------------------------------
1 | console.log('Hello World! admin section');
2 |
3 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.js/superez-gpt-builder.editor.js:
--------------------------------------------------------------------------------
1 | // BEGIN :: UPDATE API KEY //
2 | // when we click the the-aikey-btn we set the api key for current window. (at moment just storing in a global variable)
3 | // begin.
4 | g_apiKey = '';
5 | g_GPT = new ChatGPTClient(g_apiKey);
6 |
7 |
8 | // when we click the the-aikey-btn we set the api key for current window. (at moment just storing in a global variable)
9 | jQuery(document).ready(function($) {
10 | jQuery('#the-aikey-btn').click(function() {
11 | var key = $('#the-aikey').val();
12 | g_apiKey = key;
13 | g_GPT = new ChatGPTClient(g_apiKey);
14 | alert('API key set.');
15 | // blank field
16 | $('#the-aikey').val('');
17 | });
18 | });
19 | // END :: UPDATE API KEY //
20 |
21 | // BEGIN :: HANDLE UPDATE TITLE FROM REVISED //
22 | /*
23 | // Get the current post title.
24 | const currentTitle = wp.data.select('core/editor').getCurrentPost().title;
25 |
26 | // Define the new title.
27 | const newTitle = 'New Page Title';
28 |
29 | // Update the post title using the `wp.data.dispatch` method.
30 | wp.data.dispatch('core/editor').editPost({ title: newTitle });
31 |
32 | // You can also console log the old and new titles for verification.
33 | console.log('Old Title:', currentTitle);
34 | console.log('New Title:', newTitle);
35 | */
36 | // when we click the update-main-title button we update the main title with the revised title
37 | jQuery(document).ready(function($) {
38 | jQuery('.update-main-title').click(function() {
39 | var revised_title = $('#ez-base-title').val();
40 |
41 | // update the title
42 | wp.data.dispatch('core/editor').editPost({ title: revised_title });
43 | });
44 | });
45 | // END :: HANDLE UPDATE TITLE FROM REVISED //
46 |
47 |
48 | // -- end: 1
49 |
50 |
51 | // begin: 2
52 |
53 | // when slider changes, update the number
54 | jQuery(document).ready(function($) {
55 | $('#the-ai-assistant-temperature').on('input', function() {
56 | $('#the-ai-assistant-temperature-2').val($(this).val());
57 | });
58 | });
59 | // when number changes, update the slider
60 | jQuery(document).ready(function($) {
61 | $('#the-ai-assistant-temperature-2').on('input', function() {
62 | $('#the-ai-assistant-temperature').val($(this).val());
63 | });
64 | });
65 | // -- end: 2
66 |
67 |
68 |
69 |
70 | // begin: 3
71 |
72 | // find first {ai} tag in document and return the result after processing with the prompt
73 | // return error if prompt empty
74 | // if {PAGE_TITLE} in prompt, use the page title in place of that tag
75 | jQuery(document).ready(function($) {
76 |
77 | // when + block clicked, take assistant output and insert it as a block in wp editor
78 | // BEGIN :: HOW TO INSERT A BLOCK INTO THE EDITOR
79 | /*
80 | // create a block
81 | var block = wp.blocks.createBlock('core/paragraph', {
82 | content: 'Hello World!',
83 | });
84 | // add the block to the editor
85 | wp.data.dispatch('core/editor').insertBlocks(block);
86 | */
87 | // END :: HOW TO INSERT A BLOCK INTO THE EDITOR
88 | jQuery('#the-ai-assistant-add-block').on('click', function() {
89 | // get the output
90 | var output = $('#assistant-output').val();
91 | // if it is empty, error
92 | if (output == '') {
93 | alert('No content to add.');
94 | return;
95 | }
96 |
97 | // create a block
98 | var block = wp.blocks.createBlock('core/paragraph', {
99 | content: output,
100 | });
101 |
102 | // add the block to the editor
103 | // wp.data.dispatch('core/editor').insertBlocks(block); // deprecated
104 | // new: wp.data.dispatch( 'core/block-editor' ).insertBlocks`
105 | wp.data.dispatch( 'core/block-editor' ).insertBlocks( block );
106 | });
107 |
108 | // when title clicked, slidetoggle
109 | jQuery('.d-ai-assistant .title').on('click', function() {
110 | jQuery('.d-ai-assistant .ai-assistant').slideToggle(10);
111 | });
112 |
113 | // when assistant button clicked
114 | jQuery('#the-ai-assistant-btn').click(function() {
115 | // createBlock from wordpress
116 |
117 | var prompt = $('#the-prompt').val();
118 | if (prompt == '') {
119 | alert('Please enter a prompt.');
120 | return;
121 | }
122 | // get the page title
123 | var title = $('h1.editor-post-title').html();
124 | // replace {PAGE_TITLE} with title
125 | prompt = prompt.replace('{PAGE_TITLE}', title);
126 | // get the content
127 | var content = $('.editor-post-text-editor').val();
128 | // replace {PAGE_CONTENT} with content
129 | prompt = prompt.replace('{PAGE_CONTENT}', content);
130 | // get the model
131 | var model = 'gpt-3.5-turbo-16k';
132 | // get the temperature
133 | // var temperature = 0.7;
134 | var temperature = $('#the-ai-assistant-temperature').val();
135 | console.log('temperature',temperature);
136 | // get the max tokens
137 | // var max_tokens = 60;
138 | var max_tokens = $('#the-ai-assistant-max-tokens').val();
139 | console.log('max_tokens',max_tokens);
140 | // make temperate a float
141 | temperature = parseFloat(temperature);
142 | // make max tokens an int
143 | max_tokens = parseInt(max_tokens);
144 | // set the prompt up
145 | messages = [{ role: 'user', content: prompt }];
146 | // send the request, and await a response
147 | get_response(model,messages,temperature,max_tokens, '.d-ai-assistant #assistant-output');
148 |
149 | });
150 | });
151 |
152 |
153 | // BEGIN ::
154 | // create a function based off the code in .my-seo-fetch-revise-title
155 | async function update_output(parent_class)
156 | {
157 | // theButton is $(this)
158 | // title = jQuery('h1.editor-post-title').html();
159 | // use wp. javascript functions to get title
160 | const title = wp.data.select('core/editor').getCurrentPost().title;
161 | content = jQuery('.editor-post-text-editor').val(); // need a better option
162 | // get the parent div
163 | var parent_div = jQuery(parent_class);
164 | // get the target to send the output to
165 | var update_class = parent_class + ' .output';
166 |
167 | console.log('parent_class',parent_class);
168 | console.log('update_class',update_class);
169 |
170 | console.log('current_output',jQuery(update_class).val());
171 |
172 | // get the prompt // parent gpt-field // child prompt
173 | // var prompt = parent_div.find('.prompt').val();
174 | var prompt = parent_div.find('.the-preprompt').val();
175 |
176 | console.log('prompt',prompt);
177 |
178 | // replace {POST_TITLE} with title
179 | prompt = prompt.replace('{POST_TITLE}', title);
180 |
181 | // replace {POST_CONTENT} with content
182 | prompt = prompt.replace('{POST_CONTENT}', content);
183 |
184 | console.log('prompt',prompt);
185 | // get the model
186 | // var model = parent_div.find('.ai-model').val();
187 | var model = parent_div.find('.the-model').val();
188 | console.log('model',model);
189 | // get the temperature
190 | // var temperature = $('.gpt-field .ai-temperature').val();
191 | // var temperature = parent_div.find('.ai-temperature').val();
192 | var temperature = parent_div.find('.the-temp').val();
193 | console.log('temperature',temperature);
194 | // get the max tokens
195 | // var max_tokens = $('.gpt-field .ai-max-tokens').val();
196 | // var max_tokens = parent_div.find('.ai-max-tokens').val();
197 | var max_tokens = parent_div.find('.the-maxtokens').val();
198 | console.log('max_tokens',max_tokens);
199 | // make temperate a float
200 | temperature = parseFloat(temperature);
201 | // make max tokens an int
202 | max_tokens = parseInt(max_tokens);
203 | // set the prompt up
204 | messages = [{ role: 'user', content: prompt }];
205 |
206 | // send the request, and await a response
207 | await get_response(model,messages,temperature,max_tokens, update_class);
208 | }
209 |
210 | // make an array of updateables
211 | var updateables = [
212 | '.my-seo-fetch-revise-title',
213 | '.my-seo-fetch-title',
214 | '.my-seo-fetch-ai-description',
215 | '.my-seo-fetch-ai-keywords',
216 | '.my-seo-fetch-ai-categories',
217 | '.my-seo-fetch-ai-tags',
218 | ];
219 |
220 | // attach click handlers to each updateable
221 | jQuery(document).ready(function($) {
222 | updateables.forEach(function(updateable) {
223 | jQuery(updateable).on('click', async function( theButton ) {
224 | var parent_class = '.gpt-field[fld='+jQuery(this).attr('fld')+']';
225 | await update_output(parent_class);
226 | });
227 | });
228 | });
229 |
230 | // when we click my-seo-fetch-revise-title
231 |
232 | // END ::
233 |
234 |
235 | // -- end: 3
236 |
237 |
238 | // begin: 4
239 |
240 | // handle sliders for gpt-fields
241 | jQuery(document).ready(function($) {
242 | $('.gpt-field input[type=range]').on('input', function() {
243 | $(this).next().val($(this).val());
244 | });
245 | $('.gpt-field input[type=number]').on('input', function() {
246 | $(this).prev().val($(this).val());
247 | });
248 | });
249 |
250 | // default hide config
251 | jQuery(document).ready(function($) {
252 | $('.gpt-field .config-container').hide();
253 | });
254 | // when click show config
255 | jQuery(document).ready(function($) {
256 | $('.gpt-field .show-hide-config').on('click', function() {
257 | $(this).parent().find('.config-container').slideToggle(10);
258 | });
259 | });
260 |
261 | // -- end: 4
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.js/superez-gpt-builder.gptapi.js:
--------------------------------------------------------------------------------
1 |
2 | // get_response requires global: g_GPT which is a ChatGPTClient object
3 |
4 | class ChatGPTClient {
5 | constructor(apiKey) {
6 | this.apiKey = apiKey;
7 | this.baseUrl = 'https://api.openai.com/v1/chat/completions';
8 | }
9 |
10 | sendRequest(model, messages, temperature = 0.7, max_tokens=150) {
11 |
12 | const headers = {
13 | 'Content-Type': 'application/json',
14 | 'Authorization': `Bearer ${this.apiKey}`,
15 | };
16 |
17 | const requestData = {
18 | model,
19 | messages,
20 | temperature,
21 | max_tokens
22 | };
23 |
24 | // return $.ajax({
25 | // use jQuery. syntax to make it easier to use in a web browser
26 | return jQuery.ajax({
27 | type: 'POST',
28 | url: this.baseUrl,
29 | headers,
30 | data: JSON.stringify(requestData),
31 | success: (response) => response,
32 | error: (error) => error,
33 | }); // end -> ajax
34 |
35 | } // end -> sendRequest
36 | } // end -> class ChatGPTClient
37 |
38 | // requires a global: g_GPT
39 | async function get_response(model,messages,temperature, max_tokens=40, update_class='#error')
40 | {
41 | // check for blank g_GPT.apiKey
42 | if(g_GPT.apiKey == '')
43 | {
44 | // $(update_class).val('Error: No API key set.');
45 | alert('Error: No API key set.');
46 | return;
47 | }
48 |
49 | try {
50 | const response = await g_GPT.sendRequest(model, messages, temperature, max_tokens);
51 | console.log(response);
52 | assistantResponse = response.choices[0].message.content;
53 |
54 | // remove double quotes from beginning and end of string
55 | if(assistantResponse.startsWith('"') && assistantResponse.endsWith('"'))
56 | assistantResponse = assistantResponse.substring(1, assistantResponse.length - 1);
57 |
58 | jQuery(update_class).val(assistantResponse);
59 | } catch (error) {
60 | // $(update_class).val(`Error: ${error.statusText}`);
61 | // use jquery syntax to make it easier to use in a web browser
62 | // jQuery(update_class).val(`Error: ${error.statusText}`);
63 | console.log('ERROR:', error.statusText);
64 | alert('ERROR:', error.statusText);
65 | }
66 |
67 | /* sleep for 5 seconds to help prevent overloading */
68 | await new Promise(r => setTimeout(r, 5000));
69 |
70 | return;
71 | }
72 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/_inc.php/sections.php:
--------------------------------------------------------------------------------
1 | 'ez-base-title',
5 | 'label' => 'Revise Base Title',
6 | 'description' => 'The base title for the page.',
7 | 'prompt' => 'Just show the title. You will take the title [{POST_TITLE}] and generate a better title. If the title looks like it contains things that do not seem in place, remove those elements.',
8 | 'template-admin' => '',
9 | 'sanitize-type' => 'sanitize_text_field',
10 | 'escape-type' => 'esc_attr',
11 | 'button' => 'AI Revise Main Title',
12 | 'button-id' => 'my-seo-fetch-revise-title',
13 | 'ai-max-tokens' => 60,
14 | 'ai-temperature' => 0.7,
15 | 'ai-model' => 'gpt-3.5-turbo-16k', // 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-instruct', 'gpt-4', 'gpt-4-32k'
16 | 'more-buttons' => [[ 'id'=>'update-main-title', 'label'=>'Update Main Title' ]],
17 | );
18 |
19 | $g_fields[] = array(
20 | 'id' => 'ez-meta-title',
21 | 'label' => 'Meta Title',
22 | 'description' => 'The meta title for the page.',
23 | 'prompt' => 'Show me a catchy social media title for an og:title tag based on the page title for a blog called {POST_TITLE}.',
24 | 'template-admin' => '',
25 | 'sanitize-type' => 'sanitize_text_field',
26 | 'escape-type' => 'esc_attr',
27 | 'button' => 'Fetch AI Title',
28 | 'button-id' => 'my-seo-fetch-title',
29 | 'ai-max-tokens' => 60,
30 | 'ai-temperature' => 0.7,
31 | 'ai-model' => 'gpt-3.5-turbo-16k', // 'gpt-3.5-turbo-16k', 'gpt-3.5-turbo-instruct', 'gpt-4', 'gpt-4-32k'
32 | );
33 |
34 |
35 | $g_fields[] = array(
36 | 'id' => 'ez-meta-desc',
37 | 'label' => 'Meta Description',
38 | 'description' => 'The meta description for the page.',
39 | 'prompt' => 'Just show the description. Show me a catchy social media description for an og:description tag based on the page content for a blog called {POST_TITLE}.',
40 | 'template-admin' => '',
41 | 'sanitize-type' => 'sanitize_text_field',
42 | 'escape-type' => 'esc_attr',
43 | 'button' => 'Fetch AI Description',
44 | 'button-id' => 'my-seo-fetch-ai-description',
45 | 'ai-max-tokens' => 250,
46 | 'ai-temperature' => 0.7,
47 | 'ai-model' => 'gpt-3.5-turbo-16k',
48 | );
49 |
50 | $g_fields[] = array(
51 | 'id' => 'ez-meta-keywords',
52 | 'label' => 'Meta Keywords',
53 | 'description' => 'The meta keywords for the page.',
54 | 'prompt' => 'Just show the keywords with each keyword separated by a comma. No numbers. Show me a list of keywords for a blog called {POST_TITLE}. Order by most relevant to least relevant.',
55 | 'template-admin' => '',
56 | 'sanitize-type' => 'sanitize_text_field',
57 | 'escape-type' => 'esc_attr',
58 | 'button' => 'Fetch AI Keywords',
59 | 'button-id' => 'my-seo-fetch-ai-keywords',
60 | 'ai-max-tokens' => 200,
61 | 'ai-temperature' => 0.7,
62 | 'ai-model' => 'gpt-3.5-turbo-16k',
63 | );
64 |
65 | $g_fields[] = array(
66 | 'id' => 'ez-meta-categories',
67 | 'label' => 'Meta Categories',
68 | 'description' => 'The meta categories for the page.',
69 | 'prompt' => 'Just show the categories, with each category separated by a comma. No numbers. Show me a list of categories for a blog called {POST_TITLE}. Order by most relevant to least relevant.',
70 | 'template-admin' => '',
71 | 'sanitize-type' => 'sanitize_text_field',
72 | 'escape-type' => 'esc_attr',
73 | 'button' => 'Fetch AI Categories',
74 | 'button-id' => 'my-seo-fetch-ai-categories',
75 | 'ai-max-tokens' => 200,
76 | 'ai-temperature' => 0.7,
77 | 'ai-model' => 'gpt-3.5-turbo-16k',
78 | );
79 |
80 | $g_fields[] = array(
81 | 'id' => 'ez-meta-tags',
82 | 'label' => 'Meta Tags',
83 | 'description' => 'The meta tags for the page.',
84 | 'prompt' => 'Just show me the tags, with each tag separated by a comma. No numbers. Show me a list of tags for a blog called {POST_TITLE}. Order by most relevant to least relevant.',
85 | 'template-admin' => '',
86 | 'sanitize-type' => 'sanitize_text_field',
87 | 'escape-type' => 'esc_attr',
88 | 'button' => 'Fetch AI Tags',
89 | 'button-id' => 'my-seo-fetch-ai-tags',
90 | 'ai-max-tokens' => 200,
91 | 'ai-temperature' => 0.7,
92 | 'ai-model' => 'gpt-3.5-turbo-16k',
93 | );
94 |
95 |
--------------------------------------------------------------------------------
/wp-content/plugins/superez-ai-seo/superez-ai-seo.php:
--------------------------------------------------------------------------------
1 | https://github.com/g023
7 | License: 3-clause BSD license (https://opensource.org/licenses/BSD-3-Clause)
8 | */
9 |
10 |
11 | /*
12 | Features:
13 | Use the power of OpenAI GPT-3/GPT-4 API to generate content for your blog or page post in your wordpress site.
14 | - early alpha release, so use at your own risk.
15 | - personal ai assistant to help you with content ideas/creating content
16 | - ability to add gutenberg blocks to the editor after the assistant generates.
17 | - existing title revise/update using AI
18 | - mainly running in Javascript with PHP just handled on the page load.
19 | - jQuery used to access api and provide functionality.
20 | - various fields for SEO generation.
21 | - meta title, meta description, meta keywords, meta categories, meta tags...
22 | - can use short tags in editable prompts such as {PAGE_TITLE}
23 | - easy to add more fields using a simple array.
24 | - their interactivity will still need to be connected via jquery somewhere in here.
25 | - temperature can be adjusted. (0.0 = very conservative, 1.2 = very creative)
26 | - max tokens controls how many tokens you want to limit the request to
27 | - click on title of ai assistant to minimize/maximize its window
28 |
29 |
30 | INSTALL:
31 | 1) install plugin to your wp-content\plugins\ folder
32 | - inside the plugins folder, you would make a folder called superez-ai-seo and then place the files in there.
33 | eg) wp-content\plugins\superez-ai-seo\superez-ai-seo.php
34 | - write permissions not required on any of the folders at the moment
35 | 2) activate plugin
36 | - activate plugin in wordpress plugins section
37 | 3) go into a blog post or a page and you should see it as a section called 'AI SEO and AI Content Generation'
38 | - if the section is collapsed, you may need to click it to show the AI assistants.
39 | 4) add your api key to the api key field and click 'set api key'
40 | - you can get an api key from https://openai.com/blog/openai-api
41 | 5) once key is loaded you simply pick an assistant and start playing around.
42 | - you might want to throw a simple title in on the page title, and then get ai to generate a different title first.
43 | (AI Revise Main Title) and then click (Update Main Title) to update the main title with the revised title.
44 | 6) enjoy :)
45 |
46 | TODO:
47 | - maybe add a key storage at some point. Right now you have to enter it whenever you enter the page
48 | and the key is just stored in memory, which is released when you leave the page.
49 | */
50 |
51 | // This is a wordpress plugin for the admin section that helps build content using AI
52 |
53 | // add a input and button to top bar
54 | function my_seo_plugin_admin_bar() {
55 | global $wp_admin_bar;
56 |
57 | $wp_admin_bar->add_menu(array(
58 | 'id' => 'my-seo-plugin',
59 | 'title' => 'SuperEZ AI SEO',
60 | 'href' => '#',
61 | 'meta' => array(
62 | 'title' => __('SuperEZ AI SEO'),
63 | ),
64 | ));
65 |
66 | $wp_admin_bar->add_menu(array(
67 | 'id' => 'my-seo-plugin-settings',
68 | 'parent' => 'my-seo-plugin',
69 | 'title' => 'Settings',
70 | 'href' => admin_url('options-general.php?page=my-seo-plugin-settings'),
71 | 'meta' => array(
72 | 'title' => __('Settings'),
73 | ),
74 | ));
75 | /*
76 | $wp_admin_bar->add_menu(array(
77 | 'id' => 'my-seo-plugin-help',
78 | 'parent' => 'my-seo-plugin',
79 | 'title' => 'Help',
80 | 'href' => admin_url('options-general.php?page=my-seo-plugin-help'),
81 | 'meta' => array(
82 | 'title' => __('Help'),
83 | ),
84 | ));
85 | */
86 | }
87 |
88 | add_action('admin_bar_menu', 'my_seo_plugin_admin_bar', 100);
89 |
90 | // add a settings page
91 | function my_seo_plugin_settings_page() {
92 | ?>
93 |
94 |
SuperEZ AI SEO Settings
95 |
Here are the settings for the SuperEZ AI SEO plugin.