Plugin Directory


Ignore:
Timestamp:
10/05/2026 08:54:56 AM (12 days ago)
Author:
twptech
Message:

Release Sentient Forms 0.13.0 to WordPress.org SVN

File:
1 edited

Legend:

Unmodified
Added
Removed
  • sentient-forms/trunk/includes/adapters/forms/class-sentient-forms-gravity-forms-adapter.php

    r3657995 r3728451  
    108108     */
    109109    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 = [];
    110117
    111118    /**
    … …  
    627634            : [];
    628635
    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 );
    630637
    631638        $cache_key = $this->accepted_submission_cache_key( $entry, $form );
    … …  
    981988     * @return void
    982989     */
    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
    984996    {
    985997        $entry_id = absint( $entry['id'] ?? 0 );
    … …  
    11071119                $this->add_local_action_entry_note_if_missing( $entry_id, 'Sentient Forms AI', $note );
    11081120                $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                }
    11091151                $this->record_failed_spam_delivery_state( $entry_id, $runtime_mapping, $form_id );
    11101152                $events->record( $event );
    … …  
    14961538            $has_qualifying_spam ? 'spam' : $fallback_classification
    14971539        );
    1498         $this->update_entry_meta(
     1540        $this->record_spam_delivery_preference(
    14991541            $entry_id,
    15001542            self::SPAM_NOTIFICATION_PREFERENCE_META_KEY,
    … …  
    15031545                : self::SPAM_NOTIFICATION_PREFERENCE_ALLOW
    15041546        );
    1505         $this->update_entry_meta(
     1547        $this->record_spam_delivery_preference(
    15061548            $entry_id,
    15071549            self::SPAM_WEBHOOK_PREFERENCE_META_KEY,
    … …  
    15501592            {
    15511593                $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 );
    15541596
    15551597                return;
    15561598            }
    15571599
    1558             $this->update_entry_meta(
     1600            $this->record_spam_delivery_preference(
    15591601                $entry_id,
    15601602                self::SPAM_NOTIFICATION_PREFERENCE_META_KEY,
    … …  
    15631605                    : self::SPAM_NOTIFICATION_PREFERENCE_ALLOW
    15641606            );
    1565             $this->update_entry_meta(
     1607            $this->record_spam_delivery_preference(
    15661608                $entry_id,
    15671609                self::SPAM_WEBHOOK_PREFERENCE_META_KEY,
    … …  
    15821624        {
    15831625            $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;
    15861654        }
    15871655    }
    … …  
    16121680        }
    16131681
     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
    16141690        if ( $form_id > 0 )
    16151691        {
    … …  
    16191695        if ( $this->should_suppress_notifications_on_spam( $mapping ) )
    16201696        {
    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            );
    16221702        }
    16231703
    16241704        if ( $this->should_suppress_webhooks_on_spam( $mapping ) )
    16251705        {
    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            );
    16271711        }
    16281712    }
    … …  
    69937077        $this->resolve_deferred_delivery_after_async_completion(
    69947078            $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 ),
    69977085        );
    69987086    }
    … …  
    74247512        }
    74257513
     7514        $captured_hold_failure = $this->outcome_has_captured_hold_failure(
     7515            $outcome,
     7516            $this->get_deferred_notification_mapping_ids( $entry_id )
     7517        );
    74267518        $queued_mapping_ids = $this->queued_native_effect_mapping_ids( $outcome, 'notifications' );
    74277519        $queued_mapping_ids = array_values(
    … …  
    74307522        if ( [] === $queued_mapping_ids )
    74317523        {
     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
    74327535            $this->replay_deferred_notifications( $entry_id, absint( $form['id'] ?? 0 ) );
    74337536            return;
    … …  
    74357538
    74367539        $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        );
    74387547    }
    74397548
    … …  
    74507559        }
    74517560
     7561        $captured_hold_failure = $this->outcome_has_captured_hold_failure(
     7562            $outcome,
     7563            $this->get_deferred_webhook_mapping_ids( $entry_id )
     7564        );
    74527565        $queued_mapping_ids = $this->queued_native_effect_mapping_ids( $outcome, 'webhooks' );
    74537566        $queued_mapping_ids = array_values(
    … …  
    74567569        if ( [] === $queued_mapping_ids )
    74577570        {
     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
    74587582            $this->replay_deferred_webhooks( $entry_id, absint( $form['id'] ?? 0 ) );
    74597583            return;
    … …  
    74617585
    74627586        $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;
    74647626    }
    74657627
    … …  
    75207682        $current_mapping_id = $this->resolve_deferred_notification_mapping_id( $context );
    75217683        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        )
    75227692        {
    75237693            return;
    … …  
    75827752        }
    75837753
     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
    75847762        if ( $should_suppress )
    75857763        {
    … …  
    76247802        }
    76257803
     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
    76267809        $classification = $this->extract_spam_classification_for_context( $context, $result );
    76277810        if ( ! in_array( $classification, [ 'spam', 'likely_spam' ], true ) )
    76287811        {
    7629             return false;
     7812            return $this->should_hold_deferred_delivery_for_unusable_captured_spam_result( $context, $result );
    76307813        }
    76317814
    … …  
    76547837        }
    76557838
     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
    76567844        $classification = $this->extract_spam_classification_for_context( $context, $result );
    76577845        if ( ! in_array( $classification, [ 'spam', 'likely_spam' ], true ) )
    76587846        {
    7659             return false;
     7847            return $this->should_hold_deferred_delivery_for_unusable_captured_spam_result( $context, $result );
    76607848        }
    76617849
    … …  
    76647852
    76657853        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        );
    76667902    }
    76677903
Note: See TracChangeset for help on using the changeset viewer.