feat(cf7-source): capture spam submissions via wpcf7_spam and submission status

This commit is contained in:
Vladimir Bryzgalov
2026-04-17 22:47:13 +05:00
parent 4ce2fac42d
commit eb199c6d40
2 changed files with 103 additions and 0 deletions
+94
View File
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace Cf7stg;
final class CF7Source implements Interface_Spam_Source
{
public function register(): void
{
add_filter('wpcf7_spam', [$this, 'on_spam'], 9999, 2);
add_action('wpcf7_submission', [$this, 'on_submission'], 20, 1);
}
public function on_spam($spam, $submission): bool
{
if ($spam === true && is_object($submission)) {
$this->enqueue_from_submission($submission, 'Honeypot or filter');
}
return (bool)$spam;
}
public function on_submission($submission): void
{
if (!is_object($submission) || !method_exists($submission, 'get_status')) return;
if ($submission->get_status() !== 'spam') return;
$this->enqueue_from_submission($submission, 'Статус spam');
}
private function enqueue_from_submission($submission, string $fallback_reason): void
{
$fields = method_exists($submission, 'get_posted_data') ? (array)$submission->get_posted_data() : [];
$form = method_exists($submission, 'get_contact_form') ? $submission->get_contact_form() : null;
$form_title = $form && method_exists($form, 'title') ? $form->title() : '';
$form_id = $form && method_exists($form, 'id') ? (int)$form->id() : null;
$reason = $this->detect_reason($submission, $fallback_reason);
$classification = Classifier::classify($fields, ['reason' => $reason]);
$post_id = FlamingoHelper::find_post_id_for_submission($submission);
if ($post_id !== null && Queue::exists_for_flamingo($post_id, false)) {
return;
}
$ip = $this->remote_addr();
$ua = isset($_SERVER['HTTP_USER_AGENT']) ? (string)$_SERVER['HTTP_USER_AGENT'] : '';
$payload = MessageFormatter::build([
'fields' => $fields,
'classification' => $classification,
'site_title' => Settings::get_site_title(),
'form_title' => $form_title,
'submitted_at' => wp_date('d.m.Y H:i'),
'reason' => $reason,
'ip' => $ip,
'user_agent' => $ua,
'is_retro' => false,
]);
Queue::enqueue([
'flamingo_post_id' => $post_id,
'form_id' => $form_id,
'source_key' => 'cf7',
'payload_json' => wp_json_encode($payload),
'label' => $classification['label'],
'is_retro' => 0,
]);
}
private function detect_reason($submission, string $fallback): string
{
$data = method_exists($submission, 'get_posted_data') ? (array)$submission->get_posted_data() : [];
// Honeypot plugin by Nocean adds a non-empty field usually prefixed by 'wpcf7_hp' or a custom name.
foreach ($data as $k => $v) {
if (is_string($k) && (stripos($k, 'honeypot') !== false || stripos($k, 'wpcf7_hp') !== false) && !empty($v)) {
return 'Honeypot';
}
}
if (method_exists($submission, 'get_spam_log') && $submission->get_spam_log()) {
return 'Akismet';
}
return $fallback;
}
private function remote_addr(): string
{
foreach (['HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR'] as $key) {
if (!empty($_SERVER[$key])) {
$first = explode(',', (string)$_SERVER[$key])[0];
return trim($first);
}
}
return '';
}
}