| @@ -360,9 +360,8 @@ | ||
| 360 | 360 | $this->getLogger()->warning( |
| 361 | 361 | 'Rate limit exceeded for IP', |
| 362 | 362 | array( |
| 363 | 363 | 'plugin' => 'double-opt-in', |
| 364 | - 'ip' => $ip, | |
| 365 | 364 | 'form_id' => $formData->getFormId(), |
| 366 | 365 | ) |
| 367 | 366 | ); |
| 368 | 367 | do_action( 'f12_cf7_doubleoptin_rate_limited', 'ip', $ip, $formData->getFormId() ); |
| @@ -383,9 +382,8 @@ | ||
| 383 | 382 | $this->getLogger()->warning( |
| 384 | 383 | 'Rate limit exceeded for email', |
| 385 | 384 | array( |
| 386 | 385 | 'plugin' => 'double-opt-in', |
| 387 | - 'email' => $recipient, | |
| 388 | 386 | 'form_id' => $formData->getFormId(), |
| 389 | 387 | ) |
| 390 | 388 | ); |
| 391 | 389 | do_action( 'f12_cf7_doubleoptin_rate_limited', 'email', $recipient, $formData->getFormId() ); |
| @@ -423,9 +421,8 @@ | ||
| 423 | 421 | $this->getLogger()->warning( |
| 424 | 422 | 'Recipient validation failed', |
| 425 | 423 | array( |
| 426 | 424 | 'plugin' => 'double-opt-in', |
| 427 | - 'email' => $recipient, | |
| 428 | 425 | 'form_id' => $formData->getFormId(), |
| 429 | 426 | 'reason' => $errorMsg, |
| 430 | 427 | ) |
| 431 | 428 | ); |
| @@ -484,8 +481,81 @@ | ||
| 484 | 481 | $formData->getFormId() |
| 485 | 482 | ); |
| 486 | 483 | |
| 487 | 484 | return null; |
| 485 | + } | |
| 486 | + | |
| 487 | + /** | |
| 488 | + * The consent gate, asked at the form plugin's own validation stage. | |
| 489 | + * | |
| 490 | + * For integrations whose submit hook runs after the form plugin has | |
| 491 | + * already accepted the submission (WPForms `wpforms_process_complete`, | |
| 492 | + * Gravity Forms `gform_after_submission`). By then the form has been | |
| 493 | + * replaced by its confirmation, and a refused consent could only be | |
| 494 | + * reported in a toast over an empty page (5.6.2 click test). Asked from | |
| 495 | + * `wpforms_process` / `gform_validation` instead, the form plugin marks | |
| 496 | + * the checkbox like a missed required field and keeps the input. | |
| 497 | + * | |
| 498 | + * Only a refusal that would stand is returned: DOI on for the form, not | |
| 499 | + * skipped by `f12_cf7_doubleoptin_skip_option`, verdict NOT_GIVEN, gate | |
| 500 | + * enforced. Everything else — a stale field name, the gate switched off | |
| 501 | + * by filter — is left to createOptIn(), which logs it as before. | |
| 502 | + * | |
| 503 | + * @param FormDataInterface $formData The submission, normalized the same | |
| 504 | + * way the submit hook will normalize it. | |
| 505 | + * @param mixed $rawFields What the skip filter receives in the | |
| 506 | + * submit hook of this integration. | |
| 507 | + * | |
| 508 | + * @return OptInError|null The refusal, or null to let the form through. | |
| 509 | + * | |
| 510 | + * @since 5.6.2 | |
| 511 | + */ | |
| 512 | + public function refusedConsentBeforeSubmit( FormDataInterface $formData, $rawFields = array() ): ?OptInError { | |
| 513 | + $formId = $formData->getFormId(); | |
| 514 | + | |
| 515 | + if ( ! $this->isOptInEnabled( $formId ) ) { | |
| 516 | + return null; | |
| 517 | + } | |
| 518 | + | |
| 519 | + if ( apply_filters( 'f12_cf7_doubleoptin_skip_option', false, $formId, $rawFields, $this->getIdentifier() ) ) { | |
| 520 | + return null; | |
| 521 | + } | |
| 522 | + | |
| 523 | + $consentField = (string) ( $this->getFormParameter( $formId )['consent_field'] ?? '' ); | |
| 524 | + if ( $consentField === '' ) { | |
| 525 | + return null; | |
| 526 | + } | |
| 527 | + | |
| 528 | + $verdict = ConsentGate::evaluate( | |
| 529 | + $consentField, | |
| 530 | + $formData->getFields(), | |
| 531 | + $this->getKnownFieldNames( $formId ) | |
| 532 | + ); | |
| 533 | + | |
| 534 | + if ( $verdict !== ConsentGate::NOT_GIVEN || ! ConsentGate::isEnforced( $formId, $this->getIdentifier() ) ) { | |
| 535 | + return null; | |
| 536 | + } | |
| 537 | + | |
| 538 | + $this->getLogger()->info( | |
| 539 | + 'Consent acceptance not given, rejecting submission at validation', | |
| 540 | + array( | |
| 541 | + 'plugin' => 'double-opt-in', | |
| 542 | + 'form_id' => $formId, | |
| 543 | + 'integration' => $this->getIdentifier(), | |
| 544 | + 'consent_field' => $consentField, | |
| 545 | + ) | |
| 546 | + ); | |
| 547 | + | |
| 548 | + /** This action is documented in createOptIn(). */ | |
| 549 | + do_action( 'f12_cf7_doubleoptin_consent_not_given', $formId, $consentField ); | |
| 550 | + | |
| 551 | + return OptInError::fromCode( | |
| 552 | + OptInError::CONSENT_NOT_GIVEN, | |
| 553 | + array( | |
| 554 | + 'form_id' => $formId, | |
| 555 | + 'consent_field' => $consentField, | |
| 556 | + ) | |
| 557 | + ); | |
| 488 | 558 | } |
| 489 | 559 | |
| 490 | 560 | /** |
| 491 | 561 | * Validate the consent-acceptance gate (GDPR Art. 7). |