Changeset 3728451 for sentient-forms/trunk/includes/adapters/forms/class-sentient-forms-gravity-forms-adapter.php
- Timestamp:
- 10/05/2026 08:54:56 AM (12 days ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
sentient-forms/trunk/includes/adapters/forms/class-sentient-forms-gravity-forms-adapter.php
r3657995 r3728451 108 108 */ 109 109 private array $accepted_submission_outcomes = []; 110 111 /** 112 * Current Gravity Forms request spam-delivery suppressions by entry and channel. 113 * 114 * @var array<int, array<string, bool>> 115 */ 116 private array $current_request_spam_delivery_suppressions = []; 110 117 111 118 /** … … 627 634 : []; 628 635 629 $this->apply_validation_local_execution_results_to_entry( $execution_request_ids, $entry, $form );636 $this->apply_validation_local_execution_results_to_entry( $execution_request_ids, $entry, $form, $validation_result ); 630 637 631 638 $cache_key = $this->accepted_submission_cache_key( $entry, $form ); … … 981 988 * @return void 982 989 */ 983 private function apply_validation_local_execution_results_to_entry( array $execution_request_ids, array $entry, array $form ): void 990 private function apply_validation_local_execution_results_to_entry( 991 array $execution_request_ids, 992 array $entry, 993 array $form, 994 ?Sentient_Forms_Validation_Run_Result $validation_result = null 995 ): void 984 996 { 985 997 $entry_id = absint( $entry['id'] ?? 0 ); … … 1107 1119 $this->add_local_action_entry_note_if_missing( $entry_id, 'Sentient Forms AI', $note ); 1108 1120 $runtime_mapping = $this->normalize_local_first_form_mapping( $mapping ) ?? $mapping; 1121 $admitted_mapping = null; 1122 if ( $validation_result instanceof Sentient_Forms_Validation_Run_Result ) 1123 { 1124 foreach ( $validation_result->get_resolved_mappings() as $candidate_mapping ) 1125 { 1126 if ( 1127 is_array( $candidate_mapping ) 1128 && absint( $candidate_mapping['local_form_mapping_id'] ?? 0 ) === $mapping_id 1129 ) 1130 { 1131 $admitted_mapping = $candidate_mapping; 1132 break; 1133 } 1134 } 1135 } 1136 $admitted_settings = is_array( $admitted_mapping ) && is_array( $admitted_mapping['settings'] ?? null ) 1137 ? $admitted_mapping['settings'] 1138 : []; 1139 if ( 1140 is_array( $admitted_mapping ) 1141 && ( 1142 array_key_exists( 'spam_failure_delivery_policy', $admitted_mapping ) 1143 || array_key_exists( 'spam_failure_delivery_policy', $admitted_settings ) 1144 ) 1145 ) 1146 { 1147 $runtime_mapping['spam_failure_delivery_policy'] = $admitted_mapping['spam_failure_delivery_policy'] 1148 ?? $admitted_settings['spam_failure_delivery_policy']; 1149 $runtime_mapping['job_type'] = 'local_mapping'; 1150 } 1109 1151 $this->record_failed_spam_delivery_state( $entry_id, $runtime_mapping, $form_id ); 1110 1152 $events->record( $event ); … … 1496 1538 $has_qualifying_spam ? 'spam' : $fallback_classification 1497 1539 ); 1498 $this-> update_entry_meta(1540 $this->record_spam_delivery_preference( 1499 1541 $entry_id, 1500 1542 self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, … … 1503 1545 : self::SPAM_NOTIFICATION_PREFERENCE_ALLOW 1504 1546 ); 1505 $this-> update_entry_meta(1547 $this->record_spam_delivery_preference( 1506 1548 $entry_id, 1507 1549 self::SPAM_WEBHOOK_PREFERENCE_META_KEY, … … 1550 1592 { 1551 1593 $this->update_entry_meta( $entry_id, 'spam_classification', 'reviewed' ); 1552 $this-> update_entry_meta( $entry_id, self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW );1553 $this-> update_entry_meta( $entry_id, self::SPAM_WEBHOOK_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW );1594 $this->record_spam_delivery_preference( $entry_id, self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1595 $this->record_spam_delivery_preference( $entry_id, self::SPAM_WEBHOOK_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1554 1596 1555 1597 return; 1556 1598 } 1557 1599 1558 $this-> update_entry_meta(1600 $this->record_spam_delivery_preference( 1559 1601 $entry_id, 1560 1602 self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, … … 1563 1605 : self::SPAM_NOTIFICATION_PREFERENCE_ALLOW 1564 1606 ); 1565 $this-> update_entry_meta(1607 $this->record_spam_delivery_preference( 1566 1608 $entry_id, 1567 1609 self::SPAM_WEBHOOK_PREFERENCE_META_KEY, … … 1582 1624 { 1583 1625 $this->update_entry_meta( $entry_id, 'spam_classification', 'ham' ); 1584 $this->update_entry_meta( $entry_id, self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1585 $this->update_entry_meta( $entry_id, self::SPAM_WEBHOOK_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1626 $this->record_spam_delivery_preference( $entry_id, self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1627 $this->record_spam_delivery_preference( $entry_id, self::SPAM_WEBHOOK_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_ALLOW ); 1628 } 1629 } 1630 1631 /** 1632 * Record one entry delivery preference without allowing a current-request 1633 * sibling result to release suppression for that same channel. 1634 * 1635 * @param int $entry_id Gravity Forms entry id. 1636 * @param string $meta_key Native delivery preference meta key. 1637 * @param string $preference The next preference. 1638 */ 1639 private function record_spam_delivery_preference( int $entry_id, string $meta_key, string $preference ): void 1640 { 1641 if ( 1642 self::SPAM_NOTIFICATION_PREFERENCE_ALLOW === $preference 1643 && ! empty( $this->current_request_spam_delivery_suppressions[ $entry_id ][ $meta_key ] ) 1644 ) 1645 { 1646 return; 1647 } 1648 1649 $this->update_entry_meta( $entry_id, $meta_key, $preference ); 1650 1651 if ( self::SPAM_NOTIFICATION_PREFERENCE_SUPPRESS === $preference ) 1652 { 1653 $this->current_request_spam_delivery_suppressions[ $entry_id ][ $meta_key ] = true; 1586 1654 } 1587 1655 } … … 1612 1680 } 1613 1681 1682 if ( 1683 $this->has_captured_spam_failure_delivery_policy( $mapping ) 1684 && ! $this->should_hold_deferred_delivery_for_captured_spam_failure( $mapping ) 1685 ) 1686 { 1687 return; 1688 } 1689 1614 1690 if ( $form_id > 0 ) 1615 1691 { … … 1619 1695 if ( $this->should_suppress_notifications_on_spam( $mapping ) ) 1620 1696 { 1621 $this->update_entry_meta( $entry_id, self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_SUPPRESS ); 1697 $this->record_spam_delivery_preference( 1698 $entry_id, 1699 self::SPAM_NOTIFICATION_PREFERENCE_META_KEY, 1700 self::SPAM_NOTIFICATION_PREFERENCE_SUPPRESS 1701 ); 1622 1702 } 1623 1703 1624 1704 if ( $this->should_suppress_webhooks_on_spam( $mapping ) ) 1625 1705 { 1626 $this->update_entry_meta( $entry_id, self::SPAM_WEBHOOK_PREFERENCE_META_KEY, self::SPAM_NOTIFICATION_PREFERENCE_SUPPRESS ); 1706 $this->record_spam_delivery_preference( 1707 $entry_id, 1708 self::SPAM_WEBHOOK_PREFERENCE_META_KEY, 1709 self::SPAM_NOTIFICATION_PREFERENCE_SUPPRESS 1710 ); 1627 1711 } 1628 1712 } … … 6993 7077 $this->resolve_deferred_delivery_after_async_completion( 6994 7078 $context, 6995 fn (): bool => ! $is_local_mapping_error && $this->should_suppress_notifications_on_spam_for_context( $context ), 6996 fn (): bool => ! $is_local_mapping_error && $this->should_suppress_webhooks_on_spam_for_context( $context ), 7079 fn (): bool => $is_local_mapping_error 7080 ? $this->should_hold_deferred_delivery_for_captured_spam_failure( $context ) 7081 : $this->should_suppress_notifications_on_spam_for_context( $context ), 7082 fn (): bool => $is_local_mapping_error 7083 ? $this->should_hold_deferred_delivery_for_captured_spam_failure( $context ) 7084 : $this->should_suppress_webhooks_on_spam_for_context( $context ), 6997 7085 ); 6998 7086 } … … 7424 7512 } 7425 7513 7514 $captured_hold_failure = $this->outcome_has_captured_hold_failure( 7515 $outcome, 7516 $this->get_deferred_notification_mapping_ids( $entry_id ) 7517 ); 7426 7518 $queued_mapping_ids = $this->queued_native_effect_mapping_ids( $outcome, 'notifications' ); 7427 7519 $queued_mapping_ids = array_values( … … 7430 7522 if ( [] === $queued_mapping_ids ) 7431 7523 { 7524 if ( $captured_hold_failure ) 7525 { 7526 $this->update_entry_meta( 7527 $entry_id, 7528 self::DEFERRED_NOTIFICATION_DECISION_META_KEY, 7529 self::DEFERRED_NOTIFICATION_DECISION_SUPPRESS, 7530 ); 7531 $this->clear_deferred_notification_state( $entry_id ); 7532 return; 7533 } 7534 7432 7535 $this->replay_deferred_notifications( $entry_id, absint( $form['id'] ?? 0 ) ); 7433 7536 return; … … 7435 7538 7436 7539 $this->update_entry_meta( $entry_id, self::DEFERRED_NOTIFICATION_MAPPING_IDS_META_KEY, $queued_mapping_ids ); 7437 $this->update_entry_meta( $entry_id, self::DEFERRED_NOTIFICATION_DECISION_META_KEY, self::DEFERRED_NOTIFICATION_DECISION_PENDING ); 7540 $this->update_entry_meta( 7541 $entry_id, 7542 self::DEFERRED_NOTIFICATION_DECISION_META_KEY, 7543 $captured_hold_failure 7544 ? self::DEFERRED_NOTIFICATION_DECISION_SUPPRESS 7545 : self::DEFERRED_NOTIFICATION_DECISION_PENDING, 7546 ); 7438 7547 } 7439 7548 … … 7450 7559 } 7451 7560 7561 $captured_hold_failure = $this->outcome_has_captured_hold_failure( 7562 $outcome, 7563 $this->get_deferred_webhook_mapping_ids( $entry_id ) 7564 ); 7452 7565 $queued_mapping_ids = $this->queued_native_effect_mapping_ids( $outcome, 'webhooks' ); 7453 7566 $queued_mapping_ids = array_values( … … 7456 7569 if ( [] === $queued_mapping_ids ) 7457 7570 { 7571 if ( $captured_hold_failure ) 7572 { 7573 $this->update_entry_meta( 7574 $entry_id, 7575 self::DEFERRED_WEBHOOK_DECISION_META_KEY, 7576 self::DEFERRED_NOTIFICATION_DECISION_SUPPRESS, 7577 ); 7578 $this->clear_deferred_webhook_state( $entry_id ); 7579 return; 7580 } 7581 7458 7582 $this->replay_deferred_webhooks( $entry_id, absint( $form['id'] ?? 0 ) ); 7459 7583 return; … … 7461 7585 7462 7586 $this->update_entry_meta( $entry_id, self::DEFERRED_WEBHOOK_MAPPING_IDS_META_KEY, $queued_mapping_ids ); 7463 $this->update_entry_meta( $entry_id, self::DEFERRED_WEBHOOK_DECISION_META_KEY, self::DEFERRED_NOTIFICATION_DECISION_PENDING ); 7587 $this->update_entry_meta( 7588 $entry_id, 7589 self::DEFERRED_WEBHOOK_DECISION_META_KEY, 7590 $captured_hold_failure 7591 ? self::DEFERRED_NOTIFICATION_DECISION_SUPPRESS 7592 : self::DEFERRED_NOTIFICATION_DECISION_PENDING, 7593 ); 7594 } 7595 7596 /** 7597 * Determine whether a failed newly admitted mapping captured Hold for one deferred channel. 7598 * 7599 * @param array<int, string> $deferred_mapping_ids 7600 */ 7601 private function outcome_has_captured_hold_failure( 7602 Sentient_Forms_Accepted_Submission_Run_Result $outcome, 7603 array $deferred_mapping_ids 7604 ): bool 7605 { 7606 foreach ( $outcome->get_mapping_outcomes() as $mapping_id => $mapping_outcome ) 7607 { 7608 if ( 'failed' !== $mapping_outcome || ! in_array( (string) $mapping_id, $deferred_mapping_ids, true ) ) 7609 { 7610 continue; 7611 } 7612 7613 $mapping = $outcome->get_resolved_mapping( (string) $mapping_id ); 7614 $settings = is_array( $mapping['settings'] ?? null ) ? $mapping['settings'] : []; 7615 if ( 7616 'local_first' === sanitize_key( (string) ( $mapping['action_type_indicator'] ?? '' ) ) 7617 && array_key_exists( 'spam_failure_delivery_policy', $settings ) 7618 && 'allow_delivery' !== sanitize_key( (string) $settings['spam_failure_delivery_policy'] ) 7619 ) 7620 { 7621 return true; 7622 } 7623 } 7624 7625 return false; 7464 7626 } 7465 7627 … … 7520 7682 $current_mapping_id = $this->resolve_deferred_notification_mapping_id( $context ); 7521 7683 if ( '' === $current_mapping_id ) 7684 { 7685 return; 7686 } 7687 7688 if ( 7689 $this->has_captured_spam_failure_delivery_policy( $context ) 7690 && ! in_array( $current_mapping_id, $pending_mapping_ids, true ) 7691 ) 7522 7692 { 7523 7693 return; … … 7582 7752 } 7583 7753 7754 if ( 7755 $this->has_captured_spam_failure_delivery_policy( $context ) 7756 && ! in_array( $current_mapping_id, $pending_mapping_ids, true ) 7757 ) 7758 { 7759 return; 7760 } 7761 7584 7762 if ( $should_suppress ) 7585 7763 { … … 7624 7802 } 7625 7803 7804 if ( $this->has_captured_spam_failure_delivery_policy( $context ) && ! $this->extract_structured_output_valid( $result ) ) 7805 { 7806 return $this->should_hold_deferred_delivery_for_captured_spam_failure( $context ); 7807 } 7808 7626 7809 $classification = $this->extract_spam_classification_for_context( $context, $result ); 7627 7810 if ( ! in_array( $classification, [ 'spam', 'likely_spam' ], true ) ) 7628 7811 { 7629 return false;7812 return $this->should_hold_deferred_delivery_for_unusable_captured_spam_result( $context, $result ); 7630 7813 } 7631 7814 … … 7654 7837 } 7655 7838 7839 if ( $this->has_captured_spam_failure_delivery_policy( $context ) && ! $this->extract_structured_output_valid( $result ) ) 7840 { 7841 return $this->should_hold_deferred_delivery_for_captured_spam_failure( $context ); 7842 } 7843 7656 7844 $classification = $this->extract_spam_classification_for_context( $context, $result ); 7657 7845 if ( ! in_array( $classification, [ 'spam', 'likely_spam' ], true ) ) 7658 7846 { 7659 return false;7847 return $this->should_hold_deferred_delivery_for_unusable_captured_spam_result( $context, $result ); 7660 7848 } 7661 7849 … … 7664 7852 7665 7853 return ( $confidence ?? 1.0 ) >= $threshold; 7854 } 7855 7856 /** 7857 * A captured policy exists only on checks admitted after this preference was introduced. 7858 * 7859 * @param array<string, mixed> $context 7860 */ 7861 private function has_captured_spam_failure_delivery_policy( array $context ): bool 7862 { 7863 return $this->is_local_mapping_completion_context( $context ) 7864 && array_key_exists( 'spam_failure_delivery_policy', $context ); 7865 } 7866 7867 /** 7868 * @param array<string, mixed> $context 7869 */ 7870 private function should_hold_deferred_delivery_for_captured_spam_failure( array $context ): bool 7871 { 7872 if ( ! $this->has_captured_spam_failure_delivery_policy( $context ) ) 7873 { 7874 return false; 7875 } 7876 7877 return ! is_scalar( $context['spam_failure_delivery_policy'] ) 7878 || 'allow_delivery' !== sanitize_key( (string) $context['spam_failure_delivery_policy'] ); 7879 } 7880 7881 /** 7882 * @param array<string, mixed> $context 7883 * @param array<string, mixed> $result 7884 */ 7885 private function should_hold_deferred_delivery_for_unusable_captured_spam_result( array $context, array $result ): bool 7886 { 7887 if ( ! $this->should_hold_deferred_delivery_for_captured_spam_failure( $context ) ) 7888 { 7889 return false; 7890 } 7891 7892 if ( ! $this->extract_structured_output_valid( $result ) ) 7893 { 7894 return true; 7895 } 7896 7897 return ! in_array( 7898 $this->extract_spam_classification_for_context( $context, $result ), 7899 [ 'ham', 'legitimate', 'spam', 'likely_spam' ], 7900 true 7901 ); 7666 7902 } 7667 7903
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)