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]); $label = $classification['label']; $decision = self::decide_drop_action($label); if ($decision['action'] === 'skip') { Settings::increment_drop_counter($decision['counter_mode']); return; } if (!self::should_enqueue($label, $fields, $submission)) { return; } $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, 'dry_run_drop' => $decision['action'] === 'enqueue_marked', ]); if ($decision['action'] === 'enqueue_marked') { Settings::increment_drop_counter($decision['counter_mode']); } Queue::enqueue([ 'flamingo_post_id' => $post_id, 'form_id' => $form_id, 'source_key' => 'cf7', 'payload_json' => wp_json_encode($payload), 'label' => $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 ''; } /** * Decides what to do with a classified submission based on its label and the * dry-run setting. Pure function — no side effects. * * @return array{action:'enqueue'|'enqueue_marked'|'skip',counter_mode:?string} */ public static function decide_drop_action(string $label): array { if ($label !== 'drop') { return ['action' => 'enqueue', 'counter_mode' => null]; } if (Settings::is_dry_run_drop()) { return ['action' => 'enqueue_marked', 'counter_mode' => 'dry_run']; } return ['action' => 'skip', 'counter_mode' => 'real']; } /** * Filterable gate — allows external code to block non-drop submissions * via filter `cf7stg_should_enqueue`. */ public static function should_enqueue(string $label, array $fields, $submission): bool { return (bool)apply_filters('cf7stg_should_enqueue', true, $label, $fields, $submission); } }