Siteβ―Builder
Editing:
edit-close.php
writable 0666
<?php /* ============================================================ BestDealOn β Edit Business Profile (upgraded with: 1. Tokenised Tags & Location Tags with removable X buttons 2. Collapsible βSocial & Directory Linksβ section) ============================================================ */ $bizFile = __DIR__ . '/new-business.json'; if (is_readable(__DIR__.'/business.json')) { $bizFile = __DIR__.'/business.json'; // paid member } $biz = is_readable($bizFile) ? json_decode(file_get_contents($bizFile), true) : []; $ph = preg_replace('/[^\d]/','',$_GET['ph'] ?? ''); $phDir = $_SERVER['DOCUMENT_ROOT'] . '/ph/' . $ph; $newfile = $phDir . '/new-business.json'; $bizfile = $phDir . '/business.json'; $msg = ''; $fields = [ 'name' => '', 'email'=>'', 'slogan' => '', 'description' => '', 'address' => '', 'city' => '', 'state' => '', 'zip' => '', 'phone' => $ph, 'website' => '', 'tags' => [], 'location_tags' => [], 'lat'=>'', 'lon'=>'', 'twitter'=>'', 'facebook'=>'', 'instagram'=>'', 'tiktok'=>'', 'linkedin'=>'', 'youtube'=>'', 'yelp'=>'', 'angi'=>'', 'bbb'=>'', 'nextdoor'=>'' ]; /* Which JSON is being edited? */ $curFile = ''; if (is_readable($bizfile)) { $curFile = $bizfile; $fileType = 'business.json'; } elseif (is_readable($newfile)) { $curFile = $newfile; $fileType = 'new-business.json'; } else { $fileType=''; } /* Populate $fields from file */ if ($curFile) { $data = json_decode(file_get_contents($curFile), true); if (is_array($data)) foreach ($fields as $k=>$v) $fields[$k] = $data[$k] ?? $v; } /* ---------- Save Changes ---------- */ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['edit_save'])) { /* tags/location_tags arrive as CSV in hidden inputs kept in sync by JS */ $_POST['tags'] = trim($_POST['tags'] ?? ''); $_POST['location_tags'] = trim($_POST['location_tags'] ?? ''); foreach ($fields as $k=>$v) { if ($k==='tags' || $k==='location_tags') { $csv = $_POST[$k] ?? ''; $fields[$k] = array_filter(array_map('trim', explode(',', $csv))); } else { $fields[$k] = trim($_POST[$k] ?? ''); } } $saveFile = $_POST['activefile']==='business.json' ? $bizfile : $newfile; file_put_contents($saveFile, json_encode($fields, JSON_PRETTY_PRINT|JSON_UNESCAPED_UNICODE)); $msg = "β Changes saved to <b>{$_POST['activefile']}</b>!"; $curFile = $saveFile; $fileType = $_POST['activefile']; } /* ---------- Copy newβbusiness β business ---------- */ if (isset($_POST['make_paid'])) { if (is_readable($newfile)) { copy($newfile,$bizfile); $msg = "β Copied new-business.json to business.json (upgraded to paid)"; $fileType='business.json'; $curFile=$bizfile; } else $msg = "β Cannot copy: new-business.json does not exist"; } /* ---------- Cancel Membership ---------- */ if (isset($_POST['cancel_membership']) && is_file($bizfile)) { unlink($bizfile); $msg = "β Membership canceled (business.json deleted)."; if ($curFile===$bizfile) { if (is_readable($newfile)) { $curFile=$newfile; $fileType='new-business.json'; $data=json_decode(file_get_contents($curFile),true); if (is_array($data)) foreach ($fields as $k=>$v) $fields[$k]=$data[$k]??$v; } else { $curFile=''; $fileType=''; foreach($fields as $k=>$v) $fields[$k]=''; $fields['phone']=$ph; } } } /* ---------- Delete ENTIRE profile folder ---------- */ if (isset($_POST['delete_profile']) && is_dir($phDir)) { function delTree($dir){ $files=array_diff(scandir($dir),['.','..']); foreach($files as $file){ is_dir("$dir/$file")?delTree("$dir/$file"):unlink("$dir/$file"); } return rmdir($dir); } if (delTree($phDir)) { $msg="β Entire business profile deleted."; $curFile=''; $fileType=''; foreach($fields as $k=>$v) $fields[$k]=''; $fields['phone']=$ph; } else $msg="β Failed to delete the folder."; } /* Helpers */ function h($s){return htmlspecialchars($s,ENT_QUOTES,'UTF-8');} function tags_csv($a){return is_array($a)?implode(', ',$a):$a;} ?> <!DOCTYPE html><html lang="en"><head> <meta charset="utf-8"><title>Edit Business: <?=h($ph)?> | BestDealOn Admin</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <style> body{background:#f6f8fb;font-family:system-ui,Arial,sans-serif;margin:0;color:#234;} .wrap{max-width:650px;margin:2.5em auto;background:#fff;padding:2em;border-radius:17px;box-shadow:0 2px 18px #dde3fa33;} h1{text-align:center;font-size:1.42em;margin-bottom:.55em;} fieldset{margin:1.6em 0 1.2em 0;padding:1.2em;border-radius:12px;border:1.5px solid #c9d8ec;background:#f7faff;} legend{font-size:1.14em;font-weight:700;color:#306fd4;} label{font-weight:600;display:block;margin-top:.7em;} input[type=text],input[type=tel],input[type=email],textarea{width:100%;padding:.7em;border-radius:7px;border:1.4px solid #b7c2df;margin-bottom:.15em;font-size:1.08em;} input[readonly],textarea[readonly]{background:#e6eaf2;} input[type=submit],button{padding:.64em 1.4em;font-size:1.08em;font-weight:700;background:#2357d7;color:#fff;border:none;border-radius:8px;cursor:pointer;transition:background .16s;} input[type=submit]:hover:enabled,button:hover:enabled{background:#0a3798;} input[type=submit]:disabled,button:disabled{background:#8ba0c5!important;color:#dbe7fa!important;cursor:not-allowed!important;opacity:.72;} .flex{display:flex;gap:1.2em;} .flex>div{flex:1;} .inlinebtns{display:flex;gap:.9em;margin-top:1em;} .msg{text-align:center;margin-bottom:1.3em;font-size:1.06em;} .tiny{font-size:.99em;color:#557;} hr{margin:2.1em 0 1.5em 0;} .delete-profile-block{text-align:center;margin:3.5em 0 0 0;} .delete-profile-btn{background:#c41c1c!important;color:#fff!important;border-radius:10px;font-size:1.08em;padding:1.15em 2.7em;margin-top:1.7em;font-weight:700;border:none;cursor:pointer;box-shadow:0 3px 18px #de9b9b33;transition:background .14s;} .delete-profile-btn:hover{background:#ea2222!important;} /* ---- Token styles ---- */ .tag-wrap{display:flex;flex-wrap:wrap;gap:.35em;margin-bottom:.35em;} .tag-token{background:#e2e9ff;border-radius:999px;padding:.28em .75em;font-size:.92em;display:flex;align-items:center;gap:.45em;} .tag-token button{background:#ff3b3b;border:none;color:#fff;font-weight:700;border-radius:50%;width:1.25em;height:1.25em;line-height:1.1em;font-size:.85em;cursor:pointer;transform:translateY(-.5px);} .tag-token button:hover{background:#ff6767;} /* ---- Collapsible social block ---- */ #social-block{display:none;margin-top:.8em;} .show-btn{margin-top:1em;background:#5a5ad4;} .show-btn.open{background:#8b28d1;} @media(max-width:700px){.wrap{padding:1em .2em;max-width:98vw;}} </style> </head><body> <div class="wrap"> <h1>Edit Business: <?=h($fields['name'] ?: $ph)?> (<?=h($ph)?>)</h1> <?php if($msg):?><div class="msg" style="color:<?=strpos($msg,'β ')!==false?'green':'red'?>"><?=$msg?></div><?php endif;?> <?php if($curFile):?> <form method="post" id="bizForm"> <fieldset> <legend>Edit Fields (<?=h($fileType)?>)</legend> <input type="hidden" name="activefile" value="<?=h($fileType)?>"> <!-- ===== BASIC INFO ===== --> <label>Business Name</label> <input type="text" name="name" maxlength="80" value="<?=h($fields['name'])?>" required> <label>Email</label> <input type="email" name="email" maxlength="120" value="<?=h($fields['email'])?>" required placeholder="your@email.com"> <label>Slogan</label> <input type="text" name="slogan" maxlength="120" value="<?=h($fields['slogan'])?>"> <label>Description</label> <textarea name="description" maxlength="500" required><?=h($fields['description'])?></textarea> <label>Address</label> <input type="text" name="address" maxlength="120" value="<?=h($fields['address'])?>" required> <div class="flex"> <div><label>City</label><input type="text" name="city" maxlength="40" value="<?=h($fields['city'])?>" required></div> <div><label>State</label><input type="text" name="state" maxlength="2" value="<?=h($fields['state'])?>" required></div> <div><label>ZIP</label><input type="text" name="zip" maxlength="12" value="<?=h($fields['zip'])?>" required></div> </div> <div class="flex"> <div><label>Phone</label><input type="tel" name="phone" maxlength="14" value="<?=h($fields['phone'])?>" required readonly></div> <div><label>Website</label><input type="text" name="website" maxlength="120" value="<?=h($fields['website'])?>"></div> </div> <!-- ===== TAGS ===== --> <label>Tags / Services</label> <div class="tag-wrap" id="tagsTokens"></div> <input type="text" id="tagsInput" placeholder="Add commaβseparated tagsβ¦" autocomplete="off"> <input type="hidden" name="tags" id="tagsHidden" value="<?=h(tags_csv($fields['tags']))?>"> <label style="margin-top:1.2em;">Location Tags</label> <div class="tag-wrap" id="locTokens"></div> <input type="text" id="locInput" placeholder="Add commaβseparated locationsβ¦" autocomplete="off"> <input type="hidden" name="location_tags" id="locHidden" value="<?=h(tags_csv($fields['location_tags']))?>"> <hr> <!-- ===== SOCIAL LINKS (collapsible) ===== --> <button type="button" class="show-btn" id="toggleSocial">Show Social & Directory Links βΌ</button> <div id="social-block"> <legend style="margin:.6em 0 .4em 0;">Social & Directory Links</legend> <label>Twitter (URL or handle)</label> <input type="text" name="twitter" maxlength="120" value="<?=h($fields['twitter'])?>" placeholder="https://twitter.com/username or @username"> <label>Facebook (URL or handle)</label> <input type="text" name="facebook" maxlength="120" value="<?=h($fields['facebook'])?>" placeholder="https://facebook.com/username"> <label>Instagram (URL or handle)</label> <input type="text" name="instagram" maxlength="120" value="<?=h($fields['instagram'])?>" placeholder="https://instagram.com/username or @username"> <label>TikTok (URL or handle)</label> <input type="text" name="tiktok" maxlength="120" value="<?=h($fields['tiktok'])?>" placeholder="https://tiktok.com/@username or @username"> <label>LinkedIn (URL or handle)</label> <input type="text" name="linkedin" maxlength="120" value="<?=h($fields['linkedin'])?>" placeholder="https://linkedin.com/in/username"> <label>YouTube (URL or channel)</label> <input type="text" name="youtube" maxlength="120" value="<?=h($fields['youtube'])?>" placeholder="https://youtube.com/@username"> <label>Yelp (URL)</label> <input type="text" name="yelp" maxlength="150" value="<?=h($fields['yelp'])?>" placeholder="https://yelp.com/biz/yourbizname"> <label>Angi / Angie's List (URL)</label> <input type="text" name="angi" maxlength="150" value="<?=h($fields['angi'])?>" placeholder="https://angi.com/companylist/us/yourbizname"> <label>Better Business Bureau (URL)</label> <input type="text" name="bbb" maxlength="150" value="<?=h($fields['bbb'])?>" placeholder="https://bbb.org/us/yourbizname"> <label>Nextdoor (URL)</label> <input type="text" name="nextdoor" maxlength="150" value="<?=h($fields['nextdoor'])?>" placeholder="https://nextdoor.com/pages/yourbizname"> </div> <div class="flex" style="margin-top:1em;"> <div><label>Latitude</label><input type="text" name="lat" maxlength="24" value="<?=h($fields['lat'])?>"></div> <div><label>Longitude</label><input type="text" name="lon" maxlength="24" value="<?=h($fields['lon'])?>"></div> </div> <div class="inlinebtns"> <input type="submit" name="edit_save" value="Save Changes"> <?php if($fileType==='new-business.json' && is_file($newfile)):?> <button type="submit" name="make_paid" value="1" title="Copy new-business.json to business.json">Upgrade to Paid</button> <?php endif;?> <?php if($fileType==='business.json' && is_file($bizfile)):?> <button type="submit" name="cancel_membership" value="1" onclick="return confirm('Cancel membership? This will delete business.json and revert profile to free status.');" style="background:#e1a900;color:#fff;">Cancel Membership</button> <?php endif;?> </div> <div class="tiny"><b>Status:</b> <?=is_file($bizfile)?"business.json <span style='color:green;'>(PAID)</span>":"<span style='color:#b49d3c;'>Not Paid</span>"?> </div> </fieldset> </form> <hr> <fieldset> <legend>Raw <?=h($fileType)?> JSON</legend> <textarea readonly style="width:100%;min-height:120px;font-family:monospace;font-size:.98em;background:#f6fafd;border-radius:8px;padding:.7em 1em;"><?=h($curFile && is_readable($curFile)?file_get_contents($curFile):'');?></textarea> </fieldset> <?php else:?> <div class="msg" style="color:#d7262d;">No business found for phone <?=h($ph)?>.</div> <?php endif;?> <!-- ===== Delete profile ===== --> <div class="delete-profile-block"> <form method="post" onsubmit="return confirm('β οΈ Delete ENTIRE business profile and all files? This CANNOT be undone!');"> <input type="hidden" name="delete_profile" value="1"> <button type="submit" class="delete-profile-btn">Delete ENTIRE Profile & All Files</button> <div class="tiny" style="margin-top:1em;color:#d11e13;"> (Deletes the whole business folder <b>/ph/<?=h($ph)?>/</b> and ALL its contents.) </div> </form> </div> </div> <!-- .wrap --> <!-- ============================================================ JavaScript (tokeniser + collapsible socials) ============================================================ --> <script> /* ---------- Token helper ---------- */ function TokenField(config){ const wrap = document.getElementById(config.wrap); const input = document.getElementById(config.input); const hidden = document.getElementById(config.hidden); /* Build tokens from initial CSV */ hidden.value.split(',').map(s=>s.trim()).filter(Boolean).forEach(addToken); /* Add on ENTER or comma */ input.addEventListener('keydown',e=>{ if(e.key==='Enter' || e.key===','){ e.preventDefault(); processInput(); } }); input.addEventListener('blur',processInput); function processInput(){ const raw=input.value.trim(); if(!raw) return; raw.split(',').map(s=>s.trim()).filter(Boolean).forEach(addToken); input.value=''; } function addToken(label){ if(label==='') return; /* prevent duplicates (caseβinsensitive) */ const exists=[...wrap.querySelectorAll('.tag-token')].some(t=>t.dataset.val.toLowerCase()===label.toLowerCase()); if(exists) return; const span=document.createElement('span'); span.className='tag-token'; span.dataset.val=label; span.textContent=label+' '; const btn=document.createElement('button'); btn.type='button'; btn.textContent='Γ'; btn.addEventListener('click',()=>{ span.remove(); updateHidden();}); span.appendChild(btn); wrap.appendChild(span); updateHidden(); } function updateHidden(){ const vals=[...wrap.querySelectorAll('.tag-token')].map(t=>t.dataset.val); hidden.value=vals.join(', '); } } /* Init tag fields */ document.addEventListener('DOMContentLoaded',function(){ new TokenField({wrap:'tagsTokens', input:'tagsInput', hidden:'tagsHidden'}); new TokenField({wrap:'locTokens', input:'locInput', hidden:'locHidden'}); /* Collapsible social block */ const btn=document.getElementById('toggleSocial'); const block=document.getElementById('social-block'); btn.addEventListener('click',()=>{ const open=block.style.display==='block'; block.style.display=open?'none':'block'; btn.classList.toggle('open',!open); btn.textContent=(open?'Show':'Hide')+' Social & Directory Links '+(open?'βΌ':'β²'); }); }); </script> </body></html>
Save changes
Create folder
writable 0777
Create
Cancel