-
Notifications
You must be signed in to change notification settings - Fork 0
/
class-gf-email-filtering-addon.php
348 lines (302 loc) · 14 KB
/
class-gf-email-filtering-addon.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
<?php
use Gravity_Forms\Gravity_Forms\Settings\Fields\Textarea;
GFForms::include_addon_framework();
class GFEmailFilteringAddOn extends GFAddOn
{
protected $_version = GF_EMAIL_FILTERING_ADDON_VERSION;
protected $_min_gravityforms_version = '1.9.16';
protected $_slug = 'gravityforms-addon-email-filtering';
protected $_path = 'gravityforms-addon-email-filtering/gravityforms-addon-email-filtering.php';
protected $_full_path = __FILE__;
protected $_title = 'Gravity Forms Email Filtering';
protected $_short_title = 'Email Filtering Add-On';
/**
* Defines the capability needed to access the Add-On settings page.
*
* @since 2.5.4
* @access protected
* @var string $_capabilities_settings_page The capability needed to access the Add-On settings page.
*/
protected $_capabilities_settings_page = 'gravityforms_email_filtering';
/**
* Defines the capability needed to access the Add-On form settings page.
*
* @since 2.5.4
* @access protected
* @var string $_capabilities_form_settings The capability needed to access the Add-On form settings page.
*/
protected $_capabilities_form_settings = 'gravityforms_email_filtering';
/**
* Defines the capability needed to uninstall the Add-On.
*
* @since 2.5.4
* @access protected
* @var string $_capabilities_uninstall The capability needed to uninstall the Add-On.
*/
protected $_capabilities_uninstall = 'gravityforms_email_filtering_uninstall';
/**
* Defines the capabilities needed for the Post Creation Add-On
*
* @since 2.5.4
* @access protected
* @var array $_capabilities The capabilities needed for the Add-On
*/
protected $_capabilities = ['gravityforms_email_filtering', 'gravityforms_email_filtering_uninstall'];
private static $_instance = null;
public $denylist = [];
public $settings = [];
public $denylist_tooltip = 'Using one entry per line, enter a list of domains or email addresses to filter. You may also include wildcard notations to block top-level domains (e.g., *.ru).';
public $validation_tooltip = 'Please enter a default error message if a denied email is submitted. ';
/**
* Get an instance of this class.
*/
public static function get_instance(): GFEmailFilteringAddOn
{
if (self::$_instance == null) {
self::$_instance = new GFEmailFilteringAddOn();
}
return self::$_instance;
}
/**
* Add tasks or filters here that you want to perform both in the backend and frontend and for ajax requests
*/
public function init(): void {
parent::init();
$this->settings = get_option('gravityformsaddon_' . $this->_slug . '_settings');
$this->denylist = $this->getDenylist();
}
/**
* Add tasks or filters here that you want to perform only in admin.
*/
public function init_admin(): void
{
parent::init_admin();
add_action('gform_editor_js', [$this, 'gform_editor_js']);
add_action('gform_field_advanced_settings', [$this, 'gform_field_advanced_settings'], 10, 2);
add_filter('gform_tooltips', [$this, 'gform_tooltips']);
}
/**
* Add tasks or filters here that you want to perform only in the front end.
*/
public function init_frontend(): void
{
parent::init_frontend();
add_filter('gform_validation', [$this, 'gform_validation']);
}
/**
* Add the additional settings to the plugin settings page.
*/
public function plugin_settings_fields(): array
{
return [
[
'title' => __('Email Filtering Global Settings', 'gf-email-filtering-addon'),
'description' => __('If a filtered email is used in any email field, the form will error on submission. You can also globally define a list of filtered emails and/or domains and a custom validation message if a filtered email is submitted. These settings can be overridden on individual email fields in the advanced settings.', 'gf-email-filtering-addon'),
'fields' => [
[
'label' => __('Global Email Filters', 'gf-email-filtering-addon'),
'type' => 'textarea',
'name' => 'default_email_denylist',
'tooltip' => __("{$this->denylist_tooltip} This setting can be overridden on individual email fields in the advanced settings.", 'gf-email-filtering-addon'),
'class' => 'medium',
'save_callback' => [$this, 'saveDenylist'],
],
[
'label' => __('Global Validation Message', 'gf-email-filtering-addon'),
'type' => 'text',
'name' => 'default_email_denylist_error_msg',
'tooltip' => __("{$this->validation_tooltip} This setting can be overridden on individual email fields in the advanced settings.", 'gf-email-filtering-addon'),
'class' => 'medium',
],
],
],
];
}
/**
* Add setting to the email field's advanced settings.
*
* @param integer $position Specifies the position that the settings will be displayed.
* @param integer $form_id The ID of the form from which the entry value was submitted.
*/
public function gform_field_advanced_settings(int $position, ?int $form_id = null): void
{
// Create settings on position 50 (right after Field Label).
if ($position !== 50) {
return;
}
// Get settings for placeholder text.
if ($this->settings) {
$denylist_placeholder = __('Global Email Filters: ', 'gf-email-filtering-addon') . "\r\n" . implode("\r\n", $this->denylist);
$denylist_msg = __('Global Error Message: ', 'gf-email-filtering-addon') . $this->settings['default_email_denylist_error_msg'];
} else {
$denylist_placeholder = __('Set Email Filters', 'gf-email-filtering-addon');
$denylist_msg = __('Set Error Message', 'gf-email-filtering-addon');
}
$denylist_placeholder = esc_attr($denylist_placeholder);
$denylist_msg = esc_attr($denylist_msg);
$filter_label = esc_html('Filtered Emails', 'gf-email-filtering-addon');
$filter_label .= gform_tooltip('form_field_email_filtering', '', true);
$message_label = esc_html('Filtered Emails Validation Message', 'gf-email-filtering-addon');
$message_label .= gform_tooltip('form_field_email_filtering_validation', '', true);
echo <<<HTML
<li class="email_filtering_setting field_setting">
<label for="field_email_filtering">
$filter_label
</label>
<textarea id="field_email_filtering" class="fieldwidth-3" size="35" onkeyup="SetFieldProperty('email_filtering', this.value);" placeholder="$denylist_placeholder"></textarea>
</li>
<li class="email_filtering_validation field_setting">
<label for="field_email_filtering_validation">
$message_label
</label>
<input type="text" id="field_email_filtering_validation" class="fieldwidth-3" size="35" onkeyup="SetFieldProperty('email_filtering_validation', this.value);" placeholder="$denylist_msg">
</li>
HTML;
}
/**
* Add the additional tooltips to the new fields.
*/
public function gform_tooltips(array $tooltips): array
{
$tooltips['form_field_email_filtering'] = __("{$this->denylist_tooltip} This will override the globally-defined email filters. Enter 'none' to bypass the global setting and allow all email addresses.", 'gf-email-filtering-addon');
$tooltips['form_field_email_filtering_validation'] = __("{$this->validation_tooltip} This will override the globally-defined error message.", 'gf-email-filtering-addon');
return $tooltips;
}
/**
* Inject JavaScript into the form editor page.
*/
public function gform_editor_js(): void
{
echo <<<HTML
<script>
jQuery(document).ready(function($) {
// Alter the setting offered for the email input type.
// This will show all fields that the email field shows plus the custom settings
fieldSettings["email"] += ", .email_filtering_setting, .email_filtering_validation";
// Binding to the load field settings event to initialize custom settings.
$(document).bind("gform_load_field_settings", function(event, field, form){
$("#field_email_filtering").val(field["email_filtering"]);
$("#field_email_filtering_validation").val(field["email_filtering_validation"]);
});
});
</script>
HTML;
}
/**
* Add email filtering to gforms validation function.
* @see https://docs.gravityforms.com/using-gform-validation-hook/
*/
public function gform_validation(array $validation_result): array
{
// Collect form results.
$form = $validation_result['form'];
// Loop through results.
foreach ($form['fields'] as &$field) {
// If this is not an email field, skip.
if (RGFormsModel::get_input_type($field) !== 'email') {
continue;
}
// If the field is hidden by GF conditional logic, skip.
if (RGFormsModel::is_field_hidden($form, $field, [])) {
continue;
}
// Collect banned domains from the form and clean up.
if (! empty($field['email_filtering'])) {
$denylist = $this->getDenylist($field['email_filtering']);
} else {
$denylist = $this->denylist;
}
// Get the domain from user entered email.
$email = $this->clean_string(rgpost("input_{$field['id']}"));
$domain = $this->clean_string(rgar(explode('@', $email), 1));
$tld = strrchr($domain, '.');
/**
* Filter to allow third-party plugins short circuit filtering validation.
*
* @since 2.5.1
* @param bool false Default value.
* @param array $field The Field Object.
* @param string $email The email entered in the input.
* @param string $domain The full domain entered in the input.
* @param string $tld The top level domain entered in the input.
* @param array $denylist List of the blocked emailed/domains.
*/
if (apply_filters('gf_email_filtering_validation_short_circuit', false, $field, $email, $domain, $tld, $denylist)) {
continue;
}
// Create array of banned domains.
$denylist = array_map(function ($item) {
return str_replace('*', '', $item);
}, $denylist);
$denylist = array_filter($denylist);
// No filtered emails, skip.
if (empty($denylist)) {
continue;
}
// If the email, domain or tld isn't denied, skip.
if (! in_array($email, $denylist, true) && ! in_array($domain, $denylist, true) && ! in_array($tld, $denylist, true)) {
continue;
}
/**
* Filter to allow third party plugins to set the email filtering validation.
*
* @since 2.5.1
* @param bool false Default value.
* @param array $field The Field Object.
* @param string $email The email entered in the input.
* @param string $domain The full domain entered in the input.
* @param string $tld The top level domain entered in the input.
* @param array $denylist List of the blocked emailed/domains.
*/
$validation_result['is_valid'] = apply_filters('gf_email_filtering_is_valid', false, $field, $email, $domain, $tld, $denylist);
$field['failed_validation'] = true;
// Set the validation message or use the default.
if (! empty($field['email_filtering_validation'])) {
$validation_message = $field['email_filtering_validation'];
} elseif ($this->settings) {
$validation_message = $this->settings['default_email_denylist_error_msg'];
} else {
$validation_message = __('Sorry, the email address entered is not eligible for this form.', 'gf-email-filtering-addon');
}
/**
* Filter to allow third party plugins to set the email filtering validation.
*
* @since 2.5.1
* @param bool $validation_message The custom validation method.
* @param array $field The Field Object.
* @param string $email The email entered in the input.
* @param string $domain The full domain entered in the input.
* @param string $tld The top level domain entered in the input.
* @param array $denylist List of the blocked emailed/domains.
*/
$field['validation_message'] = apply_filters('gf_email_filtering_validation_message', $validation_message, $field, $email, $domain, $tld, $denylist);
}
$validation_result['form'] = $form;
return $validation_result;
}
/**
* Normalize the denylist setting upon save
*/
public function saveDenylist(Textarea $field, string $setting): string {
$denylist = str_replace(',', "\r\n", $setting);
$denylist = explode("\r\n", $denylist);
$denylist = array_map([$this, 'clean_string'], $denylist);
return implode("\r\n", $denylist);
}
/**
* Get the denylist in an array.
*/
public function getDenylist(string $denylist = ''): array {
$denylist = $denylist ?: $this->settings['default_email_denylist'];
$denylist = str_replace(',', "\r\n", $denylist);
$denylist = explode("\r\n", $denylist);
return array_map([$this, 'clean_string'], $denylist);
}
/**
* Convert a string to lowercase and remove extra whitespace.
*/
protected function clean_string(string $string): string
{
return strtolower(trim($string));
}
}