Documentation · Technical Documentation
Search Alerts Technical Notes
This document describes the Search Agent / Smart Stock Alerts feature: how visitors subscribe to saved searches, how the double-opt-in flow works, where subscriptions are stored and how the matching engine is triggered after each import.
When to use this document
Read this document if you need to:
- Diagnose missing or duplicated subscription confirmation emails.
- Understand how matching is performed and which criteria are supported.
- Plan a database backup or migration that includes the subscription table.
- Audit privacy and data-retention behaviour around saved searches.
Overview
The feature is implemented in AS24CI\Search_Agent and:
- Renders a subscription form (typically inside the search
filter zone) that POSTs to the AJAX action
as24ci_search_agent_subscribe. - Validates the email and selected criteria, generates a 64-character confirmation token and stores a pending row.
- Sends a confirmation email containing a one-click link with the token. Clicking the link activates the subscription.
- On every successful vehicle import, evaluates each active subscription against the new vehicle and sends a notification email when the criteria match.
- Provides one-click unsubscribe links in every notification email.
A bot honeypot field (as24ci_hp_field) silently discards
obvious bot submissions while returning a success response so
bots are not given diagnostic information.
Database table
Subscriptions are stored in <prefix>as24ci_search_agents:
| Column | Type | Notes |
|---|---|---|
id | BIGINT UNSIGNED AUTO_INCREMENT | Primary key. |
name | VARCHAR(255) DEFAULT '' | Optional contact name. |
email | VARCHAR(255) NOT NULL | Validated via is_email(). |
criteria | TEXT | JSON-encoded sanitised criteria. |
token | VARCHAR(64) NOT NULL | 32-byte random_bytes() hex. |
frequency | VARCHAR(20) DEFAULT 'daily' | Notification frequency placeholder. |
status | VARCHAR(20) DEFAULT 'pending' | pending, active, inactive, paused. |
created_at | DATETIME DEFAULT CURRENT_TIMESTAMP | Subscription time. |
confirmed_at | DATETIME NULL | Set when the visitor clicks the confirmation link. |
Indexes: (status), (token). The schema version is stored in
the as24ci_search_agent_db_version option and dbDelta() is
applied as needed.
Supported criteria
Search_Agent::sanitize_criteria() accepts only this whitelist
of keys; all other fields submitted with the form are discarded:
makemodelbody_typedrive_typeconditioncolormin_pricemax_pricemileage_maxstatus
Empty values and the literal string all are treated as "no
constraint" and removed from the stored criteria so the matcher
does not over-filter.
At least one criterion must remain after sanitisation; otherwise
the AJAX endpoint responds with HTTP 422 and an error message.
Step by step: subscription flow
- Visitor selects criteria in the search filter and submits their email to the search-agent form.
- Front-end POSTs
as24ci_search_agent_subscribewith theas24ci_search_agentnonce. Failed nonces return HTTP403. - The plugin validates the email and criteria, generates a token, inserts a pending row and sends the confirmation email.
- Visitor clicks the link
(
?as24ci_sa_action=confirm&token=<token>). Theinithandler verifies the token length (must be 64 characters), updates the row to active and setsconfirmed_at. - On a successful confirmation the visitor is redirected to the
home URL with
?as24ci_sa_msg=confirmed. The unsubscribe flow uses the same redirect mechanism withunsubscribed.
Step by step: matching flow
- The importer fires
as24ci_vehicle_importedafter each create or update. Search_Agent::on_vehicle_imported()runs at priority20.- Updates are skipped — only vehicles that are newly created trigger notifications, to avoid spamming subscribers when an existing vehicle changes.
- Active subscriptions are loaded and their criteria are evaluated against the vehicle's terms and post meta.
- Each match results in one notification email sent via
wp_mail()containing the vehicle title, link, criteria summary and unsubscribe URL.
Configuration reference
The Search Agent feature itself is enabled or disabled via the
plugin feature toggle as24ci_feature_search_agent. Email
templates use plain text and are translatable. The token format
is fixed (64 hex chars from random_bytes(32)).
For the full list of plugin options, see Options And Settings Storage.
Operational notes
- The endpoint is public (
wp_ajax_nopriv_*is registered) so anonymous visitors can subscribe. Authentication relies on the AJAX nonce and the honeypot. - Tokens are cryptographically random and stored as plain hex. Treat the table as containing personal data: name, email and the visitor's stored search criteria.
- Updates do not trigger notifications. Re-imports of existing listings (price drop, mileage update, etc.) are intentionally silent. Verify against the current plugin version if you plan to change this behaviour.
- The
frequencycolumn is included in the schema for future use; the current matcher sends notifications immediately on each new match. - The confirmation and unsubscribe endpoints are routed through
?as24ci_sa_action=...query parameters on the home URL — no custom rewrite rules are introduced. - The table is dropped on uninstall (independent of the *delete data on uninstall* toggle) because it holds personal data. See Uninstall And Cleanup Behavior.
Troubleshooting
- No confirmation email received — check spam folders; then
verify SMTP/mailer configuration. The plugin uses
wp_mail()for all subscription messages. - Confirmation link reports nothing — the token was empty or not exactly 64 characters, or the row was already confirmed. The endpoint silently exits if the token is malformed; this prevents enumeration attacks.
- **Subscriber receives no notifications even after a matching
import** — confirm the vehicle was a new insert (updates do
not notify), the subscription is
active, and at least one criterion is restrictive enough to map to a known meta key / taxonomy term. - Many duplicate notifications during a re-import — should not occur because updates are filtered out, but a full re-import that recreates posts from scratch would trigger notifications. Schedule full re-imports during quiet hours and consider disabling the Search Agent toggle temporarily.
- AJAX subscribe always returns success even with bad data
— the honeypot field was triggered. Confirm the form did not
inadvertently fill the hidden
as24ci_hp_fieldinput.