API Contract
Audience: integrators writing PHP against the plugin, and contributors changing the plugin’s public surface.
What is public, what is internal
Public (covered by the SemVer policy below):
- Action hooks documented in
docs/developer/hooks.md. - Filter hooks listed under “Filter hooks” in this doc.
- The REST endpoint
POST /wp-json/swh/v1/inbound-email. - The
noprivAJAX endpointwp_ajax_nopriv_swh_submit_csat. - Shortcodes
[submit_ticket]and[helpdesk_portal]with their documented attributes. - Constants
SWH_VERSION,SWH_PLUGIN_DIR,SWH_PLUGIN_URL,SWH_PLUGIN_FILE. - Helper functions documented with
@sincein PHPDoc and called from outside their defining file (e.g.swh_get_secure_ticket_link,swh_send_email,swh_set_ticket_status,swh_render_empty_state).
Internal (may change in any release):
- Functions and classes not listed above. Even if they have
swh_prefix. - Database schema beyond what
data-dictionary.mddocuments. - Admin AJAX endpoints (
wp_ajax_swh_merge_ticket,wp_ajax_swh_send_test_email,wp_ajax_swh_report_data) — these are admin-only and gated bymanage_options. - CSS class names beyond those in
component-inventory.md. - The “advisory” group argument to
swh_get_option()— it is intentionally ignored in v3.7 and consumed by v4.0 schema migration.
If you depend on an internal API, pin to a version and read the changelog before upgrading.
Versioning policy
SemVer. Breaking-change taxonomy:
| Change | Bump |
|---|---|
| Removing a public hook | MAJOR |
| Renaming a public hook | MAJOR |
| Changing a public hook signature (arg count, arg order, arg type) | MAJOR |
| Adding a public hook | MINOR |
| Removing a setting | MAJOR (operator-visible) |
| Changing a setting’s default in a way that alters runtime behaviour | MAJOR |
| Adding a setting | MINOR |
| Changing a REST endpoint URL | MAJOR |
| Adding a REST endpoint or new query/body parameter | MINOR |
| Changing a shortcode attribute default | MAJOR |
| Adding a shortcode attribute | MINOR |
| Removing a meta key without an upgrade routine | MAJOR |
| Adding a meta key | MINOR |
| Bug fixes / internal refactor with no external surface change | PATCH |
When MAJOR is unavoidable, the previous behaviour is wrapped in simple-wp-helpdesk/includes/deprecations.php so old hooks fire alongside new ones for at least one MAJOR cycle. See docs/developer/deprecations.md.
Action hooks
Listed in docs/developer/hooks.md. Enumerated for reference:
| Hook | Signature | Since |
|---|---|---|
swh_pre_ticket_create | (array $data) | 2.1.0 |
swh_ticket_created | (int $ticket_id, array $data) | 2.1.0 |
swh_ticket_status_changed | (int $ticket_id, string $old_status, string $new_status) | 3.7.0 |
swh_ticket_closed | (int $ticket_id, string $previous_status) | 3.7.0 |
swh_ticket_reopened | (int $ticket_id, string $previous_status) | 3.7.0 |
swh_ticket_replied | (int $ticket_id, int $comment_id, bool $is_staff_reply) | 3.7.0 |
swh_ticket_assigned | (int $ticket_id, int $old_user_id, int $new_user_id) | 3.7.0 |
swh_csat_submitted | (int $ticket_id, int $rating) | 3.0.0 |
swh_sla_breached | (int $ticket_id, int $minutes_over) | 3.0.0 |
See docs/developer/hooks.md for usage examples and full documentation.
Filter hooks
Enumerated from grep -rn "apply_filters(\s*['\"]swh_" simple-wp-helpdesk/:
| Hook | Signature | Purpose | Location |
|---|---|---|---|
swh_ticket_statuses | (string[] $statuses) -> string[] | Override the available ticket status labels. | includes/helpers.php:278 |
swh_ticket_priorities | (string[] $priorities) -> string[] | Override the available priority labels. | includes/helpers.php:296 |
swh_allowed_file_types | (string[] $extensions) -> string[] | Override the upload extension allowlist (default jpg, jpeg, jpe, png, gif, pdf, doc, docx, txt). Applied at both submit and reply upload paths. | frontend/class-shortcode.php:57, 517 |
swh_submission_data | (array $data) -> array | Mutate sanitized submission fields before insert. Fires after sanitization, before swh_pre_ticket_create. | frontend/class-shortcode.php:186 |
swh_autoclose_threshold | (int $days) -> int | Override the auto-close threshold (default swh_autoclose_days option). | includes/class-cron.php:51 |
swh_sla_open_statuses | (string[] $statuses) -> string[] | Statuses considered “open” by the SLA cron. | includes/class-cron.php:343 |
swh_rate_limit_ttl | (int $ttl, string $action) -> int | Override the rate-limit TTL per action. | includes/helpers.php:785 |
swh_parse_template | (string $rendered, array $data) -> string | Post-process a parsed email template body or subject. | includes/class-email.php:69 |
swh_email_headers | (string[] $headers, string $to, string $subject) -> string[] | Add or replace email headers. Canonical place to add Reply-To, BCC, or X-* headers. | includes/class-email.php:109 |
REST endpoints
| Method | Path | Auth | Body | Response |
|---|---|---|---|---|
POST | /wp-json/swh/v1/inbound-email | Authorization: Bearer <swh_inbound_secret> header. permission_callback is __return_true (auth enforced inside the handler). | Parsed-email JSON; the handler reads from, subject, body. Subject must contain [TKT-XXXX]. Sender email is compared to _ticket_email of the matched ticket via hash_equals. | 200 on accepted reply; 4xx on auth / parse / match failure. |
Registered at simple-wp-helpdesk/simple-wp-helpdesk.php:213. Handler at simple-wp-helpdesk/includes/class-email.php:222.
Idempotency: the handler does not de-duplicate inbound messages; the upstream MTA / inbound-parse provider is responsible for at-most-once delivery. The handler is safe to call repeatedly — it will insert a reply comment each time.
Authorization header note: Apache running in front of PHP-FPM strips the Authorization header by default. Operators must configure .htaccess or vhost to pass it through, or use a server-internal call path. Test section 47 documents the bypass used in CI (calling swh_handle_inbound_email() directly via wp eval).
AJAX endpoints
| Action | Auth | Purpose |
|---|---|---|
wp_ajax_nopriv_swh_submit_csat (also wp_ajax_swh_submit_csat) | nonce | Records a 1–5 CSAT rating into _ticket_csat post meta. Public surface. |
wp_ajax_swh_merge_ticket | manage_options + nonce | Admin-only ticket merge. Internal. |
wp_ajax_swh_send_test_email | manage_options + nonce | Admin-only test email sender. Internal. |
wp_ajax_swh_report_data | manage_options + nonce | Reporting data fetch with transient caching. Internal. |
Registered:
class-ticket.php:391-392— CSAT.simple-wp-helpdesk.php:173— merge.admin/class-settings.php:1035— test email.admin/class-reporting.php:12— report data.
Shortcodes
Both shortcodes are dispatched by the same handler swh_submit_ticket_shortcode() in frontend/class-shortcode.php.
| Shortcode | Attribute | Default | Effect |
|---|---|---|---|
[submit_ticket] | show_priority | yes | Show/hide the priority select field. |
[submit_ticket] | default_priority | Medium (from swh_default_priority) | Pre-select a priority value. |
[submit_ticket] | default_status | Open (from swh_default_status) | Pre-set the new ticket status on save. |
[submit_ticket] | show_lookup | yes | Show/hide the “lost your link?” lookup form below the submit form. |
[helpdesk_portal] | (same attributes) | When the URL lacks a token, renders either the My Tickets dashboard (logged-in users) or the lookup form (guests). |
Constants
| Constant | Type | Source of truth |
|---|---|---|
SWH_VERSION | string | simple-wp-helpdesk/simple-wp-helpdesk.php:19 |
SWH_PLUGIN_DIR | string | bootstrap |
SWH_PLUGIN_URL | string | bootstrap |
SWH_PLUGIN_FILE | string | bootstrap |
SWH_ICON_1X, SWH_ICON_2X, SWH_MENU_ICON | string | bootstrap (icon URLs) |
These are guaranteed across releases. Renaming or removing any of them is MAJOR.
Deprecation policy
When a public hook or function must be removed:
- The new replacement ships first, in a MINOR release.
- The old name continues to fire (or function) for at least one MAJOR cycle, implemented in
simple-wp-helpdesk/includes/deprecations.php. - Each shim calls
_deprecated_hook()or_deprecated_function()once per page load (WP’s own throttle) so debug logs surface usage. - The shim is removed only in the MAJOR release after the introduction MAJOR.
See docs/developer/deprecations.md for the current shim list.
Update protocol
Update this doc when:
- Any item in the “public surface” lists above is added, removed, renamed, or changes signature.
- A new filter hook is introduced — add a row to the filter table.
- The SemVer taxonomy is amended.
- A deprecation enters or leaves
includes/deprecations.php.