> docs/

Documentation

Everything you need to deploy, configure, and extend Point Edit Studio.

Getting Started

Installation

Point Edit Studio is a single folder. No database, no package manager, no build step.

bash
# Clone or download the repository
git clone https://github.com/pointedit/pointedit.io.git
# Or just copy the _editor folder anywhere PHP runs
cp -r _editor/ /var/www/html/
# That's it. Visit /_editor/ in your browser.

First login

The default master credentials are set in _editor/config.php:

config.php
// Before going live, generate a real bcrypt hash:
// php -r "echo password_hash('your-password', PASSWORD_BCRYPT);"
define('PE_MASTER_USERNAME', 'admin');
define('PE_MASTER_PASSWORD', '$2y$10$replace.me.with.a.real.bcrypt.hash');
define('PE_MASTER_TOTP_SECRET', ''); // leave blank for no 2FA

Log in at: http://your-server/_editor/ → enter username + password → if TOTP is set, enter code → done.

Adding your first site

After login, you'll see the dashboard. Click Add Site to configure a local or remote site. Sites are stored in _editor/sites.json.


Site Configuration

Sites are defined in _editor/sites.json. Two types: local (files on the same server) and remote (via the pe_api.php agent).

sites.json
[
  {
    "id": "my-site",
    "name": "My Website",
    "type": "local",
    "root": "/home/user/public_html",
    "url": "https://example.com",
    "created": "2026-01-01",
    "status": "active"
  },
  {
    "id": "client-site",
    "name": "Client Site",
    "type": "remote",
    "url": "https://client-site.com",
    "api_key": "sk-abc123...",
    "created": "2026-01-01",
    "status": "active"
  }
]
FieldTypeRequiredDescription
idstringYesUnique identifier, used internally and for user assignment
namestringYesDisplay name shown in the dashboard
typestringYeslocal or remote
rootstringLocal onlyAbsolute filesystem path to the site root
urlstringYesPublic URL of the site (used for preview iframe)
api_keystringRemote onlyAPI key matching the one in pe_api.php on the remote server
createdstringNoCreation date (informational)
statusstringNoactive or inactive

User Management

Users are defined in _editor/users.json. Each user has a role (admin or client) and a list of site IDs they can access.

users.json
[
  {
    "username": "admin",
    "password": "$2y$10$...",
    "totp_secret": "",
    "role": "admin",
    "sites": ["*"],
    "created": "2026-01-01",
    "last_login": null
  },
  {
    "username": "client1",
    "password": "$2y$10$...",
    "totp_secret": "",
    "role": "client",
    "sites": ["my-site"],
    "created": "2026-01-01",
    "last_login": null
  }
]
FieldTypeDescription
usernamestringLogin username
passwordstringBcrypt hash — generate with password_hash()
totp_secretstringTOTP secret (set during enrollment, blank for no 2FA)
rolestringadmin — full access, manage sites/users. client — assigned sites only
sitesarrayArray of site IDs, or ["*"] for all sites

Roles at a glance: Admins see all sites, can add/edit/remove sites, manage users, and reset TOTP. Clients see only assigned sites and use the same editor — but without admin controls.


API Reference

All API calls go to _editor/api.php?action=<name> with a JSON body (POST). Authenticated endpoints require a valid session cookie.

Auth actions

ActionAuthBodyResponse
loginNo {"username":"...","password":"..."} {"ok":true} or {"totp_required":true}
login_totpHalf {"code":"123456"} {"ok":true,"user":{...}}
totp_enrollHalf {} {"ok":true,"secret":"...","qr":"..."} (embedded QR SVG)
totp_enroll_verifyHalf {"code":"123456","nonce":"..."} {"ok":true}
logoutYes {} {"ok":true}
check {} {"ok":true,"user":{...}} if logged in, else error

Site actions (admin only)

ActionBodyDescription
list_sites{}List all sites (filtered by user role)
switch_site{"site_id":"..."}Select active site for editing
add_site{"id":"...","name":"...","type":"local",...}Create a new site
edit_site{"id":"...","name":"...",...}Update an existing site
remove_site{"id":"..."}Delete a site
check_site{"id":"..."}Ping a site to verify connectivity

File actions (requires active site)

ActionBodyDescription
tree{}Get recursive directory tree of the site
read{"path":"/index.html"}Read a file's content
save{"path":"/index.html","content":"..."}Overwrite a file. Auto-creates .bak backup
create{"path":"/new.html","content":"..."}Create a new file
linked_css{"path":"/index.html"}Extract linked CSS files from an HTML file
find_in_files{"query":"search-term","regex":false}Search across all files
replace_in_files{"find":"old","replace":"new","regex":false}Find and replace across all files
images{}List all image files in the site
seo_audit{}Crawl HTML files for SEO metadata
list_templates{}List available templates in _editor/templates/
read_template{"name":"event-template"}Read a template with placeholders

Example: reading a file and saving a change

bash
# Step 1 — Login
curl -X POST https://your-server/_editor/api.php?action=login \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"your-password"}' \
  -c cookies.txt

# Step 2 — Read a file
curl -X POST https://your-server/_editor/api.php?action=read \
  -H "Content-Type: application/json" \
  -d '{"path":"/index.html"}' \
  -b cookies.txt

# Step 3 — Save changes (auto-backup created)
curl -X POST https://your-server/_editor/api.php?action=save \
  -H "Content-Type: application/json" \
  -d '{"path":"/index.html","content":"<h1>Updated</h1>"}' \
  -b cookies.txt

Extension System

Extensions are PHP files dropped into _editor/extensions/. They can register new file types and add custom API functionality.

Creating an extension

Create a .php file in _editor/extensions/ with a manifest docblock:

extensions/my-extension.php
/** My Extension v1.0 */
if (!defined('PE_VERSION')) { http_response_code(403); exit; }

// Your extension logic here
// This file is autoloaded when the extension system runs

Registering file types

Extensions can register additional file extensions for editing via the API:

bash
curl -X POST /_editor/api.php?action=register_file_types \
  -H "Content-Type: application/json" \
  -d '{"extension_name":"JS Support","file_types":["js","jsx","ts","tsx"]}'
ActionBodyDescription
list_extensions{}List installed extension files
install_extensionmultipart form ext_fileUpload a .php extension file
register_file_types{"extension_name":"...","file_types":["js","ts"]}Register new editable file types
unregister_file_types{"extension_name":"..."}Remove a file type registration
get_registered_types{}List all registered and core file types

Security: Extension files are scanned for dangerous functions (eval, system, exec, etc.) during upload. Only admin users can install extensions.


Remote Agent

The remote agent (pe_api.php) is a single PHP file deployed to client servers. It lets you edit remote sites through the Point Edit Studio dashboard as if they were local.

Deploying the agent

bash
# Set your API key in pe_api.php first
define('PE_API_KEY', 'sk-your-secret-key-here');

# Deploy to the client server
scp _editor/pe_api.php user@client-server:/home/user/public_html/

# Add as a remote site in your dashboard with the same API key

Remote agent API

All agent calls require the X-PE-API-Key header:

bash
curl -X POST https://client-site.com/pe_api.php?action=tree \
  -H "Content-Type: application/json" \
  -H "X-PE-API-Key: sk-your-secret-key-here" \
  -d '{}'
ActionDescription
pingHealth check — returns {"ok":true,"version":"..."}
treeRecursive directory listing
readRead file content (max 2MB)
saveSave file content (auto-backup to /.pe_backups/)
linked_cssExtract linked stylesheets from HTML
find_in_filesSearch across all files
replace_in_filesFind and replace across all files
imagesScan for image files
seo_auditSEO analysis of HTML files

Security

Authentication

File system security

Server hardening

The included .htaccess provides:


Templates

Templates are HTML files in _editor/templates/ that use {{placeholder}} syntax. They can be read via the API and used as starting points for new pages. The included event-template.html demonstrates a full event page with schema.org markup and The Ticketing Co widget integration.