Skip to content
lucyeos07Public

About

Nexora — fictional B2B SaaS support platform built on WordPress (portfolio project)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Nexora — B2B Support Platform (WordPress)

Nexora is a fictional B2B SaaS customer support platform, built as a portfolio project to demonstrate WordPress development without third-party plugins — a custom block theme, two custom post types, native auth, and a role-gated agent dashboard, all on stock WordPress APIs.

🔗 View the static homepage snapshot — a frozen visual copy of the real homepage (see note below on live vs. static).

What this repo contains

This repo holds the custom WordPress theme (nexora) that powers the site — the actual code written for this project. It does not include WordPress core or the SQLite database integration, since those aren't original work; install them normally to run the theme (see Running it yourself below).

A frozen, static HTML copy of the real homepage lives in /docs and is published via GitHub Pages — that's the link above. It's a genuine mirror of the actual rendered markup/CSS (not a mockup), so the layout is exactly what the real site looks like. It's static, though: sign-in, ticket submission, the customer account, and the agent dashboard need a real WordPress backend to function, which GitHub Pages can't run.

What's built

Area Pages Notes
Marketing site /, /pricing/, /about/ Custom block theme, theme.json-based
Help Center /help-center/ kb_article CPT, 26 seeded articles
Support /submit-a-ticket/ support_ticket CPT, native form handling
Customer auth /sign-in/, /get-started/, /account/ WordPress core auth, no custom hashing
Agent dashboard /support-dashboard/ Role-gated ticket queue, triage, replies

Tech stack

  • WordPress block theme — theme.json-driven design tokens, block templates (templates/*.html), template parts (parts/header.html, parts/footer.html), PHP-driven patterns (patterns/*.php)
  • Custom post types & statuses — support_ticket, kb_article, with custom post statuses (ticket_open, ticket_in_progress, ticket_resolved, ticket_closed) instead of a bespoke status table
  • Custom PHP (inc/) — ticket submission, agent dashboard (triage, assignment, internal notes, customer replies), customer auth and account pages
  • Native WordPress APIs only — no third-party plugins; auth via wp_signon()/wp_insert_user(), forms via admin-post.php, messaging via the comment system

Architecture decisions (the "why")

No third-party plugins. Everything runs on core WordPress APIs — custom post types, post statuses, post meta, comments, and the native user/auth system. This was a constraint, not a limitation: the goal was to show what's possible with just WordPress's own primitives.

Tickets are a CPT, not a plugin's custom table. support_ticket is a public => false CPT (see inc/support-tickets.php). Custom post statuses (ticket_open, ticket_in_progress, ticket_resolved, ticket_closed) replace a bespoke status column, so all of WP's post machinery (queries, meta, capabilities, revisions) works for free.

post_author is the customer relationship. Rather than inventing a "customer ID" meta field, a ticket's post_author is literally the WordPress user who filed it. Ownership checks are just post_author === get_current_user_id() — no extra table, no extra join, and it's a pattern any WordPress developer already knows.

Comments, repurposed, carry the conversation. Internal agent notes and customer-visible replies are both stored as wp_comments rows on the ticket, distinguished by comment_type (ticket_note vs ticket_reply) and hidden from normal comment queries via a pre_get_comments filter — the same trick WooCommerce uses for order notes. This avoided a second custom table for "messages" when the comment system already models "a list of dated, attributed text entries on a post" perfectly.

Capabilities, not custom roles. current_user_can('edit_others_posts') is the one boundary used everywhere to mean "this person is a support agent" — for dashboard access, for the reply/note endpoints, and for the assignee picker. It's a real WordPress capability already granted to Editors and Admins, so there's no custom role to maintain and no privilege-escalation surface from a misconfigured role.

admin-post.php, not REST/AJAX. Every mutating action (submit ticket, update status, add note, send reply, sign in, register) posts to admin-post.php with its own add_action('admin_post_{action}', ...) handler, nonce, and capability check. No JavaScript build step, no REST controller boilerplate — just forms and redirects, which is both simpler to demo and easier to explain than a client-side SPA layer would be.

Every handler checks its own authorization. A guard on the page (template_redirect) does not protect the endpoint — admin-post.php requests never run the page template. So every handler re-checks capability and nonce independently, rather than trusting that "you got this far so you must be allowed." This was verified with real attack requests, not just code review — see Security below.

Native auth only. Sign in / sign up / sign out go through wp_signon(), wp_insert_user(), wp_set_auth_cookie(), and wp_logout_url(). No custom password hashing, no custom session handling — WordPress already solved this correctly, so it isn't reinvented.

Security posture

  • Nonces on every mutating form; capability checks independent of page guards.
  • Attack-tested: a logged-in customer hitting an agent-only endpoint gets 403; an anonymous request gets 400 (no nopriv hook registered); a forged nonce gets 403.
  • A customer cannot view another customer's ticket by guessing/editing the ?ticket= URL parameter — ownership is re-checked server-side and a failed check silently falls back to the customer's own ticket list rather than showing an error (which would otherwise confirm the ticket number exists).
  • Agent replies always attribute the real agent internally (comment_author) but always render as "Nexora Support Team" to the customer — deliberate, not an oversight, matching how real SaaS support tools anonymize the individual agent from the customer's point of view.
  • All output escaped (esc_html, esc_attr, esc_url), all input sanitized (sanitize_text_field, sanitize_textarea_field, absint) at the point of use.

Data model at a glance

support_ticket (CPT, private)
├─ post_author        → the customer (a WP user)
├─ post_status         → ticket_open | ticket_in_progress | ticket_resolved | ticket_closed
├─ post_content        → the customer's original message
├─ meta: _nexora_ticket_number       → e.g. NX-1008 (customer-facing ID)
├─ meta: _nexora_ticket_category     → account-login | billing-payments | technical-issue | integration | api | other
├─ meta: _nexora_ticket_priority     → low | medium | high | urgent
├─ meta: _nexora_ticket_assigned_to  → agent user ID
└─ comments (repurposed)
   ├─ comment_type = ticket_note     → internal only, hidden from customer + default queries
   └─ comment_type = ticket_reply    → customer-visible, shown as "Nexora Support Team"

Not built (deliberately out of scope)

Email notifications, bulk ticket actions, SLA timers, custom agent roles, reporting/analytics. These would be natural next steps for a production product but weren't needed to demonstrate the architecture.

Running it yourself

This theme was built and tested with WordPress Studio (local WordPress + SQLite). To run it:

  1. Create a WordPress site (Studio, Local, or any standard WP install)
  2. Copy this repo's contents into wp-content/themes/nexora/
  3. Activate the theme
  4. Create the required pages (/pricing/, /help-center/, /submit-a-ticket/, /sign-in/, /get-started/, /account/, /support-dashboard/, /about/, /contact-support/) — block-theme templates auto-map to a page by its slug (page-{slug}.html)

Note on the demo

Nexora is a fictional B2B SaaS product created as a portfolio project — not a real business. Product copy, sample tickets, and knowledge-base articles are original but invented for demonstration purposes.

About

Nexora — fictional B2B SaaS support platform built on WordPress (portfolio project)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages