PluginProbe
Mailgun for WordPress / 2.1.8
Mailgun for WordPress v2.1.8
2.2.3 2.2.2 2.2.1 trunk 1.9.9 2.0.0 2.0.1 2.1.0 2.1.1 2.1.10 2.1.2 2.1.3 2.1.4 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0
mailgun / mailgun.php

mailgun.php in Mailgun for WordPress 2.1.8, at mailgun.php

544 lines 19.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Mailgun
4 * Plugin URI: http://wordpress.org/extend/plugins/mailgun/
5 * Description: Mailgun integration for WordPress
6 * Version: 2.1.8
7 * Requires PHP: 7.4
8 * Requires at least: 4.4
9 * Author: Mailgun
10 * Author URI: http://www.mailgun.com/
11 * License: GPLv2 or later
12 * Text Domain: mailgun
13 * Domain Path: /languages/.
14 *
15 * @package Mailgun
16 */
17
18 /*
19 * mailgun-wordpress-plugin - Sending mail from Wordpress using Mailgun
20 * Copyright (C) 2016 Mailgun, et al.
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License along
33 * with this program; if not, write to the Free Software Foundation, Inc.,
34 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
35 */
36
37 /**
38 * Entrypoint for the Mailgun plugin. Sets up the mailing "strategy" -
39 * either API or SMTP.
40 *
41 * Registers handlers for later actions and sets up config variables with
42 * WordPress.
43 */
44 class Mailgun {
45
46 /**
47 * @var Mailgun $instance
48 */
49 private static Mailgun $instance;
50
51 /**
52 * @var false|mixed|null
53 */
54 private $options;
55
56 /**
57 * @var string
58 */
59 protected string $plugin_file;
60
61 /**
62 * @var string
63 */
64 protected string $plugin_basename;
65
66 /**
67 * @var string
68 */
69 protected string $assetsDir;
70
71 /**
72 * @var string
73 */
74 private string $api_endpoint;
75
76 /**
77 * Setup shared functionality for Admin and Front End.
78 */
79 public function __construct() {
80 $this->options = get_option( 'mailgun' );
81 $this->plugin_file = __FILE__;
82 $this->plugin_basename = plugin_basename( $this->plugin_file );
83 $this->assetsDir = plugin_dir_url( $this->plugin_file ) . 'assets/';
84
85 // Either override the wp_mail function or configure PHPMailer to use the
86 // Mailgun SMTP servers
87 // When using SMTP, we also need to inject a `wp_mail` filter to make "from" settings
88 // work properly. Fixed issues with 1.5.7+
89 if ( $this->get_option( 'useAPI' ) || ( defined( 'MAILGUN_USEAPI' ) && MAILGUN_USEAPI ) ) {
90 if ( ! function_exists( 'wp_mail' ) ) {
91 if ( ! include_once __DIR__ . '/includes/wp-mail-api.php' ) {
92 $this->deactivate_and_die( __DIR__ . '/includes/wp-mail-api.php' );
93 }
94 }
95 } else {
96 // Using SMTP, include the SMTP filter
97 if ( ! function_exists( 'mg_smtp_mail_filter' ) ) {
98 if ( ! include __DIR__ . '/includes/wp-mail-smtp.php' ) {
99 $this->deactivate_and_die( __DIR__ . '/includes/wp-mail-smtp.php' );
100 }
101 }
102 add_filter( 'wp_mail', 'mg_smtp_mail_filter' );
103 add_action( 'phpmailer_init', array( &$this, 'phpmailer_init' ) );
104 add_action( 'wp_mail_failed', 'wp_mail_failed' );
105 }
106 }
107
108 /**
109 * @return static
110 */
111 public static function getInstance(): Mailgun {
112 if ( ! isset( self::$instance ) ) {
113 self::$instance = new self();
114 }
115
116 return self::$instance;
117 }
118
119 /**
120 * Get specific option from the options table.
121 *
122 * @param string $option Name of option to be used as array key for retrieving the specific value
123 * @param array|null $options Array to iterate over for specific values
124 * @param bool $defaultValue Default value to return if option is not found
125 * @return mixed
126 */
127 public function get_option( string $option, ?array $options = null, bool $defaultValue = false ) {
128 if ( is_null( $options ) ) {
129 $options = &$this->options;
130 }
131
132 if ( isset( $options[ $option ] ) ) {
133 return $options[ $option ];
134 }
135
136 return $defaultValue;
137 }
138
139 /**
140 * Hook into phpmailer to override SMTP based configurations
141 * to use the Mailgun SMTP server.
142 *
143 * @param object $phpmailer The PHPMailer object to modify by reference
144 *
145 * @return void
146 */
147 public function phpmailer_init( &$phpmailer ): void {
148 $username = ( defined( 'MAILGUN_USERNAME' ) && MAILGUN_USERNAME ) ? MAILGUN_USERNAME : $this->get_option( 'username' );
149 $domain = ( defined( 'MAILGUN_DOMAIN' ) && MAILGUN_DOMAIN ) ? MAILGUN_DOMAIN : $this->get_option( 'domain' );
150 $username = preg_replace( '/@.+$/', '', $username ) . "@{$domain}";
151 $secure = ( defined( 'MAILGUN_SECURE' ) && MAILGUN_SECURE ) ? MAILGUN_SECURE : $this->get_option( 'secure' );
152 $sectype = ( defined( 'MAILGUN_SECTYPE' ) && MAILGUN_SECTYPE ) ? MAILGUN_SECTYPE : $this->get_option( 'sectype' );
153 $password = ( defined( 'MAILGUN_PASSWORD' ) && MAILGUN_PASSWORD ) ? MAILGUN_PASSWORD : $this->get_option( 'password' );
154 $region = ( defined( 'MAILGUN_REGION' ) && MAILGUN_REGION ) ? MAILGUN_REGION : $this->get_option( 'region' );
155
156 $smtp_endpoint = mg_smtp_get_region( $region );
157 $smtp_endpoint = (bool) $smtp_endpoint ? $smtp_endpoint : 'smtp.mailgun.org';
158
159 $phpmailer->Mailer = 'smtp';
160 $phpmailer->Host = $smtp_endpoint;
161
162 if ( 'ssl' === $sectype ) {
163 // For SSL-only connections, use 465
164 $phpmailer->Port = 465;
165 } else {
166 // Otherwise, use 587.
167 $phpmailer->Port = 587;
168 }
169
170 $phpmailer->SMTPAuth = true;
171 $phpmailer->Username = $username;
172 $phpmailer->Password = $password;
173
174 $phpmailer->SMTPSecure = (bool) $secure ? $sectype : '';
175 // Without this line... wp_mail for SMTP-only will always return false. But why? :(
176 $phpmailer->Debugoutput = 'mg_smtp_debug_output';
177 $phpmailer->SMTPDebug = 2;
178
179 // Emit some logging for SMTP connection
180 mg_smtp_debug_output(
181 sprintf( 'PHPMailer configured to send via %s:%s', $phpmailer->Host, $phpmailer->Port ),
182 'DEBUG'
183 );
184 }
185
186 /**
187 * Deactivate this plugin and die.
188 * Deactivate the plugin when files critical to it's operation cannot be loaded
189 *
190 * @param string $file files critical to plugin functionality
191 *
192 * @return void
193 */
194 public function deactivate_and_die( $file ): void {
195 load_plugin_textdomain( 'mailgun', false, 'mailgun/languages' );
196 $message = sprintf(
197 __( 'Mailgun has been automatically deactivated because the file <strong>%s</strong> is missing. Please reinstall the plugin and reactivate.' ),
198 $file
199 );
200 if ( ! function_exists( 'deactivate_plugins' ) ) {
201 include ABSPATH . 'wp-admin/includes/plugin.php';
202 }
203 deactivate_plugins( __FILE__ );
204 wp_die( $message );
205 }
206
207 /**
208 * Make a Mailgun api call.
209 *
210 * @param string $uri The endpoint for the Mailgun API
211 * @param array $params Array of parameters passed to the API
212 * @param string $method The form request type
213 *
214 * @return string
215 */
216 public function api_call( string $uri, array $params = array(), string $method = 'POST' ): string {
217 $options = get_option( 'mailgun' );
218 $getRegion = ( defined( 'MAILGUN_REGION' ) && MAILGUN_REGION ) ? MAILGUN_REGION : $options['region'];
219 $apiKey = ( defined( 'MAILGUN_APIKEY' ) && MAILGUN_APIKEY ) ? MAILGUN_APIKEY : $options['apiKey'];
220 $domain = ( defined( 'MAILGUN_DOMAIN' ) && MAILGUN_DOMAIN ) ? MAILGUN_DOMAIN : $options['domain'];
221
222 if ( ! function_exists( 'mg_api_get_region' ) ) {
223 include __DIR__ . '/includes/mg-filter.php';
224 }
225 $region = mg_api_get_region( $getRegion );
226 $this->api_endpoint = ( $region ) ?: 'https://api.mailgun.net/v3/';
227
228 $time = time();
229 $url = $this->api_endpoint . $uri;
230 $headers = [
231 'Authorization' => 'Basic ' . base64_encode( "api:{$apiKey}" ),
232 ];
233
234 switch ( $method ) {
235 case 'GET':
236 $params['sess'] = '';
237 $querystring = http_build_query( $params );
238 $url = $url . '?' . $querystring;
239 $params = '';
240 break;
241 case 'POST':
242 case 'PUT':
243 case 'DELETE':
244 $params['sess'] = '';
245 $params['time'] = $time;
246 $params['hash'] = sha1( date( 'U' ) );
247 break;
248 }
249
250 // make the request
251 $args = [
252 'method' => $method,
253 'body' => $params,
254 'headers' => $headers,
255 'sslverify' => true,
256 ];
257
258 // make the remote request
259 $result = wp_remote_request( $url, $args );
260 if ( ! is_wp_error( $result ) ) {
261 return $result['body'];
262 }
263
264 if ( is_callable( $result ) ) {
265 return $result->get_error_message();
266 }
267
268 if ( is_array( $result ) ) {
269 if ( isset( $result['response'] ) ) {
270 return $result['response']['message'] ?? '';
271 }
272 }
273
274 return '';
275 }
276
277 /**
278 * Get account associated lists.
279 *
280 * @return array
281 *
282 * @throws JsonException
283 */
284 public function get_lists(): array {
285 $results = [];
286
287 $lists_json = $this->api_call( 'lists', [], 'GET' );
288
289 $lists_arr = json_decode( $lists_json, true, 512, JSON_THROW_ON_ERROR );
290 if ( isset( $lists_arr['items'] ) && ! empty( $lists_arr['items'] ) ) {
291 $results = $lists_arr['items'];
292 }
293
294 return $results;
295 }
296
297 /**
298 * Handle add list ajax post.
299 *
300 * @return void json
301 *
302 * @throws JsonException
303 */
304 public function add_list(): void {
305 $name = sanitize_text_field( $_POST['name'] ?? null );
306 $email = sanitize_text_field( $_POST['email'] ?? null );
307 $list_addresses = [];
308 foreach ( $_POST['addresses'] as $address => $val ) {
309 $list_addresses[ sanitize_text_field( $address ) ] = sanitize_text_field( $val );
310 }
311
312 if ( ! empty( $list_addresses ) ) {
313 $result = [];
314 foreach ( $list_addresses as $address => $val ) {
315 $result[] = $this->api_call(
316 "lists/{$address}/members",
317 [
318 'address' => $email,
319 'name' => $name,
320 ]
321 );
322 }
323 $message = 'Thank you!';
324 if ( $result ) {
325 $message = 'Something went wrong';
326 $response = json_decode( $result[0], true );
327 if ( is_array( $response ) && isset( $response['message'] ) ) {
328 $message = $response['message'];
329 }
330 }
331 echo json_encode(
332 [
333 'status' => 200,
334 'message' => $message,
335 ],
336 JSON_THROW_ON_ERROR
337 );
338 } else {
339 echo json_encode(
340 [
341 'status' => 500,
342 'message' => 'Uh oh. We weren\'t able to add you to the list' . count( $list_addresses ) ? 's.' : '. Please try again.',
343 ],
344 JSON_THROW_ON_ERROR
345 );
346 }
347 wp_die();
348 }
349
350 /**
351 * Frontend List Form.
352 *
353 * @param string $list_address Mailgun address list id
354 * @param array $args widget arguments
355 * @throws JsonException
356 */
357 public function list_form( string $list_address, array $args = array() ): void {
358 $widgetId = $args['widget_id'] ?? 0;
359 $widget_class_id = "mailgun-list-widget-{$widgetId}";
360 $form_class_id = "list-form-{$widgetId}";
361
362 // List addresses from the plugin config
363 $list_addresses = array_map( 'trim', explode( ',', $list_address ) );
364
365 // All list info from the API; used for list info when more than one list is available to subscribe to
366 $all_list_addresses = $this->get_lists();
367 ?>
368 <div class="mailgun-list-widget-front <?php echo esc_attr( $widget_class_id ); ?> widget">
369 <form class="list-form <?php echo esc_attr( $form_class_id ); ?>">
370 <div class="mailgun-list-widget-inputs">
371 <?php if ( isset( $args['list_title'] ) ) : ?>
372 <div class="mailgun-list-title">
373 <h4 class="widget-title">
374 <span><?php echo wp_kses_data( $args['list_title'] ); ?></span>
375 </h4>
376 </div>
377 <?php endif; ?>
378 <?php if ( isset( $args['list_description'] ) ) : ?>
379 <div class="mailgun-list-description">
380 <p class="widget-description">
381 <span><?php echo wp_kses_data( $args['list_description'] ); ?></span>
382 </p>
383 </div>
384 <?php endif; ?>
385 <?php if ( isset( $args['collect_name'] ) && (int) $args['collect_name'] === 1 ) : ?>
386 <p class="mailgun-list-widget-name">
387 <strong>Name:</strong>
388 <input type="text" name="name"/>
389 </p>
390 <?php endif; ?>
391 <p class="mailgun-list-widget-email">
392 <strong>Email:</strong>
393 <input type="text" name="email"/>
394 </p>
395 </div>
396
397 <?php if ( count( $list_addresses ) > '1' ) : ?>
398 <ul class="mailgun-lists" style="list-style: none;">
399 <?php
400 foreach ( $all_list_addresses as $la ) :
401 if ( ! in_array( $la['address'], $list_addresses, true ) ) :
402 continue;
403 endif;
404 ?>
405 <li>
406 <input type="checkbox" class="mailgun-list-name"
407 name="addresses[<?php echo esc_attr( $la['address'] ); ?>]"/> <?php echo esc_attr( $la['name'] ?: $la['address'] ); ?>
408 </li>
409 <?php endforeach; ?>
410 </ul>
411 <?php else : ?>
412 <input type="hidden" name="addresses[<?php echo esc_attr( $list_addresses[0] ); ?>]" value="on"/>
413 <?php endif; ?>
414
415 <input class="mailgun-list-submit-button" data-form-id="<?php echo esc_attr( $form_class_id ); ?>" type="button"
416 value="Subscribe"/>
417 <input type="hidden" name="mailgun-submission" value="1"/>
418
419 </form>
420 <div class="widget-list-panel result-panel" style="display:none;">
421 <span>Thank you for subscribing!</span>
422 </div>
423 </div>
424
425 <script>
426 jQuery(document).ready(function () {
427
428 jQuery('.mailgun-list-submit-button').on('click', function () {
429
430 var form_id = jQuery(this).data('form-id')
431
432 if (jQuery('.mailgun-list-name').length > 0 && jQuery('.' + form_id + ' .mailgun-list-name:checked').length < 1) {
433 alert('Please select a list to subscribe to.')
434 return
435 }
436
437 if (jQuery('.' + form_id + ' .mailgun-list-widget-name input') && jQuery('.' + form_id + ' .mailgun-list-widget-name input').val() === '') {
438 alert('Please enter your subscription name.')
439 return
440 }
441
442 if (jQuery('.' + form_id + ' .mailgun-list-widget-email input').val() === '') {
443 alert('Please enter your subscription email.')
444 return
445 }
446
447 jQuery.ajax({
448 url: '<?php echo admin_url( 'admin-ajax.php?action=add_list' ); ?>',
449 action: 'add_list',
450 type: 'post',
451 dataType: 'json',
452 data: jQuery('.' + form_id + '').serialize(),
453 success: function (data) {
454 data_msg = data.message
455 already_exists = false
456 if (data_msg !== undefined) {
457 already_exists = data_msg.indexOf('Address already exists') > -1
458 }
459
460 // success
461 if ((data.status === 200)) {
462 jQuery('.<?php echo esc_attr( $widget_class_id ); ?> .widget-list-panel').css('display', 'none')
463 jQuery('.<?php echo esc_attr( $widget_class_id ); ?> .list-form').css('display', 'none')
464 jQuery('.<?php echo esc_attr( $widget_class_id ); ?> .result-panel').css('display', 'block')
465 // error
466 } else {
467 alert(data_msg)
468 }
469 }
470 })
471 })
472 })
473 </script>
474
475 <?php
476 }
477
478 /**
479 * Initialize List Form.
480 *
481 * @param array $atts Form attributes
482 *
483 * @return string
484 *
485 * @throws JsonException
486 */
487 public function build_list_form( array $atts ): string {
488 if ( isset( $atts['id'] ) && $atts['id'] !== '' ) {
489 $args['widget_id'] = md5( rand( 10000, 99999 ) . $atts['id'] );
490
491 if (isset( $atts['collect_name'] ) ) {
492 $args['collect_name'] = true;
493 }
494
495 if (isset( $atts['title'] ) ) {
496 $args['list_title'] = $atts['title'];
497 }
498
499 if (isset( $atts['description'] ) ) {
500 $args['list_description'] = $atts['description'];
501 }
502
503 ob_start();
504 $this->list_form( $atts['id'], $args );
505 return ob_get_clean();
506 }
507
508 return '<span>Mailgun list ID needed to render form!</span>
509 <br/>
510 <strong>Example :</strong> [mailgun id="[your list id]"]';
511 }
512
513 /**
514 * Initialize List Widget.
515 */
516 public function load_list_widget() {
517 register_widget( 'List_Widget' );
518 add_shortcode( 'mailgun', array( &$this, 'build_list_form' ) );
519 }
520
521 /**
522 * @return string
523 */
524 public function getAssetsPath(): string {
525 return $this->assetsDir;
526 }
527 }
528
529 $mailgun = Mailgun::getInstance();
530
531 if (include __DIR__ . '/includes/widget.php' ) {
532 add_action('widgets_init', array( &$mailgun, 'load_list_widget' ));
533 add_action('wp_ajax_nopriv_add_list', array( &$mailgun, 'add_list' ));
534 add_action('wp_ajax_add_list', array( &$mailgun, 'add_list' ));
535 }
536
537 if (is_admin()) {
538 if (include __DIR__ . '/includes/admin.php') {
539 $mailgunAdmin = new MailgunAdmin();
540 } else {
541 $mailgun->deactivate_and_die(__DIR__ . '/includes/admin.php');
542 }
543 }
544