Guides
PHP and WordPress
A plain PHP handler, and WordPress filters for Contact Form 7 and WPForms.
Plain PHP
<?php
function spamex_classify(array $f): ?array {
$body = json_encode([
'name' => $f['name'] ?? '',
'email' => $f['email'] ?? '',
'subject' => $f['subject'] ?? '',
'message' => $f['message'] ?? '',
'honeypot' => $f['website'] ?? '', // your hidden trap field
'form_load_ts' => isset($f['form_load_ts']) ? (float) $f['form_load_ts'] : null,
'submit_ts' => time(),
'ip' => $_SERVER['REMOTE_ADDR'] ?? null,
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
]);
$ch = curl_init('https://api.spamex.dev/v1/classify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SPAMEX_KEY'), 'Content-Type: application/json'],
]);
$res = curl_exec($ch);
$code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
return ($code === 200 && $res) ? json_decode($res, true) : null; // null = fail open
}
$verdict = spamex_classify($_POST);
if ($verdict && $verdict['label'] === 'spam') {
// quarantine; keep $verdict['id'] for feedback
} else {
// deliver
}
WordPress: Contact Form 7
Add to a small plugin or your theme’s functions.php, together with the spamex_classify function above. Define SPAMEX_KEY in wp-config.php and read it with getenv or constant.
add_filter('wpcf7_spam', function ($spam, $submission) {
if ($spam) {
return $spam;
}
$d = $submission->get_posted_data();
$v = spamex_classify([
'name' => $d['your-name'] ?? '',
'email' => $d['your-email'] ?? '',
'subject' => $d['your-subject'] ?? '',
'message' => $d['your-message'] ?? '',
'website' => $d['website'] ?? '',
]);
return $v && $v['label'] === 'spam';
}, 10, 2);
Contact Form 7 keeps spam submissions out of the mail and, with Flamingo installed, in a reviewable list where you can act on the reasons.
WordPress: WPForms
add_filter('wpforms_process_honeypot', '__return_false'); // let spamex judge instead
add_action('wpforms_process', function ($fields, $entry, $form_data) {
$text = implode("\n", array_map(
fn($f) => is_array($f['value'] ?? null) ? '' : (string) ($f['value'] ?? ''),
$fields
));
$v = spamex_classify(['message' => $text, 'email' => $entry['fields'][1] ?? '']);
if ($v && $v['label'] === 'spam') {
wpforms()->process->errors[$form_data['id']]['header'] = 'Your message could not be sent. Please email us instead.';
}
}, 10, 3);
Adjust the field ids to your form. A hidden trap field and load/submit timestamps in the form add two free signals; the quickstart shows how.
Feedback
$ch = curl_init('https://api.spamex.dev/v1/feedback');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode(['id' => $storedVerdictId, 'label' => 'ham']),
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . getenv('SPAMEX_KEY'), 'Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
]);
curl_exec($ch);