| 1 |
<?php |
| 2 |
/** |
| 3 |
* Content Brief Prompts Class |
| 4 |
* |
| 5 |
* Handles content brief generation AI prompts. |
| 6 |
* Preserves exact functionality from original Content Brief Generator implementation. |
| 7 |
* |
| 8 |
* @package ThinkRank |
| 9 |
* @subpackage AI\Prompts |
| 10 |
* @since 1.0.0 |
| 11 |
*/ |
| 12 |
|
| 13 |
declare(strict_types=1); |
| 14 |
|
| 15 |
namespace ThinkRank\AI\Prompts; |
| 16 |
|
| 17 |
// Prevent direct access |
| 18 |
if (!defined('ABSPATH')) { |
| 19 |
exit; |
| 20 |
} |
| 21 |
|
| 22 |
/** |
| 23 |
* Content Brief Prompts Class |
| 24 |
* |
| 25 |
* Centralized content brief prompt building for consistent AI optimization across all providers. |
| 26 |
* Handles comprehensive content brief generation with SEO, competitor analysis, and content strategy. |
| 27 |
* |
| 28 |
* @since 1.0.0 |
| 29 |
*/ |
| 30 |
class Content_Brief_Prompts { |
| 31 |
|
| 32 |
/** |
| 33 |
* Build content brief generation prompt |
| 34 |
* |
| 35 |
* @since 1.0.0 |
| 36 |
* |
| 37 |
* @param array $target_keywords Primary and secondary keywords |
| 38 |
* @param string $content_type Type of content |
| 39 |
* @param string $target_audience Target audience |
| 40 |
* @param string $content_length Desired content length |
| 41 |
* @param string $tone Content tone |
| 42 |
* @param string $competitor_analysis Pre-analyzed competitor content (or empty string) |
| 43 |
* @param string $additional_context Additional context |
| 44 |
* @param string $provider AI provider |
| 45 |
* @return string Generated prompt |
| 46 |
*/ |
| 47 |
public function build_content_brief_prompt( |
| 48 |
array $target_keywords, |
| 49 |
string $content_type, |
| 50 |
string $target_audience, |
| 51 |
string $content_length, |
| 52 |
string $tone, |
| 53 |
string $competitor_analysis, |
| 54 |
string $additional_context, |
| 55 |
string $provider = 'openai', |
| 56 |
string $language = '' |
| 57 |
): string { |
| 58 |
$primary_keyword = $target_keywords[0] ?? ''; |
| 59 |
$secondary_keywords = array_slice($target_keywords, 1); |
| 60 |
|
| 61 |
$word_count_map = [ |
| 62 |
'short' => '500-800 words', |
| 63 |
'medium' => '1000-1500 words', |
| 64 |
'long' => '2000+ words' |
| 65 |
]; |
| 66 |
|
| 67 |
$prompt = "Generate a comprehensive content brief for a {$content_type} targeting \"{$primary_keyword}\" with these specifications:\n\n"; |
| 68 |
if ($language !== '') { |
| 69 |
// Keep the whole brief in the site/post language instead of |
| 70 |
// defaulting to English on non-English sites (issue #234). |
| 71 |
$prompt .= "LANGUAGE (critical): Write the ENTIRE brief — outline, titles, descriptions, keywords and every other piece of text — in {$language}. Do NOT translate to English or switch languages.\n\n"; |
| 72 |
} |
| 73 |
$prompt .= "Target Keywords: " . implode(', ', $target_keywords) . "\n"; |
| 74 |
$prompt .= "Content Type: {$content_type}\n"; |
| 75 |
$prompt .= "Target Audience: {$target_audience}\n"; |
| 76 |
$prompt .= "Desired Length: {$word_count_map[$content_length]}\n"; |
| 77 |
$prompt .= "Tone: {$tone}\n"; |
| 78 |
|
| 79 |
if (!empty($competitor_analysis)) { |
| 80 |
$prompt .= "Competitor Analysis:\n" . $competitor_analysis . "\n"; |
| 81 |
} |
| 82 |
|
| 83 |
if (!empty($additional_context)) { |
| 84 |
$prompt .= "Additional Context: {$additional_context}\n"; |
| 85 |
} |
| 86 |
|
| 87 |
$prompt .= "\nPlease provide a comprehensive, structured response with:\n\n"; |
| 88 |
|
| 89 |
$prompt .= "1. CONTENT OUTLINE:\n"; |
| 90 |
$prompt .= " Create a detailed H1-H3 structure with:\n"; |
| 91 |
$prompt .= " - Clear, SEO-optimized headings\n"; |
| 92 |
$prompt .= " - Word count estimates for each section\n"; |
| 93 |
$prompt .= " - 2-3 key points to cover under each heading\n"; |
| 94 |
$prompt .= " - Relevant keywords to include in each section\n\n"; |
| 95 |
|
| 96 |
$prompt .= "2. SEO METADATA PACKAGE:\n"; |
| 97 |
$prompt .= " TITLES:\n"; |
| 98 |
$prompt .= " - 3-5 compelling title suggestions (50-60 characters)\n"; |
| 99 |
$prompt .= " META DESCRIPTIONS:\n"; |
| 100 |
$prompt .= " - 3-4 meta description variations (150-160 characters)\n"; |
| 101 |
$prompt .= " - Include primary keyword and compelling CTA in each\n"; |
| 102 |
$prompt .= " URL SLUGS:\n"; |
| 103 |
$prompt .= " - 3 SEO-friendly URL slug suggestions (lowercase, hyphens)\n"; |
| 104 |
$prompt .= " FOCUS KEYWORD ANALYSIS:\n"; |
| 105 |
$prompt .= " - Primary keyword placement recommendations\n"; |
| 106 |
$prompt .= " - Secondary keyword integration strategy\n"; |
| 107 |
$prompt .= " - Keyword density guidelines (1-2% for primary)\n"; |
| 108 |
$prompt .= " RELATED KEYWORDS:\n"; |
| 109 |
$prompt .= " - 8-12 LSI and semantic keywords to naturally include\n"; |
| 110 |
$prompt .= " - Long-tail keyword variations\n"; |
| 111 |
$prompt .= " INTERNAL LINKING:\n"; |
| 112 |
$prompt .= " - Specific internal linking opportunities\n\n"; |
| 113 |
|
| 114 |
$prompt .= "3. SOCIAL MEDIA & SCHEMA MARKUP:\n"; |
| 115 |
$prompt .= " SOCIAL MEDIA META TAGS:\n"; |
| 116 |
$prompt .= " - Open Graph title (55 characters max)\n"; |
| 117 |
$prompt .= " - Open Graph description (125 characters max)\n"; |
| 118 |
$prompt .= " - Twitter Card title (70 characters max)\n"; |
| 119 |
$prompt .= " - Twitter Card description (125 characters max)\n"; |
| 120 |
$prompt .= " SCHEMA MARKUP SUGGESTIONS:\n"; |
| 121 |
$prompt .= " - Recommended schema types (Article, FAQ, HowTo, etc.)\n"; |
| 122 |
$prompt .= " - Key schema properties to include\n"; |
| 123 |
$prompt .= " - FAQ schema questions if applicable\n\n"; |
| 124 |
|
| 125 |
$prompt .= "4. VISUAL CONTENT STRATEGY:\n"; |
| 126 |
$prompt .= " IMAGE RECOMMENDATIONS:\n"; |
| 127 |
$prompt .= " - 5-8 specific image types needed\n"; |
| 128 |
$prompt .= " - Alt text suggestions for each image type\n"; |
| 129 |
$prompt .= " - Image placement recommendations\n"; |
| 130 |
$prompt .= " INFOGRAPHIC OPPORTUNITIES:\n"; |
| 131 |
$prompt .= " - Data visualization suggestions\n"; |
| 132 |
$prompt .= " - Process diagrams or flowcharts\n\n"; |
| 133 |
|
| 134 |
$prompt .= "5. COMPETITOR ANALYSIS & CONTENT GAPS:\n"; |
| 135 |
if (!empty($competitor_urls)) { |
| 136 |
$prompt .= " Based on the competitor analysis above:\n"; |
| 137 |
$prompt .= " - Specific content gaps in competitor articles\n"; |
| 138 |
$prompt .= " - How to improve upon competitor headings and structure\n"; |
| 139 |
$prompt .= " - Topics competitors cover poorly or miss entirely\n"; |
| 140 |
$prompt .= " - Opportunities to create more comprehensive content\n"; |
| 141 |
} else { |
| 142 |
$prompt .= " - What competitors typically miss in this topic area\n"; |
| 143 |
$prompt .= " - Unique angles or perspectives to take\n"; |
| 144 |
$prompt .= " - Questions readers have that aren't being answered\n"; |
| 145 |
} |
| 146 |
$prompt .= "\n"; |
| 147 |
|
| 148 |
$prompt .= "6. CALL-TO-ACTION SUGGESTIONS:\n"; |
| 149 |
$prompt .= " - 3-5 compelling CTAs appropriate for the content type\n"; |
| 150 |
$prompt .= " - Placement recommendations within the content\n\n"; |
| 151 |
|
| 152 |
$prompt .= "7. WRITING GUIDELINES:\n"; |
| 153 |
$prompt .= " - Tone and style recommendations\n"; |
| 154 |
$prompt .= " - Key messages to emphasize\n"; |
| 155 |
$prompt .= " - Content format suggestions (lists, tables, etc.)\n\n"; |
| 156 |
|
| 157 |
$prompt .= "8. FULL ARTICLE DRAFT:\n"; |
| 158 |
$prompt .= " Write the complete, publish-ready article body ({$word_count_map[$content_length]}) that follows the outline above.\n"; |
| 159 |
$prompt .= " - Format as clean HTML using <h2>/<h3> headings, <p>, <ul>/<ol>, and <blockquote>. Do NOT include an <h1> (the post title is the H1).\n"; |
| 160 |
$prompt .= " - Write in a {$tone} tone for a {$target_audience} audience, naturally weaving in the target and related keywords.\n"; |
| 161 |
$prompt .= " - Cover every outline section with real prose (no placeholders) and finish with a relevant call to action.\n\n"; |
| 162 |
|
| 163 |
$prompt .= "IMPORTANT: Respond with a valid JSON object using this exact structure:\n\n"; |
| 164 |
$prompt .= "{\n"; |
| 165 |
$prompt .= " \"title_suggestions\": [\"Title 1\", \"Title 2\", \"Title 3\", \"Title 4\", \"Title 5\"],\n"; |
| 166 |
$prompt .= " \"meta_descriptions\": [\"Meta 1\", \"Meta 2\", \"Meta 3\", \"Meta 4\"],\n"; |
| 167 |
$prompt .= " \"url_slugs\": [\"slug-1\", \"slug-2\", \"slug-3\"],\n"; |
| 168 |
$prompt .= " \"outline\": [\n"; |
| 169 |
$prompt .= " {\n"; |
| 170 |
// No level label in the value. It duplicated the `level` field on the |
| 171 |
// next line and taught the model that a heading string begins with its |
| 172 |
// own level, which it then carried into content_body — so drafted |
| 173 |
// articles came back with <h2>H2: Real Heading</h2> (#410). |
| 174 |
$prompt .= " \"heading\": \"Main Title\",\n"; |
| 175 |
$prompt .= " \"level\": 1,\n"; |
| 176 |
$prompt .= " \"word_count\": 50,\n"; |
| 177 |
$prompt .= " \"key_points\": [\"Point 1\", \"Point 2\", \"Point 3\"],\n"; |
| 178 |
$prompt .= " \"keywords\": [\"keyword1\", \"keyword2\"]\n"; |
| 179 |
$prompt .= " }\n"; |
| 180 |
$prompt .= " ],\n"; |
| 181 |
$prompt .= " \"focus_keyword_analysis\": {\n"; |
| 182 |
$prompt .= " \"primary_placement\": [\"H1 title\", \"First paragraph\", \"3-4 headings\"],\n"; |
| 183 |
$prompt .= " \"secondary_integration\": [\"Use secondary keywords naturally throughout content\", \"Focus on user intent and semantic relevance\"],\n"; |
| 184 |
$prompt .= " \"density_guidelines\": [\"Primary keyword: 1-2%\", \"Secondary keywords: 0.5-1%\"]\n"; |
| 185 |
$prompt .= " },\n"; |
| 186 |
$prompt .= " \"related_keywords\": [\"keyword1\", \"keyword2\", \"keyword3\"],\n"; |
| 187 |
$prompt .= " \"internal_linking\": [\"Link suggestion 1\", \"Link suggestion 2\"],\n"; |
| 188 |
$prompt .= " \"social_media\": {\n"; |
| 189 |
$prompt .= " \"open_graph\": {\n"; |
| 190 |
$prompt .= " \"title\": \"OG Title (55 chars max)\",\n"; |
| 191 |
$prompt .= " \"description\": \"OG Description (125 chars max)\"\n"; |
| 192 |
$prompt .= " },\n"; |
| 193 |
$prompt .= " \"twitter_card\": {\n"; |
| 194 |
$prompt .= " \"title\": \"Twitter Title (70 chars max)\",\n"; |
| 195 |
$prompt .= " \"description\": \"Twitter Description (125 chars max)\"\n"; |
| 196 |
$prompt .= " }\n"; |
| 197 |
$prompt .= " },\n"; |
| 198 |
$prompt .= " \"schema_markup\": {\n"; |
| 199 |
$prompt .= " \"recommended_types\": [\"Article\", \"HowTo\", \"FAQ\"],\n"; |
| 200 |
$prompt .= " \"key_properties\": [\"headline\", \"description\", \"author\"],\n"; |
| 201 |
$prompt .= " \"faq_questions\": [\"Question 1?\", \"Question 2?\"]\n"; |
| 202 |
$prompt .= " },\n"; |
| 203 |
$prompt .= " \"visual_content\": {\n"; |
| 204 |
$prompt .= " \"image_recommendations\": [\n"; |
| 205 |
$prompt .= " {\n"; |
| 206 |
$prompt .= " \"type\": \"Featured Image\",\n"; |
| 207 |
$prompt .= " \"description\": \"Professional image description\",\n"; |
| 208 |
$prompt .= " \"alt_text\": \"Alt text suggestion\"\n"; |
| 209 |
$prompt .= " }\n"; |
| 210 |
$prompt .= " ],\n"; |
| 211 |
$prompt .= " \"infographic_opportunities\": [\"Data visualization 1\", \"Process diagram 2\"]\n"; |
| 212 |
$prompt .= " },\n"; |
| 213 |
$prompt .= " \"competitor_analysis\": {\n"; |
| 214 |
$prompt .= " \"content_gaps\": [\"Gap 1\", \"Gap 2\"],\n"; |
| 215 |
$prompt .= " \"unique_angles\": [\"Angle 1\", \"Angle 2\"],\n"; |
| 216 |
$prompt .= " \"unanswered_questions\": [\"Question 1\", \"Question 2\"]\n"; |
| 217 |
$prompt .= " },\n"; |
| 218 |
$prompt .= " \"call_to_actions\": [\n"; |
| 219 |
$prompt .= " {\n"; |
| 220 |
$prompt .= " \"text\": \"CTA text\",\n"; |
| 221 |
$prompt .= " \"placement\": \"End of post\"\n"; |
| 222 |
$prompt .= " }\n"; |
| 223 |
$prompt .= " ],\n"; |
| 224 |
$prompt .= " \"writing_guidelines\": {\n"; |
| 225 |
$prompt .= " \"tone_recommendations\": [\"Professional\", \"Informative\", \"Actionable\"],\n"; |
| 226 |
$prompt .= " \"key_messages\": [\"Message 1\", \"Message 2\"],\n"; |
| 227 |
$prompt .= " \"format_suggestions\": [\"Bullet points\", \"Short paragraphs\", \"Clear headings\"]\n"; |
| 228 |
$prompt .= " },\n"; |
| 229 |
$prompt .= " \"content_body\": \"<h2>Section heading</h2><p>The complete article written out in clean HTML, following the outline...</p>\"\n"; |
| 230 |
$prompt .= "}\n\n"; |
| 231 |
$prompt .= "Respond ONLY with valid JSON. Do not include any text before or after the JSON object."; |
| 232 |
|
| 233 |
return $prompt; |
| 234 |
} |
| 235 |
} |
| 236 |
|