PluginProbe
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder / 3.3.1
Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder v3.3.1
3.3.1 V-3.3.0 3.2.2 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 V3.0.3 V3.0.2 -3.0.1 V_3.0.0 1.1.1 1.1.8 1.2 1.3 1.4 1.4.18 1.5.2 1.9 2.0 2.10.0 2.10.1 All 138 releases
bit-form / includes / Core / Fallback / SubmitActionFallback.php

SubmitActionFallback.php in Bit Form – Contact Form, Payment Forms, Multi Step Forms, Calculator & Custom Form Builder 3.3.1, at includes/Core/Fallback/SubmitActionFallback.php

137 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace BitCode\BitForm\Core\Fallback;
4
5 use BitCode\BitForm\Core\Database\DB;
6 use BitCode\BitForm\Core\Database\EmailTemplateModel;
7 use BitCode\BitForm\Core\Database\IntegrationModel;
8 use BitCode\BitForm\Core\Database\SuccessMessageModel;
9 use BitCode\BitForm\Core\Database\WorkFlowModel;
10 use BitCode\BitForm\Core\WorkFlow\Helper;
11
12 /**
13 * Backward-compat migration for the workflow-decoupling refactor.
14 *
15 * Before the refactor, confirmation messages / redirects / email notifications / integrations ran
16 * ONLY when referenced by an active classic workflow. After the refactor they execute by default
17 * (no conditional logic). To preserve existing forms, any such feature that is NOT referenced by an
18 * active classic/basic onsubmit workflow (or referenced only by inactive workflows) is deactivated
19 * here (status = 0). Runs once for existing installs only (FallBack skips fresh installs); idempotent.
20 */
21 class SubmitActionFallback
22 {
23 private const MIGRATED_OPTION = 'bitform_orphan_submit_action_migrated';
24
25 public function deactivateOrphanActions()
26 {
27 if (get_option(self::MIGRATED_OPTION)) {
28 return;
29 }
30
31 // A missing column makes the referenced-ids query error, which would read as "nothing
32 // referenced" and disable every action. Bail without marking migrated so a later request retries.
33 if (!$this->workflowSchemaReady()) {
34 return;
35 }
36
37 $referenced = $this->activeWorkflowReferencedIds();
38 // A query error here must NOT be interpreted as "nothing is referenced" — abort and retry later.
39 if (null === $referenced) {
40 return;
41 }
42
43 $this->deactivateMessages($referenced['successMsg']);
44 $this->deactivateIntegrations($referenced['redirectPage'], $referenced['integrations']);
45 $this->deactivateEmailTemplates($referenced['mailNotify']);
46
47 update_option(self::MIGRATED_OPTION, true, false);
48 }
49
50 /**
51 * Self-heal the columns the referenced-ids query filters on (`workflow_category`,
52 * `workflow_status`); false when they still cannot be created, so the caller retries later.
53 */
54 private function workflowSchemaReady()
55 {
56 return DB::ensureWorkflowSchema();
57 }
58
59 /**
60 * Ids referenced by ANY ACTIVE classic/basic workflow success action (global, ids are unique).
61 * Not limited to onsubmit: integrations/emails can also be referenced by delete workflows
62 * (executeOnDelete runs webhooks/mail) — a feature used by any active workflow must stay active.
63 *
64 * @return array|null keyed action ids, or null when the query errored (caller must abort)
65 */
66 private function activeWorkflowReferencedIds()
67 {
68 $rows = (new WorkFlowModel())->get(
69 ['id', 'workflow_condition'],
70 [
71 'workflow_status' => 1,
72 'workflow_category' => ['classic'],
73 ]
74 );
75 if (is_wp_error($rows)) {
76 // 'result_empty' just means no active classic workflows exist — that is a valid empty set,
77 // not a failure. Any other error means we cannot trust the reference list; abort.
78 return 'result_empty' === $rows->get_error_code() ? Helper::collectReferencedActionIds([]) : null;
79 }
80 return Helper::collectReferencedActionIds($rows);
81 }
82
83 private function deactivateMessages($referencedMsgIds)
84 {
85 $model = new SuccessMessageModel();
86 $messages = $model->get(['id', 'message_config'], []);
87 if (empty($messages) || is_wp_error($messages)) {
88 return;
89 }
90 foreach ($messages as $message) {
91 if (isset($referencedMsgIds[(string) $message->id])) {
92 continue;
93 }
94 $config = !empty($message->message_config) ? json_decode($message->message_config) : null;
95 if (!is_object($config)) {
96 $config = new \stdClass();
97 }
98 if (isset($config->status) && 0 === (int) $config->status) {
99 continue;
100 }
101 $config->status = 0;
102 $model->update(['message_config' => wp_json_encode($config)], ['id' => $message->id]);
103 }
104 }
105
106 private function deactivateIntegrations($referencedRedirectIds, $referencedIntegIds)
107 {
108 $model = new IntegrationModel();
109 $integrations = $model->get(['id', 'integration_type', 'status'], ['category' => 'form']);
110 if (empty($integrations) || is_wp_error($integrations)) {
111 return;
112 }
113 foreach ($integrations as $integration) {
114 $referenced = 'redirectPage' === $integration->integration_type ? $referencedRedirectIds : $referencedIntegIds;
115 if (isset($referenced[(string) $integration->id]) || 0 === (int) $integration->status) {
116 continue;
117 }
118 $model->update(['status' => 0], ['id' => $integration->id]);
119 }
120 }
121
122 private function deactivateEmailTemplates($referencedMailIds)
123 {
124 $model = new EmailTemplateModel();
125 $templates = $model->get(['id', 'status'], []);
126 if (empty($templates) || is_wp_error($templates)) {
127 return;
128 }
129 foreach ($templates as $template) {
130 if (isset($referencedMailIds[(string) $template->id]) || 0 === (int) $template->status) {
131 continue;
132 }
133 $model->update(['status' => 0], ['id' => $template->id]);
134 }
135 }
136 }
137