Site Builder
Editing:
add.php
writable 0666
<?php /************************************************************************** * ADD NEW SOCIAL PROFILE – /social/add.php * ---------------------------------------------------------------------- * © 2025 BestDealOn – Free to modify. Requires PHP 8.1+ * * Exactly mirrors the original /business/add.php, except: * • root dir = /social/ * • folder slug = sanitised @handle * • json filename = new-social.json *************************************************************************/ declare(strict_types=1); /* ---------- CONFIG ---------------------------------------------------- */ $socialDir = $_SERVER['DOCUMENT_ROOT'] . '/social/'; // root for all profiles $templateFile = $_SERVER['DOCUMENT_ROOT'] . '/social/profile-index.php'; // mini landing page $stateBounds = $_SERVER['DOCUMENT_ROOT'] . '/geo/json-data/states-bounds.json'; // needed for US‑only gate date_default_timezone_set('UTC'); /* ---------- ensure /social exists ------------------------------------ */ if (!is_dir($socialDir) && !mkdir($socialDir, 0777, true)) { die('Unable to create /social/ directory – check permissions.'); } /* ---------- helper: slugify an @handle ------------------------------- */ function slugify_handle(string $h): string { $h = ltrim(trim($h), '@'); // drop leading @ return preg_replace('/[^a-z0-9_]/i', '', strtolower($h)); } /* ---------- helper: list of 2‑letter US states ----------------------- */ $usStates = []; if (is_file($stateBounds)) { $bounds = json_decode(file_get_contents($stateBounds), true, 512, JSON_THROW_ON_ERROR); foreach ($bounds as $row) { if (isset($row['state']) && strlen($row['state']) === 2) { $usStates[] = strtoupper($row['state']); } } } /* ---------- POST handler --------------------------------------------- */ $msg = ''; if ($_SERVER['REQUEST_METHOD'] === 'POST') { /* basic required inputs */ $rawHandle = $_POST['handle'] ?? ''; $display = trim($_POST['display_name'] ?? ''); $email = trim($_POST['email'] ?? ''); if ($rawHandle === '' || $display === '' || $email === '') { $msg = '❌ Handle, display name, and email are required.'; } elseif (empty($_POST['lat']) || empty($_POST['lon'])) { $msg = '❌ Please click “Locate Me” and wait for the location to lock.'; } else { $slug = slugify_handle($rawHandle); if ($slug === '') { $msg = '❌ Handle must contain at least one alphanumeric character.'; } elseif (is_dir($socialDir . $slug)) { $msg = "❌ That profile already exists! <a href=\"/social/view.php?user=$slug\">View it</a>"; } else { $state = strtoupper(trim($_POST['state'] ?? '')); if (!in_array($state, $usStates, true)) { $msg = '❌ Only U.S. influencers can register (invalid state code).'; } else { /* assemble record -------------------------------------------------- */ $record = [ /* core */ 'handle' => '@' . $slug, 'slug' => $slug, 'display_name' => $display, 'email' => $email, 'slogan' => mb_substr(trim($_POST['slogan'] ?? ''), 0, 160), 'description' => mb_substr(trim($_POST['description'] ?? ''), 0, 240), /* location */ 'address' => trim($_POST['address'] ?? ''), 'city' => trim($_POST['city'] ?? ''), 'state' => $state, 'zip' => trim($_POST['zip'] ?? ''), 'lat' => trim($_POST['lat']), 'lon' => trim($_POST['lon']), /* contact */ 'phone' => preg_replace('/\D/', '', $_POST['phone'] ?? ''), 'website' => trim($_POST['website'] ?? ''), /* influencer channels */ 'channels' => [ 'video' => [ 'youtube' => trim($_POST['youtube'] ?? ''), 'rumble' => trim($_POST['rumble'] ?? ''), 'odysee' => trim($_POST['odysee'] ?? '') ], 'podcast' => [ 'spotify' => trim($_POST['spotify'] ?? ''), 'apple' => trim($_POST['apple'] ?? ''), 'rss' => trim($_POST['podcast_rss'] ?? '') ], 'social' => [ 'twitter' => trim($_POST['twitter'] ?? ''), 'tiktok' => trim($_POST['tiktok'] ?? ''), 'instagram' => trim($_POST['instagram'] ?? ''), 'facebook' => trim($_POST['facebook'] ?? ''), 'linkedin' => trim($_POST['linkedin'] ?? ''), 'patreon' => trim($_POST['patreon'] ?? '') ] ], /* tags */ 'tags' => array_filter(array_map('trim', explode(',', $_POST['tags'] ?? ''))), 'location_tags' => array_filter(array_map('trim', explode(',', $_POST['location_tags'] ?? ''))), /* misc */ 'premium' => isset($_POST['premium']), 'created' => date(DATE_ATOM) ]; /* write to disk ---------------------------------------------------- */ $dir = $socialDir . $slug; mkdir($dir, 0777, true); file_put_contents( "$dir/new-social.json", json_encode($record, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES), LOCK_EX ); /* optional: copy template landing page --------------------------- */ if (is_file($templateFile)) { copy($templateFile, "$dir/index.php"); } /* go to the public view page ------------------------------------- */ header("Location: /social/view.php?user=$slug"); exit; } } } } ?> <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>Add Social Profile</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> :root{--fg:#222;--bg:#f5f8fb;--accent:#0077ff} body{background:var(--bg);margin:0;font-family:system-ui,Arial,sans-serif;color:var(--fg)} h1{font-size:1.55rem;margin:.7em 0} .lab{display:block;margin:.4em 0 .15em;font-weight:600} input,textarea{width:100%;box-sizing:border-box;padding:.46em .55em;font-size:1em;border:1px solid #bbb;border-radius:4px} button{padding:.58em 1.25em;border:0;border-radius:4px;background:var(--accent);color:#fff;font-size:1.04em;cursor:pointer} button:disabled{opacity:.55} .locked-input{background:#f4f4f4} .location-tag{display:inline-block;margin:.18em .22em;padding:.23em .5em .18em;background:#e4ecff;border-radius:14px;font-size:.88em} .location-tag .del{margin-left:.35em;cursor:pointer;font-weight:700} .social-toggle{cursor:pointer;font-weight:600;margin:1em 0} .collapsed{display:none} .arrow{display:inline-block;transition:.18s transform} #geo-status{font-size:.92em;margin-left:.5em;color:#555} #step1{font-weight:600} </style> <script src="/geo/locate.js" defer></script> </head> <body> <div style="max-width:660px;margin:1.4em auto;padding:1.25em 1.6em;background:#fff;border-radius:8px;box-shadow:0 2px 7px rgba(0,0,0,.06)"> <h1>Add Social Deals Profile</h1> <?php if ($msg): ?> <p style="color:#c00;font-weight:600"><?= htmlspecialchars($msg) ?></p> <?php endif; ?> <p id="step1">Step 1 – Click “Locate Me”.</p> <p> <button id="locateBtn" onclick="locateMe()">Locate Me</button> <span id="geo-status"></span> </p> <form id="social-form" method="post" autocomplete="off" style="display:none"> <!-- hidden coords --> <input type="hidden" id="lat" name="lat"> <input type="hidden" id="lon" name="lon"> <!-- handle --> <label class="lab" for="handle">Primary Handle (Twitter/X etc.)</label> <input id="handle" name="handle" maxlength="40" placeholder="@username" required> <div style="margin-bottom:.6em"> Profile ID: <span id="profile-id" style="font-family:monospace"></span> </div> <!-- contact --> <label class="lab" for="display_name">Display Name</label> <input id="display_name" name="display_name" maxlength="80" required> <label class="lab" for="email">Email</label> <input id="email" name="email" type="email" maxlength="120" required> <label class="lab" for="phone">Phone (optional)</label> <input id="phone" name="phone" maxlength="16" placeholder="(727)-610-1111"> <label class="lab" for="website">Website (optional)</label> <input id="website" name="website" maxlength="120" placeholder="https://yourbrand.com"> <label class="lab" for="slogan">Slogan (160 chars max)</label> <input id="slogan" name="slogan" maxlength="160"> <label class="lab" for="description">Short Description (240 chars max)</label> <textarea id="description" name="description" rows="3" maxlength="240"></textarea> <!-- address --> <label class="lab" for="address">Street Address (optional)</label> <input id="address" name="address" maxlength="100"> <div style="display:flex;gap:1em"> <div style="flex:2"> <label class="lab" for="city">City</label> <input id="city" name="city" maxlength="40" required> </div> <div style="flex:1.1"> <label class="lab" for="state">State (2‑letter)</label> <input id="state" name="state" maxlength="2" required> </div> <div style="flex:1.3"> <label class="lab" for="zip">ZIP</label> <input id="zip" name="zip" maxlength="12" required> </div> </div> <hr style="margin:1.6em 0 .9em"> <!-- influencer channels (collapsible) --> <div id="socialToggle" class="social-toggle"><span class="arrow">▸</span> Add influencer links</div> <div id="channelWrap" class="collapsed"> <h3 style="margin:.6em 0 .3em">Video</h3> <label class="lab" for="youtube">YouTube</label> <input id="youtube" name="youtube" placeholder="https://youtube.com/@username" maxlength="120"> <label class="lab" for="rumble">Rumble</label> <input id="rumble" name="rumble" placeholder="https://rumble.com/user" maxlength="120"> <label class="lab" for="odysee">Odysee/LBRY</label> <input id="odysee" name="odysee" placeholder="https://odysee.com/@username" maxlength="120"> <h3 style="margin:1em 0 .3em">Podcast</h3> <label class="lab" for="spotify">Spotify</label> <input id="spotify" name="spotify" placeholder="https://open.spotify.com/show/…" maxlength="120"> <label class="lab" for="apple">Apple Podcasts</label> <input id="apple" name="apple" placeholder="https://podcasts.apple.com/…" maxlength="120"> <label class="lab" for="podcast_rss">Podcast RSS</label> <input id="podcast_rss" name="podcast_rss" placeholder="https://example.com/feed.xml" maxlength="120"> <h3 style="margin:1em 0 .3em">Social</h3> <label class="lab" for="twitter">Twitter/X</label> <input id="twitter" name="twitter" placeholder="@username or full URL" maxlength="120"> <label class="lab" for="tiktok">TikTok</label> <input id="tiktok" name="tiktok" placeholder="@username or full URL" maxlength="120"> <label class="lab" for="instagram">Instagram</label> <input id="instagram" name="instagram" placeholder="@username or full URL" maxlength="120"> <label class="lab" for="facebook">Facebook</label> <input id="facebook" name="facebook" placeholder="https://facebook.com/username" maxlength="120"> <label class="lab" for="linkedin">LinkedIn</label> <input id="linkedin" name="linkedin" placeholder="https://linkedin.com/in/username" maxlength="120"> <label class="lab" for="patreon">Patreon</label> <input id="patreon" name="patreon" placeholder="https://patreon.com/username" maxlength="120"> </div> <hr style="margin:1.6em 0 .9em"> <!-- tags --> <label class="lab" for="tags">Service / Product Tags (comma separated)</label> <input id="tags" name="tags" maxlength="120" placeholder="e.g. Tech, Gadgets"> <label class="lab">Location Tags</label> <div id="location-tags" style="margin-bottom:.4em"></div> <input type="hidden" id="location_tags" name="location_tags"> <input type="text" id="addTag" placeholder="Add more tags and press Enter" autocomplete="off"> <label class="lab"><input type="checkbox" name="premium"> Premium listing</label> <p style="margin-top:1.45em"><button type="submit">Create Profile</button></p> </form> </div> <script> /* slug preview */ document.getElementById('handle').addEventListener('input', e => { const slug = e.target.value.replace(/^@/, '').toLowerCase().replace(/[^a-z0-9_]/g, ''); document.getElementById('profile-id').textContent = slug || '—'; }); /* show / hide channel list */ document.getElementById('socialToggle').addEventListener('click', () => { const wrap = document.getElementById('channelWrap'); wrap.classList.toggle('collapsed'); const arrow = document.querySelector('#socialToggle .arrow'); arrow.style.transform = wrap.classList.contains('collapsed') ? '' : 'rotate(90deg)'; }); </script> </body> </html>
Save changes
Create folder
writable 0777
Create
Cancel