Siteβ―Builder
Editing:
editnice.php
writable 0666
<?php /* ============================================================ BestDealOn β Edit Business Profile (v2 β tag UX refined) ============================================================ */ $bizFile = __DIR__.'/new-business.json'; if (is_readable(__DIR__.'/business.json')) $bizFile = __DIR__.'/business.json'; $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 file are we editing? */ $curFile=''; $fileType=''; if (is_readable($bizfile)){ $curFile=$bizfile; $fileType='business.json'; } elseif (is_readable($newfile)){ $curFile=$newfile; $fileType='new-business.json'; } 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 ---------- */ if ($_SERVER['REQUEST_METHOD']==='POST' && isset($_POST['edit_save'])){ $_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']; } /* ---------- Upgrade / Cancel / Delete (unchanged) ---------- */ if (isset($_POST['make_paid']) && is_readable($newfile)){ copy($newfile,$bizfile); $msg="β Copied new-business.json to business.json (upgraded to paid)"; $curFile=$bizfile; $fileType='business.json'; } 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; } } } if (isset($_POST['delete_profile']) && is_dir($phDir)){ function delTree($d){$f=array_diff(scandir($d),['.','..']);foreach($f as $file){is_dir("$d/$file")?delTree("$d/$file"):unlink("$d/$file");}return rmdir($d);} $msg=delTree($phDir)?"β Entire business profile deleted.":"β Failed to delete folder."; if (strpos($msg,'β ')!==false){ $curFile=''; $fileType=''; foreach($fields as $k=>$v) $fields[$k]=''; $fields['phone']=$ph; } } /* Helpers */ function h($s){return htmlspecialchars($s,ENT_QUOTES,'UTF-8');} function 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> /* ---------- Layout & Typography ---------- */ 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;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;} textarea[name="description"]{min-height:170px;} /* β extra room */ 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 styling (compact) ---------- */ .tag-wrap{ display:flex; flex-wrap:wrap; gap:.25em; /* was .4em */ margin-bottom:.35em; } .tag-token{ background:#ecf1ff; border:1px solid #c5d0ff; border-radius:999px; padding:.18em .55em; /* was .26em .75em */ font-size:.90em; /* was .93em */ display:flex; align-items:center; } .tag-token button{ background:none; border:none; color:#ff3535; font-size:1.05em; /* was 1.08em */ font-weight:700; line-height:1em; margin-left:.25em; /* was .35em */ cursor:pointer; } .tag-token button:hover{color:#ff6767;} /* ---------- Collapsible social block ---------- */ #social-block{display:none;margin-top:.8em;} .show-btn {margin-top:1em;background:#5a5ad4;} .show-btn.open {background:#8b28d1;} /* ---------- Responsive ---------- */ @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(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(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'])?>"> <label>Facebook (URL or handle)</label><input type="text" name="facebook" maxlength="120" value="<?=h($fields['facebook'])?>"> <label>Instagram (URL or handle)</label><input type="text" name="instagram" maxlength="120" value="<?=h($fields['instagram'])?>"> <label>TikTok (URL or handle)</label><input type="text" name="tiktok" maxlength="120" value="<?=h($fields['tiktok'])?>"> <label>LinkedIn (URL or handle)</label><input type="text" name="linkedin" maxlength="120" value="<?=h($fields['linkedin'])?>"> <label>YouTube (URL or channel)</label><input type="text" name="youtube" maxlength="120" value="<?=h($fields['youtube'])?>"> <label>Yelp (URL)</label><input type="text" name="yelp" maxlength="150" value="<?=h($fields['yelp'])?>"> <label>Angi / Angie's List (URL)</label><input type="text" name="angi" maxlength="150" value="<?=h($fields['angi'])?>"> <label>Better Business Bureau (URL)</label><input type="text" name="bbb" maxlength="150" value="<?=h($fields['bbb'])?>"> <label>Nextdoor (URL)</label><input type="text" name="nextdoor" maxlength="150" value="<?=h($fields['nextdoor'])?>"> </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> /* ---------- TokenField helper ---------- */ function TokenField(cfg){ const wrap = document.getElementById(cfg.wrap), input = document.getElementById(cfg.input), hidden = document.getElementById(cfg.hidden); /* build initial tokens */ hidden.value.split(',').map(s=>s.trim()).filter(Boolean).forEach(addToken); /* Create tokens on Enter or blur only */ input.addEventListener('keydown',e=>{ if(e.key==='Enter'){ e.preventDefault(); processInput(); } }); input.addEventListener('blur',processInput); /* Make sure hidden field is correct on submit */ document.getElementById('bizForm').addEventListener('submit',updateHidden); 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(', '); /* append any text still in input so it is not lost on save */ if(input.value.trim()){ hidden.value+=(hidden.value? ', ':'')+input.value.trim(); } } } document.addEventListener('DOMContentLoaded',()=>{ new TokenField({wrap:'tagsTokens',input:'tagsInput',hidden:'tagsHidden'}); new TokenField({wrap:'locTokens', input:'locInput', hidden:'locHidden'}); /* Collapsible socials */ const btn=document.getElementById('toggleSocial'), blk=document.getElementById('social-block'); btn.addEventListener('click',()=>{ const open=blk.style.display==='block'; blk.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