PluginProbe
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder / 6.2.15
Fluent Forms – Customizable Contact Forms, Survey, Quiz, & Conversational Form Builder v6.2.15
6.2.15 6.2.14 6.2.13 6.2.12 6.2.10 6.2.11 6.2.9 6.2.8 6.2.7 6.2.6 6.2.5 6.2.4 6.2.3 6.2.2 3.6.22 3.6.31 3.6.40 3.6.41 3.6.42 3.6.50 3.6.51 3.6.60 3.6.61 3.6.62 3.6.64 All 197 releases
← All changes | app/Services/FormBuilder/Notifications/EmailNotificationActions.php +201 -16 3.6.40 → 6.2.15 View file →
@@ -1,8 +1,12 @@
1 1 <?php
2 2
3 3 namespace FluentForm\App\Services\FormBuilder\Notifications;
4 4
5 +defined('ABSPATH') or die;
6 +
7 +use FluentForm\App\Helpers\Helper;
8 +use FluentForm\App\Services\FormBuilder\ShortCodeParser;
5 9 use FluentForm\Framework\Foundation\Application;
6 10 use FluentForm\Framework\Helpers\ArrayHelper;
7 11
8 12 class EmailNotificationActions
@@ -15,39 +19,134 @@
15 19 }
16 20
17 21 public function register()
18 22 {
19 - add_filter('fluentform_notifying_async_email_notifications', '__return_false', 9);
23 + add_filter('fluentform/notifying_async_email_notifications', '__return_false', 9);
24 + add_filter('fluentform/notifying_async_notifications', '__return_false', 9);
20 25
21 - add_filter('fluentform_global_notification_active_types', function ($types) {
26 + add_filter('fluentform/global_notification_active_types', function ($types) {
22 27 $types['notifications'] = 'email_notifications';
23 28 return $types;
24 29 });
25 30
26 - add_action('fluentform_integration_notify_notifications', array($this, 'notify'), 10, 4);
31 + add_action('fluentform/integration_notify_notifications', [$this, 'notify'], 10, 4);
32 +
33 + add_action('fluentform/notify_on_form_submit', [$this, 'notifyOnSubmitPaymentForm'], 10, 3);
27 34 }
28 35
36 + public function notifyOnSubmitPaymentForm($submissionId, $submissionData, $form)
37 + {
38 + $emailFeeds = wpFluent()->table('fluentform_form_meta')
39 + ->where('form_id', $form->id)
40 + ->where('meta_key', 'notifications')
41 + ->get();
42 +
43 + if (count($emailFeeds) === 0) {
44 + return;
45 + }
46 +
47 + $formData = $this->getFormData($submissionId);
48 + $notificationManager = new \FluentForm\App\Services\Integrations\GlobalNotificationManager(wpFluentForm());
49 +
50 + $activeEmailFeeds = $notificationManager->getEnabledFeeds($emailFeeds, $formData, $submissionId);
51 + if (! $activeEmailFeeds) {
52 + return;
53 + }
54 +
55 + $onSubmitEmailFeeds = array_filter($activeEmailFeeds, function ($feed) {
56 + return 'payment_form_submit' == ArrayHelper::get($feed, 'settings.feed_trigger_event');
57 + });
58 +
59 + if (! $onSubmitEmailFeeds || 'yes' === Helper::getSubmissionMeta($submissionId, '_ff_on_submit_email_sent')) {
60 + return;
61 + }
62 +
63 + $entry = $this->getEntry($submissionId);
64 +
65 + foreach ($onSubmitEmailFeeds as $feed) {
66 + $processedValues = $feed['settings'];
67 + unset($processedValues['conditionals']);
68 +
69 + $processedValues = ShortCodeParser::parse(
70 + $processedValues,
71 + $submissionId,
72 + $formData,
73 + $form,
74 + false,
75 + $feed['meta_key']
76 + );
77 + $feed['processedValues'] = $processedValues;
78 +
79 + $this->notify($feed, $formData, $entry, $form);
80 + }
81 +
82 + Helper::setSubmissionMeta($submissionId, '_ff_on_submit_email_sent', 'yes', $form->id);
83 + }
84 +
29 85 public function notify($feed, $formData, $entry, $form)
30 86 {
87 + // A payment_success email asserts a settled charge, so gate it on the payment status
88 + // for every payment form -- not only those with a Payment Method field.
89 + $isTriggerOnPaymentSuccess = ArrayHelper::get($feed, 'processedValues.feed_trigger_event') === 'payment_success';
90 + if (!empty($form->has_payment) && $isTriggerOnPaymentSuccess && !$this->paymentSucceeded($entry, $form)) {
91 + return;
92 + }
93 +
31 94 $notifier = $this->app->make(
32 95 'FluentForm\App\Services\FormBuilder\Notifications\EmailNotification'
33 96 );
34 97
35 98 $emailData = $feed['processedValues'];
99 + $emailAttachments = $this->getAttachments($emailData, $formData, $entry, $form);
100 + if ($emailAttachments) {
101 + $emailData['attachments'] = $emailAttachments;
102 + }
36 103
104 + $notifier->notify($emailData, $formData, $form, $entry->id);
105 + }
106 +
107 + // Whether a payment_success trigger may fire for this entry.
108 + protected function paymentSucceeded($entry, $form)
109 + {
110 + $paymentStatus = is_null($entry->payment_status ?? null) ? '' : (string) $entry->payment_status;
111 +
112 + // Settled → a custom/settled status a gateway registered still fires; it is only the
113 + // known-unsettled ones that defer.
114 + if ('' !== $paymentStatus) {
115 + $unsettledStatuses = apply_filters('fluentform/unsettled_payment_statuses', [
116 + 'pending', 'failed', 'requires_review', 'cancelled', 'refunded', 'partially-refunded',
117 + ]);
118 + return !in_array($paymentStatus, $unsettledStatuses, true);
119 + }
120 +
121 + // Empty status is a $0 order: fulfil a coupon-zeroed purchase, not an omitted or zeroed input.
122 + $isFreeOrder = 'yes' === Helper::getSubmissionMeta($entry->id, '_ff_zero_total_free_order');
123 +
124 + return (bool) apply_filters('fluentform/send_payment_success_on_zero_total', $isFreeOrder, $entry, $form);
125 + }
126 +
127 + /**
128 + * @param $emailData
129 + * @param $formData
130 + * @param $entry
131 + * @param $form
132 + *
133 + * @return array
134 + */
135 + private function getAttachments($emailData, $formData, $entry, $form)
136 + {
37 137 $emailAttachments = [];
38 - if(!empty($emailData['attachments']) && is_array($emailData['attachments'])) {
138 +
139 + $uploadDir = wp_upload_dir();
140 +
141 + if (!empty($emailData['attachments']) && is_array($emailData['attachments'])) {
39 142 $attachments = [];
40 143 foreach ($emailData['attachments'] as $name) {
41 144 $fileUrls = ArrayHelper::get($formData, $name);
42 - if($fileUrls && is_array($fileUrls)) {
145 + if ($fileUrls && is_array($fileUrls)) {
43 146 foreach ($fileUrls as $url) {
44 - $filePath = str_replace(
45 - site_url(''),
46 - wp_normalize_path( untrailingslashit( ABSPATH ) ),
47 - $url
48 - );
49 - if(file_exists($filePath)) {
147 + $filePath = $this->resolveUploadAttachmentPath($url, $uploadDir);
148 + if ($filePath) {
50 149 $attachments[] = $filePath;
51 150 }
52 151 }
53 152 }
@@ -53,14 +152,100 @@
53 152 }
54 153 }
55 154 $emailAttachments = $attachments;
56 155 }
156 + $mediaAttachments = ArrayHelper::get($emailData, 'media_attachments');
157 + if (!empty($mediaAttachments) && is_array($mediaAttachments)) {
158 + $attachments = [];
159 + foreach ($mediaAttachments as $file) {
160 + $fileUrl = ArrayHelper::get($file, 'url');
161 + $filePath = $this->resolveUploadAttachmentPath($fileUrl, $uploadDir);
162 + if ($filePath) {
163 + $attachments[] = $filePath;
164 + }
165 + }
166 + $emailAttachments = array_merge($emailAttachments, $attachments);
167 + }
168 +
169 + $emailAttachments = apply_filters_deprecated(
170 + 'fluentform_email_attachments',
171 + [
172 + $emailAttachments,
173 + $emailData,
174 + $formData,
175 + $entry,
176 + $form
177 + ],
178 + FLUENTFORM_FRAMEWORK_UPGRADE,
179 + 'fluentform/email_attachments',
180 + 'Use fluentform/email_attachments instead of fluentform_email_attachments.'
181 + );
182 + // let others to apply attachments
183 + $emailAttachments = apply_filters(
184 + 'fluentform/email_attachments',
185 + $emailAttachments,
186 + $emailData,
187 + $formData,
188 + $entry,
189 + $form
190 + );
191 + return $emailAttachments;
192 + }
57 193
58 - // let others to apply attachments
59 - $emailAttachments = apply_filters('fluentform_email_attachments', $emailAttachments, $emailData, $formData, $entry, $form);
60 - if($emailAttachments) {
61 - $emailData['attachments'] = $emailAttachments;
194 + private function resolveUploadAttachmentPath($fileUrl, $uploadDir)
195 + {
196 + if (!$fileUrl || empty($uploadDir['baseurl']) || empty($uploadDir['basedir'])) {
197 + return null;
62 198 }
63 199
64 - $notifier->notify($emailData, $formData, $form, $entry->id);
200 + $normalizedUrl = strtok($fileUrl, '?#');
201 + if (strpos($normalizedUrl, $uploadDir['baseurl']) !== 0) {
202 + return null;
203 + }
204 +
205 + $relativePath = rawurldecode(str_replace($uploadDir['baseurl'], '', $normalizedUrl));
206 + $relativePath = ltrim(wp_normalize_path($relativePath), '/');
207 +
208 + if (!$relativePath || strpos($relativePath, '../') !== false) {
209 + return null;
210 + }
211 +
212 + $uploadsBaseDir = realpath($uploadDir['basedir']);
213 + if (!$uploadsBaseDir) {
214 + return null;
215 + }
216 +
217 + $uploadsBaseDir = trailingslashit(wp_normalize_path($uploadsBaseDir));
218 + $resolvedPath = realpath($uploadsBaseDir . $relativePath);
219 +
220 + if (!$resolvedPath) {
221 + return null;
222 + }
223 +
224 + $resolvedPath = wp_normalize_path($resolvedPath);
225 + if (strpos($resolvedPath, $uploadsBaseDir) !== 0 || !is_file($resolvedPath)) {
226 + return null;
227 + }
228 +
229 + return $resolvedPath;
230 + }
231 +
232 + public function getFormData($submissionId)
233 + {
234 + $submission = wpFluent()->table('fluentform_submissions')
235 + ->where('id', $submissionId)
236 + ->first();
237 +
238 + if (! $submission) {
239 + return false;
240 + }
241 +
242 + return json_decode($submission->response, true);
243 + }
244 +
245 + public function getEntry($submissionId)
246 + {
247 + return wpFluent()->table('fluentform_submissions')
248 + ->where('id', $submissionId)
249 + ->first();
65 250 }
66 251 }