Site Builder
Editing:
admin.php
writable 0666
<?php declare(strict_types=1); /* --- must be first so AI toolbar can save the key --- */ session_start(); require_once $_SERVER['DOCUMENT_ROOT'].'/openai/init.php'; ai_handle_key_post(); // <- captures the key if the toolbar posted require_once __DIR__.'/_core.php'; /* ---------- helpers ---------- */ function safe_name(string $name): string { return preg_replace('~[^a-zA-Z0-9.\-_]~','-', $name); } /* ---------- handle product create/update POST ---------- */ $notice = $createdUrl = null; if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['do']) && $_POST['do']==='save-product') { // DO NOT call ai_handle_key_post() here again; it already ran above. $category = slugify($_POST['category'] ?? ''); $asin = asin_clean($_POST['asin'] ?? ''); $affurl = trim($_POST['affiliate_url'] ?? ''); $titleOV = trim($_POST['title_override'] ?? ''); $subtitle = trim($_POST['subtitle'] ?? ''); $reftext = trim($_POST['reference_text'] ?? ''); if (!$category || !$asin || !$affurl) { $notice = "Category, ASIN, and Affiliate URL are required."; } else { // Ensure category and product stubs exist $catDir = __DIR__."/$category"; if (!is_dir($catDir)) { @mkdir($catDir, 0775, true); write_category_stub($catDir); } $prodDir = "$catDir/$asin"; if (!is_dir($prodDir)) { @mkdir($prodDir, 0775, true); write_product_stub($prodDir); } // Upload images directly into the ASIN folder $images = []; if (!empty($_FILES['images']) && is_array($_FILES['images']['name'])) { $seq = 0; for ($i=0; $i<count($_FILES['images']['name']); $i++) { if ($_FILES['images']['error'][$i] === UPLOAD_ERR_OK) { $ext = strtolower(pathinfo($_FILES['images']['name'][$i], PATHINFO_EXTENSION)); if (!in_array($ext, ['jpg','jpeg','png','webp','gif'])) $ext = 'jpg'; $name = $seq===0 ? "hero.$ext" : "angle-$seq.$ext"; $seq++; move_uploaded_file($_FILES['images']['tmp_name'][$i], "$prodDir/$name"); $images[] = $name; } } } else if (is_file("$prodDir/product.json")) { $existing = json_decode(file_get_contents("$prodDir/product.json"), true); if (!empty($existing['images'])) $images = $existing['images']; } // Build AI prompt for ORIGINAL copy (no prices/ratings/reviews) $prompt = <<<PROMPT You are creating ORIGINAL, non-infringing product copy for a review-style catalog. Rules: - Write everything in new words (no quotes, no near-verbatim copying). - EXCLUDE any pricing, star ratings, or customer reviews. - Focus on features, use-cases, practical pros/cons, and who it's for. - Bullets must be short (max ~10 words each). - Tone: helpful, neutral, safety-conscious. - Output ONLY valid JSON, no Markdown, following this schema: { "title": string, "subtitle": string, "summary": string, "bullets": string[], "pros": string[], "cons": string[], "badges": string[] } Reference text (to be paraphrased into original language): {$reftext} PROMPT; $genRaw = $reftext ? ai_chat($prompt) : ''; $gen = $genRaw ? json_decode($genRaw, true) : null; if (!is_array($gen)) $gen = []; // Manual overrides if ($titleOV) $gen['title'] = $titleOV; if ($subtitle) $gen['subtitle'] = $subtitle; // Defaults $gen += ['title'=>"Product $asin",'subtitle'=>'','summary'=>'','bullets'=>[],'pros'=>[],'cons'=>[],'badges'=>[]]; // Save product.json (manual mode) $payload = [ 'mode' => 'manual', 'asin' => $asin, 'category' => $category, 'title' => $gen['title'], 'subtitle' => $gen['subtitle'] ?? '', 'summary' => $gen['summary'], 'bullets' => array_values(array_filter($gen['bullets'])), 'pros' => array_values(array_filter($gen['pros'])), 'cons' => array_values(array_filter($gen['cons'])), 'badges' => array_values(array_filter($gen['badges'])), 'affiliate_url' => $affurl, 'images' => $images, 'last_updated' => gmdate('c') ]; file_put_contents("$prodDir/product.json", json_encode($payload, JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT), LOCK_EX); $createdUrl = "/amazon/$category/$asin/"; $notice = "Saved. <a href=\"$createdUrl\" target=\"_blank\">Open product page</a>"; } } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"/> <title>Amazon Manual Builder</title> <style> body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif;font-size:18px;line-height:1.6;margin:0;background:#111;color:#f5f5f5} .wrap{max-width:900px;margin:0 auto;padding:24px} input,textarea,button{font-size:18px;padding:10px;width:100%;border-radius:10px;border:2px solid #444;background:#1a1a1a;color:#f5f5f5} label{display:block;margin-top:14px} .row{display:grid;grid-template-columns:1fr 1fr;gap:12px} .btn{display:inline-block;padding:12px 16px;border:3px solid #fff;border-radius:10px;text-decoration:none;color:#fff;font-weight:700;background:#000} .btn:hover{background:#fff;color:#000} .notice{padding:12px;border:2px solid #3a3;border-radius:10px;background:#102e10;margin:10px 0} .bar{margin-bottom:12px} </style> </head> <body> <div class="wrap"> <!-- AI key bar lives OUTSIDE any other form --> <div class="bar"> <?php ai_render_key_bar(); ?> </div> <h1 style="margin:0 0 10px;">Manual Product Builder</h1> <p style="margin:0 0 14px; color:#bbb;">Everything lands inside <code>/amazon/{category}/{ASIN}/</code> (JSON + images).</p> <?php if ($notice): ?><div class="notice"><?php echo $notice; ?></div><?php endif; ?> <!-- Your product form --> <form method="post" enctype="multipart/form-data"> <input type="hidden" name="do" value="save-product"/> <div class="row"> <label>Category (slug) <input name="category" placeholder="iphone-16-cases" required> </label> <label>ASIN <input name="asin" placeholder="B0CXXXXXXX" required> </label> </div> <label>Affiliate URL (SiteStripe Text link) <input name="affiliate_url" type="url" placeholder="https://www.amazon.com/...&tag=bestdealon0d-20" required> </label> <div class="row"> <label>Title (optional override) <input name="title_override" placeholder="RF‑Safe Pick: QuantaCase for iPhone 16 Pro Max"> </label> <label>Subtitle (optional) <input name="subtitle" placeholder="Minimalist flip, no magnets, precisely placed shielding"> </label> </div> <label>Your images (you own rights). Upload multiple. First becomes hero.* <input type="file" name="images[]" accept="image/*" multiple> </label> <label>Reference text for AI to paraphrase into ORIGINAL copy (no prices/ratings) <textarea name="reference_text" rows="10" placeholder="Paste specs/features from manufacturer or notes. The AI will rewrite into new words."></textarea> </label> <p style="margin-top:14px;"><button class="btn" type="submit">Create / Update Product</button></p> <p style="color:#bbb;margin-top:8px;">* Files are saved directly in the ASIN folder as <code>hero.jpg</code>, <code>angle-1.jpg</code>, …</p> </form> </div> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel