AltusPlatform API Plugin + API/Shortcodes Manager + Dynamic Instruction Shortcodes
CODEX MASTER BUILD INSTRUCTIONS
AltusPlatform API Plugin + API/Shortcodes Manager + Dynamic Instruction Shortcodes
Plugin Slug: altus-api
Language: PHP (WordPress)
Compatibility: PHP 7.4.11 → 8.4
No schema migrations (no CREATE/ALTER; use WP options for docs storage; only read/write existing Altus tables).
Must use argus-core DB variables ($client_server_database, $acc_server_database) and $wpdb.
0) The Objective
Create a WordPress plugin named altus-api that provides:
-
A secure, versioned REST API under:
/wp-json/altus/v1/…
-
A backend admin console in wp-admin:
Altus Platform → API & Shortcodes with these pages:
-
Dashboard
-
API Keys (read-only list + optional validation tool)
-
API Docs & Rules (WYSIWYG manual editor)
-
Shortcode Inventory (manual registry editor)
-
A front-end dynamic instruction system using shortcodes:
-
(renders API docs snippets by section)
Global
All Altus Platform endpoints require Authorization headers. Use HTTPS only. Responses are wrapped with success/data/meta or success/error/meta. Contact, course, and enrollment writes are idempotent when the same identifiers are used.
-
(renders a shortcode’s documentation)
-
(renders named instruction blocks, with internal/public modes)
1) Hard Requirements (Do Not Deviate)
1.1 Platform & Security
-
PHP compatibility: 7.4.11 through 8.4
-
-
Header: Authorization: Bearer {deacon_key}
-
Validate against acc_keys.deacon_key in the Altus shared DB ($acc_server_database).
All REST endpoints require API token:
-
-
Never echo/print inside endpoints; always return WP_REST_Response.
-
No SQL errors or stack traces returned to clients.
1.2 Database Conventions
-
Use WordPress $wpdb and prepared statements everywhere.
-
Use $acc_server_database to query Altus shared tables.
-
-
acc_keys (token auth)
-
acc_contacts, acc_contactsmeta (contacts)
-
ae_course, ae_coursemeta (courses)
-
ae_enrollments (enrollments)
Tables involved (minimum v1):
-
-
No schema changes.
1.3 Logging Standards
-
Create logs/update-log.txt and follow the Codex logging template format used across Altus plugins.
-
Include DB IMPACT (should be “None” unless new meta_keys are introduced).
2) Deliverables (Exact Plugin File Structure)
Create:
/wp-content/plugins/altus-api/
Required tree:
altus-api/
altus-api.php
readme.txt
logs/
update-log.txt
includes/
class-altus-api-router.php
class-altus-api-auth.php
class-altus-api-db.php
class-altus-api-response.php
class-altus-api-admin.php
class-altus-api-docs.php
class-altus-api-shortcodes.php
endpoints/
class-altus-api-contacts.php
class-altus-api-courses.php
class-altus-api-enrollments.php
admin/
views/
page-api-dashboard.php
page-api-keys.php
page-api-docs.php
page-shortcodes.php
3) Bootstrap File:
altus-api.php
Implement:
-
Plugin header
-
defined(‘ABSPATH’) || exit;
-
require_once all needed class files
-
Initialize:
-
REST router on rest_api_init
-
Admin UI only when is_admin()
-
Shortcodes always
-
Activation hook to seed docs/options if missing
-
Graceful failure requirement:
If argus-core variables aren’t available ($acc_server_database missing), plugin must:
-
still activate without fatal error
-
but REST endpoints return a consistent error stating config missing
4) Response Wrapper:
class-altus-api-response.php
Centralize all responses.
4.1 Success JSON Shape
{
"ok": true,
"data": {},
"meta": {
"version": "v1",
"request_id": "uuid",
"timestamp": "ISO8601"
}
}
4.2 Error JSON Shape
{
"ok": false,
"error": {
"code": "altus_auth_invalid",
"message": "Unauthorized",
"status": 401
},
"meta": {
"version": "v1",
"request_id": "uuid",
"timestamp": "ISO8601"
}
}
4.3 Methods
-
public static function success($data, $status = 200, $version = ‘v1’): WP_REST_Response
-
public static function error(WP_Error $err, $version = ‘v1’): WP_REST_Response
-
public static function request_id(): string (uuid-like; can be wp_generate_uuid4)
5) Authentication:
class-altus-api-auth.php
Implement:
5.1 Method Signature
public function authenticate_request(WP_REST_Request $request): array
Returns:
-
[‘ok’ => true, ‘key_row’ => (object)$row]
-
or [‘ok’ => false, ‘error’ => WP_Error]
5.2 Rules
-
Read Authorization header.
-
Require Bearer {token} format.
-
Query Altus shared DB table: acc_keys by deacon_key = %s.
-
If no match → WP_Error altus_auth_invalid, status 401
-
If match → OK.
5.3 Optional Host/Site Validation (Implement Now, But Non-Blocking)
If possible:
-
compare request host to acc_keys.site_url if set
-
if mismatch, return 403 error altus_auth_site_mismatch
Do not hard-fail if site_url is NULL.
6) DB Access Layer:
class-altus-api-db.php
Create a thin repository wrapper using $wpdb.
6.1 DB Targeting
All SQL must query using fully-qualified table names like:
-
{$acc_server_database}.acc_keys
-
{$acc_server_database}.acc_contacts
-
{$acc_server_database}.acc_contactsmeta
-
{$acc_server_database}.ae_course
-
{$acc_server_database}.ae_coursemeta
-
{$acc_server_database}.ae_enrollments
6.2 Required Helper Methods
Contacts
-
get_contact_by_id(int $id): ?array
-
get_contact_by_email(string $email): ?array
-
get_contact_meta(int $contact_id): array (key=>value)
-
upsert_contact(array $payload): array
-
must support idempotent behavior: if email exists, update the existing record by default (safe).
-
-
upsert_contact_meta(int $contact_id, array $meta): void
Courses
-
get_course(int $id): ?array
-
get_course_meta(int $course_id): array (key=>value)
-
list_courses(array $args): array
-
upsert_course(array $payload): array
-
upsert_course_meta(int $course_id, array $meta): void
Enrollments
-
list_enrollments(array $filters): array
-
find_enrollment(int $contact_id, int $course_id, ?string $blog_master_key = null): ?array
-
create_or_update_enrollment(array $payload): array (idempotent)
-
update_enrollment(int $id, array $payload): array
6.3 Prepared Statements Only
Every query uses $wpdb->prepare().
6.4 Whitelisting Columns
Create explicit arrays of allowed columns for updates:
-
contact columns allowed
-
course columns allowed
-
enrollment columns allowed
Reject unknown columns with WP_Error(‘altus_invalid_field’, …).
7) REST Router:
class-altus-api-router.php
Register routes under namespace:
-
altus/v1
All routes must use a permission_callback that:
-
calls Altus_API_Auth->authenticate_request()
-
returns true if ok
-
otherwise returns the WP_Error (WP will send it; but you should intercept in handlers and wrap into Altus_API_Response error wrapper)
Important: Prefer doing auth in permission_callback, and in each handler assume authorized.
8) Endpoints Implementation (REST)
8.1 Contacts Endpoint —
endpoints/class-altus-api-contacts.php
Routes:
-
GET /contacts/(?P<id>\d+)
-
GET /contacts (supports ?email=…)
-
POST /contacts
-
PUT /contacts/(?P<id>\d+)
Behavior:
-
GET by id returns:
-
contact base fields from acc_contacts
-
meta as key/value from acc_contactsmeta
-
-
GET by email: same output; 404 if not found
-
POST:
-
if email exists → update existing contact by default; return existing id (idempotent)
-
allow force_create=true to create anyway (optional; if implemented, must still avoid duplicate constraints if any exist)
-
-
PUT:
-
updates base + meta
-
if id not found → 404
-
Payload Rules:
-
base fields (example): first_name, last_name, primary_email, display_name
-
meta fields: object meta: { “altus_role”:”…”, “ae_certificate_name”:”…” }
Sanitization:
-
email: sanitize_email + is_email
-
names/text: sanitize_text_field
-
meta keys: sanitize_key
-
meta values: default sanitize_text_field unless key indicates HTML, then wp_kses_post
8.2 Courses Endpoint —
endpoints/class-altus-api-courses.php
Routes:
-
GET /courses supports params:
-
master_key, status, search, limit, offset
-
-
GET /courses/(?P<id>\d+)
-
POST /courses
-
PUT /courses/(?P<id>\d+)
Behavior:
-
GET course returns:
-
core from ae_course
-
meta key/value from ae_coursemeta
-
-
GET list supports:
-
simple search by title fields
-
pagination (limit/offset)
-
-
POST/PUT:
-
update core fields (whitelist)
-
upsert meta values (key/value)
-
return full course object
-
Sanitization:
-
numeric fields cast safely
-
dates validate (ISO8601 or Y-m-d), store consistent format expected by DB
8.3 Enrollments Endpoint —
endpoints/class-altus-api-enrollments.php
Routes:
-
GET /enrollments supports:
-
contact_id, course_id, optional blog_master_key
-
-
POST /enrollments
-
PUT /enrollments/(?P<id>\d+)
POST rules:
-
require contact_id, course_id
-
optional:
-
transaction_id
-
enrolled default 1
-
blog_master_key (if omitted, use default master_key or infer; if you can’t infer reliably, require it in payload)
-
-
set enrollment_date to NOW if missing
-
if enrollment exists for (contact_id, course_id, blog_master_key) → update/return existing (idempotent)
PUT allowed fields:
-
course_completion_date
-
ae_course_completed
-
ae_evaluation_completed
-
ae_evaluation_completed_date
-
received_credit
(These must match your enrollment table usage; do not invent new fields.)
9) Admin Console (wp-admin)
Implement in class-altus-api-admin.php + view files.
9.1 Menu
Add menu:
Altus Platform → API & Shortcodes
Pages:
-
Dashboard
-
API Keys
-
API Docs & Rules
-
Shortcode Inventory
Access control:
-
default capability: manage_options
-
do NOT implement custom altus_role mapping in v1 (keep simple)
9.2 Dashboard View (
page-api-dashboard.php
)
Show:
-
Plugin version
-
REST namespace altus/v1
-
count of API keys (SELECT COUNT(*) from acc_keys)
-
“Test endpoint” button:
-
performs a server-side request to a lightweight internal function (not remote HTTP) that returns OK if DB configured
-
9.3 API Keys View (page-api-keys.php)
Read-only list:
-
columns: id, site_url, master_key, wp_blog_id, date_added
-
mask token:
-
show first 4 + last 4 of deacon_key
-
never print full token by default
Optional tool:
-
-
“Validate token” input that checks existence and prints matched row metadata (still never stores the token)
9.4 API Docs & Rules View (page-api-docs.php)
This is your editable “manual.”
Storage (WordPress options):
-
altus_api_docs_v1 (JSON map)
Sections to edit (each with wp_editor()):
-
Global Rules
-
Auth
-
Contacts
-
Courses
-
Enrollments
-
Errors
-
Examples
Requirements:
-
Save with nonce
-
Sanitize using wp_kses_post on save and output
-
Add an activation seeding function: if option missing, set a default starter manual
9.5 Shortcode Inventory View (page-shortcodes.php)
Storage:
-
altus_shortcode_docs_v1 (JSON array)
Features:
-
Display plugin-owned shortcodes (from the shortcode class)
-
Provide a UI section to edit the stored inventory entries:
-
tag
-
title
-
purpose
-
audience
-
attributes list
-
examples list
-
related_api list
-
notes
-
flags: legacy boolean
-
Use:
-
nonce
-
sanitize all fields; notes can be wp_kses_post
10) Docs Manager + Shortcodes (Front-End Dynamic Instructions)
10.1 Docs Manager:
class-altus-api-docs.php
Responsibilities:
-
Get/set options:
-
altus_api_docs_v1
-
altus_shortcode_docs_v1
-
altus_instructions_v1
-
-
Provide helper methods:
-
get_api_docs($version): array
-
get_api_doc_section($version, $section): string
-
get_shortcode_doc($version, $tag): ?array
-
get_instruction($version, $key): ?array
-
-
Provide defaults on activation (seed content if missing)
10.2 Shortcodes:
class-altus-api-shortcodes.php
Register these:
A) Global
All Altus Platform endpoints require Authorization headers. Use HTTPS only. Responses are wrapped with success/data/meta or success/error/meta. Contact, course, and enrollment writes are idempotent when the same identifiers are used.
Global
All Altus Platform endpoints require Authorization headers. Use HTTPS only. Responses are wrapped with success/data/meta or success/error/meta. Contact, course, and enrollment writes are idempotent when the same identifiers are used.
Attributes:
-
section (global|auth|contacts|courses|enrollments|errors|examples)
-
version default v1
-
format default html
-
context optional
Behavior:
-
load altus_api_docs_{version}
-
render only requested section
-
wrap in a container with a heading
-
sanitize output with wp_kses_post
-
add filter hook:
-
apply_filters(‘altus_api_docs_output’, $html, $section, $version, $context)
-
B)
Attributes:
-
tag required
-
version default v1
-
variant short|full|admin (default full)
-
show_examples yes|no (default yes)
Behavior:
-
load entry from altus_shortcode_docs_{version}
-
render structured info:
-
Purpose, Audience, Attributes, Examples, Related API
-
-
If not found:
-
show nothing for non-admins
-
show a small “Doc not found” note for admins
-
C)
Attributes:
-
key required
-
version default v1
-
mode public|internal default public
-
title optional override
Storage:
-
altus_instructions_v1 map:
{
"hubspot_deal_refresh": {
"title": "HubSpot Deal Refresh – How It Works",
"public_html": "<p>...</p>",
"internal_html": "<p>...</p>"
}
}
Behavior:
-
if mode=internal:
-
show internal_html only to admins; otherwise show nothing
-
-
sanitize output with wp_kses_post
11) Seed Default Documentation (On Activation)
On plugin activation:
-
if altus_api_docs_v1 missing, create it with:
-
Global Rules: auth required, response wrappers, idempotency notes
-
Each endpoint section: routes + sample curl + sample JSON payloads
-
-
if altus_shortcode_docs_v1 missing, create an empty array (or add 1 example entry)
-
if altus_instructions_v1 missing, create with at least:
-
hubspot_deal_refresh example (public/internal placeholders)
-
12) Testing & Verification (Codex Must Provide)
Codex must include in its final output:
12.1 Example
curl
calls
-
Auth failure example (no header)
-
Contacts GET by id
-
Contacts POST create/upsert
-
Courses GET
-
Enrollments POST (idempotent)
-
Enrollments PUT completion updates
Example:
curl -sS -H "Authorization: Bearer YOUR_TOKEN" \
"https://YOURDOMAIN/wp-json/altus/v1/courses/2810"
12.2 “Known Good” Example Request/Response
-
Create/Upsert Contact
-
Create/Upsert Enrollment
-
Fetch Course with meta
12.3 PHP Compatibility Confirmation
-
confirm no typed properties that break 7.4
-
avoid PHP 8-only syntax
-
no fatal when activating on 7.4
13) Definition of Done (Acceptance Criteria)
✅ Plugin activates without fatal errors
✅ /wp-json/altus/v1/… routes exist and require Bearer token
✅ Consistent JSON wrapper responses
✅ DB access uses prepared statements and $acc_server_database
✅ Contacts/Courses/Enrollments work end-to-end
✅ Admin menu exists with 4 pages and saves docs/options correctly
✅ Shortcodes render front-end instruction content safely
✅ No schema changes
✅ logs/update-log.txt created and filled using Altus logging standard
14) Implementation Notes (How Codex Should Code It)
-
Keep endpoint classes thin; put DB logic in class-altus-api-db.php
-
Use WP_Error for all errors; wrap via response helper
-
Sanitize all inputs; whitelist all updatable DB columns
-
Never show full API tokens in UI or shortcodes
-
Use nonces + capability checks for all admin saves
