Building a tutorial generator with the Gemini API is a great way to streamline your workflow for creating HTML and PHP articles. To make the code snippets “copy-paste friendly” with a professional dark theme, we need to combine a few specific technologies.
Here is a blueprint for how you can build this tool.
1. The Tech Stack
* Backend: PHP (to handle API requests and save your generated articles).
* AI Engine: Gemini API (using the gemini-1.5-flash model for speed and low cost).
* Frontend: HTML5 & CSS3 (with a Dark Mode aesthetic).
* Code Enhancements: Prism.js or Highlight.js (for the syntax highlighting) and a simple JavaScript “Clipboard” function.
2. High-Level Architecture
3. Key Components of the Tool
A. The Gemini API Prompt
To get the best results, you should use a System Instruction or a highly structured prompt. You want Gemini to return the tutorial in a specific format (like Markdown or raw HTML) so your tool can display it immediately.
Suggested Prompt Structure:
> “Create a tutorial about [Topic]. Format the output as a clean article. Wrap all code snippets in <pre><code class=’language-php’>…</code></pre> tags. Ensure the code is production-ready.”
>
B. The “Dark Theme” Code Container
In your CSS, you can define a sleek dark container for your code. Using a library like Prism.js makes this easy, but here is a custom CSS snippet for that “developer” look:
/* Custom Dark Theme Code Block */
.code-container {
background: #1e1e1e;
color: #d4d4d4;
border-radius: 8px;
padding: 1.5rem;
position: relative;
font-family: ‘Fira Code’, monospace;
overflow-x: auto;
}
.copy-button {
position: absolute;
top: 10px;
right: 10px;
background: #444;
color: white;
border: none;
padding: 5px 10px;
border-radius: 4px;
cursor: pointer;
}
C. The PHP API Wrapper
Since you mentioned working with PHP, you can use curl to talk to the Gemini API.
// Simple PHP function to call Gemini
function generateTutorial($topic, $apiKey) {
$url = “https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=” . $apiKey;
$data = [
“contents” => [[
“parts” => [[“text” => “Write a PHP tutorial on $topic. Include copyable code blocks.”]]
]]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [‘Content-Type: application/json’]);
$response = curl_exec($ch);
return json_decode($response, true);
}
4. Making it “Copy-Paste” Easy
To implement the copy functionality, you can add a small JavaScript listener that targets your <pre> tags.
The Logic:
* Add a “Copy” button to every generated code block.
* Use navigator.clipboard.writeText() to grab the text inside the code tag.
* Show a “Copied!” message for user feedback.
Using Prism.js is an excellent choice. It’s lightweight and offers the “Tomorrow Night” or “Okaidia” dark themes, which look great for PHP and HTML.
Since you’ll be fetching content dynamically via the Gemini API, the key is to ensure Prism “re-scans” the page to highlight the new code blocks once the AI finishes generating.
1. The Full Implementation (index.php)
This single-file script handles the prompt, the API request, and uses the Prism.js CDN with the Copy to Clipboard plugin.
<?php
// Replace with your actual Gemini API Key
$apiKey = “YOUR_GEMINI_API_KEY”;
$tutorialHtml = “”;
if ($_SERVER[‘REQUEST_METHOD’] === ‘POST’ && !empty($_POST[‘topic’])) {
$topic = htmlspecialchars($_POST[‘topic’]);
// System instruction to force the correct HTML structure for Prism.js
$prompt = “Write a technical tutorial about $topic.
Use HTML tags for structure (h2, p, ul).
IMPORTANT: Wrap every code example in <pre class=’line-numbers’><code class=’language-php’>…</code></pre>
or <code class=’language-html’> depending on the content.”;
$url = “https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=” . $apiKey;
$payload = [
“contents” => [[“parts” => [[“text” => $prompt]]]]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [‘Content-Type: application/json’]);
$result = json_decode(curl_exec($ch), true);
$tutorialHtml = $result[‘candidates’][0][‘content’][‘parts’][0][‘text’] ?? “Error generating content.”;
}
?>
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>AI Tutorial Generator</title>
<link href=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css” rel=”stylesheet” />
<link href=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.css” rel=”stylesheet” />
<link href=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css” rel=”stylesheet” />
<style>
body { background-color: #121212; color: #e0e0e0; font-family: sans-serif; line-height: 1.6; padding: 40px; }
.container { max-width: 900px; margin: auto; }
input[type=”text”] { width: 70%; padding: 12px; border-radius: 4px; border: 1px solid #333; background: #222; color: white; }
button { padding: 12px 24px; background: #007bff; border: none; color: white; cursor: pointer; border-radius: 4px; }
.output-area { margin-top: 40px; background: #1e1e1e; padding: 25px; border-radius: 8px; border: 1px solid #333; }
h1, h2 { color: #fff; }
</style>
</head>
<body>
<div class=”container”>
<h1>Gemini PHP/HTML Tutorial Maker</h1>
<form method=”POST”>
<input type=”text” name=”topic” placeholder=”e.g., PHP PDO Connection Tutorial” required>
<button type=”submit”>Generate Article</button>
</form>
<?php if ($tutorialHtml): ?>
<div class=”output-area”>
<?php echo $tutorialHtml; ?>
</div>
<?php endif; ?>
</div>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js”></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js”></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/toolbar/prism-toolbar.min.js”></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/copy-to-clipboard/prism-copy-to-clipboard.min.js”></script>
<script src=”https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js”></script>
<script>
// If you ever switch to an AJAX-based fetch, call this to re-highlight:
// Prism.highlightAll();
</script>
</body>
</html>
2. Why this works for you:
* Copy-to-Clipboard: I included the prism-copy-to-clipboard plugin. It automatically adds a “Copy” button to the top-right of every dark code block.
* PHP Integration: The prism-php.min.js component is loaded specifically so your PHP tags <?php … ?> are recognized and colored correctly.
* Article Layout: By asking Gemini to return h2, p, and ul tags, the output integrates seamlessly into your webpage without extra parsing.
3. Pro-Tip: Handling HTML Tags
When Gemini generates HTML tutorials, it might try to render the actual HTML tags instead of showing them as code. In the prompt, I specified:
> Wrap every code example in <pre><code>…</code></pre>
>
To ensure the HTML tags are visible as text and not rendered by the browser, Prism.js handles the escaping if the AI sends encoded characters (like <), but usually, the language-html class in Prism is smart enough to handle the display.
Would you like me to refine the prompt further so it includes a specific “Difficulty Level” (Beginner/Expert) for the generated tutorials?
Since we have the generator working, let’s focus on SEO and Persistence. If you are building these for informational web pages, you probably don’t want to just view them once; you want to save them and make them search-engine friendly.
Here are three high-value features we can add to your tool:
1. Automatic Slug & Metadata Generation
Instead of just generating the article body, we can ask Gemini to provide a JSON object that includes a URL slug, a Meta Description, and an Article Title. This makes the output ready for a production PHP site immediately.
The prompt change:
> “Return the response in JSON format with keys: ‘title’, ‘slug’, ‘meta_description’, and ‘content_html’. The content_html must use Prism.js compatible tags.”
>
2. Export to File System
Since you create articles in HTML/PHP format, we can add a “Save to Server” button. This would:
* Create a new folder (e.g., /tutorials/).
* Save the content as tutorial-name.php.
* Automatically wrap it in your site’s standard header and footer.
3. Image Placeholder Injection
AI currently struggles to place perfect local images, but we can instruct Gemini to insert <img> tags with specific alt text and a placeholder class. You can then use a script to automatically swap those with relevant screenshots or Unsplash API images.
Implementation Suggestion: The “Article Manager” Logic
If you want to move toward a professional “Article Creator” setup, we could modify the code to include an “Export as PHP File” function. Here is how that logic looks:
if (isset($_POST[‘save_file’])) {
$filename = $_POST[‘slug’] . “.php”;
$content = $_POST[‘full_html_content’];
// Logic to wrap the AI content in your standard template
$template = “<?php include(‘header.php’); ?>” . $content . “<?php include(‘footer.php’); ?>”;
file_put_contents(“output/” . $filename, $template);
echo “File saved successfully as ” . $filename;
}
Which direction should we go?
* Option A: Automation – I can write the code to automatically save these generated articles into a folder on your server as .html or .php files.
* Option B: SEO Enhancement – I can refine the Gemini prompt and the PHP script to generate meta tags, keywords, and structured data (JSON-LD) for each tutorial.
Combining SEO Automation with a File Saving System transforms your tool from a simple demo into a powerful CMS (Content Management System) for your tutorials.
Here is the plan:
* JSON Schema Output: We’ll force Gemini to return a structured JSON object so we can extract the title, slug, and meta description reliably.
* Automatic File Creation: The script will save a .php file using the generated slug as the filename.
* SEO Template: Each saved file will automatically include the correct <title> and <meta> tags.
The Improved Script (generator.php)
<?php
$apiKey = “YOUR_GEMINI_API_KEY”;
$outputMessage = “”;
if ($_SERVER[‘REQUEST_METHOD’] === ‘POST’ && !empty($_POST[‘topic’])) {
$topic = htmlspecialchars($_POST[‘topic’]);
// We request a strict JSON format
$prompt = “Create a PHP/HTML tutorial about ‘$topic’.
Return ONLY a JSON object with these keys:
‘title’: A catchy SEO title.
‘slug’: A URL-friendly version of the title (lowercase, hyphens).
‘meta_description’: A 150-character summary for Google.
‘content_html’: The tutorial body using Prism.js tags <pre><code class=’language-php’>.”;
$url = “https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-flash:generateContent?key=” . $apiKey;
// Set response_mime_type to application/json for better reliability
$payload = [
“contents” => [[“parts” => [[“text” => $prompt]]]],
“generationConfig” => [“response_mime_type” => “application/json”]
];
$ch = curl_init($url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [‘Content-Type: application/json’]);
$response = curl_exec($ch);
$result = json_decode($response, true);
// Parse the JSON string from Gemini’s response
$rawData = $result[‘candidates’][0][‘content’][‘parts’][0][‘text’];
$data = json_decode($rawData, true);
if ($data) {
// — FILE SAVING LOGIC —
$filename = “tutorials/” . $data[‘slug’] . “.php”;
// Ensure directory exists
if (!is_dir(‘tutorials’)) { mkdir(‘tutorials’, 0777, true); }
// Create the full PHP file content with SEO tags
$fileTemplate = “<?php \$pageTitle = \”{$data[‘title’]}\”; \$metaDesc = \”{$data[‘meta_description’]}\”; ?>
<!DOCTYPE html>
<html>
<head>
<title><?php echo \$pageTitle; ?></title>
<meta name=’description’ content='<?php echo \$metaDesc; ?>’>
<link href=’https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css’ rel=’stylesheet’ />
</head>
<body style=’background:#121212; color:#eee; padding:50px;’>
<h1>{$data[‘title’]}</h1>
<div class=’content’>{$data[‘content_html’]}</div>
<script src=’https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js’></script>
<script src=’https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-php.min.js’></script>
</body>
</html>”;
if (file_put_contents($filename, $fileTemplate)) {
$outputMessage = “Success! Article saved as: <a href=’$filename’ target=’_blank’>$filename</a>”;
}
}
}
?>
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>SEO Tutorial Generator</title>
<style>
body { background: #1a1a1a; color: white; font-family: sans-serif; padding: 50px; text-align: center; }
input { padding: 10px; width: 300px; border-radius: 5px; border: none; }
button { padding: 10px 20px; cursor: pointer; background: #28a745; color: white; border: none; border-radius: 5px; }
.alert { margin-top: 20px; color: #75ff75; }
</style>
</head>
<body>
<h1>AI Article Factory</h1>
<form method=”POST”>
<input type=”text” name=”topic” placeholder=”Tutorial Topic…” required>
<button type=”submit”>Generate & Save</button>
</form>
<div class=”alert”><?php echo $outputMessage; ?></div>
</body>
</html>
Why this setup is effective:
* JSON-LD/Meta Ready: By asking Gemini for a slug and meta_description, you aren’t just getting text—you’re getting a complete web asset ready for deployment.
* Structured Content: The use of generationConfig with response_mime_type ensures the AI doesn’t “talk back” with conversational filler; it gives you pure data you can parse.
* Persistence: Instead of just echoing the content to the screen, file_put_contents creates a physical file on your server that you can link to immediately.
Would you like me to show you how to add a “Search” or “Listing” page so you can see all your generated articles in a table?
To complete your tool, we’ll create a dedicated listing page that scans your tutorials/ folder and displays the articles in a clean, dark-themed table. This page will also include a real-time search filter.
Since we are already saving the $pageTitle and $metaDesc inside the generated files, we can use a simple PHP script to “peek” into those files and pull the data for the list.
1. The Listing & Search Page (list.php)
This script uses glob() to find all .php files in your directory and regex to extract the metadata for a professional look.
<!DOCTYPE html>
<html lang=”en”>
<head>
<meta charset=”UTF-8″>
<title>Manage Tutorials</title>
<style>
body { background: #121212; color: #eee; font-family: ‘Segoe UI’, sans-serif; padding: 40px; }
.container { max-width: 1000px; margin: auto; }
.controls { display: flex; justify-content: space-between; margin-bottom: 20px; }
input#search { padding: 10px; width: 300px; border-radius: 5px; border: 1px solid #333; background: #222; color: white; }
table { width: 100%; border-collapse: collapse; background: #1e1e1e; border-radius: 8px; overflow: hidden; }
th, td { padding: 15px; text-align: left; border-bottom: 1px solid #333; }
th { background: #252525; color: #007bff; }
tr:hover { background: #292929; }
.btn { padding: 5px 12px; border-radius: 4px; text-decoration: none; font-size: 14px; }
.view-btn { background: #007bff; color: white; }
.create-btn { background: #28a745; color: white; padding: 10px 20px; }
</style>
</head>
<body>
<div class=”container”>
<div class=”controls”>
<h1>Article Library</h1>
<a href=”generator.php” class=”btn create-btn”>+ New Tutorial</a>
</div>
<input type=”text” id=”search” placeholder=”Search tutorials…” onkeyup=”filterTable()”>
<table id=”tutorialTable”>
<thead>
<tr>
<th>Title</th>
<th>Meta Description</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php
$files = glob(“tutorials/*.php”);
foreach ($files as $file) {
$content = file_get_contents($file);
// Extract Title and Description using Regex
preg_match(‘/\$pageTitle = “(.*?)”;/’, $content, $titleMatch);
preg_match(‘/\$metaDesc = “(.*?)”;/’, $content, $descMatch);
$title = $titleMatch[1] ?? basename($file);
$desc = $descMatch[1] ?? “No description available.”;
?>
<tr>
<td><strong><?php echo $title; ?></strong></td>
<td><small><?php echo $desc; ?></small></td>
<td><a href=”<?php echo $file; ?>” class=”btn view-btn” target=”_blank”>View</a></td>
</tr>
<?php } ?>
</tbody>
</table>
</div>
<script>
function filterTable() {
let input = document.getElementById(“search”).value.toUpperCase();
let rows = document.getElementById(“tutorialTable”).getElementsByTagName(“tr”);
for (let i = 1; i < rows.length; i++) {
let titleColumn = rows[i].getElementsByTagName(“td”)[0];
if (titleColumn) {
let textValue = titleColumn.textContent || titleColumn.innerText;
rows[i].style::display = textValue.toUpperCase().indexOf(input) > -1 ? “” : “none”;
}
}
}
</script>
</body>
</html>
2. How the System Connects
The flow is now a complete lifecycle for your web pages:
* Generate: You use generator.php to prompt Gemini.
* Save: The script creates a physical .php file with SEO tags and Prism.js styling in the tutorials/ folder.
* Manage: You use list.php to search through your library and open the tutorials.
3. High-Value Refinements
* Security: If you put this online, ensure you add a simple password check to generator.php so others don’t use your Gemini API quota.
* Dynamic Breadcrumbs: You can now modify your file template to include a “Back to Library” link at the top of every generated article.
Next Step
Since you are creating these as informational pages, would you like me to show you how to add a “Table of Contents” generator that automatically creates clickable links for every <h2> tag Gemini generates?
Discover more from NathanLegakis.com
Subscribe to get the latest posts sent to your email.
Leave a Reply