Mailgun for WordPress - Version 1.8.5

Version Description

Download this release

Release Info

Developer omykhailenko
Plugin Icon 128x128 Mailgun for WordPress
Version 1.8.5
Comparing to
See all releases

Code changes from version 1.7.9 to 1.8.5

.gitignore CHANGED
@@ -1,3 +1,4 @@
1
  svn/
2
  .idea/
3
- docker-compose.yaml
 
1
  svn/
2
  .idea/
3
+ docker-compose.yaml
4
+ .git
CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
  Changelog
2
  =========
 
 
 
 
 
3
 
4
  1.7.9 (2021-05-24)
5
  - API Key description
1
  Changelog
2
  =========
3
+ 1.8.5 (2022-09-21)
4
+ - Make code changes to have more optimized way to use Mailgun object in the code
5
+
6
+ 1.8.3 (2022-08-30)
7
+ - Plugin refactoring. Widget fixes for working with Legacy Widget Block. PHP8.0 support check
8
 
9
  1.7.9 (2021-05-24)
10
  - API Key description
includes/admin.php CHANGED
@@ -1,493 +1,477 @@
1
  <?php
2
 
3
- /*
4
- * mailgun-wordpress-plugin - Sending mail from Wordpress using Mailgun
5
- * Copyright (C) 2016 Mailgun, et al.
6
- *
7
- * This program is free software; you can redistribute it and/or modify
8
- * it under the terms of the GNU General Public License as published by
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License along
18
- * with this program; if not, write to the Free Software Foundation, Inc.,
19
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
- */
21
-
22
- class MailgunAdmin extends Mailgun
23
- {
24
- /**
25
- * @var array Array of "safe" option defaults.
26
- */
27
- private $defaults;
28
-
29
- /**
30
- * Setup backend functionality in WordPress.
31
- *
32
- * @return void
33
- *
34
- * @since 0.1
35
- */
36
- public function __construct()
37
- {
38
- Mailgun::__construct();
39
-
40
- // Load localizations if available
41
- load_plugin_textdomain('mailgun', false, 'mailgun/languages');
42
-
43
- // Activation hook
44
- register_activation_hook($this->plugin_file, array(&$this, 'init'));
45
-
46
- // Hook into admin_init and register settings and potentially register an admin_notice
47
- add_action('admin_init', array(&$this, 'admin_init'));
48
-
49
- // Activate the options page
50
- add_action('admin_menu', array(&$this, 'admin_menu'));
51
-
52
- // Register an AJAX action for testing mail sending capabilities
53
- add_action('wp_ajax_mailgun-test', array(&$this, 'ajax_send_test'));
54
- }
55
-
56
- /**
57
- * Initialize the default options during plugin activation.
58
- *
59
- * @return void
60
- *
61
- * @since 0.1
62
- */
63
- public function init()
64
- {
65
- $sitename = strtolower($_SERVER[ 'SERVER_NAME' ]);
66
- if (substr($sitename, 0, 4) == 'www.'):
67
- $sitename = substr($sitename, 4);
68
- endif;
69
-
70
- $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
71
- $regionDefault = $region ?: 'us';
72
-
73
- $this->defaults = array(
74
- 'region' => $regionDefault,
75
- 'useAPI' => '1',
76
- 'apiKey' => '',
77
- 'domain' => '',
78
- 'username' => '',
79
- 'password' => '',
80
- 'secure' => '1',
81
- 'sectype' => 'tls',
82
- 'track-clicks' => '',
83
- 'track-opens' => '',
84
- 'campaign-id' => '',
85
- 'override-from' => '0',
86
- 'tag' => $sitename,
87
- );
88
- if (!$this->options):
89
- $this->options = $this->defaults;
90
- add_option('mailgun', $this->options);
91
- endif;
92
- }
93
-
94
- /**
95
- * Add the options page.
96
- *
97
- * @return void
98
- *
99
- * @since 0.1
100
- */
101
- public function admin_menu()
102
- {
103
- if (current_user_can('manage_options')):
104
- $this->hook_suffix = add_options_page(__('Mailgun', 'mailgun'), __('Mailgun', 'mailgun'),
105
- 'manage_options', 'mailgun', array(&$this, 'options_page'));
106
- add_options_page(__('Mailgun Lists', 'mailgun'), __('Mailgun Lists', 'mailgun'), 'manage_options',
107
- 'mailgun-lists', array(&$this, 'lists_page'));
108
- add_action("admin_print_scripts-{$this->hook_suffix}", array(&$this, 'admin_js'));
109
- add_filter("plugin_action_links_{$this->plugin_basename}", array(&$this, 'filter_plugin_actions'));
110
- add_action("admin_footer-{$this->hook_suffix}", array(&$this, 'admin_footer_js'));
111
- endif;
112
- }
113
-
114
- /**
115
- * Enqueue javascript required for the admin settings page.
116
- *
117
- * @return void
118
- *
119
- * @since 0.1
120
- */
121
- public function admin_js()
122
- {
123
- wp_enqueue_script('jquery');
124
- }
125
-
126
- /**
127
- * Output JS to footer for enhanced admin page functionality.
128
- *
129
- * @since 0.1
130
- */
131
- public function admin_footer_js()
132
- {
133
- ?>
134
- <script type="text/javascript">
135
- /* <![CDATA[ */
136
- var mailgunApiOrNot = function () {
 
 
137
  if (jQuery('#mailgun-api').val() == 1) {
138
- jQuery('.mailgun-smtp').hide()
139
- jQuery('.mailgun-api').show()
140
  } else {
141
- jQuery('.mailgun-api').hide()
142
- jQuery('.mailgun-smtp').show()
143
  }
144
 
145
- }
146
- var formModified = false
147
- jQuery().ready(function () {
148
  mailgunApiOrNot()
149
  jQuery('#mailgun-api').change(function () {
150
- mailgunApiOrNot()
151
  })
152
  jQuery('#mailgun-test').click(function (e) {
153
- e.preventDefault()
154
- if (formModified) {
155
- var doTest = confirm('<?php _e('The Mailgun plugin configuration has changed since you last saved. Do you wish to test anyway?\n\nClick "Cancel" and then "Save Changes" if you wish to save your changes.',
156
- 'mailgun'); ?>')
157
- if (!doTest) {
158
- return false
 
159
  }
160
- }
161
- jQuery(this).val('<?php _e('Testing...', 'mailgun'); ?>')
162
- jQuery('#mailgun-test-result').text('')
163
- jQuery.get(
164
- ajaxurl,
165
- {
166
- action: 'mailgun-test',
167
- _wpnonce: '<?php echo wp_create_nonce(); ?>'
168
- }
169
- )
170
- .complete(function () {
171
- jQuery('#mailgun-test').val('<?php _e('Test Configuration', 'mailgun'); ?>')
172
- })
173
- .success(function (data) {
174
- alert(
175
- 'Mailgun ' + data.method + ' Test ' + data.message
176
- + '; status "' + data.error + '"'
177
- )
178
- })
179
- .error(function () {
180
- alert('Mailgun Test <?php _e('Failure', 'mailgun'); ?>')
181
- })
182
  })
183
  jQuery('#mailgun-form').change(function () {
184
- formModified = true
185
  })
186
- })
187
- /* ]]> */
188
- </script>
189
- <?php
190
- }
191
-
192
- /**
193
- * Output the options page.
194
- *
195
- * @return void
196
- *
197
- * @since 0.1
198
- */
199
- public function options_page()
200
- {
201
- if (!@include 'options-page.php'):
202
- printf(__('<div id="message" class="updated fade"><p>The options page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
203
- 'mailgun'), dirname(__FILE__) . '/options-page.php');
204
- endif;
205
- }
206
-
207
- /**
208
- * Output the lists page.
209
- *
210
- * @return void
211
- *
212
- * @since 0.1
213
- */
214
- public function lists_page()
215
- {
216
- if (!@include 'lists-page.php'):
217
- printf(__('<div id="message" class="updated fade"><p>The lists page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
218
- 'mailgun'), dirname(__FILE__) . '/lists-page.php');
219
- endif;
220
- }
221
-
222
- /**
223
- * Wrapper function hooked into admin_init to register settings
224
- * and potentially register an admin notice if the plugin hasn't
225
- * been configured yet.
226
- *
227
- * @return void
228
- *
229
- * @since 0.1
230
- */
231
- public function admin_init()
232
- {
233
- $this->register_settings();
234
- $region = $this->get_option('region');
235
- $apiKey = $this->get_option('apiKey');
236
- $useAPI = $this->get_option('useAPI');
237
- $password = $this->get_option('password');
238
-
239
- add_action('admin_notices', array(&$this, 'admin_notices'));
240
- }
241
-
242
- /**
243
- * Whitelist the mailgun options.
244
- *
245
- * @return void
246
- *
247
- * @since 0.1
248
- */
249
- public function register_settings()
250
- {
251
- register_setting('mailgun', 'mailgun', array(&$this, 'validation'));
252
- }
253
-
254
- /**
255
- * Data validation callback function for options.
256
- *
257
- * @param array $options An array of options posted from the options page
258
- *
259
- * @return array
260
- *
261
- * @since 0.1
262
- */
263
- public function validation($options)
264
- {
265
- $apiKey = trim($options[ 'apiKey' ]);
266
- $username = trim($options[ 'username' ]);
267
- if (!empty($apiKey)):
268
- $pos = strpos($apiKey, 'api:');
269
- if ($pos !== false && $pos == 0):
270
- $apiKey = substr($apiKey, 4);
271
- endif;
272
-
273
- if (1 === preg_match('(\w{32}-\w{8}-\w{8})', $apiKey)):
274
- $options[ 'apiKey' ] = $apiKey;
275
- else:
276
- $pos = strpos($apiKey, 'key-');
277
- if ($pos === false || $pos > 4):
278
- $apiKey = "key-{$apiKey}";
279
- endif;
280
-
281
- $options[ 'apiKey' ] = $apiKey;
282
- endif;
283
- endif;
284
-
285
- if (!empty($username)):
286
- $username = preg_replace('/@.+$/', '', $username);
287
- $options[ 'username' ] = $username;
288
- endif;
289
-
290
- foreach ($options as $key => $value) {
291
- $options[ $key ] = trim($value);
292
- }
293
-
294
- if (empty($options[ 'override-from' ])):
295
- $options[ 'override-from' ] = $this->defaults[ 'override-from' ];
296
- endif;
297
-
298
- if (empty($options[ 'sectype' ])):
299
- $options[ 'sectype' ] = $this->defaults[ 'sectype' ];
300
- endif;
301
-
302
- $this->options = $options;
303
-
304
- return $options;
305
- }
306
-
307
- /**
308
- * Function to output an admin notice
309
- * when plugin settings or constants need to be configured
310
- *
311
- * @return void
312
- *
313
- * @since 0.1
314
- */
315
- public function admin_notices()
316
- {
317
- $screen = get_current_screen();
318
- if (!current_user_can('manage_options') || $screen->id == $this->hook_suffix):
319
- return;
320
- endif;
321
-
322
- $smtpPasswordUndefined = ( !$this->get_option('password') && ( !defined('MAILGUN_PASSWORD') || !MAILGUN_PASSWORD ) );
323
- $smtpActiveNotConfigured = ( $this->get_option('useAPI') === '0' && $smtpPasswordUndefined );
324
- $apiRegionUndefined = ( !$this->get_option('region') && ( !defined('MAILGUN_REGION') || !MAILGUN_REGION ) );
325
- $apiKeyUndefined = ( !$this->get_option('apiKey') && ( !defined('MAILGUN_APIKEY') || !MAILGUN_APIKEY ));
326
- $apiActiveNotConfigured = ( $this->get_option('useAPI') === '1' && ( $apiRegionUndefined || $apiKeyUndefined ) );
327
-
328
- if ($apiActiveNotConfigured || $smtpActiveNotConfigured):
329
- ?>
330
- <div id='mailgun-warning' class='notice notice-warning is-dismissible'>
331
- <p>
332
- <?php
333
- printf(
334
- __('Mailgun now supports multiple regions! The U.S. region will be used by default, but you can choose the EU region. You can configure your Mailgun settings in your wp-config.php file or <a href="%1$s">here</a>',
335
- 'mailgun'),
336
- menu_page_url('mailgun', false)
337
- );
338
- ?>
339
- </p>
340
- </div>
341
- <?php
342
- endif;
343
-
344
- if ($this->get_option('override-from') === '1' &&
345
- (!$this->get_option('from-name') || !$this->get_option('from-address'))
346
- ):
347
- ?>
348
- <div id='mailgun-warning' class='notice notice-warning is-dismissible'>
349
- <p>
350
- <strong>
351
- <?php _e('Mailgun is almost ready. ', 'mailgun'); ?>
352
- </strong>
353
- <?php
354
- printf(
355
- __('"Override From" option requires that "From Name" and "From Address" be set to work properly! <a href="%1$s">Configure Mailgun now</a>.',
356
- 'mailgun'),
357
- menu_page_url('mailgun', false)
358
- );
359
- ?>
360
- </p>
361
- </div>
362
- <?php
363
- endif;
364
- }
365
-
366
- /**
367
- * Add a settings link to the plugin actions.
368
- *
369
- * @param array $links Array of the plugin action links
370
- *
371
- * @return array
372
- *
373
- * @since 0.1
374
- */
375
- public function filter_plugin_actions($links)
376
- {
377
- $settings_link = '<a href="' . menu_page_url('mailgun', false) . '">' . __('Settings', 'mailgun') . '</a>';
378
- array_unshift($links, $settings_link);
379
-
380
- return $links;
381
- }
382
-
383
- /**
384
- * AJAX callback function to test mail sending functionality.
385
- *
386
- * @return string
387
- *
388
- * @since 0.1
389
- */
390
- public function ajax_send_test()
391
- {
392
- nocache_headers();
393
- header('Content-Type: application/json');
394
-
395
- if (!current_user_can('manage_options') || !wp_verify_nonce($_GET[ '_wpnonce' ])):
396
- die(
397
- json_encode(
398
- array(
399
- 'message' => __('Unauthorized', 'mailgun'),
400
- 'method' => null,
401
- 'error' => __('Unauthorized', 'mailgun'),
402
- )
403
- )
404
- );
405
- endif;
406
-
407
- $getRegion = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
408
- $useAPI = (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI) ? MAILGUN_USEAPI : $this->get_option('useAPI');
409
- $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
410
- $sectype = (defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : $this->get_option('sectype');
411
-
412
- if ((bool) !$getRegion):
413
- mg_api_last_error(__("Region has not been selected", "mailgun"));
414
- else:
415
- if ($getRegion === 'us'):
416
- $region = __("U.S./North America", "mailgun");
417
- endif;
418
-
419
- if ($getRegion === "eu"):
420
- $region = __("Europe", "mailgun");
421
- endif;
422
- endif;
423
-
424
- if ((bool) $useAPI):
425
- $method = __('HTTP API', 'mailgun');
426
- else:
427
- $method = ((bool) $secure) ? __('Secure SMTP', 'mailgun') : __('Insecure SMTP', 'mailgun');
428
- if ((bool) $secure):
429
- $method = $method . sprintf(__(' via %s', 'mailgun'), $sectype);
430
- endif;
431
- endif;
432
-
433
- $admin_email = get_option('admin_email');
434
- $result = wp_mail(
435
- $admin_email,
436
- __('Mailgun WordPress Plugin Test', 'mailgun'),
437
- sprintf(__("This is a test email generated by the Mailgun WordPress plugin.\n\nIf you have received this message, the requested test has succeeded.\n\nThe sending region is set to %s.\n\nThe method used to send this email was: %s.",
438
- 'mailgun'), $region, $method),
439
- array('Content-Type: text/plain')
440
- );
441
-
442
- if ((bool) $useAPI):
443
- if (!function_exists('mg_api_last_error')):
444
- if (!include dirname(__FILE__) . '/wp-mail-api.php'):
445
- self::deactivate_and_die(dirname(__FILE__) . '/wp-mail-api.php');
446
- endif;
447
- endif;
448
-
449
- $error_msg = mg_api_last_error();
450
- else:
451
- if (!function_exists('mg_smtp_last_error')):
452
- if (!include dirname(__FILE__) . '/wp-mail-smtp.php'):
453
- self::deactivate_and_die(dirname(__FILE__) . '/wp-mail-smtp.php');
454
- endif;
455
- endif;
456
-
457
- $error_msg = mg_smtp_last_error();
458
- endif;
459
-
460
- // Admin Email is used as 'to' parameter, but in case of 'Test Configuration' this message is not clear for the user, so replaced with more appropriate one
461
- if (false !== strpos($error_msg, "'to'") && false !== strpos($error_msg, 'is not a valid')):
462
- $error_msg = sprintf(
463
- "Administration Email Address (%s) is not valid and can't be used for test, you can change it at General Setting page",
464
- $admin_email
465
- );
466
- endif;
467
-
468
- if ($result):
469
- die(
470
- json_encode(
471
- array(
472
- 'message' => __('Success', 'mailgun'),
473
- 'method' => $method,
474
- 'error' => __('Success', 'mailgun'),
475
- )
476
- )
477
- );
478
- else:
479
- // Error message will always be returned in case of failure, if not - connection wasn't successful
480
- $error_msg = $error_msg ? $error_msg : "Can't connect to Mailgun";
481
-
482
- die(
483
- json_encode(
484
- array(
485
- 'message' => __('Failure', 'mailgun'),
486
- 'method' => $method,
487
- 'error' => $error_msg,
488
- )
489
- )
490
- );
491
- endif;
492
- }
493
- }
1
  <?php
2
 
3
+ /*
4
+ * mailgun-wordpress-plugin - Sending mail from WordPress using Mailgun
5
+ * Copyright (C) 2016 Mailgun, et al.
6
+ *
7
+ * This program is free software; you can redistribute it and/or modify
8
+ * it under the terms of the GNU General Public License as published by
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License along
18
+ * with this program; if not, write to the Free Software Foundation, Inc.,
19
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
+ */
21
+
22
+ class MailgunAdmin extends Mailgun
23
+ {
24
+ /**
25
+ * @var array Array of "safe" option defaults.
26
+ */
27
+ private $defaults;
28
+
29
+ /**
30
+ * @var array
31
+ */
32
+ protected $options = [];
33
+
34
+ protected $hook_suffix;
35
+
36
+ /**
37
+ * Setup backend functionality in WordPress.
38
+ *
39
+ * @return void
40
+ *
41
+ */
42
+ public function __construct()
43
+ {
44
+ parent::__construct();
45
+
46
+ // Load localizations if available
47
+ load_plugin_textdomain('mailgun', false, 'mailgun/languages');
48
+
49
+ // Activation hook
50
+ register_activation_hook($this->plugin_file, array(&$this, 'init'));
51
+
52
+ // Hook into admin_init and register settings and potentially register an admin_notice
53
+ add_action('admin_init', array(&$this, 'admin_init'));
54
+
55
+ // Activate the options page
56
+ add_action('admin_menu', array(&$this, 'admin_menu'));
57
+
58
+ // Register an AJAX action for testing mail sending capabilities
59
+ add_action('wp_ajax_mailgun-test', array(&$this, 'ajax_send_test'));
60
+ }
61
+
62
+ /**
63
+ * Initialize the default options during plugin activation.
64
+ *
65
+ * @return void
66
+ *
67
+ */
68
+ public function init()
69
+ {
70
+ $sitename = strtolower($_SERVER['SERVER_NAME']);
71
+ if (substr($sitename, 0, 4) === 'www.') {
72
+ $sitename = substr($sitename, 4);
73
+ }
74
+
75
+ $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
76
+ $regionDefault = $region ?: 'us';
77
+
78
+ $this->defaults = array(
79
+ 'region' => $regionDefault,
80
+ 'useAPI' => '1',
81
+ 'apiKey' => '',
82
+ 'domain' => '',
83
+ 'username' => '',
84
+ 'password' => '',
85
+ 'secure' => '1',
86
+ 'sectype' => 'tls',
87
+ 'track-clicks' => '',
88
+ 'track-opens' => '',
89
+ 'campaign-id' => '',
90
+ 'override-from' => '0',
91
+ 'tag' => $sitename,
92
+ );
93
+ if (!$this->options) {
94
+ $this->options = $this->defaults;
95
+ add_option('mailgun', $this->options);
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Add the options page.
101
+ *
102
+ * @return void
103
+ *
104
+ */
105
+ public function admin_menu()
106
+ {
107
+ if (current_user_can('manage_options')) {
108
+ $this->hook_suffix = add_options_page(__('Mailgun', 'mailgun'), __('Mailgun', 'mailgun'),
109
+ 'manage_options', 'mailgun', array(&$this, 'options_page'));
110
+ add_options_page(__('Mailgun Lists', 'mailgun'), __('Mailgun Lists', 'mailgun'), 'manage_options',
111
+ 'mailgun-lists', array(&$this, 'lists_page'));
112
+ add_action("admin_print_scripts-{$this->hook_suffix}", array(&$this, 'admin_js'));
113
+ add_filter("plugin_action_links_{$this->plugin_basename}", array(&$this, 'filter_plugin_actions'));
114
+ add_action("admin_footer-{$this->hook_suffix}", array(&$this, 'admin_footer_js'));
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Enqueue javascript required for the admin settings page.
120
+ *
121
+ * @return void
122
+ *
123
+ */
124
+ public function admin_js()
125
+ {
126
+ wp_enqueue_script('jquery');
127
+ }
128
+
129
+ /**
130
+ * Output JS to footer for enhanced admin page functionality.
131
+ *
132
+ */
133
+ public function admin_footer_js()
134
+ {
135
+ ?>
136
+ <script type="text/javascript">
137
+ /* <![CDATA[ */
138
+ var mailgunApiOrNot = function () {
139
  if (jQuery('#mailgun-api').val() == 1) {
140
+ jQuery('.mailgun-smtp').hide()
141
+ jQuery('.mailgun-api').show()
142
  } else {
143
+ jQuery('.mailgun-api').hide()
144
+ jQuery('.mailgun-smtp').show()
145
  }
146
 
147
+ }
148
+ var formModified = false
149
+ jQuery().ready(function () {
150
  mailgunApiOrNot()
151
  jQuery('#mailgun-api').change(function () {
152
+ mailgunApiOrNot()
153
  })
154
  jQuery('#mailgun-test').click(function (e) {
155
+ e.preventDefault()
156
+ if (formModified) {
157
+ var doTest = confirm('<?php _e('The Mailgun plugin configuration has changed since you last saved. Do you wish to test anyway?\n\nClick "Cancel" and then "Save Changes" if you wish to save your changes.',
158
+ 'mailgun'); ?>')
159
+ if (!doTest) {
160
+ return false
161
+ }
162
  }
163
+ jQuery(this).val('<?php _e('Testing...', 'mailgun'); ?>')
164
+ jQuery('#mailgun-test-result').text('')
165
+ jQuery.get(
166
+ ajaxurl,
167
+ {
168
+ action: 'mailgun-test',
169
+ _wpnonce: '<?php echo wp_create_nonce(); ?>'
170
+ }
171
+ )
172
+ .complete(function () {
173
+ jQuery('#mailgun-test').val('<?php _e('Test Configuration', 'mailgun'); ?>')
174
+ })
175
+ .success(function (data) {
176
+ alert(
177
+ 'Mailgun ' + data.method + ' Test ' + data.message
178
+ + '; status "' + data.error + '"'
179
+ )
180
+ })
181
+ .error(function () {
182
+ alert('Mailgun Test <?php _e('Failure', 'mailgun'); ?>')
183
+ })
 
184
  })
185
  jQuery('#mailgun-form').change(function () {
186
+ formModified = true
187
  })
188
+ })
189
+ /* ]]> */
190
+ </script>
191
+ <?php
192
+ }
193
+
194
+ /**
195
+ * Output the options page.
196
+ *
197
+ * @return void
198
+ *
199
+ */
200
+ public function options_page()
201
+ {
202
+ if (!@include 'options-page.php') {
203
+ printf(__('<div id="message" class="updated fade"><p>The options page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
204
+ 'mailgun'), __DIR__ . '/options-page.php');
205
+ }
206
+ }
207
+
208
+ /**
209
+ * Output the lists page.
210
+ *
211
+ * @return void
212
+ *
213
+ */
214
+ public function lists_page()
215
+ {
216
+ if (!@include 'lists-page.php') {
217
+ printf(__('<div id="message" class="updated fade"><p>The lists page for the <strong>Mailgun</strong> plugin cannot be displayed. The file <strong>%s</strong> is missing. Please reinstall the plugin.</p></div>',
218
+ 'mailgun'), __DIR__ . '/lists-page.php');
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Wrapper function hooked into admin_init to register settings
224
+ * and potentially register an admin notice if the plugin hasn't
225
+ * been configured yet.
226
+ *
227
+ * @return void
228
+ *
229
+ */
230
+ public function admin_init()
231
+ {
232
+ $this->register_settings();
233
+ $region = $this->get_option('region');
234
+ $apiKey = $this->get_option('apiKey');
235
+ $useAPI = $this->get_option('useAPI');
236
+ $password = $this->get_option('password');
237
+
238
+ add_action('admin_notices', array(&$this, 'admin_notices'));
239
+ }
240
+
241
+ /**
242
+ * Whitelist the mailgun options.
243
+ *
244
+ * @return void
245
+ *
246
+ */
247
+ public function register_settings()
248
+ {
249
+ register_setting('mailgun', 'mailgun', array(&$this, 'validation'));
250
+ }
251
+
252
+ /**
253
+ * Data validation callback function for options.
254
+ *
255
+ * @param array $options An array of options posted from the options page
256
+ *
257
+ * @return array
258
+ *
259
+ */
260
+ public function validation(array $options)
261
+ {
262
+ $apiKey = trim($options['apiKey']);
263
+ $username = trim($options['username']);
264
+ if (!empty($apiKey)) {
265
+ $pos = strpos($apiKey, 'api:');
266
+ if ($pos !== false && $pos == 0) {
267
+ $apiKey = substr($apiKey, 4);
268
+ }
269
+
270
+ if (1 === preg_match('(\w{32}-\w{8}-\w{8})', $apiKey)) {
271
+ $options['apiKey'] = $apiKey;
272
+ } else {
273
+ $pos = strpos($apiKey, 'key-');
274
+ if ($pos === false || $pos > 4) {
275
+ $apiKey = "key-{$apiKey}";
276
+ }
277
+ $options['apiKey'] = $apiKey;
278
+ }
279
+ }
280
+
281
+ if (!empty($username)) {
282
+ $username = preg_replace('/@.+$/', '', $username);
283
+ $options['username'] = $username;
284
+ }
285
+
286
+ foreach ($options as $key => $value) {
287
+ $options[$key] = trim($value);
288
+ }
289
+
290
+ if (empty($options['override-from'])) {
291
+ $options['override-from'] = $this->defaults['override-from'];
292
+ }
293
+
294
+ if (empty($options['sectype'])) {
295
+ $options['sectype'] = $this->defaults['sectype'];
296
+ }
297
+
298
+ $this->options = $options;
299
+
300
+ return $options;
301
+ }
302
+
303
+ /**
304
+ * Function to output an admin notice
305
+ * when plugin settings or constants need to be configured
306
+ *
307
+ * @return void
308
+ *
309
+ */
310
+ public function admin_notices()
311
+ {
312
+ $screen = get_current_screen();
313
+ if (!current_user_can('manage_options') || $screen->id == $this->hook_suffix):
314
+ return;
315
+ endif;
316
+
317
+ $smtpPasswordUndefined = (!$this->get_option('password') && (!defined('MAILGUN_PASSWORD') || !MAILGUN_PASSWORD));
318
+ $smtpActiveNotConfigured = ($this->get_option('useAPI') === '0' && $smtpPasswordUndefined);
319
+ $apiRegionUndefined = (!$this->get_option('region') && (!defined('MAILGUN_REGION') || !MAILGUN_REGION));
320
+ $apiKeyUndefined = (!$this->get_option('apiKey') && (!defined('MAILGUN_APIKEY') || !MAILGUN_APIKEY));
321
+ $apiActiveNotConfigured = ($this->get_option('useAPI') === '1' && ($apiRegionUndefined || $apiKeyUndefined));
322
+
323
+ if ($apiActiveNotConfigured || $smtpActiveNotConfigured):
324
+ ?>
325
+ <div id='mailgun-warning' class='notice notice-warning is-dismissible'>
326
+ <p>
327
+ <?php
328
+ printf(
329
+ __('Mailgun now supports multiple regions! The U.S. region will be used by default, but you can choose the EU region. You can configure your Mailgun settings in your wp-config.php file or <a href="%1$s">here</a>',
330
+ 'mailgun'),
331
+ menu_page_url('mailgun', false)
332
+ );
333
+ ?>
334
+ </p>
335
+ </div>
336
+ <?php
337
+ endif;
338
+
339
+ if ($this->get_option('override-from') === '1' &&
340
+ (!$this->get_option('from-name') || !$this->get_option('from-address'))
341
+ ):
342
+ ?>
343
+ <div id='mailgun-warning' class='notice notice-warning is-dismissible'>
344
+ <p>
345
+ <strong>
346
+ <?php _e('Mailgun is almost ready. ', 'mailgun'); ?>
347
+ </strong>
348
+ <?php
349
+ printf(
350
+ __('"Override From" option requires that "From Name" and "From Address" be set to work properly! <a href="%1$s">Configure Mailgun now</a>.',
351
+ 'mailgun'),
352
+ menu_page_url('mailgun', false)
353
+ );
354
+ ?>
355
+ </p>
356
+ </div>
357
+ <?php
358
+ endif;
359
+ }
360
+
361
+ /**
362
+ * Add a settings link to the plugin actions.
363
+ *
364
+ * @param array $links Array of the plugin action links
365
+ *
366
+ * @return array
367
+ *
368
+ */
369
+ public function filter_plugin_actions($links)
370
+ {
371
+ $settings_link = '<a href="' . menu_page_url('mailgun', false) . '">' . __('Settings', 'mailgun') . '</a>';
372
+ array_unshift($links, $settings_link);
373
+
374
+ return $links;
375
+ }
376
+
377
+ /**
378
+ * AJAX callback function to test mail sending functionality.
379
+ *
380
+ * @return string
381
+ *
382
+ * @throws JsonException
383
+ */
384
+ public function ajax_send_test()
385
+ {
386
+ nocache_headers();
387
+ header('Content-Type: application/json');
388
+
389
+ if (!current_user_can('manage_options') || !wp_verify_nonce($_GET['_wpnonce'])):
390
+ die(
391
+ json_encode(array(
392
+ 'message' => __('Unauthorized', 'mailgun'),
393
+ 'method' => null,
394
+ 'error' => __('Unauthorized', 'mailgun'),
395
+ ), JSON_THROW_ON_ERROR)
396
+ );
397
+ endif;
398
+
399
+ $getRegion = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $this->get_option('region');
400
+ $useAPI = (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI) ? MAILGUN_USEAPI : $this->get_option('useAPI');
401
+ $secure = (defined('MAILGUN_SECURE') && MAILGUN_SECURE) ? MAILGUN_SECURE : $this->get_option('secure');
402
+ $sectype = (defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : $this->get_option('sectype');
403
+
404
+ if (!$getRegion) {
405
+ mg_api_last_error(__("Region has not been selected", "mailgun"));
406
+ } else {
407
+ if ($getRegion === 'us') {
408
+ $region = __("U.S./North America", "mailgun");
409
+ }
410
+ if ($getRegion === "eu") {
411
+ $region = __("Europe", "mailgun");
412
+ }
413
+ }
414
+
415
+ if ($useAPI) {
416
+ $method = __('HTTP API', 'mailgun');
417
+ } else {
418
+ $method = ($secure) ? __('Secure SMTP', 'mailgun') : __('Insecure SMTP', 'mailgun');
419
+ if ($secure) {
420
+ $method .= sprintf(__(' via %s', 'mailgun'), $sectype);
421
+ }
422
+ }
423
+
424
+ $admin_email = get_option('admin_email');
425
+ $result = wp_mail(
426
+ $admin_email,
427
+ __('Mailgun WordPress Plugin Test', 'mailgun'),
428
+ sprintf(__("This is a test email generated by the Mailgun WordPress plugin.\n\nIf you have received this message, the requested test has succeeded.\n\nThe sending region is set to %s.\n\nThe method used to send this email was: %s.",
429
+ 'mailgun'), $region, $method),
430
+ ['Content-Type: text/plain']
431
+ );
432
+
433
+ if ($useAPI) {
434
+ if (!function_exists('mg_api_last_error')) {
435
+ if (!include __DIR__ . '/wp-mail-api.php') {
436
+ $this->deactivate_and_die(__DIR__ . '/wp-mail-api.php');
437
+ }
438
+ }
439
+ $error_msg = mg_api_last_error();
440
+ } else {
441
+ if (!function_exists('mg_smtp_last_error')) {
442
+ if (!include __DIR__ . '/wp-mail-smtp.php') {
443
+ $this->deactivate_and_die(__DIR__ . '/wp-mail-smtp.php');
444
+ }
445
+ }
446
+ $error_msg = mg_smtp_last_error();
447
+ }
448
+
449
+ // Admin Email is used as 'to' parameter, but in case of 'Test Configuration' this message is not clear for the user, so replaced with more appropriate one
450
+ if (false !== strpos($error_msg, "'to'") && false !== strpos($error_msg, 'is not a valid')) {
451
+ $error_msg = sprintf(
452
+ "Administration Email Address (%s) is not valid and can't be used for test, you can change it at General Setting page",
453
+ $admin_email
454
+ );
455
+ }
456
+
457
+ if ($result) {
458
+ die(
459
+ json_encode(array(
460
+ 'message' => __('Success', 'mailgun'),
461
+ 'method' => $method,
462
+ 'error' => __('Success', 'mailgun'),
463
+ ), JSON_THROW_ON_ERROR)
464
+ );
465
+ }
466
+
467
+ // Error message will always be returned in case of failure, if not - connection wasn't successful
468
+ $error_msg = $error_msg ?: "Can't connect to Mailgun";
469
+ die(
470
+ json_encode(array(
471
+ 'message' => __('Failure', 'mailgun'),
472
+ 'method' => $method,
473
+ 'error' => $error_msg,
474
+ ), JSON_THROW_ON_ERROR)
475
+ );
476
+ }
477
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/lists-page.php CHANGED
@@ -19,22 +19,24 @@
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
- global $mailgun;
23
 
24
  // check mailgun domain & api key
25
  $missing_error = '';
26
  $api_key = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $this->get_option('apiKey');
27
  $mailgun_domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $this->get_option('domain');
28
- if ($api_key != ''):
29
- if ($mailgun_domain == ''):
 
30
  $missing_error = '<strong style="color:red;">Missing or invalid Mailgun Domain</strong>. ';
31
- endif;
32
- else:
33
  $missing_error = '<strong style="color:red;">Missing or invalid API Key</strong>. ';
34
- endif;
35
 
36
  // import available lists
37
  $lists_arr = $mailgun->get_lists();
 
38
 
39
  ?>
40
 
@@ -44,7 +46,7 @@ $lists_arr = $mailgun->get_lists();
44
 
45
  <span class="alignright">
46
  <a target="_blank" href="http://www.mailgun.com/">
47
- <img src="https://assets.mailgun.com/img/mailgun.svg" alt="Mailgun" style="width: 10em;"/>
48
  </a>
49
  </span>
50
 
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
+ $mailgun = Mailgun::getInstance();
23
 
24
  // check mailgun domain & api key
25
  $missing_error = '';
26
  $api_key = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $this->get_option('apiKey');
27
  $mailgun_domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $this->get_option('domain');
28
+
29
+ if ($api_key != '') {
30
+ if ($mailgun_domain == '') {
31
  $missing_error = '<strong style="color:red;">Missing or invalid Mailgun Domain</strong>. ';
32
+ }
33
+ } else {
34
  $missing_error = '<strong style="color:red;">Missing or invalid API Key</strong>. ';
35
+ }
36
 
37
  // import available lists
38
  $lists_arr = $mailgun->get_lists();
39
+ $icon = $mailgun->getAssetsPath() . 'icon-128x128.png';
40
 
41
  ?>
42
 
46
 
47
  <span class="alignright">
48
  <a target="_blank" href="http://www.mailgun.com/">
49
+ <img src="<?php echo $icon?>" alt="Mailgun" style="width: 50px;"/>
50
  </a>
51
  </span>
52
 
includes/mg-filter.php CHANGED
@@ -23,26 +23,28 @@
23
  /**
24
  * Tries several methods to get the MIME Content-Type of a file.
25
  *
26
- * @param string $filepath
27
- * @param string $default_type If all methods fail, fallback to $default_type
28
  *
29
- * @return string Content-Type
30
  *
31
- * @since 1.5.4
32
  */
33
- function get_mime_content_type($filepath, $default_type = 'text/plain')
34
  {
35
  if (function_exists('mime_content_type')) {
36
  return mime_content_type($filepath);
37
- } elseif (function_exists('finfo_file')) {
 
 
38
  $fi = finfo_open(FILEINFO_MIME_TYPE);
39
  $ret = finfo_file($fi, $filepath);
40
  finfo_close($fi);
41
 
42
  return $ret;
43
- } else {
44
- return $default_type;
45
  }
 
 
46
  }
47
 
48
  /**
@@ -59,16 +61,16 @@ function get_mime_content_type($filepath, $default_type = 'text/plain')
59
  * `$from_addr` before being returned. The filtered result is null-tested
60
  * before being returned.
61
  *
62
- * @return string
63
  *
64
- * @since 1.5.8
65
  */
66
  function mg_detect_from_name($from_name_header = null)
67
  {
68
  // Get options to avoid strict mode problems
69
  $mg_opts = get_option('mailgun');
70
- $mg_override_from = (isset($mg_opts['override-from'])) ? $mg_opts['override-from'] : null;
71
- $mg_from_name = (isset($mg_opts['from-name'])) ? $mg_opts['from-name'] : null;
72
 
73
  $from_name = null;
74
 
@@ -79,7 +81,7 @@ function mg_detect_from_name($from_name_header = null)
79
  } elseif (defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) {
80
  $from_name = MAILGUN_FROM_NAME;
81
  } else {
82
- if (is_null($mg_from_name) || empty($mg_from_name)) {
83
  if (function_exists('get_current_site')) {
84
  $from_name = get_current_site()->site_name;
85
  } else {
@@ -96,7 +98,7 @@ function mg_detect_from_name($from_name_header = null)
96
  'wp_mail_from_name',
97
  $from_name
98
  );
99
- if (!is_null($filter_from_name) && !empty($filter_from_name)) {
100
  $from_name = $filter_from_name;
101
  }
102
  }
@@ -124,18 +126,18 @@ function mg_detect_from_name($from_name_header = null)
124
  * might appear to be another option but some hosts may refuse to
125
  * relay mail from an unknown domain.
126
  *
127
- * @link http://trac.wordpress.org/ticket/5007.
128
  *
129
- * @return string
130
  *
131
- * @since 1.5.8
132
  */
133
- function mg_detect_from_address($from_addr_header = null)
134
  {
135
  // Get options to avoid strict mode problems
136
  $mg_opts = get_option('mailgun');
137
- $mg_override_from = (isset($mg_opts['override-from'])) ? $mg_opts['override-from'] : null;
138
- $mg_from_addr = (isset($mg_opts['from-address'])) ? $mg_opts['from-address'] : null;
139
 
140
  $from_addr = null;
141
 
@@ -146,7 +148,7 @@ function mg_detect_from_address($from_addr_header = null)
146
  } elseif (defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) {
147
  $from_addr = MAILGUN_FROM_ADDRESS;
148
  } else {
149
- if (is_null($mg_from_addr) || empty($mg_from_addr)) {
150
  if (function_exists('get_current_site')) {
151
  $sitedomain = get_current_site()->domain;
152
  } else {
@@ -156,7 +158,7 @@ function mg_detect_from_address($from_addr_header = null)
156
  }
157
  }
158
 
159
- $from_addr = 'wordpress@'.$sitedomain;
160
  } else {
161
  $from_addr = $mg_from_addr;
162
  }
@@ -193,19 +195,18 @@ function mg_detect_from_address($from_addr_header = null)
193
  * )
194
  * )
195
  *
196
- * @param string|array $headers
197
  *
198
- * @return array
199
  *
200
- * @since 1.5.8
201
  */
202
- function mg_parse_headers($headers = array())
203
  {
204
  if (empty($headers)) {
205
- return array();
206
  }
207
 
208
- $tmp = array();
209
  if (!is_array($headers)) {
210
  $tmp = explode("\n", str_replace("\r\n", "\n", $headers));
211
  } else {
@@ -219,7 +220,7 @@ function mg_parse_headers($headers = array())
219
  $boundary = null;
220
  $parts = null;
221
 
222
- foreach ((array) $tmp as $header) {
223
  // If this header does not contain a ':', is it a fold?
224
  if (false === strpos($header, ':')) {
225
  // Does this header have a boundary?
@@ -239,15 +240,15 @@ function mg_parse_headers($headers = array())
239
  $name = trim($name);
240
  $value = trim($value);
241
 
242
- if ( !isset($new_headers[$name]) ) {
243
  $new_headers[$name] = array();
244
  }
245
 
246
- array_push($new_headers[$name], array(
247
- 'value' => $value,
248
- 'boundary' => $boundary,
249
- 'parts' => $parts,
250
- ));
251
  }
252
  }
253
 
@@ -258,13 +259,13 @@ function mg_parse_headers($headers = array())
258
  * Takes a header array in the format produced by mg_parse_headers and
259
  * dumps them down in to a submittable header format.
260
  *
261
- * @param array $headers Headers to dump
262
  *
263
- * @return string String of \r\n separated headers
264
  *
265
- * @since 1.5.8
266
  */
267
- function mg_dump_headers($headers = null)
268
  {
269
  if (is_null($headers) || !is_array($headers)) {
270
  return '';
@@ -277,7 +278,7 @@ function mg_dump_headers($headers = null)
277
 
278
  foreach ($values as $content) {
279
  // XXX - Is it actually okay to discard `parts` and `boundary`?
280
- array_push($header_values, $content['value']);
281
  }
282
 
283
  $header_string .= sprintf("%s\r\n", implode(", ", $header_values));
@@ -290,18 +291,21 @@ function mg_dump_headers($headers = null)
290
  * Set the API endpoint based on the region selected.
291
  * Value can be "0" if not selected, "us" or "eu"
292
  *
293
- * @param string $getRegion Region value set either in config or Mailgun plugin settings.
294
  *
295
- * @return bool|string
296
  *
297
- * @since 1.5.12
298
  */
299
  function mg_api_get_region($getRegion)
300
  {
301
  switch ($getRegion) {
302
- case 'us': return 'https://api.mailgun.net/v3/';
303
- case 'eu': return 'https://api.eu.mailgun.net/v3/';
304
- default: return false;
 
 
 
305
  }
306
  }
307
 
@@ -309,17 +313,20 @@ function mg_api_get_region($getRegion)
309
  * Set the SMTP endpoint based on the region selected.
310
  * Value can be "0" if not selected, "us" or "eu"
311
  *
312
- * @param string $getRegion Region value set either in config or Mailgun plugin settings.
313
  *
314
- * @return bool|string
315
  *
316
- * @since 1.5.12
317
  */
318
  function mg_smtp_get_region($getRegion)
319
  {
320
  switch ($getRegion) {
321
- case 'us': return 'smtp.mailgun.org';
322
- case 'eu': return 'smtp.eu.mailgun.org';
323
- default: return false;
 
 
 
324
  }
325
  }
23
  /**
24
  * Tries several methods to get the MIME Content-Type of a file.
25
  *
26
+ * @param string $filepath
27
+ * @param string $default_type If all methods fail, fallback to $default_type
28
  *
29
+ * @return string Content-Type
30
  *
31
+ * @since 1.5.4
32
  */
33
+ function get_mime_content_type(string $filepath, string $default_type = 'text/plain'): string
34
  {
35
  if (function_exists('mime_content_type')) {
36
  return mime_content_type($filepath);
37
+ }
38
+
39
+ if (function_exists('finfo_file')) {
40
  $fi = finfo_open(FILEINFO_MIME_TYPE);
41
  $ret = finfo_file($fi, $filepath);
42
  finfo_close($fi);
43
 
44
  return $ret;
 
 
45
  }
46
+
47
+ return $default_type;
48
  }
49
 
50
  /**
61
  * `$from_addr` before being returned. The filtered result is null-tested
62
  * before being returned.
63
  *
64
+ * @return string
65
  *
66
+ * @since 1.5.8
67
  */
68
  function mg_detect_from_name($from_name_header = null)
69
  {
70
  // Get options to avoid strict mode problems
71
  $mg_opts = get_option('mailgun');
72
+ $mg_override_from = $mg_opts['override-from'] ?? null;
73
+ $mg_from_name = $mg_opts['from-name'] ?? null;
74
 
75
  $from_name = null;
76
 
81
  } elseif (defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) {
82
  $from_name = MAILGUN_FROM_NAME;
83
  } else {
84
+ if (empty($mg_from_name)) {
85
  if (function_exists('get_current_site')) {
86
  $from_name = get_current_site()->site_name;
87
  } else {
98
  'wp_mail_from_name',
99
  $from_name
100
  );
101
+ if (!empty($filter_from_name)) {
102
  $from_name = $filter_from_name;
103
  }
104
  }
126
  * might appear to be another option but some hosts may refuse to
127
  * relay mail from an unknown domain.
128
  *
129
+ * @link http://trac.wordpress.org/ticket/5007.
130
  *
131
+ * @return string
132
  *
133
+ * @since 1.5.8
134
  */
135
+ function mg_detect_from_address($from_addr_header = null): string
136
  {
137
  // Get options to avoid strict mode problems
138
  $mg_opts = get_option('mailgun');
139
+ $mg_override_from = $mg_opts['override-from'] ?? null;
140
+ $mg_from_addr = $mg_opts['from-address'] ?? null;
141
 
142
  $from_addr = null;
143
 
148
  } elseif (defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) {
149
  $from_addr = MAILGUN_FROM_ADDRESS;
150
  } else {
151
+ if (empty($mg_from_addr)) {
152
  if (function_exists('get_current_site')) {
153
  $sitedomain = get_current_site()->domain;
154
  } else {
158
  }
159
  }
160
 
161
+ $from_addr = 'wordpress@' . $sitedomain;
162
  } else {
163
  $from_addr = $mg_from_addr;
164
  }
195
  * )
196
  * )
197
  *
198
+ * @param string|array $headers
199
  *
200
+ * @return array
201
  *
202
+ * @since 1.5.8
203
  */
204
+ function mg_parse_headers($headers = []): array
205
  {
206
  if (empty($headers)) {
207
+ return [];
208
  }
209
 
 
210
  if (!is_array($headers)) {
211
  $tmp = explode("\n", str_replace("\r\n", "\n", $headers));
212
  } else {
220
  $boundary = null;
221
  $parts = null;
222
 
223
+ foreach ((array)$tmp as $header) {
224
  // If this header does not contain a ':', is it a fold?
225
  if (false === strpos($header, ':')) {
226
  // Does this header have a boundary?
240
  $name = trim($name);
241
  $value = trim($value);
242
 
243
+ if (!isset($new_headers[$name])) {
244
  $new_headers[$name] = array();
245
  }
246
 
247
+ $new_headers[$name][] = array(
248
+ 'value' => $value,
249
+ 'boundary' => $boundary,
250
+ 'parts' => $parts,
251
+ );
252
  }
253
  }
254
 
259
  * Takes a header array in the format produced by mg_parse_headers and
260
  * dumps them down in to a submittable header format.
261
  *
262
+ * @param array $headers Headers to dump
263
  *
264
+ * @return string String of \r\n separated headers
265
  *
266
+ * @since 1.5.8
267
  */
268
+ function mg_dump_headers($headers = null): string
269
  {
270
  if (is_null($headers) || !is_array($headers)) {
271
  return '';
278
 
279
  foreach ($values as $content) {
280
  // XXX - Is it actually okay to discard `parts` and `boundary`?
281
+ $header_values[] = $content['value'];
282
  }
283
 
284
  $header_string .= sprintf("%s\r\n", implode(", ", $header_values));
291
  * Set the API endpoint based on the region selected.
292
  * Value can be "0" if not selected, "us" or "eu"
293
  *
294
+ * @param string $getRegion Region value set either in config or Mailgun plugin settings.
295
  *
296
+ * @return bool|string
297
  *
298
+ * @since 1.5.12
299
  */
300
  function mg_api_get_region($getRegion)
301
  {
302
  switch ($getRegion) {
303
+ case 'us':
304
+ return 'https://api.mailgun.net/v3/';
305
+ case 'eu':
306
+ return 'https://api.eu.mailgun.net/v3/';
307
+ default:
308
+ return false;
309
  }
310
  }
311
 
313
  * Set the SMTP endpoint based on the region selected.
314
  * Value can be "0" if not selected, "us" or "eu"
315
  *
316
+ * @param string $getRegion Region value set either in config or Mailgun plugin settings.
317
  *
318
+ * @return bool|string
319
  *
320
+ * @since 1.5.12
321
  */
322
  function mg_smtp_get_region($getRegion)
323
  {
324
  switch ($getRegion) {
325
+ case 'us':
326
+ return 'smtp.mailgun.org';
327
+ case 'eu':
328
+ return 'smtp.eu.mailgun.org';
329
+ default:
330
+ return false;
331
  }
332
  }
includes/options-page.php CHANGED
@@ -19,43 +19,45 @@
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
 
 
22
  $mailgun_domain_const = ((defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : null);
23
- $mailgun_domain = $mailgun_domain_const ? $mailgun_domain_const : $this->get_option('domain');
24
 
25
  $mailgun_region_const = ((defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : null);
26
- $mailgun_region = $mailgun_region_const ? $mailgun_region_const : $this->get_option('region');
27
 
28
  $mailgun_api_key_const = ((defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : null);
29
- $mailgun_api_key = $mailgun_api_key_const ? $mailgun_api_key_const : $this->get_option('apiKey');
30
 
31
  $mailgun_username_const = ((defined('MAILGUN_USERNAME') && MAILGUN_USERNAME) ? MAILGUN_USERNAME : null);
32
- $mailgun_username = $mailgun_username_const ? $mailgun_username_const : $this->get_option('username');
33
 
34
  $mailgun_password_const = ((defined('MAILGUN_PASSWORD') && MAILGUN_PASSWORD) ? MAILGUN_PASSWORD : null);
35
- $mailgun_password = $mailgun_password_const ? $mailgun_password_const : $this->get_option('password');
36
 
37
  $mailgun_sectype_const = ((defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : null);
38
- $mailgun_sectype = $mailgun_sectype_const ? $mailgun_sectype_const : $this->get_option('sectype');
39
 
40
  $mailgun_from_name_const = ((defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) ? MAILGUN_FROM_NAME : null);
41
- $mailgun_from_name = $mailgun_from_name_const ? $mailgun_from_name_const : $this->get_option('from-name');
42
 
43
  $mailgun_from_address_const = ((defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) ? MAILGUN_FROM_ADDRESS : null);
44
- $mailgun_from_address = $mailgun_from_address_const ? $mailgun_from_address_const : $this->get_option('from-address');
45
 
46
  $mailgun_secure_const = (defined('MAILGUN_SECURE') ? MAILGUN_SECURE : null);
47
  $mailgun_secure = !is_null($mailgun_secure_const) ? ((string)(1 * $mailgun_secure_const)) : $this->get_option('secure');
48
 
49
  $mailgun_use_api_const = (defined('MAILGUN_USEAPI') ? MAILGUN_USEAPI : null);
50
  $mailgun_use_api = !is_null($mailgun_use_api_const) ? ((string)(1 * $mailgun_use_api_const)) : $this->get_option('useAPI');
51
-
52
 
53
  ?>
54
  <div class="wrap">
55
  <div id="icon-options-general" class="icon32"><br/></div>
56
  <span class="alignright">
57
  <a target="_blank" href="http://www.mailgun.com/">
58
- <img src="https://assets.mailgun.com/img/mailgun.svg" alt="Mailgun" style="width:10em;"/>
59
  </a>
60
  </span>
61
  <h2><?php _e('Mailgun', 'mailgun'); ?></h2>
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
+ $mailgun = Mailgun::getInstance();
23
+
24
  $mailgun_domain_const = ((defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : null);
25
+ $mailgun_domain = $mailgun_domain_const ?: $this->get_option('domain');
26
 
27
  $mailgun_region_const = ((defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : null);
28
+ $mailgun_region = $mailgun_region_const ?: $this->get_option('region');
29
 
30
  $mailgun_api_key_const = ((defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : null);
31
+ $mailgun_api_key = $mailgun_api_key_const ?: $this->get_option('apiKey');
32
 
33
  $mailgun_username_const = ((defined('MAILGUN_USERNAME') && MAILGUN_USERNAME) ? MAILGUN_USERNAME : null);
34
+ $mailgun_username = $mailgun_username_const ?: $this->get_option('username');
35
 
36
  $mailgun_password_const = ((defined('MAILGUN_PASSWORD') && MAILGUN_PASSWORD) ? MAILGUN_PASSWORD : null);
37
+ $mailgun_password = $mailgun_password_const ?: $this->get_option('password');
38
 
39
  $mailgun_sectype_const = ((defined('MAILGUN_SECTYPE') && MAILGUN_SECTYPE) ? MAILGUN_SECTYPE : null);
40
+ $mailgun_sectype = $mailgun_sectype_const ?: $this->get_option('sectype');
41
 
42
  $mailgun_from_name_const = ((defined('MAILGUN_FROM_NAME') && MAILGUN_FROM_NAME) ? MAILGUN_FROM_NAME : null);
43
+ $mailgun_from_name = $mailgun_from_name_const ?: $this->get_option('from-name');
44
 
45
  $mailgun_from_address_const = ((defined('MAILGUN_FROM_ADDRESS') && MAILGUN_FROM_ADDRESS) ? MAILGUN_FROM_ADDRESS : null);
46
+ $mailgun_from_address = $mailgun_from_address_const ?: $this->get_option('from-address');
47
 
48
  $mailgun_secure_const = (defined('MAILGUN_SECURE') ? MAILGUN_SECURE : null);
49
  $mailgun_secure = !is_null($mailgun_secure_const) ? ((string)(1 * $mailgun_secure_const)) : $this->get_option('secure');
50
 
51
  $mailgun_use_api_const = (defined('MAILGUN_USEAPI') ? MAILGUN_USEAPI : null);
52
  $mailgun_use_api = !is_null($mailgun_use_api_const) ? ((string)(1 * $mailgun_use_api_const)) : $this->get_option('useAPI');
53
+ $icon = $mailgun->getAssetsPath() . 'icon-128x128.png';
54
 
55
  ?>
56
  <div class="wrap">
57
  <div id="icon-options-general" class="icon32"><br/></div>
58
  <span class="alignright">
59
  <a target="_blank" href="http://www.mailgun.com/">
60
+ <img src="<?php echo $icon?>" alt="Mailgun" style="width:50px;"/>
61
  </a>
62
  </span>
63
  <h2><?php _e('Mailgun', 'mailgun'); ?></h2>
includes/widget.php CHANGED
@@ -19,7 +19,7 @@
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
- class list_widget extends WP_Widget
23
  {
24
  public function __construct()
25
  {
@@ -37,8 +37,11 @@ class list_widget extends WP_Widget
37
  // This is where the action happens
38
  public function widget($args, $instance)
39
  {
40
- global $mailgun;
41
 
 
 
 
42
  // vars
43
  $list_address = apply_filters('list_address', $instance['list_address']);
44
 
@@ -60,8 +63,6 @@ class list_widget extends WP_Widget
60
  // Widget Backend
61
  public function form($instance)
62
  {
63
- global $mailgun;
64
-
65
  if (isset($instance['list_address'])) {
66
  $list_address = $instance['list_address'];
67
  } else {
@@ -74,8 +75,8 @@ class list_widget extends WP_Widget
74
  $collect_name = '';
75
  }
76
 
77
- $list_title = isset($instance['list_title']) ? $instance['list_title'] : null;
78
- $list_description = isset($instance['list_description']) ? $instance['list_description'] : null;
79
 
80
  // Widget admin form
81
  ?>
19
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20
  */
21
 
22
+ class list_widget extends \WP_Widget
23
  {
24
  public function __construct()
25
  {
37
  // This is where the action happens
38
  public function widget($args, $instance)
39
  {
40
+ $mailgun = Mailgun::getInstance();
41
 
42
+ if (!isset($instance['list_address']) || !$instance['list_address']) {
43
+ return;
44
+ }
45
  // vars
46
  $list_address = apply_filters('list_address', $instance['list_address']);
47
 
63
  // Widget Backend
64
  public function form($instance)
65
  {
 
 
66
  if (isset($instance['list_address'])) {
67
  $list_address = $instance['list_address'];
68
  } else {
75
  $collect_name = '';
76
  }
77
 
78
+ $list_title = $instance['list_title'] ?? null;
79
+ $list_description = $instance['list_description'] ?? null;
80
 
81
  // Widget admin form
82
  ?>
includes/wp-mail-api.php CHANGED
@@ -20,19 +20,19 @@
20
  */
21
 
22
  // Include MG filter functions
23
- if (!include dirname(__FILE__).'/mg-filter.php') {
24
- Mailgun::deactivate_and_die(dirname(__FILE__).'/mg-filter.php');
25
  }
26
 
27
  /**
28
  * mg_api_last_error is a compound getter/setter for the last error that was
29
  * encountered during a Mailgun API call.
30
  *
31
- * @param string $error OPTIONAL
32
  *
33
- * @return string Last error that occurred.
34
  *
35
- * @since 1.5.0
36
  */
37
  function mg_api_last_error($error = null)
38
  {
@@ -40,12 +40,12 @@ function mg_api_last_error($error = null)
40
 
41
  if (null === $error) {
42
  return $last_error;
43
- } else {
44
- $tmp = $last_error;
45
- $last_error = $error;
46
-
47
- return $tmp;
48
  }
 
 
 
 
 
49
  }
50
 
51
  /*
@@ -79,14 +79,14 @@ function mg_mutate_to_rcpt_vars_cb($to_addrs)
79
 
80
  // TODO: Also add folding to prevent hitting the 998 char limit on headers.
81
  return array(
82
- 'to' => '%recipient%',
83
  'rcpt_vars' => json_encode($rcpt_vars),
84
  );
85
  }
86
  }
87
 
88
  return array(
89
- 'to' => $to_addrs,
90
  'rcpt_vars' => null,
91
  );
92
  }
@@ -98,365 +98,354 @@ function mg_mutate_to_rcpt_vars_cb($to_addrs)
98
  * Based off of the core wp_mail function, but with modifications required to
99
  * send email using the Mailgun HTTP API
100
  *
101
- * @param string|array $to Array or comma-separated list of email addresses to send message.
102
- * @param string $subject Email subject
103
- * @param string $message Message contents
104
- * @param string|array $headers Optional. Additional headers.
105
- * @param string|array $attachments Optional. Files to attach.
106
  *
107
- * @return bool Whether the email contents were sent successfully.
108
  *
109
  * @global PHPMailer\PHPMailer\PHPMailer $phpmailer
110
  *
111
- * @since 0.1
112
  */
113
  if (!function_exists('wp_mail')) {
114
- function wp_mail($to, $subject, $message, $headers = '', $attachments = array())
115
- {
116
- // Compact the input, apply the filters, and extract them back out
117
- extract(apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments')));
 
 
 
 
118
 
119
- $mailgun = get_option('mailgun');
120
- $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $mailgun['region'];
121
- $apiKey = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $mailgun['apiKey'];
122
- $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $mailgun['domain'];
123
 
124
- if (empty($apiKey) || empty($domain)) {
125
- return false;
126
- }
127
 
128
- // If a region is not set via defines or through the options page, default to US region.
129
- if (!((bool) $region)) {
130
- error_log('[Mailgun] No region configuration was found! Defaulting to US region.');
131
- $region = 'us';
132
- }
133
 
134
- if (!is_array($attachments)) {
135
- $attachments = explode("\n", str_replace("\r\n", "\n", $attachments));
136
- }
137
 
138
- // Headers
139
- if (empty($headers)) {
140
- $headers = array();
141
- } else {
142
- if (!is_array($headers)) {
143
- // Explode the headers out, so this function can take both
144
- // string headers and an array of headers.
145
- $tempheaders = explode("\n", str_replace("\r\n", "\n", $headers));
146
  } else {
147
- $tempheaders = $headers;
148
- }
149
- $headers = array();
150
- $cc = array();
151
- $bcc = array();
152
-
153
- // If it's actually got contents
154
- if (!empty($tempheaders)) {
155
- // Iterate through the raw headers
156
- foreach ((array) $tempheaders as $header) {
157
- if (strpos($header, ':') === false) {
158
- if (false !== stripos($header, 'boundary=')) {
159
- $parts = preg_split('/boundary=/i', trim($header));
160
- $boundary = trim(str_replace(array("'", '"'), '', $parts[1]));
161
- }
162
- continue;
163
- }
164
- // Explode them out
165
- list($name, $content) = explode(':', trim($header), 2);
166
-
167
- // Cleanup crew
168
- $name = trim($name);
169
- $content = trim($content);
170
-
171
- switch (strtolower($name)) {
172
- // Mainly for legacy -- process a From: header if it's there
173
- case 'from':
174
- if (strpos($content, '<') !== false) {
175
- // So... making my life hard again?
176
- $from_name = substr($content, 0, strpos($content, '<') - 1);
177
- $from_name = str_replace('"', '', $from_name);
178
- $from_name = trim($from_name);
179
-
180
- $from_email = substr($content, strpos($content, '<') + 1);
181
- $from_email = str_replace('>', '', $from_email);
182
- $from_email = trim($from_email);
183
- } else {
184
- $from_email = trim($content);
185
- }
186
- break;
187
- case 'content-type':
188
- if (strpos($content, ';') !== false) {
189
- list($type, $charset) = explode(';', $content);
190
- $content_type = trim($type);
191
- if (false !== stripos($charset, 'charset=')) {
192
- $charset = trim(str_replace(array('charset=', '"'), '', $charset));
193
- } elseif (false !== stripos($charset, 'boundary=')) {
194
- $boundary = trim(str_replace(array('BOUNDARY=', 'boundary=', '"'), '', $charset));
195
- $charset = '';
196
  }
197
- } else {
198
- $content_type = trim($content);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
199
  }
200
- break;
201
- case 'cc':
202
- $cc = array_merge((array) $cc, explode(',', $content));
203
- break;
204
- case 'bcc':
205
- $bcc = array_merge((array) $bcc, explode(',', $content));
206
- break;
207
- default:
208
- // Add it to our grand headers array
209
- $headers[trim($name)] = trim($content);
210
- break;
211
  }
212
  }
213
  }
214
- }
215
-
216
- if (!isset($from_name)) {
217
- $from_name = null;
218
- }
219
 
220
- if (!isset($from_email)) {
221
- $from_email = null;
222
- }
223
 
224
- $from_name = mg_detect_from_name($from_name);
225
- $from_email = mg_detect_from_address($from_email);
 
226
 
227
- $body = array(
228
- 'from' => "{$from_name} <{$from_email}>",
229
- 'to' => $to,
230
- 'subject' => $subject,
231
- );
232
 
233
- $rcpt_data = apply_filters('mg_mutate_to_rcpt_vars', $to);
234
- if (!is_null($rcpt_data['rcpt_vars'])) {
235
- $body['recipient-variables'] = $rcpt_data['rcpt_vars'];
236
- }
 
237
 
238
- $body['o:tag'] = array();
239
- $body['o:tracking-clicks'] = !empty($mailgun['track-clicks']) ? $mailgun['track-clicks'] : 'no';
240
- $body['o:tracking-opens'] = empty($mailgun['track-opens']) ? 'no' : 'yes';
 
241
 
242
- // this is the wordpress site tag
243
- if (isset($mailgun['tag'])) {
244
- $tags = explode(',', str_replace(' ', '', $mailgun['tag']));
245
- $body['o:tag'] = $tags;
246
- }
247
 
248
- // campaign-id now refers to a list of tags which will be appended to the site tag
249
- if (!empty($mailgun['campaign-id'])) {
250
- $tags = explode(',', str_replace(' ', '', $mailgun['campaign-id']));
251
- if (empty($body['o:tag'])) {
252
  $body['o:tag'] = $tags;
253
- } elseif (is_array($body['o:tag'])) {
254
- $body['o:tag'] = array_merge($body['o:tag'], $tags);
255
- } else {
256
- $body['o:tag'] .= ','.$tags;
257
  }
258
- }
259
 
260
- /**
261
- * Filter tags.
262
- *
263
- * @param array $tags Mailgun tags.
264
- * @param string $to To address.
265
- * @param string $subject Subject line.
266
- * @param string $message Message content.
267
- * @param array $headers Headers array.
268
- * @param array $attachments Attachments array.
269
- * @param string $region Mailgun region.
270
- * @param string $domain Mailgun domain.
271
- *
272
- * @return array Mailgun tags.
273
- */
274
- $body['o:tag'] = apply_filters( 'mailgun_tags', $body['o:tag'], $to, $subject, $message, $headers, $attachments, $region, $domain );
275
-
276
- if (!empty($cc) && is_array($cc)) {
277
- $body['cc'] = implode(', ', $cc);
278
- }
279
 
280
- if (!empty($bcc) && is_array($bcc)) {
281
- $body['bcc'] = implode(', ', $bcc);
282
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
283
 
284
- // If we are not given a Content-Type in the supplied headers,
285
- // write the message body to a file and try to determine the mimetype
286
- // using get_mime_content_type.
287
- if (!isset($content_type)) {
288
- $tmppath = tempnam(get_temp_dir(), 'mg');
289
- $tmp = fopen($tmppath, 'w+');
290
 
291
- fwrite($tmp, $message);
292
- fclose($tmp);
 
 
 
 
293
 
294
- $content_type = get_mime_content_type($tmppath, 'text/plain');
 
295
 
296
- unlink($tmppath);
297
- }
298
 
299
- // Allow external content type filter to function normally
300
- if (has_filter('wp_mail_content_type')) {
301
- $content_type = apply_filters(
302
- 'wp_mail_content_type',
303
- $content_type
304
- );
305
- }
306
 
307
- if ('text/plain' === $content_type) {
308
- $body['text'] = $message;
309
- } else if ('text/html' === $content_type) {
310
- $body['html'] = $message;
311
- } else {
312
- // Unknown Content-Type??
313
- error_log('[mailgun] Got unknown Content-Type: ' . $content_type);
314
- $body['text'] = $message;
315
- $body['html'] = $message;
316
- }
317
 
318
- // Some plugins, such as WooCommerce (@see WC_Email::handle_multipart()), to handle multipart/alternative with html
319
- // and plaintext messages hooks into phpmailer_init action to override AltBody property directly in $phpmailer,
320
- // so we should allow them to do this, and then get overridden plain text body from $phpmailer.
321
- // Partly, this logic is taken from original wp_mail function.
322
- if (false !== stripos($content_type, 'multipart')) {
323
- global $phpmailer;
324
-
325
- // (Re)create it, if it's gone missing.
326
- if (!($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer)) {
327
- require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
328
- require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
329
- require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
330
- $phpmailer = new PHPMailer\PHPMailer\PHPMailer(true);
331
-
332
- $phpmailer::$validator = static function ($email) {
333
- return (bool)is_email($email);
334
- };
335
  }
336
 
337
- /**
338
- * Fires after PHPMailer is initialized.
339
- *
340
- * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
341
- */
342
- do_action_ref_array('phpmailer_init', array(&$phpmailer));
 
 
 
 
 
 
 
 
 
 
 
 
343
 
344
- $plainTextMessage = $phpmailer->AltBody;
 
 
 
 
 
345
 
346
- if ($plainTextMessage) {
347
- $body['text'] = $plainTextMessage;
 
 
 
348
  }
349
- }
350
 
351
- // If we don't have a charset from the input headers
352
- if (!isset($charset)) {
353
- $charset = get_bloginfo('charset');
354
- }
355
 
356
- // Set the content-type and charset
357
- $charset = apply_filters('wp_mail_charset', $charset);
358
- if (isset($headers['Content-Type'])) {
359
- if (!strstr($headers['Content-Type'], 'charset')) {
360
- $headers['Content-Type'] = rtrim($headers['Content-Type'], '; ')."; charset={$charset}";
 
361
  }
362
- }
363
 
364
- // Set custom headers
365
- if (!empty($headers)) {
366
- foreach ((array) $headers as $name => $content) {
367
- $body["h:{$name}"] = $content;
 
368
  }
369
 
370
- // TODO: Can we handle this?
371
- //if ( false !== stripos( $content_type, 'multipart' ) && ! empty($boundary) )
372
- // $phpmailer->AddCustomHeader( sprintf( "Content-Type: %s;\n\t boundary=\"%s\"", $content_type, $boundary ) );
373
- }
 
374
 
375
- /*
376
- * Deconstruct post array and create POST payload.
377
- * This entire routine is because wp_remote_post does
378
- * not support files directly.
379
- */
380
 
381
- $payload = '';
 
382
 
383
- // First, generate a boundary for the multipart message.
384
- $boundary = sha1(uniqid('', true));
 
 
 
385
 
386
- // Allow other plugins to apply body changes before creating the payload.
387
- $body = apply_filters('mg_mutate_message_body', $body);
388
- if ( ($body_payload = mg_build_payload_from_body($body, $boundary)) != null ) {
389
- $payload .= $body_payload;
390
- }
391
 
392
- // TODO: Special handling for multipart/alternative mail
393
- // if ('multipart/alternative' === $content_type) {
394
- // // Build payload from mime
395
- // // error_log(sprintf('building message payload from multipart/alternative'));
396
- // // error_log($body['message']);
397
- // // error_log('Attachments:');
398
- // // foreach ($attachments as $attachment) {
399
- // // error_log($attachment);
400
- // // }
401
- // }
402
-
403
- // Allow other plugins to apply attachment changes before writing to the payload.
404
- $attachments = apply_filters('mg_mutate_attachments', $attachments);
405
- if ( ($attachment_payload = mg_build_attachments_payload($attachments, $boundary)) != null ) {
406
- $payload .= $attachment_payload;
407
- }
408
 
409
- $payload .= '--'.$boundary.'--';
 
 
 
 
 
 
410
 
411
- $data = array(
412
- 'body' => $payload,
413
- 'headers' => array(
414
- 'Authorization' => 'Basic '.base64_encode("api:{$apiKey}"),
415
- 'Content-Type' => 'multipart/form-data; boundary='.$boundary,
416
- ),
417
- );
418
 
419
- $endpoint = mg_api_get_region($region);
420
- $endpoint = ($endpoint) ? $endpoint : 'https://api.mailgun.net/v3/';
421
- $url = $endpoint."{$domain}/messages";
 
 
 
422
 
423
- // TODO: Mailgun only supports 1000 recipients per request, since we are
424
- // overriding this function, let's add looping here to handle that
425
- $response = wp_remote_post($url, $data);
426
- if (is_wp_error($response)) {
427
- // Store WP error in last error.
428
- mg_api_last_error($response->get_error_message());
429
 
430
- return false;
431
- }
432
 
433
- $response_code = wp_remote_retrieve_response_code($response);
434
- $response_body = json_decode(wp_remote_retrieve_body($response));
 
 
 
 
 
 
435
 
436
- // Mailgun API should *always* return a `message` field, even when
437
- // $response_code != 200, so a lack of `message` indicates something
438
- // is broken.
439
- if ((int) $response_code != 200 || !isset($response_body->message)) {
440
- // Store response code and HTTP response message in last error.
441
- $response_message = wp_remote_retrieve_response_message($response);
442
- $errmsg = "$response_code - $response_message";
443
- mg_api_last_error($errmsg);
444
 
445
- return false;
446
- }
 
447
 
448
- // Not sure there is any additional checking that needs to be done here, but why not?
449
- if ($response_body->message != 'Queued. Thank you.') {
450
- mg_api_last_error($response_body->message);
451
 
452
- return false;
453
  }
454
-
455
- return true;
456
- }
457
  }
458
 
459
- function mg_build_payload_from_body($body, $boundary) {
 
460
  $payload = '';
461
 
462
  // Iterate through pre-built params and build payload:
@@ -464,16 +453,16 @@ function mg_build_payload_from_body($body, $boundary) {
464
  if (is_array($value)) {
465
  $parent_key = $key;
466
  foreach ($value as $key => $value) {
467
- $payload .= '--'.$boundary;
468
  $payload .= "\r\n";
469
- $payload .= 'Content-Disposition: form-data; name="'.$parent_key."\"\r\n\r\n";
470
  $payload .= $value;
471
  $payload .= "\r\n";
472
  }
473
  } else {
474
- $payload .= '--'.$boundary;
475
  $payload .= "\r\n";
476
- $payload .= 'Content-Disposition: form-data; name="'.$key.'"'."\r\n\r\n";
477
  $payload .= $value;
478
  $payload .= "\r\n";
479
  }
@@ -482,10 +471,8 @@ function mg_build_payload_from_body($body, $boundary) {
482
  return $payload;
483
  }
484
 
485
- function mg_build_payload_from_mime($body, $boundary) {
486
- }
487
-
488
- function mg_build_attachments_payload($attachments, $boundary) {
489
  $payload = '';
490
 
491
  // If we have attachments, add them to the payload.
@@ -493,9 +480,9 @@ function mg_build_attachments_payload($attachments, $boundary) {
493
  $i = 0;
494
  foreach ($attachments as $attachment) {
495
  if (!empty($attachment)) {
496
- $payload .= '--'.$boundary;
497
  $payload .= "\r\n";
498
- $payload .= 'Content-Disposition: form-data; name="attachment['.$i.']"; filename="'.basename($attachment).'"'."\r\n\r\n";
499
  $payload .= file_get_contents($attachment);
500
  $payload .= "\r\n";
501
  $i++;
20
  */
21
 
22
  // Include MG filter functions
23
+ if (!include __DIR__ . '/mg-filter.php') {
24
+ (new Mailgun)->deactivate_and_die(__DIR__ . '/mg-filter.php');
25
  }
26
 
27
  /**
28
  * mg_api_last_error is a compound getter/setter for the last error that was
29
  * encountered during a Mailgun API call.
30
  *
31
+ * @param string $error OPTIONAL
32
  *
33
+ * @return string Last error that occurred.
34
  *
35
+ * @since 1.5.0
36
  */
37
  function mg_api_last_error($error = null)
38
  {
40
 
41
  if (null === $error) {
42
  return $last_error;
 
 
 
 
 
43
  }
44
+
45
+ $tmp = $last_error;
46
+ $last_error = $error;
47
+
48
+ return $tmp;
49
  }
50
 
51
  /*
79
 
80
  // TODO: Also add folding to prevent hitting the 998 char limit on headers.
81
  return array(
82
+ 'to' => '%recipient%',
83
  'rcpt_vars' => json_encode($rcpt_vars),
84
  );
85
  }
86
  }
87
 
88
  return array(
89
+ 'to' => $to_addrs,
90
  'rcpt_vars' => null,
91
  );
92
  }
98
  * Based off of the core wp_mail function, but with modifications required to
99
  * send email using the Mailgun HTTP API
100
  *
101
+ * @param string|array $to Array or comma-separated list of email addresses to send message.
102
+ * @param string $subject Email subject
103
+ * @param string $message Message contents
104
+ * @param string|array $headers Optional. Additional headers.
105
+ * @param string|array $attachments Optional. Files to attach.
106
  *
107
+ * @return bool Whether the email contents were sent successfully.
108
  *
109
  * @global PHPMailer\PHPMailer\PHPMailer $phpmailer
110
  *
 
111
  */
112
  if (!function_exists('wp_mail')) {
113
+ function wp_mail($to, $subject, $message, $headers = '', $attachments = array())
114
+ {
115
+ // Compact the input, apply the filters, and extract them back out
116
+ $extractData = apply_filters('wp_mail', compact('to', 'subject', 'message', 'headers', 'attachments'));
117
+ if (!is_array($extractData)) {
118
+ $extractData = (array)$extractData;
119
+ }
120
+ extract($extractData, EXTR_OVERWRITE);
121
 
122
+ $mailgun = get_option('mailgun');
123
+ $region = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $mailgun['region'];
124
+ $apiKey = (defined('MAILGUN_APIKEY') && MAILGUN_APIKEY) ? MAILGUN_APIKEY : $mailgun['apiKey'];
125
+ $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $mailgun['domain'];
126
 
127
+ if (empty($apiKey) || empty($domain)) {
128
+ return false;
129
+ }
130
 
131
+ // If a region is not set via defines or through the options page, default to US region.
132
+ if (!((bool)$region)) {
133
+ error_log('[Mailgun] No region configuration was found! Defaulting to US region.');
134
+ $region = 'us';
135
+ }
136
 
137
+ if (!is_array($attachments)) {
138
+ $attachments = explode("\n", str_replace("\r\n", "\n", $attachments));
139
+ }
140
 
141
+ // Headers
142
+ if (empty($headers)) {
143
+ $headers = [];
 
 
 
 
 
144
  } else {
145
+ if (!is_array($headers)) {
146
+ // Explode the headers out, so this function can take both
147
+ // string headers and an array of headers.
148
+ $tempheaders = explode("\n", str_replace("\r\n", "\n", $headers));
149
+ } else {
150
+ $tempheaders = $headers;
151
+ }
152
+ $headers = [];
153
+ $cc = [];
154
+ $bcc = [];
155
+
156
+ // If it's actually got contents
157
+ if (!empty($tempheaders)) {
158
+ // Iterate through the raw headers
159
+ foreach ((array)$tempheaders as $header) {
160
+ if (strpos($header, ':') === false) {
161
+ if (false !== stripos($header, 'boundary=')) {
162
+ $parts = preg_split('/boundary=/i', trim($header));
163
+ $boundary = trim(str_replace(["'", '"'], '', $parts[1]));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
+ continue;
166
+ }
167
+ // Explode them out
168
+ list($name, $content) = explode(':', trim($header), 2);
169
+
170
+ // Cleanup crew
171
+ $name = trim($name);
172
+ $content = trim($content);
173
+
174
+ switch (strtolower($name)) {
175
+ // Mainly for legacy -- process a From: header if it's there
176
+ case 'from':
177
+ if (strpos($content, '<') !== false) {
178
+ // So... making my life hard again?
179
+ $from_name = substr($content, 0, strpos($content, '<') - 1);
180
+ $from_name = str_replace('"', '', $from_name);
181
+ $from_name = trim($from_name);
182
+
183
+ $from_email = substr($content, strpos($content, '<') + 1);
184
+ $from_email = str_replace('>', '', $from_email);
185
+ $from_email = trim($from_email);
186
+ } else {
187
+ $from_email = trim($content);
188
+ }
189
+ break;
190
+ case 'content-type':
191
+ if (strpos($content, ';') !== false) {
192
+ list($type, $charset) = explode(';', $content);
193
+ $content_type = trim($type);
194
+ if (false !== stripos($charset, 'charset=')) {
195
+ $charset = trim(str_replace(array('charset=', '"'), '', $charset));
196
+ } elseif (false !== stripos($charset, 'boundary=')) {
197
+ $boundary = trim(str_replace(array('BOUNDARY=', 'boundary=', '"'), '', $charset));
198
+ $charset = '';
199
+ }
200
+ } else {
201
+ $content_type = trim($content);
202
+ }
203
+ break;
204
+ case 'cc':
205
+ $cc = array_merge((array)$cc, explode(',', $content));
206
+ break;
207
+ case 'bcc':
208
+ $bcc = array_merge((array)$bcc, explode(',', $content));
209
+ break;
210
+ default:
211
+ // Add it to our grand headers array
212
+ $headers[trim($name)] = trim($content);
213
+ break;
214
  }
 
 
 
 
 
 
 
 
 
 
 
215
  }
216
  }
217
  }
 
 
 
 
 
218
 
219
+ if (!isset($from_name)) {
220
+ $from_name = null;
221
+ }
222
 
223
+ if (!isset($from_email)) {
224
+ $from_email = null;
225
+ }
226
 
227
+ $from_name = mg_detect_from_name($from_name);
228
+ $from_email = mg_detect_from_address($from_email);
 
 
 
229
 
230
+ $body = array(
231
+ 'from' => "{$from_name} <{$from_email}>",
232
+ 'to' => $to,
233
+ 'subject' => $subject,
234
+ );
235
 
236
+ $rcpt_data = apply_filters('mg_mutate_to_rcpt_vars', $to);
237
+ if (!is_null($rcpt_data['rcpt_vars'])) {
238
+ $body['recipient-variables'] = $rcpt_data['rcpt_vars'];
239
+ }
240
 
241
+ $body['o:tag'] = array();
242
+ $body['o:tracking-clicks'] = !empty($mailgun['track-clicks']) ? $mailgun['track-clicks'] : 'no';
243
+ $body['o:tracking-opens'] = empty($mailgun['track-opens']) ? 'no' : 'yes';
 
 
244
 
245
+ // this is the wordpress site tag
246
+ if (isset($mailgun['tag'])) {
247
+ $tags = explode(',', str_replace(' ', '', $mailgun['tag']));
 
248
  $body['o:tag'] = $tags;
 
 
 
 
249
  }
 
250
 
251
+ // campaign-id now refers to a list of tags which will be appended to the site tag
252
+ if (!empty($mailgun['campaign-id'])) {
253
+ $tags = explode(',', str_replace(' ', '', $mailgun['campaign-id']));
254
+ if (empty($body['o:tag'])) {
255
+ $body['o:tag'] = $tags;
256
+ } elseif (is_array($body['o:tag'])) {
257
+ $body['o:tag'] = array_merge($body['o:tag'], $tags);
258
+ } else {
259
+ $body['o:tag'] .= ',' . $tags;
260
+ }
261
+ }
 
 
 
 
 
 
 
 
262
 
263
+ /**
264
+ * Filter tags.
265
+ *
266
+ * @param array $tags Mailgun tags.
267
+ * @param string $to To address.
268
+ * @param string $subject Subject line.
269
+ * @param string $message Message content.
270
+ * @param array $headers Headers array.
271
+ * @param array $attachments Attachments array.
272
+ * @param string $region Mailgun region.
273
+ * @param string $domain Mailgun domain.
274
+ *
275
+ * @return array Mailgun tags.
276
+ */
277
+ $body['o:tag'] = apply_filters('mailgun_tags', $body['o:tag'], $to, $subject, $message, $headers, $attachments, $region, $domain);
278
+
279
+ if (!empty($cc) && is_array($cc)) {
280
+ $body['cc'] = implode(', ', $cc);
281
+ }
282
 
283
+ if (!empty($bcc) && is_array($bcc)) {
284
+ $body['bcc'] = implode(', ', $bcc);
285
+ }
 
 
 
286
 
287
+ // If we are not given a Content-Type in the supplied headers,
288
+ // write the message body to a file and try to determine the mimetype
289
+ // using get_mime_content_type.
290
+ if (!isset($content_type)) {
291
+ $tmppath = tempnam(get_temp_dir(), 'mg');
292
+ $tmp = fopen($tmppath, 'w+');
293
 
294
+ fwrite($tmp, $message);
295
+ fclose($tmp);
296
 
297
+ $content_type = get_mime_content_type($tmppath, 'text/plain');
 
298
 
299
+ unlink($tmppath);
300
+ }
 
 
 
 
 
301
 
302
+ // Allow external content type filter to function normally
303
+ if (has_filter('wp_mail_content_type')) {
304
+ $content_type = apply_filters(
305
+ 'wp_mail_content_type',
306
+ $content_type
307
+ );
308
+ }
 
 
 
309
 
310
+ if ('text/plain' === $content_type) {
311
+ $body['text'] = $message;
312
+ } else if ('text/html' === $content_type) {
313
+ $body['html'] = $message;
314
+ } else {
315
+ // Unknown Content-Type??
316
+ error_log('[mailgun] Got unknown Content-Type: ' . $content_type);
317
+ $body['text'] = $message;
318
+ $body['html'] = $message;
 
 
 
 
 
 
 
 
319
  }
320
 
321
+ // Some plugins, such as WooCommerce (@see WC_Email::handle_multipart()), to handle multipart/alternative with html
322
+ // and plaintext messages hooks into phpmailer_init action to override AltBody property directly in $phpmailer,
323
+ // so we should allow them to do this, and then get overridden plain text body from $phpmailer.
324
+ // Partly, this logic is taken from original wp_mail function.
325
+ if (false !== stripos($content_type, 'multipart')) {
326
+ global $phpmailer;
327
+
328
+ // (Re)create it, if it's gone missing.
329
+ if (!($phpmailer instanceof PHPMailer\PHPMailer\PHPMailer)) {
330
+ require_once ABSPATH . WPINC . '/PHPMailer/PHPMailer.php';
331
+ require_once ABSPATH . WPINC . '/PHPMailer/SMTP.php';
332
+ require_once ABSPATH . WPINC . '/PHPMailer/Exception.php';
333
+ $phpmailer = new PHPMailer\PHPMailer\PHPMailer(true);
334
+
335
+ $phpmailer::$validator = static function ($email) {
336
+ return (bool)is_email($email);
337
+ };
338
+ }
339
 
340
+ /**
341
+ * Fires after PHPMailer is initialized.
342
+ *
343
+ * @param PHPMailer $phpmailer The PHPMailer instance (passed by reference).
344
+ */
345
+ do_action_ref_array('phpmailer_init', array(&$phpmailer));
346
 
347
+ $plainTextMessage = $phpmailer->AltBody;
348
+
349
+ if ($plainTextMessage) {
350
+ $body['text'] = $plainTextMessage;
351
+ }
352
  }
 
353
 
354
+ // If we don't have a charset from the input headers
355
+ if (!isset($charset)) {
356
+ $charset = get_bloginfo('charset');
357
+ }
358
 
359
+ // Set the content-type and charset
360
+ $charset = apply_filters('wp_mail_charset', $charset);
361
+ if (isset($headers['Content-Type'])) {
362
+ if (!strstr($headers['Content-Type'], 'charset')) {
363
+ $headers['Content-Type'] = rtrim($headers['Content-Type'], '; ') . "; charset={$charset}";
364
+ }
365
  }
 
366
 
367
+ // Set custom headers
368
+ if (!empty($headers)) {
369
+ foreach ((array)$headers as $name => $content) {
370
+ $body["h:{$name}"] = $content;
371
+ }
372
  }
373
 
374
+ /*
375
+ * Deconstruct post array and create POST payload.
376
+ * This entire routine is because wp_remote_post does
377
+ * not support files directly.
378
+ */
379
 
380
+ $payload = '';
 
 
 
 
381
 
382
+ // First, generate a boundary for the multipart message.
383
+ $boundary = sha1(uniqid('', true));
384
 
385
+ // Allow other plugins to apply body changes before creating the payload.
386
+ $body = apply_filters('mg_mutate_message_body', $body);
387
+ if (($body_payload = mg_build_payload_from_body($body, $boundary)) != null) {
388
+ $payload .= $body_payload;
389
+ }
390
 
391
+ // Allow other plugins to apply attachment changes before writing to the payload.
392
+ $attachments = apply_filters('mg_mutate_attachments', $attachments);
393
+ if (($attachment_payload = mg_build_attachments_payload($attachments, $boundary)) != null) {
394
+ $payload .= $attachment_payload;
395
+ }
396
 
397
+ $payload .= '--' . $boundary . '--';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
398
 
399
+ $data = array(
400
+ 'body' => $payload,
401
+ 'headers' => array(
402
+ 'Authorization' => 'Basic ' . base64_encode("api:{$apiKey}"),
403
+ 'Content-Type' => 'multipart/form-data; boundary=' . $boundary,
404
+ ),
405
+ );
406
 
407
+ $endpoint = mg_api_get_region($region);
408
+ $endpoint = ($endpoint) ? $endpoint : 'https://api.mailgun.net/v3/';
409
+ $url = $endpoint . "{$domain}/messages";
 
 
 
 
410
 
411
+ // TODO: Mailgun only supports 1000 recipients per request, since we are
412
+ // overriding this function, let's add looping here to handle that
413
+ $response = wp_remote_post($url, $data);
414
+ if (is_wp_error($response)) {
415
+ // Store WP error in last error.
416
+ mg_api_last_error($response->get_error_message());
417
 
418
+ return false;
419
+ }
 
 
 
 
420
 
421
+ $response_code = wp_remote_retrieve_response_code($response);
422
+ $response_body = json_decode(wp_remote_retrieve_body($response));
423
 
424
+ // Mailgun API should *always* return a `message` field, even when
425
+ // $response_code != 200, so a lack of `message` indicates something
426
+ // is broken.
427
+ if ((int)$response_code != 200 || !isset($response_body->message)) {
428
+ // Store response code and HTTP response message in last error.
429
+ $response_message = wp_remote_retrieve_response_message($response);
430
+ $errmsg = "$response_code - $response_message";
431
+ mg_api_last_error($errmsg);
432
 
433
+ return false;
434
+ }
 
 
 
 
 
 
435
 
436
+ // Not sure there is any additional checking that needs to be done here, but why not?
437
+ if ($response_body->message != 'Queued. Thank you.') {
438
+ mg_api_last_error($response_body->message);
439
 
440
+ return false;
441
+ }
 
442
 
443
+ return true;
444
  }
 
 
 
445
  }
446
 
447
+ function mg_build_payload_from_body($body, $boundary)
448
+ {
449
  $payload = '';
450
 
451
  // Iterate through pre-built params and build payload:
453
  if (is_array($value)) {
454
  $parent_key = $key;
455
  foreach ($value as $key => $value) {
456
+ $payload .= '--' . $boundary;
457
  $payload .= "\r\n";
458
+ $payload .= 'Content-Disposition: form-data; name="' . $parent_key . "\"\r\n\r\n";
459
  $payload .= $value;
460
  $payload .= "\r\n";
461
  }
462
  } else {
463
+ $payload .= '--' . $boundary;
464
  $payload .= "\r\n";
465
+ $payload .= 'Content-Disposition: form-data; name="' . $key . '"' . "\r\n\r\n";
466
  $payload .= $value;
467
  $payload .= "\r\n";
468
  }
471
  return $payload;
472
  }
473
 
474
+ function mg_build_attachments_payload($attachments, $boundary)
475
+ {
 
 
476
  $payload = '';
477
 
478
  // If we have attachments, add them to the payload.
480
  $i = 0;
481
  foreach ($attachments as $attachment) {
482
  if (!empty($attachment)) {
483
+ $payload .= '--' . $boundary;
484
  $payload .= "\r\n";
485
+ $payload .= 'Content-Disposition: form-data; name="attachment[' . $i . ']"; filename="' . basename($attachment) . '"' . "\r\n\r\n";
486
  $payload .= file_get_contents($attachment);
487
  $payload .= "\r\n";
488
  $i++;
includes/wp-mail-smtp.php CHANGED
@@ -20,8 +20,8 @@
20
  */
21
 
22
  // Include MG filter functions
23
- if (!include dirname(__FILE__).'/mg-filter.php') {
24
- Mailgun::deactivate_and_die(dirname(__FILE__).'/mg-filter.php');
25
  }
26
 
27
  /**
@@ -40,12 +40,12 @@ function mg_smtp_last_error($error = null)
40
 
41
  if (null === $error) {
42
  return $last_error;
43
- } else {
44
- $tmp = $last_error;
45
- $last_error = $error;
46
-
47
- return $tmp;
48
  }
 
 
 
 
 
49
  }
50
 
51
  /**
@@ -54,11 +54,11 @@ function mg_smtp_last_error($error = null)
54
  * @param string $str Log message
55
  * @param string $level Logging level
56
  *
57
- * @return none
58
  *
59
  * @since 1.5.7
60
  */
61
- function mg_smtp_debug_output($str, $level)
62
  {
63
  if (defined('MG_DEBUG_SMTP') && MG_DEBUG_SMTP) {
64
  error_log("PHPMailer [$level] $str");
@@ -69,9 +69,9 @@ function mg_smtp_debug_output($str, $level)
69
  * Capture and store the failure message from PHPmailer so the user will
70
  * actually know what is wrong.
71
  *
72
- * @param WP_Error $error Error raised by Wordpress/PHPmailer
73
  *
74
- * @return none
75
  *
76
  * @since 1.5.7
77
  */
@@ -86,7 +86,7 @@ function wp_mail_failed($error)
86
 
87
  /**
88
  * Provides a `wp_mail` compatible filter for SMTP sends through the
89
- * Wordpress PHPmailer transport.
90
  *
91
  * @param array $args Compacted array of arguments.
92
  *
@@ -97,7 +97,7 @@ function wp_mail_failed($error)
97
  function mg_smtp_mail_filter(array $args)
98
  {
99
  // Extract the arguments from array to ($to, $subject, $message, $headers, $attachments)
100
- extract($args);
101
 
102
  // $headers and $attachments are optional - make sure they exist
103
  $headers = (!isset($headers)) ? '' : $headers;
@@ -109,7 +109,7 @@ function mg_smtp_mail_filter(array $args)
109
  // Filter the `From:` header
110
  $from_header = (isset($mg_headers['From'])) ? $mg_headers['From'][0] : null;
111
 
112
- list($from_name, $from_addr) = array(null, null);
113
  if (!is_null($from_header)) {
114
  $content = $from_header['value'];
115
  $boundary = $from_header['boundary'];
20
  */
21
 
22
  // Include MG filter functions
23
+ if (!include __DIR__ .'/mg-filter.php') {
24
+ (new Mailgun)->deactivate_and_die(__DIR__ .'/mg-filter.php');
25
  }
26
 
27
  /**
40
 
41
  if (null === $error) {
42
  return $last_error;
 
 
 
 
 
43
  }
44
+
45
+ $tmp = $last_error;
46
+ $last_error = $error;
47
+
48
+ return $tmp;
49
  }
50
 
51
  /**
54
  * @param string $str Log message
55
  * @param string $level Logging level
56
  *
57
+ * @return void
58
  *
59
  * @since 1.5.7
60
  */
61
+ function mg_smtp_debug_output(string $str, $level)
62
  {
63
  if (defined('MG_DEBUG_SMTP') && MG_DEBUG_SMTP) {
64
  error_log("PHPMailer [$level] $str");
69
  * Capture and store the failure message from PHPmailer so the user will
70
  * actually know what is wrong.
71
  *
72
+ * @param WP_Error $error Error raised by WordPress/PHPmailer
73
  *
74
+ * @return void
75
  *
76
  * @since 1.5.7
77
  */
86
 
87
  /**
88
  * Provides a `wp_mail` compatible filter for SMTP sends through the
89
+ * WordPress PHPmailer transport.
90
  *
91
  * @param array $args Compacted array of arguments.
92
  *
97
  function mg_smtp_mail_filter(array $args)
98
  {
99
  // Extract the arguments from array to ($to, $subject, $message, $headers, $attachments)
100
+ extract($args, EXTR_OVERWRITE);
101
 
102
  // $headers and $attachments are optional - make sure they exist
103
  $headers = (!isset($headers)) ? '' : $headers;
109
  // Filter the `From:` header
110
  $from_header = (isset($mg_headers['From'])) ? $mg_headers['From'][0] : null;
111
 
112
+ list($from_name, $from_addr) = [null, null];
113
  if (!is_null($from_header)) {
114
  $content = $from_header['value'];
115
  $boundary = $from_header['boundary'];
mailgun.php CHANGED
@@ -1,10 +1,9 @@
1
  <?php
2
-
3
  /**
4
  * Plugin Name: Mailgun
5
  * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
6
  * Description: Mailgun integration for WordPress
7
- * Version: 1.7.9
8
  * Author: Mailgun
9
  * Author URI: http://www.mailgun.com/
10
  * License: GPLv2 or later
@@ -36,65 +35,102 @@
36
  * either API or SMTP.
37
  *
38
  * Registers handlers for later actions and sets up config variables with
39
- * Wordpress.
40
  */
41
  class Mailgun
42
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43
  /**
44
  * Setup shared functionality for Admin and Front End.
45
  *
46
- * @since 0.1
47
  */
48
  public function __construct()
49
  {
50
  $this->options = get_option('mailgun');
51
  $this->plugin_file = __FILE__;
52
  $this->plugin_basename = plugin_basename($this->plugin_file);
 
53
 
54
  // Either override the wp_mail function or configure PHPMailer to use the
55
  // Mailgun SMTP servers
56
  // When using SMTP, we also need to inject a `wp_mail` filter to make "from" settings
57
- // work properly. Fixes issues with 1.5.7+
58
- if ($this->get_option('useAPI') || (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI)):
59
- if (!function_exists('wp_mail')):
60
- if (!include dirname(__FILE__) . '/includes/wp-mail-api.php'):
61
- self::deactivate_and_die(dirname(__FILE__) . '/includes/wp-mail-api.php');
62
- endif;
63
- endif;
64
- else:
65
  // Using SMTP, include the SMTP filter
66
- if (!function_exists('mg_smtp_mail_filter')):
67
- if (!include dirname(__FILE__) . '/includes/wp-mail-smtp.php'):
68
- self::deactivate_and_die(dirname(__FILE__) . '/includes/wp-mail-smtp.php');
69
- endif;
70
- endif;
71
  add_filter('wp_mail', 'mg_smtp_mail_filter');
72
- add_action('phpmailer_init', array(&$this, 'phpmailer_init'));
73
  add_action('wp_mail_failed', 'wp_mail_failed');
74
- endif;
 
 
 
 
 
 
 
 
 
 
 
 
75
  }
76
 
77
  /**
78
  * Get specific option from the options table.
79
  *
80
- * @param string $option Name of option to be used as array key for retrieving the specific value
81
- * @param array $options Array to iterate over for specific values
82
- * @param bool $default False if no options are set
83
  *
84
  * @return mixed
85
  *
86
- * @since 0.1
87
  */
88
- public function get_option($option, $options = null, $default = false)
89
  {
90
- if (is_null($options)):
91
  $options = &$this->options;
92
- endif;
93
- if (isset($options[ $option ])):
94
- return $options[ $option ];
95
- else:
96
- return $default;
97
- endif;
 
98
  }
99
 
100
  /**
@@ -105,7 +141,6 @@ class Mailgun
105
  *
106
  * @return void
107
  *
108
- * @since 0.1
109
  */
110
  public function phpmailer_init(&$phpmailer)
111
  {
@@ -123,13 +158,13 @@ class Mailgun
123
  $phpmailer->Mailer = 'smtp';
124
  $phpmailer->Host = $smtp_endpoint;
125
 
126
- if ('ssl' === $sectype):
127
  // For SSL-only connections, use 465
128
  $phpmailer->Port = 465;
129
- else:
130
  // Otherwise, use 587.
131
  $phpmailer->Port = 587;
132
- endif;
133
 
134
  $phpmailer->SMTPAuth = true;
135
  $phpmailer->Username = $username;
@@ -152,17 +187,15 @@ class Mailgun
152
  * @param $file Files critical to plugin functionality
153
  *
154
  * @return void
155
- *
156
- * @since 0.1
157
  */
158
  public function deactivate_and_die($file)
159
  {
160
  load_plugin_textdomain('mailgun', false, 'mailgun/languages');
161
  $message = sprintf(__('Mailgun has been automatically deactivated because the file <strong>%s</strong> is missing. Please reinstall the plugin and reactivate.'),
162
  $file);
163
- if (!function_exists('deactivate_plugins')):
164
  include ABSPATH . 'wp-admin/includes/plugin.php';
165
- endif;
166
  deactivate_plugins(__FILE__);
167
  wp_die($message);
168
  }
@@ -174,11 +207,10 @@ class Mailgun
174
  * @param array $params Array of parameters passed to the API
175
  * @param string $method The form request type
176
  *
177
- * @return array
178
  *
179
- * @since 0.1
180
  */
181
- public function api_call($uri, $params = array(), $method = 'POST')
182
  {
183
  $options = get_option('mailgun');
184
  $getRegion = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $options[ 'region' ];
@@ -186,13 +218,13 @@ class Mailgun
186
  $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $options[ 'domain' ];
187
 
188
  $region = mg_api_get_region($getRegion);
189
- $this->api_endpoint = ($region) ? $region : 'https://api.mailgun.net/v3/';
190
 
191
  $time = time();
192
  $url = $this->api_endpoint . $uri;
193
- $headers = array(
194
  'Authorization' => 'Basic ' . base64_encode("api:{$apiKey}"),
195
- );
196
 
197
  switch ($method) {
198
  case 'GET':
@@ -211,20 +243,31 @@ class Mailgun
211
  }
212
 
213
  // make the request
214
- $args = array(
215
  'method' => $method,
216
  'body' => $params,
217
  'headers' => $headers,
218
  'sslverify' => true,
219
- );
220
 
221
  // make the remote request
222
  $result = wp_remote_request($url, $args);
223
- if (!is_wp_error($result)):
224
- return $result[ 'body' ];
225
- else:
 
 
226
  return $result->get_error_message();
227
- endif;
 
 
 
 
 
 
 
 
 
228
  }
229
 
230
  /**
@@ -232,17 +275,18 @@ class Mailgun
232
  *
233
  * @return array
234
  *
235
- * @since 0.1
236
  */
237
- public function get_lists()
238
  {
239
- $results = array();
240
 
241
- $lists_json = $this->api_call('lists', array(), 'GET');
242
- $lists_arr = json_decode($lists_json, true);
243
- if (isset($lists_arr[ 'items' ]) && !empty($lists_arr[ 'items' ])):
244
- $results = $lists_arr[ 'items' ];
245
- endif;
 
246
 
247
  return $results;
248
  }
@@ -250,54 +294,64 @@ class Mailgun
250
  /**
251
  * Handle add list ajax post.
252
  *
253
- * @return string json
254
  *
255
- * @since 0.1
256
  */
257
  public function add_list()
258
  {
259
- $response = array();
260
-
261
- $name = isset($_POST[ 'name' ]) ? $_POST[ 'name' ] : null;
262
- $email = isset($_POST[ 'email' ]) ? $_POST[ 'email' ] : null;
263
 
264
- $list_addresses = $_POST[ 'addresses' ];
265
 
266
- if (!empty($list_addresses)):
267
- foreach ($list_addresses as $address => $val):
268
- $response[] = $this->api_call(
 
269
  "lists/{$address}/members",
270
- array(
271
  'address' => $email,
272
  'name' => $name,
273
- )
274
  );
275
- endforeach;
 
 
 
 
 
 
 
276
 
277
- echo json_encode(array('status' => 200, 'message' => 'Thank you!'));
278
- else:
279
- echo json_encode(array(
 
 
 
 
280
  'status' => 500,
281
  'message' => 'Uh oh. We weren\'t able to add you to the list' . count($list_addresses) ? 's.' : '. Please try again.'
282
- ));
283
- endif;
284
-
285
  wp_die();
286
  }
287
 
288
  /**
289
  * Frontend List Form.
290
  *
291
- * @param string $list_address Mailgun address list id
292
- * @param array $args widget arguments
293
- * @param array $instance widget instance params
294
  *
295
- * @since 0.1
296
  */
297
- public function list_form($list_address, $args = array(), $instance = array())
298
  {
299
- $widget_class_id = "mailgun-list-widget-{$args['widget_id']}";
300
- $form_class_id = "list-form-{$args['widget_id']}";
 
301
 
302
  // List addresses from the plugin config
303
  $list_addresses = array_map('trim', explode(',', $list_address));
@@ -322,7 +376,7 @@ class Mailgun
322
  </p>
323
  </div>
324
  <?php endif; ?>
325
- <?php if (isset($args[ 'collect_name' ]) && intval($args[ 'collect_name' ]) === 1): ?>
326
  <p class="mailgun-list-widget-name">
327
  <strong>Name:</strong>
328
  <input type="text" name="name"/>
@@ -391,7 +445,6 @@ class Mailgun
391
  dataType: 'json',
392
  data: jQuery('.' + form_id + '').serialize(),
393
  success: function (data) {
394
-
395
  data_msg = data.message
396
  already_exists = false
397
  if (data_msg !== undefined) {
@@ -419,68 +472,69 @@ class Mailgun
419
  /**
420
  * Initialize List Form.
421
  *
422
- * @param array $atts Form attributes
423
  *
424
  * @return string
425
  *
426
- * @since 0.1
427
  */
428
- public function build_list_form($atts)
429
  {
430
- if (isset($atts[ 'id' ]) && $atts[ 'id' ] != ''):
431
- $args[ 'widget_id' ] = md5(rand(10000, 99999) . $atts[ 'id' ]);
432
 
433
- if (isset($atts[ 'collect_name' ])):
434
- $args[ 'collect_name' ] = true;
435
- endif;
436
 
437
- if (isset($atts[ 'title' ])):
438
- $args[ 'list_title' ] = $atts[ 'title' ];
439
- endif;
440
 
441
- if (isset($atts[ 'description' ])):
442
- $args[ 'list_description' ] = $atts[ 'description' ];
443
- endif;
444
 
445
  ob_start();
446
- $this->list_form($atts[ 'id' ], $args);
447
- $output_string = ob_get_contents();
448
- ob_end_clean();
449
-
450
- return $output_string;
451
- else:
452
- ?>
453
- <span>Mailgun list ID needed to render form!</span>
454
- <br/>
455
- <strong>Example :</strong> [mailgun id="[your list id]"]
456
- <?php
457
- endif;
458
  }
459
 
460
  /**
461
  * Initialize List Widget.
462
- *
463
- * @since 0.1
464
  */
465
  public function load_list_widget()
466
  {
467
  register_widget('list_widget');
468
- add_shortcode('mailgun', array(&$this, 'build_list_form'));
 
 
 
 
 
 
 
 
469
  }
470
  }
471
 
472
- $mailgun = new Mailgun();
473
 
474
- if (@include dirname(__FILE__) . '/includes/widget.php'):
475
- add_action('widgets_init', array(&$mailgun, 'load_list_widget'));
476
- add_action('wp_ajax_nopriv_add_list', array(&$mailgun, 'add_list'));
477
- add_action('wp_ajax_add_list', array(&$mailgun, 'add_list'));
478
- endif;
479
 
480
- if (is_admin()):
481
- if (@include dirname(__FILE__) . '/includes/admin.php'):
482
  $mailgunAdmin = new MailgunAdmin();
483
- else:
484
- Mailgun::deactivate_and_die(dirname(__FILE__) . '/includes/admin.php');
485
- endif;
486
- endif;
1
  <?php
 
2
  /**
3
  * Plugin Name: Mailgun
4
  * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
5
  * Description: Mailgun integration for WordPress
6
+ * Version: 1.8.5
7
  * Author: Mailgun
8
  * Author URI: http://www.mailgun.com/
9
  * License: GPLv2 or later
35
  * either API or SMTP.
36
  *
37
  * Registers handlers for later actions and sets up config variables with
38
+ * WordPress.
39
  */
40
  class Mailgun
41
  {
42
+ /**
43
+ * @var Mailgun $instance
44
+ */
45
+ private static $instance;
46
+
47
+ /**
48
+ * @var false|mixed|null
49
+ */
50
+ private $options;
51
+
52
+ /**
53
+ * @var string
54
+ */
55
+ protected $plugin_file;
56
+
57
+ /**
58
+ * @var string
59
+ */
60
+ protected $plugin_basename;
61
+
62
+ /**
63
+ * @var string
64
+ */
65
+ protected $assetsDir;
66
+
67
  /**
68
  * Setup shared functionality for Admin and Front End.
69
  *
 
70
  */
71
  public function __construct()
72
  {
73
  $this->options = get_option('mailgun');
74
  $this->plugin_file = __FILE__;
75
  $this->plugin_basename = plugin_basename($this->plugin_file);
76
+ $this->assetsDir = plugin_dir_url($this->plugin_file) . 'assets/';
77
 
78
  // Either override the wp_mail function or configure PHPMailer to use the
79
  // Mailgun SMTP servers
80
  // When using SMTP, we also need to inject a `wp_mail` filter to make "from" settings
81
+ // work properly. Fixed issues with 1.5.7+
82
+ if ($this->get_option('useAPI') || (defined('MAILGUN_USEAPI') && MAILGUN_USEAPI)) {
83
+ if (!function_exists('wp_mail')) {
84
+ if (!include __DIR__ . '/includes/wp-mail-api.php') {
85
+ $this->deactivate_and_die(__DIR__ . '/includes/wp-mail-api.php');
86
+ }
87
+ }
88
+ } else {
89
  // Using SMTP, include the SMTP filter
90
+ if (!function_exists('mg_smtp_mail_filter')) {
91
+ if (!include __DIR__ . '/includes/wp-mail-smtp.php') {
92
+ $this->deactivate_and_die(__DIR__ . '/includes/wp-mail-smtp.php');
93
+ }
94
+ }
95
  add_filter('wp_mail', 'mg_smtp_mail_filter');
96
+ add_action('phpmailer_init', [&$this, 'phpmailer_init']);
97
  add_action('wp_mail_failed', 'wp_mail_failed');
98
+ }
99
+ }
100
+
101
+ /**
102
+ * @return static
103
+ */
104
+ public static function getInstance()
105
+ {
106
+ if (!isset(self::$instance)) {
107
+ self::$instance = new self();
108
+ }
109
+
110
+ return self::$instance;
111
  }
112
 
113
  /**
114
  * Get specific option from the options table.
115
  *
116
+ * @param string $option Name of option to be used as array key for retrieving the specific value
117
+ * @param array|null $options Array to iterate over for specific values
118
+ * @param bool $default False if no options are set
119
  *
120
  * @return mixed
121
  *
 
122
  */
123
+ public function get_option(string $option, ?array $options = null, bool $default = false)
124
  {
125
+ if (is_null($options)) {
126
  $options = &$this->options;
127
+ }
128
+
129
+ if (isset($options[$option])) {
130
+ return $options[$option];
131
+ }
132
+
133
+ return $default;
134
  }
135
 
136
  /**
141
  *
142
  * @return void
143
  *
 
144
  */
145
  public function phpmailer_init(&$phpmailer)
146
  {
158
  $phpmailer->Mailer = 'smtp';
159
  $phpmailer->Host = $smtp_endpoint;
160
 
161
+ if ('ssl' === $sectype) {
162
  // For SSL-only connections, use 465
163
  $phpmailer->Port = 465;
164
+ } else {
165
  // Otherwise, use 587.
166
  $phpmailer->Port = 587;
167
+ }
168
 
169
  $phpmailer->SMTPAuth = true;
170
  $phpmailer->Username = $username;
187
  * @param $file Files critical to plugin functionality
188
  *
189
  * @return void
 
 
190
  */
191
  public function deactivate_and_die($file)
192
  {
193
  load_plugin_textdomain('mailgun', false, 'mailgun/languages');
194
  $message = sprintf(__('Mailgun has been automatically deactivated because the file <strong>%s</strong> is missing. Please reinstall the plugin and reactivate.'),
195
  $file);
196
+ if (!function_exists('deactivate_plugins')) {
197
  include ABSPATH . 'wp-admin/includes/plugin.php';
198
+ }
199
  deactivate_plugins(__FILE__);
200
  wp_die($message);
201
  }
207
  * @param array $params Array of parameters passed to the API
208
  * @param string $method The form request type
209
  *
210
+ * @return string
211
  *
 
212
  */
213
+ public function api_call($uri, $params = [], $method = 'POST'): string
214
  {
215
  $options = get_option('mailgun');
216
  $getRegion = (defined('MAILGUN_REGION') && MAILGUN_REGION) ? MAILGUN_REGION : $options[ 'region' ];
218
  $domain = (defined('MAILGUN_DOMAIN') && MAILGUN_DOMAIN) ? MAILGUN_DOMAIN : $options[ 'domain' ];
219
 
220
  $region = mg_api_get_region($getRegion);
221
+ $this->api_endpoint = ($region) ?: 'https://api.mailgun.net/v3/';
222
 
223
  $time = time();
224
  $url = $this->api_endpoint . $uri;
225
+ $headers = [
226
  'Authorization' => 'Basic ' . base64_encode("api:{$apiKey}"),
227
+ ];
228
 
229
  switch ($method) {
230
  case 'GET':
243
  }
244
 
245
  // make the request
246
+ $args = [
247
  'method' => $method,
248
  'body' => $params,
249
  'headers' => $headers,
250
  'sslverify' => true,
251
+ ];
252
 
253
  // make the remote request
254
  $result = wp_remote_request($url, $args);
255
+ if (!is_wp_error($result)) {
256
+ return $result['body'];
257
+ }
258
+
259
+ if (is_callable($result)) {
260
  return $result->get_error_message();
261
+ }
262
+
263
+ if (is_array($result)) {
264
+ if (isset($result['response'])) {
265
+ return $result['response']['message'] ?? '';
266
+ }
267
+ }
268
+
269
+ return '';
270
+
271
  }
272
 
273
  /**
275
  *
276
  * @return array
277
  *
278
+ * @throws JsonException
279
  */
280
+ public function get_lists(): array
281
  {
282
+ $results = [];
283
 
284
+ $lists_json = $this->api_call('lists', [], 'GET');
285
+
286
+ $lists_arr = json_decode($lists_json, true, 512, JSON_THROW_ON_ERROR);
287
+ if (isset($lists_arr[ 'items' ]) && !empty($lists_arr[ 'items' ])) {
288
+ $results = $lists_arr['items'];
289
+ }
290
 
291
  return $results;
292
  }
294
  /**
295
  * Handle add list ajax post.
296
  *
297
+ * @return void json
298
  *
299
+ * @throws JsonException
300
  */
301
  public function add_list()
302
  {
303
+ $name = $_POST['name'] ?? null;
304
+ $email = $_POST['email'] ?? null;
 
 
305
 
306
+ $list_addresses = $_POST['addresses'];
307
 
308
+ if (!empty($list_addresses)) {
309
+ $result = [];
310
+ foreach ($list_addresses as $address => $val) {
311
+ $result[] = $this->api_call(
312
  "lists/{$address}/members",
313
+ [
314
  'address' => $email,
315
  'name' => $name,
316
+ ]
317
  );
318
+ }
319
+ $message = 'Thank you!';
320
+ if ($result) {
321
+ $message = 'Something went wrong';
322
+ $response = json_decode($result[0], true);
323
+ if (is_array($response) && isset($response['message'])) {
324
+ $message = $response['message'];
325
+ }
326
 
327
+ }
328
+ echo json_encode([
329
+ 'status' => 200,
330
+ 'message' => $message
331
+ ], JSON_THROW_ON_ERROR);
332
+ } else {
333
+ echo json_encode([
334
  'status' => 500,
335
  'message' => 'Uh oh. We weren\'t able to add you to the list' . count($list_addresses) ? 's.' : '. Please try again.'
336
+ ], JSON_THROW_ON_ERROR);
337
+ }
 
338
  wp_die();
339
  }
340
 
341
  /**
342
  * Frontend List Form.
343
  *
344
+ * @param string $list_address Mailgun address list id
345
+ * @param array $args widget arguments
346
+ * @param array $instance widget instance params
347
  *
348
+ * @throws JsonException
349
  */
350
+ public function list_form(string $list_address, array $args = [], array $instance = [])
351
  {
352
+ $widgetId = $args['widget_id'] ?? 0;
353
+ $widget_class_id = "mailgun-list-widget-{$widgetId}";
354
+ $form_class_id = "list-form-{$widgetId}";
355
 
356
  // List addresses from the plugin config
357
  $list_addresses = array_map('trim', explode(',', $list_address));
376
  </p>
377
  </div>
378
  <?php endif; ?>
379
+ <?php if (isset($args[ 'collect_name' ]) && (int)$args['collect_name'] === 1): ?>
380
  <p class="mailgun-list-widget-name">
381
  <strong>Name:</strong>
382
  <input type="text" name="name"/>
445
  dataType: 'json',
446
  data: jQuery('.' + form_id + '').serialize(),
447
  success: function (data) {
 
448
  data_msg = data.message
449
  already_exists = false
450
  if (data_msg !== undefined) {
472
  /**
473
  * Initialize List Form.
474
  *
475
+ * @param array $atts Form attributes
476
  *
477
  * @return string
478
  *
479
+ * @throws JsonException
480
  */
481
+ public function build_list_form(array $atts): string
482
  {
483
+ if (isset($atts['id']) && $atts['id'] != '') {
484
+ $args['widget_id'] = md5(rand(10000, 99999) . $atts['id']);
485
 
486
+ if (isset($atts['collect_name'])) {
487
+ $args['collect_name'] = true;
488
+ }
489
 
490
+ if (isset($atts['title'])) {
491
+ $args['list_title'] = $atts['title'];
492
+ }
493
 
494
+ if (isset($atts['description'])) {
495
+ $args['list_description'] = $atts['description'];
496
+ }
497
 
498
  ob_start();
499
+ $this->list_form($atts['id'], $args);
500
+ return ob_get_clean();
501
+ }
502
+
503
+ return '<span>Mailgun list ID needed to render form!</span>
504
+ <br/>
505
+ <strong>Example :</strong> [mailgun id="[your list id]"]';
 
 
 
 
 
506
  }
507
 
508
  /**
509
  * Initialize List Widget.
 
 
510
  */
511
  public function load_list_widget()
512
  {
513
  register_widget('list_widget');
514
+ add_shortcode('mailgun', [&$this, 'build_list_form']);
515
+ }
516
+
517
+ /**
518
+ * @return string
519
+ */
520
+ public function getAssetsPath(): string
521
+ {
522
+ return $this->assetsDir;
523
  }
524
  }
525
 
526
+ $mailgun = Mailgun::getInstance();
527
 
528
+ if (@include __DIR__ . '/includes/widget.php') {
529
+ add_action('widgets_init', [&$mailgun, 'load_list_widget']);
530
+ add_action('wp_ajax_nopriv_add_list', [&$mailgun, 'add_list']);
531
+ add_action('wp_ajax_add_list', [&$mailgun, 'add_list']);
532
+ }
533
 
534
+ if (is_admin()) {
535
+ if (@include __DIR__ . '/includes/admin.php') {
536
  $mailgunAdmin = new MailgunAdmin();
537
+ } else {
538
+ $mailgun->deactivate_and_die(__DIR__ . '/includes/admin.php');
539
+ }
540
+ }
readme.md ADDED
@@ -0,0 +1,337 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Mailgun for WordPress
2
+ =====================
3
+
4
+ Contributors: mailgun, sivel, lookahead.io, m35dev
5
+ Tags: mailgun, smtp, http, api, mail, email
6
+ Requires at least: 3.3
7
+ Tested up to: 6.0.1
8
+ Stable tag: 1.8.5
9
+ License: GPLv2 or later
10
+
11
+
12
+ Easily send email from your WordPress site through Mailgun using the HTTP API or SMTP.
13
+
14
+
15
+ ## Description
16
+
17
+ [Mailgun](http://www.mailgun.com/) is the email automation engine trusted by over 10,000 website and application developers for sending, receiving and tracking emails. By taking advantage of Mailgun's powerful email APIs, developers can spend more time building awesome websites and less time fighting with email servers. Mailgun supports all of the most popular languages including PHP, Ruby, Python, C# and Java.
18
+
19
+ One particularly useful feature of this plugin is that it provides you with a way to send email when the server you are on does not support SMTP or where outbound SMTP is restricted since the plug-in uses the Mailgun HTTP API for sending email by default. All you need to use the plugin is a [Mailgun account](http://www.mailgun.com/). Mailgun has a free account that lets you send up to 200 emails per day, which is great for testing. Paid subscriptions are available for increased limits.
20
+
21
+ The latest version of this plugin now supports regions. Select either U.S./North America or Europe to choose the API endpoint from which you will send email.
22
+
23
+ The current version of this plugin only handles sending emails, tracking and tagging and list subscription.
24
+
25
+
26
+ ## Installation
27
+
28
+ 1. Upload the `mailgun` folder to the `/wp-content/plugins/` directory or install directly through the plugin installer
29
+ 2. Activate the plugin through the 'Plugins' menu in WordPress or by using the link provided by the plugin installer
30
+ 3. Visit the settings page in the Admin at `Settings -> Mailgun` and configure the plugin with your account details
31
+ 4. Click the Test Configuration button to verify that your settings are correct.
32
+ 5. Click View Available Lists to review shortcode settings for lists in your Mailgun account that you may wish to help users subscribe to
33
+
34
+
35
+ == Frequently Asked Questions ==
36
+
37
+ - Testing the configuration fails when using the HTTP API
38
+
39
+ Your web server may not allow outbound HTTP connections. Set `Use HTTP API` to "No", and fill out the configuration options to SMTP and test again.
40
+
41
+ - Testing the configuration fails when using SMTP
42
+
43
+ Your web server may not allow outbound SMTP connections on port 465 for secure connections or 587 for unsecured connections. Try changing `Use Secure SMTP` to "No" or "Yes" depending on your current configuration and testing again. If both fail, try setting `Use HTTP API` to "Yes" and testing again.
44
+
45
+ If you *have* to use SMTP and something is still going horribly wrong, enable debug mode in WordPress and also add the `MG_DEBUG_SMTP` constant to your `wp-config.php`, like so:
46
+
47
+ `
48
+ define( 'MG_DEBUG_SMTP', true );
49
+ `
50
+
51
+ - Can this be configured globally for WordPress Multisite?
52
+
53
+ Yes, using the following constants that can be placed in wp-config.php:
54
+
55
+ ### Important note
56
+ Constant `MAILGUN_USEAPI` IS REQUIRED
57
+
58
+ ```
59
+ MAILGUN_REGION Type: string Choices: 'us' or 'eu'
60
+ ex. define('MAILGUN_REGION', 'us');
61
+ MAILGUN_USEAPI Type: boolean Choices: '0' or '1' (0 = false/no)
62
+ MAILGUN_APIKEY Type: string
63
+ MAILGUN_DOMAIN Type: string
64
+ MAILGUN_USERNAME Type: string
65
+ MAILGUN_PASSWORD Type: string
66
+ MAILGUN_SECURE Type: boolean Choices: '0' or '1' (0 = false/no)
67
+ MAILGUN_SECTYPE Type: string Choices: 'ssl' or 'tls'
68
+ MAILGUN_FROM_NAME Type: string
69
+ MAILGUN_FROM_ADDRESS Type: string
70
+ ```
71
+
72
+ - What hooks are available for use with other plugins?
73
+
74
+ `mg_use_recipient_vars_syntax`
75
+ Mutates messages to use recipient variables syntax - see
76
+ https://documentation.mailgun.com/user_manual.html#batch-sending for more info.
77
+
78
+ Should accept a list of `To` addresses.
79
+
80
+ Should *only* return `true` or `false`.
81
+
82
+ `mg_mutate_message_body`
83
+ Allows an external plugin to mutate the message body before sending.
84
+
85
+ Should accept an array, `$body`.
86
+
87
+ Should return a new array to replace `$body`.
88
+
89
+ `mg_mutate_attachments`
90
+ Allows an external plugin to mutate the attachments on the message before
91
+ sending.
92
+
93
+ Should accept an array, `$attachments`.
94
+
95
+ Should return a new array to replace `$attachments`.
96
+
97
+ - What hooks are available for use with other plugins?
98
+
99
+ `mg_use_recipient_vars_syntax`
100
+ Mutates messages to use recipient variables syntax - see
101
+ https://documentation.mailgun.com/en/latest/user_manual.html#batch-sending for more info.
102
+
103
+ Should accept a list of `To` addresses.
104
+
105
+ Should *only* return `true` or `false`.
106
+
107
+ `mg_mutate_message_body`
108
+ Allows an external plugin to mutate the message body before sending.
109
+
110
+ Should accept an array, `$body`.
111
+
112
+ Should return a new array to replace `$body`.
113
+
114
+ `mg_mutate_attachments`
115
+ Allows an external plugin to mutate the attachments on the message before
116
+ sending.
117
+
118
+ Should accept an array, `$attachments`.
119
+
120
+ Should return a new array to replace `$attachments`.
121
+
122
+
123
+ == Screenshots ==
124
+
125
+ 1. Configuration options for using the Mailgun HTTP API
126
+ 2. Configuration options for using the Mailgun SMTP servers
127
+ 3. Administration option to View Available Lists for subscription
128
+ 4. Setting up a Subscription Widget
129
+ 5. Using a Subscription Code
130
+ 6. Subscription Form Seen By Site Visitors
131
+
132
+
133
+ == Changelog ==
134
+ = 1.8.3 (2022-08-30): =
135
+ - Plugin refactoring. Widget fixes for working with Legacy Widget Block. PHP8.0 support check
136
+
137
+ = 1.8.2 (2022-08-24): =
138
+ - Plugin refactoring. Small fixes
139
+
140
+ = 1.8.1 (2022-08-19): =
141
+ - backward compatibility with php7.0
142
+
143
+ = 1.8.0 (2022-08-18): =
144
+ - Plugin refactoring. Using new languages constructions. Extended readme. Update version
145
+
146
+ = 1.7.9 (2021-05-24): =
147
+ - API Key description
148
+
149
+ = 1.7.8 (2021-05-13): =
150
+ - Tested WP 5.7.1
151
+
152
+ = 1.7.7 (2021-03-16): =
153
+ - Updated assets, tested WP 5.7
154
+
155
+ = 1.7.6 (2021-02-19): =
156
+ - Sync versions across plugin files
157
+
158
+ = 1.7.3 (2021-02-19): =
159
+ - Update plugin version
160
+
161
+ = 1.7.2 (2020-10-07): =
162
+ - Test plugin with PHP 7.4.
163
+ - Test plugin up to WordPress 5.5.1.
164
+
165
+ = 1.7.1 (2019-02-07): =
166
+ - Reinstall settings page for multisites.
167
+
168
+ = 1.7 (2019-01-21): =
169
+ - Remove settings page for multisites.
170
+ - Simplify admin notifications.
171
+ - Test plugin with PHP 7.2.
172
+ - Test plugin up to WordPress 5.0.3.
173
+
174
+ = 1.6.1 (2018-10-08): =
175
+ - Restore Settings page form for all install types.
176
+
177
+ = 1.6 (2018-9-21): =
178
+ - Refactor admin notifications
179
+ - Enable Settings page for all WordPress install types
180
+ - Enable Test Configuration for all WordPress install types
181
+ - Test plugin up to WordPress 4.9.8.
182
+
183
+ = 1.5.14 (2018-09-11): =
184
+ - Force SSL-secured SMTP connections to use port 465 (SMTPS) to connect, 587 for plain and TLS
185
+ - Support region endpoint switching for SMTP
186
+
187
+ = 1.5.13.1 (2018-08-15): =
188
+ - Fix line breaks in Test Configuration email
189
+
190
+ = 1.5.13 (2018-08-14): =
191
+ - Default to US region if no region is configured in settings
192
+ - Add admin notification about region configuration
193
+ - Log an error message when an email is sent with no explicit region configured
194
+
195
+ = 1.5.12.3 (2018-08-09): =
196
+ - Fix Region select menu default when wp-config.php variable is set
197
+ - Fix front end email input validation
198
+
199
+ = 1.5.12.2 (2018-08-09): =
200
+ - Fix plugin not saving after update
201
+
202
+ = 1.5.12.1 (2018-08-06): =
203
+ - Fix for backwards compatibility
204
+
205
+ = 1.5.12 (2018-08-02): =
206
+ - Add EU endpoint for Mailgun HTTP API
207
+ - Fix broken logo image on Lists page
208
+ - Test plugin up to Wordpress 4.9.7
209
+
210
+ = 1.5.11 (2018-05-30): =
211
+ - Fix an issue with authentication failing for newer API keys
212
+ - Test plugin up to Wordpress 4.9.6
213
+
214
+ = 1.5.10 (2017-11-22): =
215
+ - Fix back to settings link on lists page (https://github.com/mailgun/wordpress-plugin/pull/65)
216
+ - Fix a bug causing `text/html` emails to send as both `text/plain` *and* `text/html` parts
217
+
218
+ = 1.5.9 (2017-09-13): =
219
+ - Add a configuration option to allow setting security type for SMTP connection (SSL / TLS)
220
+
221
+ = 1.5.8.5 (2017-09-05): =
222
+ - Change default click tracking setting to `htmlonly` (https://github.com/mailgun/wordpress-plugin/pull/58)
223
+ - Change PHPMailer set-up stanza to use TLS
224
+
225
+ = 1.5.8.4 (2017-06-28): =
226
+ - Packaging fix which takes care of an odd filtering issue (https://wordpress.org/support/topic/1-5-8-3-broke-the-mg_mutate_message_body-filter)
227
+
228
+ = 1.5.8.3 (2017-06-13): =
229
+ - Fix a bug causing only the last header value to be used when multiple headers of the same type are specified (https://wordpress.org/support/topic/bug-with-mg_parse_headers/)
230
+ - Added `pt_BR` translations (thanks @emersonbroga)
231
+
232
+ = 1.5.8.2 (2017-02-27): =
233
+ - Fix a bug causing empty tags to be sent with messages (#51)
234
+ - Add `mg_mutate_message_body` hook to allow other plugins to modify the message body before send
235
+ - Add `mg_mutate_attachments` hook to allow other plugins to modify the message attachments before send
236
+ - Fix a bug causing the AJAX test to fail incorrectly.
237
+
238
+ = 1.5.8.2 (2017-02-27): =
239
+ - Fix a bug causing empty tags to be sent with messages (#51)
240
+ - Add `mg_mutate_message_body` hook to allow other plugins to modify the message body before send
241
+ - Add `mg_mutate_attachments` hook to allow other plugins to modify the message attachments before send
242
+ - Fix a bug causing the AJAX test to fail incorrectly.
243
+
244
+ = 1.5.8.1 (2017-02-06): =
245
+ - Fix "Undefined property: MailgunAdmin::$hook_suffix" (#48)
246
+ - Fix "Undefined variable: from_name on every email process" (API and SMTP) (#49)
247
+ - Admin code now loads only on admin user access
248
+
249
+ = 1.5.8 (2017-01-23): =
250
+ * Rewrite a large chunk of old SMTP code
251
+ * Fix a bug with SMTP + "override from" that was introduced in 1.5.7
252
+ * SMTP debug logging is now controlled by `MG_DEBUG_SMTP` constant
253
+
254
+ = 1.5.7.1 (2017-01-18): =
255
+ * Fix an odd `Undefined property: MailgunAdmin::$defaults` when saving config
256
+ * Fix strict mode notice for using `$mailgun['override-from']` without checking `isset`
257
+
258
+ = 1.5.7 (2017-01-04): =
259
+ * Add better support for using recipient variables for batch mailing.
260
+ * Clarify wording on `From Address` note
261
+ * Detect from name and address for `phpmailer_init` / SMTP now will honour Mailgun "From Name / From Addr" settings
262
+ * SMTP configuration test will now provide the error message, if the send fails
263
+ * Fix `undefined variable: content_type` error in `wp-mail.php` (https://wordpress.org/support/topic/minor-bug-on-version-version-1-5-6/#post-8634762)
264
+ * Fix `undefined index: override-from` error in `wp-mail.php` (https://wordpress.org/support/topic/php-notice-undefined-index-override-from/)
265
+
266
+ = 1.5.6 (2016-12-30): =
267
+ * Fix a very subtle bug causing fatal errors with older PHP versions < 5.5
268
+ * Respect `wp_mail_content_type` (#37 - @FPCSJames)
269
+
270
+ = 1.5.5 (2016-12-27): =
271
+ * Restructure the `admin_notices` code
272
+ * Restructure the "From Name" / "From Address" code
273
+ * Add option to override "From Name" / "From Address" setting set by other plugins
274
+ * Fix a bug causing default "From Name" / "From Address" to be always applied in some cases
275
+ * Moved plugin header up in entrypoint file (https://wordpress.org/support/topic/plugin-activation-due-to-header/#post-8598062)
276
+ * Fixed a bug causing "Override From" to be set to "yes" after upgrades
277
+
278
+ = 1.5.4 (2016-12-23): =
279
+ * Changed some missed bracketed array usages to `array()` syntax
280
+ * Fix `wp_mail_from` / `wp_mail_from_name` not working on old PHP / WP versions
281
+ * Add a wrapper for using `mime_content_type` / `finfo_file`
282
+
283
+ = 1.5.3 (2016-12-22): =
284
+ * Changed all bracketed array usages to `array()` syntax for older PHP support
285
+ * Redesigned `Content-Type` processing code to not make such large assumptions
286
+ * Mailgun logo is now loaded over HTTPS
287
+ * Fixed undefined variable issue with from email / from name code
288
+
289
+ = 1.5.2 (2016-12-22): =
290
+ * Added option fields for setting a From name and address
291
+
292
+ = 1.5.1 (2016-12-21): =
293
+ * Fixed an issue causing plugin upgrades from <1.5 -> >=1.5 to deactivate
294
+
295
+ = 1.5 (2016-12-19): =
296
+ * Added Catalan language support (@DavidGarciaCat)
297
+ * Added Spanish language support (@DavidGarciaCat)
298
+ * Added German language support (@lsinger)
299
+ * Fixed incorrect SMTP hostname
300
+ * Applied PSR standards across codebase
301
+ * Applied open tracking bugfix
302
+ * Applied tags bugfix
303
+ * Applied `Mailgun Lists` admin panel bugfix
304
+ * Fixed click tracking dropdown
305
+ * Fixed click tracking and open tracking
306
+ * Now try to process *all* sent mails as HTML, see L201 wp-mail.php for details
307
+ * Mailgun logo now loads on both admin pages ;)
308
+ * Now using the Mailgun API v3 endpoint!
309
+ * Configuration test will now present either an error from the API or the HTTP response code + message
310
+
311
+ = 1.4.1 (2015-12-01): =
312
+ * Clarify compatibility with WordPress 4.3
313
+
314
+ = 1.4 (2015-11-15): =
315
+ * Added shortcode and widget support for list subscription
316
+
317
+ = 1.3.1 (2014-11-19): =
318
+ * Switched to Semantic Versioning
319
+ * Fixed issue with campaigns and tags
320
+
321
+ = 1.3 (2014-08-25): =
322
+ * Added check to ignore empty attachments
323
+
324
+ = 1.2 (2014-08-19): =
325
+ * Fixed errors related to undefined variable. https://github.com/mailgun/wordpress-plugin/pull/3
326
+
327
+ = 1.1 (2013-12-09): =
328
+ * Attachments are now handled properly.
329
+ * Added ability to customize tags and campaigns.
330
+ * Added ability to toggle URL and open tracking.
331
+
332
+ = 1.0 (2012-11-27): =
333
+ * Re-release to update versioning to start at 1.0 instead of 0.1
334
+
335
+ = 0.1 (2012-11-21): =
336
+ * Initial Release
337
+
readme.txt CHANGED
@@ -4,8 +4,8 @@ Mailgun for WordPress
4
  Contributors: mailgun, sivel, lookahead.io, m35dev
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
- Tested up to: 5.7.2
8
- Stable tag: 1.7.9
9
  License: GPLv2 or later
10
 
11
 
@@ -128,6 +128,17 @@ MAILGUN_FROM_ADDRESS Type: string
128
 
129
 
130
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  = 1.7.9 (2021-05-24): =
133
  - API Key description
4
  Contributors: mailgun, sivel, lookahead.io, m35dev
5
  Tags: mailgun, smtp, http, api, mail, email
6
  Requires at least: 3.3
7
+ Tested up to: 6.0.1
8
+ Stable tag: 1.8.5
9
  License: GPLv2 or later
10
 
11
 
128
 
129
 
130
  == Changelog ==
131
+ = 1.8.3 (2022-08-30): =
132
+ - Plugin refactoring. Widget fixes for working with Legacy Widget Block. PHP8.0 support check
133
+
134
+ = 1.8.2 (2022-08-24): =
135
+ - Plugin refactoring. Small fixes
136
+
137
+ = 1.8.1 (2022-08-19): =
138
+ - backward compatibility with php7.0
139
+
140
+ = 1.8.0 (2022-08-18): =
141
+ - Plugin refactoring. Using new languages constructions. Extended readme. Update version
142
 
143
  = 1.7.9 (2021-05-24): =
144
  - API Key description