NectarPress Architecture Reference¶
Internal reference for Nectar Digit engineers and contributors. Covers module structure, data flows, custom database tables, and API surfaces.
Module Map¶
nectarpress/
├── functions.php 33-line bootloader: constants + require bootstrap.php
├── includes/
│ ├── bootstrap.php Central module loader (all require_once in one place)
│ ├── helpers.php Pure utilities (zero side-effects, loads first)
│ │
│ ├── license/ License engine (Sprint 2)
│ │ ├── client.php NectarPress_License_Client — JWT verify, HMAC signing
│ │ ├── feature-gate.php nectarpress_has_feature() + NECTARPRESS_PLAN_FEATURES
│ │ ├── cron.php 03:15 NPT daily heartbeat
│ │ ├── update-checker.php Atomic swap updater + WP update UI hooks
│ │ └── ui.php Admin license tab
│ │
│ ├── security/ Security hardening (Sprint 3)
│ │ ├── integrity-monitor.php NectarPress_Integrity_Monitor
│ │ ├── alerts.php NectarPress_Alerts — email/dashboard/beacon
│ │ ├── csp-builder.php NectarPress_CSP_Builder
│ │ ├── rate-limit.php Token-bucket rate limiter
│ │ └── upload-sanitiser.php SVG/PDF/JPEG sanitizer + EXIF strip
│ │
│ ├── payments/ Payment gateways (Sprint 2)
│ │ ├── currency.php NPR/paisa helpers
│ │ ├── tax-calculator.php 13% VAT calculator
│ │ ├── orders-cpt.php np_lic_order + np_sub_order CPTs
│ │ ├── webhook-handler.php Payment callback handler
│ │ └── gateways/
│ │ ├── khalti.php Khalti v2 (/lookup/ always called on return)
│ │ ├── bank-deposit.php Manual verification, 72h auto-cancel
│ │ └── qr-payment.php QR screenshot upload
│ │
│ ├── subscription/ Reader subscription engine (Sprint 2)
│ │ ├── plans-cpt.php np_sub_plan CPT
│ │ ├── memberships.php State machine + np_premium_reader role
│ │ └── paywall.php Article count / scroll / time triggers
│ │
│ ├── newsroom/ Editorial workflow (Sprint 4)
│ │ ├── reporter-roles.php 5 roles, 11 caps, beat-based map_meta_cap
│ │ ├── editorial-workflow.php 7-state machine, all transitions
│ │ ├── byline-multi.php N reporters per post, Schema.org author array
│ │ ├── corrections.php 4 types, retraction banner, CorrectionComment
│ │ ├── reporter-directory.php /reporters/ auto-page, region seeder
│ │ ├── revisions-audit.php wp_nectarpress_audit custom table
│ │ ├── notifications.php Throttled email + webhook
│ │ ├── editorial-dashboard.php 3 dashboards
│ │ └── plagiarism-flag.php Pre-publish hook (no provider hardcoded)
│ │
│ ├── onboarding/ Setup wizard + demo content (Sprint 5)
│ │ ├── wizard.php NectarPress_Setup_Wizard (7 steps, AJAX)
│ │ ├── wizard-steps.php Step render + save callbacks
│ │ ├── importer.php NectarPress_Demo_Importer (idempotent + rollback)
│ │ └── checklist.php Post-wizard dashboard widget
│ │
│ ├── a11y/ Accessibility (Sprint 6)
│ │ └── a11y-frontend.php Skip link, lang attrs, live regions, alt warnings
│ │
│ ├── performance/ Performance optimization (Sprint 6)
│ │ ├── perf-assets.php Font preloads, script defer, resource hints, CLS
│ │ ├── perf-cache.php Object cache wrapper + DB indexes + cleanup cron
│ │ └── i18n-helpers.php Date/number/currency formatters, time-ago
│ │
│ └── cli/ WP-CLI commands (Sprint 3 + Sprint 5)
│ ├── command-update.php wp nectarpress update
│ ├── command-setup.php wp nectarpress setup
│ ├── command-demo.php wp nectarpress demo
│ └── command-doctor.php wp nectarpress doctor
│
├── assets/
│ ├── css/
│ │ ├── a11y.css Skip link, focus indicators, live regions
│ │ ├── fonts.css Self-hosted Mukta + Noto Devanagari declarations
│ │ ├── style-rtl.css RTL overrides (rtlcss + manual)
│ │ ├── wizard.css Setup wizard admin styles
│ │ ├── modern.css Contemporary UI layer (Sprint 1)
│ │ ├── style-dark-mode.css Dark mode overrides
│ │ └── print.css Print stylesheet
│ ├── js/
│ │ ├── a11y.js Focus trap, ticker live region, tab widget
│ │ ├── analytics-loader.js Lazy GTM/GA4/Pixel loader
│ │ └── wizard.js Setup wizard navigation + progress
│ ├── fonts/ Self-hosted WOFF2 files (Mukta, Noto, Kalimati)
│ └── demo-packs/ JSON demo content manifests
│ ├── solo-blog.json
│ ├── sme-portal.json
│ └── enterprise-daily.json
│
├── languages/ i18n POT + PO files
│ ├── nectarpress.pot
│ ├── ne_NP.po / .mo
│ └── ne_IN.po / .mo
│
├── tests/
│ ├── Unit/ PHPUnit unit tests (no WP required)
│ └── bootstrap.php
│
└── docs/ Documentation (you are here)
Data Flow: License Verification¶
cron_04_15 NPT
└── NectarPress_License_Client::verify()
├── Reads stored JWT from wp_options
├── POSTs HMAC-signed payload to license.nectardigit.com/api/verify
│ Payload: { site_url, wp_version, php_version, theme_version,
│ license_key_hash, last_verified_at }
│ Response: { status, plan, features[], expires_at, new_jwt? }
├── Verifies response signature (ES256 / ECDSA P-256)
├── Stores new JWT + expiry in wp_options (autoload=no)
└── Fires nectarpress/license/activated or nectarpress/license/verification_failed
Data Flow: Demo Import¶
NectarPress_Demo_Importer::import($slug, $options)
├── Validates plan access (nectarpress_has_feature)
├── Loads JSON manifest from assets/demo-packs/<slug>.json
├── Generates import token (bin2hex(random_bytes(12)))
├── Import pipeline (order matters — dependencies first):
│ 1. theme_options → update_option() for each key
│ 2. categories → wp_insert_term() (idempotent via get_term_by)
│ 3. tags → wp_insert_term()
│ 4. users → wp_insert_user() (idempotent via get_user_by)
│ 5. media → wp_insert_attachment() (placeholder)
│ 6. posts → wp_insert_post() + update_post_meta(_nectarpress_demo_import_id)
│ 7. bylines → update_post_meta(nr_bylines)
│ 8. ePaper CPTs → wp_insert_post(post_type=np_epaper)
│ 9. ads → wp_insert_post(post_type=np_ad)
│ 10. polls → wp_insert_post(post_type=np_poll)
├── Stores external_id → wp_id map in nectarpress_demo_imports option
└── Fires nectarpress/demo/import_complete
Data Flow: Editorial Post Publish¶
Editor clicks "Approve for Publish" in Gutenberg
└── AJAX → NectarPress_NR_Workflow::handle_transition_ajax()
├── check_ajax_referer('np_nr_transition_nonce')
├── Validates current_user_can(nr_approve_for_publish, $post_id)
│ → map_meta_cap checks beat assignment if user is np_editor
├── NectarPress_NR_Workflow::transition($post_id, 'approved', $actor_id, $comment)
│ ├── Updates nr_workflow_state post meta
│ ├── Writes to wp_nectarpress_audit table
│ ├── Fires nectarpress/nr/workflow_transition action
│ └── Triggers NectarPress_NR_Notifications::notify_transition()
└── Returns JSON { success, new_state, available_transitions[] }
Custom Database Tables¶
wp_nectarpress_audit¶
Created by NectarPress_NR_Audit::maybe_create_table() via dbDelta.
| Column | Type | Description |
|---|---|---|
id | bigint(20) unsigned | Auto-increment primary key |
post_id | bigint(20) | Post being audited |
event_type | varchar(50) | e.g., workflow_transition, byline_change |
from_state | varchar(30) | Previous state |
to_state | varchar(30) | New state |
actor_id | bigint(20) | User who triggered the event |
comment_text | text | Optional comment |
event_payload | longtext (JSON) | Full event data |
ip_address | varchar(45) | IPv4 or IPv6 |
created_at | datetime | UTC timestamp |
Indexed on: (post_id, created_at), (actor_id, created_at), (event_type, created_at).
API Surface¶
License Server (license.nectardigit.com/api/)¶
All endpoints require HMAC-SHA256 signature in X-NP-Signature header.
| Method | Endpoint | Description |
|---|---|---|
| POST | /activate | Activate key on domain |
| POST | /verify | Daily heartbeat verification |
| POST | /deactivate | Remove domain binding |
| GET | /update-info | Check for theme updates |
Internal AJAX (/wp-admin/admin-ajax.php)¶
| Action | Auth | Description |
|---|---|---|
np_wizard_step | nonce | Advance/save wizard step |
np_wizard_import_status | nonce | Poll demo import progress |
np_nr_transition | nonce + cap check | Workflow state transition |
np_nr_byline_save | nonce + cap check | Save multi-byline data |
np_license_activate | nonce + admin | Activate license key |
np_license_deactivate | nonce + admin | Deactivate license |
Security Architecture¶
- License keys: stored encrypted via
nectarpress_encrypt()(AES-256-CBC, key fromwp_salt('auth')) - JWT verification: ECDSA P-256 (ES256) — public key embedded in theme, fingerprint checked against
NECTARPRESS_PUBKEY_FINGERPRINTconstant to prevent on-disk key swap - Rate limiting: token-bucket per IP — anonymous page views never throttled
- File integrity: SHA-256 hash baseline signed with Ed25519; verification runs in 100-file chunks during low-traffic window (02:00–05:00 NPT)