PluginProbe
Booking Calendar / 11.8.1
Booking Calendar v11.8.1
11.8.2 11.8.1 11.8 11.7 11.6.1 11.6 11.5 11.4.3 11.4.2 11.4.1 11.4 11.3 11.2.1 11.2 11.1 11.0 10.15.7 10.15.6 10.1.3 10.10 10.10.1 10.10.2 10.11 10.11.2 10.11.3 All 202 releases
booking / core / any / api-emails.php

api-emails.php in Booking Calendar 11.8.1, at core/any/api-emails.php

618 lines 24.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @version 1.1
4 * @package General Emails API
5 * @category General Emails API Fields for Settings page and Functions for Sending emails.
6 * @author wpdevelop
7 *
8 * @web-site https://wpbookingcalendar.com/
9 * @email info@wpbookingcalendar.com
10 * @modified 2016-05-12, 2015-10-06
11 */
12
13 if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
14
15 // Email Settings API - Saving different options
16 abstract class WPBC_Emails_API extends WPBC_Settings_API {
17
18 public $sending;
19 public $replace = array();
20
21
22
23 /**
24 * Email Settings API Constructor
25 * During creation, system try to load values from DB, if exist.
26 *
27 * @param type $id - "Pure Email Template name
28 */
29 public function __construct( $id, $init_fields_values = array()) {
30
31 $options = array(
32 'db_prefix_option' => 'booking_email_'
33 , 'db_saving_type' => 'togather' // { 'togather' (Default), 'separate', 'separate_prefix' }
34 );
35 // Email template saved as:
36 // ( "booking_email_" . $id ) >>> "booking_email_new_admin"
37
38 parent::__construct( $id, $options, $init_fields_values ); // Define ID of Setting page and options
39
40 add_filter( 'phpmailer_init', array( $this, 'process_multipart' ) ); // For multipart messages
41
42 add_action( 'wp_mail_failed', array($this, 'email_error_parse') ); // Parse any errors during sending emails.
43 }
44
45
46
47 /**
48 * This function must be overriden - Initialise Settings Form Fields
49
50 public function init_settings_fields() {
51
52 $this->fields = array();
53
54 $this->fields['enabled'] = array(
55 'type' => 'checkbox'
56 , 'default' => 'On'
57 , 'title' => __('Enable / Disable', 'booking')
58 , 'label' => __('Enable this email notification', 'booking')
59 , 'description' => ''
60 , 'group' => 'general'
61
62 );
63 // ...
64 }
65 /**/
66
67
68
69 // <editor-fold defaultstate="collapsed" desc=" Suport functions " >
70
71 /**
72 * List of preg* regular expression patterns to search for replace in plain emails.
73 * More: https://raw.github.com/ushahidi/wp-silcc/master/class.html2text.inc
74 */
75 private function get_plain_search_array() {
76 return array(
77 "/\r/", // Non-legal carriage return
78 '/&(nbsp|#160);/i', // Non-breaking space
79 '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i', // Double quotes
80 '/&(apos|rsquo|lsquo|#8216|#8217);/i', // Single quotes
81 '/&gt;/i', // Greater-than
82 '/&lt;/i', // Less-than
83 '/&#38;/i', // Ampersand
84 '/&#038;/i', // Ampersand
85 '/&amp;/i', // Ampersand
86 '/&(copy|#169);/i', // Copyright
87 '/&(trade|#8482|#153);/i', // Trademark
88 '/&(reg|#174);/i', // Registered
89 '/&(mdash|#151|#8212);/i', // mdash
90 '/&(ndash|minus|#8211|#8722);/i', // ndash
91 '/&(bull|#149|#8226);/i', // Bullet
92 '/&(pound|#163);/i', // Pound sign
93 '/&(euro|#8364);/i', // Euro sign
94 '/&#36;/', // Dollar sign
95 '/&[^&;]+;/i', // Unknown/unhandled entities
96 '/[ ]{2,}/' // Runs of spaces, post-handling
97 );
98
99 }
100
101
102 /** List of symbols "for Replace To" */
103 private function get_plain_replace_array() {
104
105 return array(
106 '', // Non-legal carriage return
107 ' ', // Non-breaking space
108 '"', // Double quotes
109 "'", // Single quotes
110 '>', // Greater-than
111 '<', // Less-than
112 '&', // Ampersand
113 '&', // Ampersand
114 '&', // Ampersand
115 '(c)', // Copyright
116 '(tm)', // Trademark
117 '(R)', // Registered
118 '--', // mdash
119 '-', // ndash
120 '*', // Bullet
121 '£', // Pound sign
122 'EUR', // Euro sign. € ?
123 '$', // Dollar sign
124 '', // Unknown/unhandled entities
125 ' ' // Runs of spaces, post-handling
126 );
127 }
128
129
130 /**
131 * Esacpe and replace any HTML entities
132 *
133 * @param type $string
134 * @return string
135 */
136 public function esc_to_plain_text( $string ) {
137
138 // //Replace <a href="http://server.com">Link</a> to Link( http://server.com )
139 // $pattern = "/<a(.*)+href=[\"|']+([^\"']+)(?=(\"|'))[^>]*>(.*)<\/a>/" ; //"/(?<=href=(\"|'))[^\"']+(?=(\"|'))/i";
140 // $newurl = "$4 ($2)";
141 // $string = preg_replace($pattern,$newurl,$string);
142
143 $newstring = preg_replace( $this->get_plain_search_array(), $this->get_plain_replace_array(), wp_strip_all_tags( $string ) );
144 return $newstring;
145 }
146
147
148 /**
149 * Set array for replacing shortcodes in Email Content and Subject
150 *
151 * @param array $replace - if this parameter skipped, then array reseted to empty array
152 */
153 function set_replace( $replace = array() ) {
154 $this->replace = $replace;
155 }
156
157
158 /**
159 * Replace shortcodes in givven string. Usually its Email Content and Subject
160 *
161 * @param string $subject
162 */
163 public function replace_shortcodes( $subject ) {
164
165 $defaults = array(
166 'ip' => wpbc_get_user_ip()
167 , 'blogname' => wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES )
168 , 'siteurl' => get_site_url()
169 );
170
171 $replace = wp_parse_args( $this->replace, $defaults );
172
173 foreach ( $replace as $replace_shortcode => $replace_value ) {
174
175 // FixIn: 8.9.3.2.
176 if ( is_null( $replace_value ) ) {
177 $replace_value = '';
178 };
179
180 $subject = str_replace( array( '[' . $replace_shortcode . ']'
181 , '{' . $replace_shortcode . '}' )
182 , $replace_value
183 , $subject );
184
185 }
186
187 return $subject;
188 }
189
190 // </editor-fold>
191
192
193 // <editor-fold defaultstate="collapsed" desc=" Pure Email functions " >
194
195 /**
196 * For MultiPart email define plain text - AltBody
197 *
198 * Also additionaly fix Sender - its have to be same as From
199 *
200 * @param PHPMailer $mailer
201 * @return PHPMailer
202 */
203 public function process_multipart( $mailer ) {
204
205 //if ( $this->sending && $this->get_email_content_type() == 'multipart' ) {
206 if ( $this->sending ) {
207
208 if ( $this->get_email_content_type() == 'multipart' )
209 $mailer->AltBody = wordwrap( $this->esc_to_plain_text( $this->replace_shortcodes( $this->get_content_plain() ) ) );
210
211 $mailer->Sender = $mailer->From;
212
213 //$this->sending = false; // If we set it to false, then we can not trigger for any Mail errors in this CLASS
214 }
215
216 return $mailer;
217 }
218
219
220 /**
221 * Get type of Email: 'plain' | 'html' | 'multipart'
222 *
223 * @return string
224 */
225 public function get_email_content_type() {
226
227 return $this->fields_values['email_content_type'] && class_exists( 'DOMDocument' ) ? $this->fields_values['email_content_type'] : 'plain';
228 }
229
230
231 /**
232 * Get Email Content Type: 'text/plain' | 'text/html' | 'multipart/alternative'
233 *
234 * @return string
235 */
236 public function get_content_type() {
237
238 switch ( $this->get_email_content_type() ) {
239 case 'html' :
240 return 'text/html';
241 case 'multipart' :
242 return 'multipart/alternative';
243 default :
244 return 'text/plain';
245 }
246 }
247
248
249 /**
250 * Define Email Headers. For exmaple: "Conte type:" 'text/plain' | 'text/html' | 'multipart/alternative' or "From": Name <email@server.com>
251 *
252 * @return string
253 */
254 public function get_headers( $additional_params = array() ) {
255
256 $mail_headers = '';
257
258 $from_address = $this->get_from__email_address();
259
260 if ( ! empty( $from_address ) ) {
261 $mail_headers .= 'From: ' . $this->get_from__name() . ' <' . $from_address . '> ' . "\r\n" ;
262 } else {
263 /* If we don't have an email from the input headers default to wordpress@$sitename
264 * Some hosts will block outgoing mail from this address if it doesn't exist but
265 * there's no easy alternative. Defaulting to admin_email might appear to be another
266 * option but some hosts may refuse to relay mail from an unknown domain. See
267 * https://core.trac.wordpress.org/ticket/5007.
268 */
269 }
270
271 $mail_headers .= 'Content-Type: ' . $this->get_content_type() . "\r\n" ;
272
273 $mail_headers = apply_filters( 'wpbc_email_api_get_headers_after', $mail_headers, $this->id, $this->fields_values , $this->replace, $additional_params );
274
275 return $mail_headers;
276 }
277
278
279 /**
280 * Get Content of Email
281 *
282 * @return string
283 */
284 public function get_content() {
285
286 if ( $this->get_email_content_type() == 'plain' ) {
287 $email_content = $this->esc_to_plain_text( $this->replace_shortcodes( $this->get_content_plain() ) );
288 } else {
289 $email_content = $this->replace_shortcodes( $this->get_content_html() );
290 }
291
292 $email_content = apply_filters( 'wpbc_email_api_get_content_after' , $email_content, $this->id, $this->get_email_content_type() );
293
294 // Remove all shortcodes, which is not replaced early.
295 $email_content = preg_replace ('/[\[\{][a-zA-Z0-9.,_-]{0,}[\]\}]/', '', $email_content);
296
297 return wordwrap( $email_content, 100 );
298 }
299
300
301 /**
302 * Get Email Content as Text (from Plain Text template)
303 *
304 * @return string
305 */
306 function get_content_plain() {
307
308 //require_once( dirname(__FILE__) . '/emails_tpl/standard-text-tpl.php' );
309 //require_once( dirname(__FILE__) . '/emails_tpl/plain-text-tpl.php' );
310 if ( isset( $this->fields_values['template_file'] ) ) {
311 $email_tpl_name = $this->fields_values['template_file'];
312 } else {
313 $email_tpl_name = 'plain';
314 }
315
316 if ( file_exists( dirname(__FILE__) . '/emails_tpl/'. $email_tpl_name .'-text-tpl.php' ) )
317 require_once( dirname(__FILE__) . '/emails_tpl/'. $email_tpl_name .'-text-tpl.php' );
318 else
319 require_once( dirname(__FILE__) . '/emails_tpl/plain-text-tpl.php' );
320
321 $fields_values = $this->fields_values;
322
323 $fields_values = apply_filters( 'wpbc_email_api_get_content_before' , $fields_values, $this->id , 'plain' ); //Ability to parse 'content', 'header_content', 'footer_content' for different languges, etc ....
324
325 if ( function_exists( 'wpbc_email_template_' . $email_tpl_name . '_text' ) )
326 $plain_email = call_user_func_array( 'wpbc_email_template_' . $email_tpl_name . '_text' , array( $fields_values ) );
327 else
328 $plain_email = wpbc_email_template_text( $fields_values );
329
330 // Replace <p> | <br> to \n
331 $plain_email = preg_replace( '/<(br|p)[\t\s]*[\/]?>/i', "\n", $plain_email );
332 // $plain_email = str_replace( array('<br/>', '<br>'), "\n", $plain_email );
333
334 return $plain_email;
335 }
336
337
338 /**
339 * Get Email Content as HTML (from HTML template)
340 *
341 * @return type
342 */
343 function get_content_html() {
344
345 // Load specific Email Template: ///////////////////////////////////
346 if ( isset( $this->fields_values['template_file'] ) ) {
347 $email_tpl_name = $this->fields_values['template_file'];
348 } else {
349 $email_tpl_name = 'plain';
350 }
351 //require_once( dirname(__FILE__) . '/emails_tpl/standard-html-tpl.php' );
352 //require_once( dirname(__FILE__) . '/emails_tpl/plain-html-tpl.php' );
353
354 if ( file_exists( dirname(__FILE__) . '/emails_tpl/'. $email_tpl_name .'-html-tpl.php' ) )
355 require_once( dirname(__FILE__) . '/emails_tpl/'. $email_tpl_name .'-html-tpl.php' );
356 else
357 require_once( dirname(__FILE__) . '/emails_tpl/plain-html-tpl.php' );
358 ////////////////////////////////////////////////////////////////////
359
360 $fields_values = $this->fields_values;
361
362 $fields_values = apply_filters( 'wpbc_email_api_get_content_before' , $fields_values, $this->id , 'html' ); //Ability to parse 'content', 'header_content', 'footer_content' for different languges, etc ....
363
364 if ( function_exists( 'wpbc_email_template_' . $email_tpl_name . '_html' ) )
365 $html_email = call_user_func_array( 'wpbc_email_template_' . $email_tpl_name . '_html' , array( $fields_values ) );
366 else
367 $html_email = wpbc_email_template_html( $fields_values );
368
369 return $html_email;
370 }
371
372
373 /**
374 * Get escaped Email Subject
375 *
376 * @return string
377 */
378 public function get_subject() {
379
380 $subject = $this->fields_values['subject'];
381
382 $subject = apply_filters( 'wpbc_email_api_get_subject_before' , $subject, $this->id );
383
384 $subject = $this->esc_to_plain_text( $this->replace_shortcodes( $subject ) );
385
386 $subject = apply_filters( 'wpbc_email_api_get_subject_after' , $subject, $this->id );
387
388 return $subject;
389 }
390
391
392 /**
393 * Get escapeed Name from any not supporting characters
394 *
395 * @return string
396 */
397 public function get_from__name() {
398 return wp_specialchars_decode( esc_html( stripslashes( $this->fields_values['from_name'] ) ), ENT_QUOTES );
399 }
400
401
402 /**
403 * Get sanitized Email address
404 *
405 * @return type
406 */
407 public function get_from__email_address() {
408 return sanitize_email( $this->fields_values['from'] );
409 }
410
411
412 /**
413 * For future support, right now does not support
414 *
415 * @return empty string
416 */
417 public function get_attachments() {
418 return '';
419 }
420
421
422 /**
423 * Check email and format it
424 *
425 * @param string $emails
426 * @return string
427 */
428 public function validate_emails( $emails ) {
429
430 $emails = str_replace( ';', ',', $emails );
431
432 if ( ! is_array( $emails ) ) {
433 $emails = explode( ',', $emails );
434 }
435
436 $emails_list = array();
437 foreach ( (array) $emails as $recipient ) {
438
439 // Break $recipient into name and address parts if in the format "Foo <bar@baz.com>".
440 $recipient_name = '';
441 if ( preg_match( '/(.*)<(.+)>/', $recipient, $matches ) ) {
442 if ( count( $matches ) == 3 ) {
443 $recipient_name = $matches[1];
444 $recipient = $matches[2];
445 }
446 } else {
447 // Check about correct format of email.
448 if ( preg_match( '/([\w\.\-_]+)?\w+@[\w\-_]+(\.\w+){1,}/im', $recipient, $matches ) ) { // FixIn: 8.7.7.2.
449 $recipient = $matches[0];
450 }
451 }
452
453 $recipient_name = trim( wp_specialchars_decode( esc_html( stripslashes( $recipient_name ) ), ENT_QUOTES ) );
454 // FixIn: 10.15.5.1.
455 //$emails_list[] = ( empty( $recipient_name ) ? '' : $recipient_name . ' ' ) . '<' . sanitize_email( $recipient ) . '>';
456 $sanitized_email_address = sanitize_email( $recipient );
457 if ( ! empty( $sanitized_email_address ) ) {
458 $emails_list[] = '<' . sanitize_email( $recipient ) . '>';
459 }
460
461 }
462
463 $emails_list = implode( ',', $emails_list );
464
465 return $emails_list;
466 }
467
468
469 /**
470 * Make Email Sending by using wp_mail standard function.
471 *
472 * @param string $to - Email
473 * @param array $replace - accociated array of values to replace in email Body and Subject. Exmaple: array( 'name' => 'Jo', 'secondname' => 'Smith' )
474 *
475 * @return boolean Sent or Failed to send.
476 */
477 public function send( $to = '', $replace = array() ) {
478
479 $return = false;
480
481 // if ( empty( $to ) ) { return $return; } //.
482
483 $this->sending = true;
484
485 $this->set_replace( $replace );
486
487 $to = $this->validate_emails( $to );
488
489 $subject = $this->get_subject();
490 $message = $this->get_content();
491 $headers = $this->get_headers();
492 $attachments = $this->get_attachments();
493 // FixIn: 10.15.5.2.
494 $attachments = apply_filters( 'wpbc_email_attachments', $attachments, $this->id, $replace );
495
496 $is_send_email = true;
497
498 $is_send_email = apply_filters( 'wpbc_email_api_is_allow_send', $is_send_email, $this->id, $this->fields_values );
499
500 if ( $is_send_email ) {
501 $to = apply_filters( 'wpbc_email_api_send_field_to', $to ); // FixIn: 8.1.3.1.
502 // FixIn: 8.5.2.22.
503 if ( ! empty( $to ) ) {
504 $return = wp_mail( $to, $subject, $message, $headers, $attachments );
505 }
506 }
507
508 $this->sending = false;
509
510 // Send Copy to admin email.
511 if (
512 ( isset( $this->fields_values['copy_to_admin'] ) )
513 && ( $this->fields_values['copy_to_admin'] == 'On' )
514 ){
515
516 $this->sending = true;
517
518 $subject = __('Email copy to', 'booking') . ' ' . str_replace( array( '<', '>' ), '', $to) . ' - ' . $subject;
519
520 $headers = $this->get_headers( array( 'reply' => $to ) );
521
522 // FixIn: 8.1.2.17.
523 if ( ! empty( $this->fields_values['to'] ) ) {
524 $admin_to = $this->fields_values['to'];
525 if ( ! empty( $this->fields_values['to_name'] )) {
526 $admin_to_name = $this->fields_values['to_name'];
527 }
528
529
530 if ( ( strpos( $this->fields_values['to'], ',') === false ) && ( strpos( $this->fields_values['to'], ';') === false ) ) {
531
532 $valid_email = sanitize_email( $this->fields_values['to'] );
533 if ( ! empty( $valid_email ) )
534 $to = trim( wp_specialchars_decode( esc_html( stripslashes( $this->fields_values['to_name'] ) ), ENT_QUOTES ) )
535 . ' <' . $valid_email . '> ';
536 } else {
537
538 // Comma separated several emails - validate all these emails in Email API class
539 $to_array = $this->fields_values['to'];
540
541 $to_array = str_replace(';', ',', $to_array);
542 if ( !is_array( $to_array ) ) $to_array = explode( ',', $to_array );
543
544 $to_name = str_replace(';', ',', $this->fields_values['to_name']);
545 if ( !is_array( $to_name ) ) $to_name = explode( ',', $to_name );
546
547 $to = array();
548 foreach ( $to_array as $to_ind => $to_email) {
549
550 $to_name_str = $to_name[ ( count( $to_name ) - 1 ) ];
551
552 if ( isset( $to_name[ $to_ind ] ) )
553 $to_name_str = $to_name[ $to_ind ];
554
555 $valid_email = sanitize_email( $to_email );
556 if ( ! empty( $valid_email ) )
557 $to[] = trim( wp_specialchars_decode( esc_html( stripslashes( $to_name_str ) ), ENT_QUOTES ) ) . ' <' . $valid_email . '> ';
558 }
559 $to = implode(',', $to);
560
561 }
562
563
564 } else { //FixIn: 8.1.2.17 - END
565
566 $to = $this->validate_emails( $this->get_from__name() . ' <' . $this->get_from__email_address() . '> ' );
567
568 } // FixIn: 8.1.2.17.
569
570 $is_send_email = apply_filters( 'wpbc_email_api_is_allow_send_copy', $is_send_email, $this->id, $this->fields_values );
571
572 if ( $is_send_email ) {
573 $to = apply_filters( 'wpbc_email_api_send_copy_field_to', $to ); // FixIn: 8.1.3.1.
574 // FixIn: 8.5.2.22.
575 if ( ! empty( $to ) ) {
576 $return_copy = wp_mail( $to, $subject, $message, $headers, $attachments );
577 }
578 }
579
580 $this->sending = false;
581 }
582
583 $this->set_replace(); // Reset replace parameter
584
585 return $return;
586 }
587 // </editor-fold>
588
589
590 /**
591 * Show possible erros during sending emails.
592 *
593 * @param type $wp_error_object - new WP_Error( $e->getCode(), $e->getMessage(), $mail_error_data )
594 */
595 public function email_error_parse( $wp_error_object ) {
596 //debuge( $wp_error_object );
597 if ( $this->sending ) { // Check if this error generated for email relative to this class.
598
599 $error_description_array = array();
600 if ( isset( $wp_error_object->errors ) )
601 foreach ( $wp_error_object->errors as $key_error => $error_description ) {
602 $error_description_array[] = implode(' ', $error_description );
603 }
604
605 if ( ! empty( $error_description_array ) ) {
606 $error_description = implode(' ', $error_description_array ) ;
607
608 do_action('wpbc_email_sending_error', $wp_error_object, $error_description );
609
610 } else {
611 do_action('wpbc_email_sending_error', $wp_error_object, '' );
612 }
613 }
614 }
615
616 }
617
618