1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) exit;
4
5 6 7 8 9 10 11 12 13 14 15 16
17 abstract class WC_Email extends WC_Settings_API {
18
19
20 var $id;
21
22
23 var $title;
24
25
26 var $enabled;
27
28
29 var $description;
30
31
32 var $template_plain;
33
34
35 var $template_html;
36
37
38 var $template_base;
39
40
41 var $recipient;
42
43
44 var $heading;
45
46
47 var $subject;
48
49
50 var $object;
51
52
53 var $find;
54
55
56 var $replace;
57
58
59 var $mime_boundary;
60
61
62 var ;
63
64
65 var $sending;
66
67 68 69 70 71 72 73 74 75
76 var $plain_search = array(
77 "/\r/",
78 '/&(nbsp|#160);/i',
79 '/&(quot|rdquo|ldquo|#8220|#8221|#147|#148);/i',
80
81 '/&(apos|rsquo|lsquo|#8216|#8217);/i',
82 '/>/i',
83 '/</i',
84 '/&/i',
85 '/&/i',
86 '/&/i',
87 '/&(copy|#169);/i',
88 '/&(trade|#8482|#153);/i',
89 '/&(reg|#174);/i',
90 '/&(mdash|#151|#8212);/i',
91 '/&(ndash|minus|#8211|#8722);/i',
92 '/&(bull|#149|#8226);/i',
93 '/&(pound|#163);/i',
94 '/&(euro|#8364);/i',
95 '/$/',
96 '/&[^&;]+;/i',
97 '/[ ]{2,}/'
98 );
99
100 101 102 103 104 105 106
107 var $plain_replace = array(
108 '',
109 ' ',
110 '"',
111 "'",
112 '>',
113 '<',
114 '&',
115 '&',
116 '&',
117 '(c)',
118 '(tm)',
119 '(R)',
120 '--',
121 '-',
122 '*',
123 '£',
124 'EUR',
125 '$',
126 '',
127 ' '
128 );
129
130 131 132 133 134
135 function __construct() {
136
137
138 $this->init_form_fields();
139 $this->init_settings();
140
141
142 add_action( 'woocommerce_update_options_email_' . $this->id, array( $this, 'process_admin_options' ) );
143
144
145 if ( is_null( $this->template_base ) ) {
146 $this->template_base = WC()->plugin_path() . '/templates/';
147 }
148
149
150 $this->heading = $this->get_option( 'heading', $this->heading );
151 $this->subject = $this->get_option( 'subject', $this->subject );
152 $this->email_type = $this->get_option( 'email_type' );
153 $this->enabled = $this->get_option( 'enabled' );
154
155
156 $this->find = array( '{blogname}', '{site_title}' );
157 $this->replace = array( $this->get_blogname(), $this->get_blogname() );
158
159
160 add_filter( 'phpmailer_init', array( $this, 'handle_multipart' ) );
161
162
163 add_filter( 'woocommerce_email_style_inline_tags', array( $this, 'style_inline_tags' ) );
164 add_filter( 'woocommerce_email_style_inline_h1_tag', array( $this, 'style_inline_h1_tag' ) );
165 add_filter( 'woocommerce_email_style_inline_h2_tag', array( $this, 'style_inline_h2_tag' ) );
166 add_filter( 'woocommerce_email_style_inline_h3_tag', array( $this, 'style_inline_h3_tag' ) );
167 add_filter( 'woocommerce_email_style_inline_a_tag', array( $this, 'style_inline_a_tag' ) );
168 add_filter( 'woocommerce_email_style_inline_img_tag', array( $this, 'style_inline_img_tag' ) );
169 }
170
171 172 173 174 175 176 177
178 function handle_multipart( $mailer ) {
179
180 if ( $this->sending && $this->get_email_type() == 'multipart' ) {
181
182 $mailer->AltBody = wordwrap( preg_replace( $this->plain_search, $this->plain_replace, strip_tags( $this->get_content_plain() ) ) );
183
184 $this->sending = false;
185 }
186
187 return $mailer;
188 }
189
190 191 192 193 194 195 196
197 function format_string( $string ) {
198 return str_replace( $this->find, $this->replace, $string );
199 }
200 201 202 203 204 205
206 function get_subject() {
207 return apply_filters( 'woocommerce_email_subject_' . $this->id, $this->format_string( $this->subject ), $this->object );
208 }
209
210 211 212 213 214 215
216 function get_heading() {
217 return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $this->heading ), $this->object );
218 }
219
220 221 222 223 224 225
226 function get_recipient() {
227 return apply_filters( 'woocommerce_email_recipient_' . $this->id, $this->recipient, $this->object );
228 }
229
230 231 232 233 234 235
236 function get_headers() {
237 return apply_filters( 'woocommerce_email_headers', "Content-Type: " . $this->get_content_type() . "\r\n", $this->id, $this->object );
238 }
239
240 241 242 243 244 245
246 function get_attachments() {
247 return apply_filters( 'woocommerce_email_attachments', array(), $this->id, $this->object );
248 }
249
250 251 252 253 254 255
256 function get_email_type() {
257 return $this->email_type ? $this->email_type : 'plain';
258 }
259
260 261 262 263 264 265
266 function get_content_type() {
267 switch ( $this->get_email_type() ) {
268 case "html" :
269 return 'text/html';
270 case "multipart" :
271 return 'multipart/alternative';
272 default :
273 return 'text/plain';
274 }
275 }
276
277 278 279 280 281 282 283
284 function get_option( $key, $empty_value = null ) {
285 return __( parent::get_option( $key, $empty_value ) );
286 }
287
288 289 290 291 292 293
294 function is_enabled() {
295 $enabled = $this->enabled == "yes" ? true : false;
296
297 return apply_filters( 'woocommerce_email_enabled_' . $this->id, $enabled, $this->object );
298 }
299
300 301 302 303 304 305
306 function get_blogname() {
307 return wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );
308 }
309
310 311 312 313 314 315
316 function get_content() {
317
318 $this->sending = true;
319
320 if ( $this->get_email_type() == 'plain' ) {
321 $email_content = preg_replace( $this->plain_search, $this->plain_replace, strip_tags( $this->get_content_plain() ) );
322 } else {
323 $email_content = $this->style_inline( $this->get_content_html() );
324 }
325
326 return wordwrap( $email_content, 70 );
327 }
328
329 330 331 332 333 334 335
336 function style_inline_tags($tags) {
337 return array_unique( array_merge( $tags, array( 'h1', 'h2', 'h3', 'a', 'img' ) ) );
338 }
339
340 341 342 343 344 345
346 function style_inline_h1_tag($styles) {
347 $styles['color'] = get_option( 'woocommerce_email_text_color' );
348 $styles['display'] = 'block';
349 $styles['font-family'] = 'Arial';
350 $styles['font-size'] = '34px';
351 $styles['font-weight'] = 'bold';
352 $styles['margin-top'] = '10px';
353 $styles['margin-right'] = '0';
354 $styles['margin-bottom'] = '10px';
355 $styles['margin-left'] = '0';
356 $styles['text-align'] = 'left';
357 $styles['line-height'] = '150%';
358
359 return $styles;
360 }
361
362 363 364 365 366 367
368 function style_inline_h2_tag($styles) {
369 $styles['color'] = get_option( 'woocommerce_email_text_color' );
370 $styles['display'] = 'block';
371 $styles['font-family'] = 'Arial';
372 $styles['font-size'] = '30px';
373 $styles['font-weight'] = 'bold';
374 $styles['margin-top'] = '10px';
375 $styles['margin-right'] = '0';
376 $styles['margin-bottom'] = '10px';
377 $styles['margin-left'] = '0';
378 $styles['text-align'] = 'left';
379 $styles['line-height'] = '150%';
380
381 return $styles;
382 }
383
384 385 386 387 388 389 390
391 function style_inline_h3_tag($styles) {
392 $styles['color'] = get_option( 'woocommerce_email_text_color' );
393 $styles['display'] = 'block';
394 $styles['font-family'] = 'Arial';
395 $styles['font-size'] = '26px';
396 $styles['font-weight'] = 'bold';
397 $styles['margin-top'] = '10px';
398 $styles['margin-right'] = '0';
399 $styles['margin-bottom'] = '10px';
400 $styles['margin-left'] = '0';
401 $styles['text-align'] = 'left';
402 $styles['line-height'] = '150%';
403
404 return $styles;
405 }
406
407 408 409 410
411 function style_inline_a_tag($styles) {
412 $styles['color'] = get_option( 'woocommerce_email_text_color' );
413 $styles['font-weight'] = 'normal';
414 $styles['text-decoration'] = 'underline';
415
416 return $styles;
417 }
418
419 420 421 422 423 424 425
426 function style_inline_img_tag($styles) {
427 $styles['display'] = 'inline';
428 $styles['border'] = 'none';
429 $styles['font-size'] = '14px';
430 $styles['font-weight'] = 'bold';
431 $styles['height'] = 'auto';
432 $styles['line-height'] = '100%';
433 $styles['outline'] = 'none';
434 $styles['text-decoration'] = 'none';
435 $styles['text-transform'] = 'capitalize';
436
437 return $styles;
438 }
439
440 441 442 443 444 445
446 function get_style_inline_tags() {
447 return apply_filters( 'woocommerce_email_style_inline_tags', array() );
448 }
449
450 451 452 453 454 455 456
457 function get_style_inline_for_tag($tag) {
458 $styles = apply_filters( 'woocommerce_email_style_inline_' . $tag . '_tag', array() );
459 $css = array();
460
461 foreach( $styles as $property => $value ) {
462 $css[] = $property . ':' . $value;
463 }
464
465 return implode('; ', $css);
466 }
467
468 469 470 471 472 473 474
475 function style_inline( $content ) {
476 if ( ! class_exists( 'DOMDocument' ) ) {
477 return $content;
478 }
479
480 $dom = new DOMDocument();
481 libxml_use_internal_errors( true );
482 @$dom->loadHTML( $content );
483 libxml_clear_errors();
484
485 foreach( $this->get_style_inline_tags() as $tag ) {
486 $nodes = $dom->getElementsByTagName($tag);
487
488 foreach( $nodes as $node ) {
489 if ( ! $node->hasAttribute( 'style' ) ) {
490 $node->setAttribute( 'style', $this->get_style_inline_for_tag($tag) );
491 }
492 }
493 }
494
495 $content = $dom->saveHTML();
496
497 return $content;
498 }
499
500 501 502 503 504 505
506 function get_content_plain() {}
507
508 509 510 511 512 513
514 function get_content_html() {}
515
516 517 518 519 520 521
522 function get_from_name() {
523 return wp_specialchars_decode( esc_html( get_option( 'woocommerce_email_from_name' ) ), ENT_QUOTES );
524 }
525
526 527 528 529 530 531
532 function get_from_address() {
533 return sanitize_email( get_option( 'woocommerce_email_from_address' ) );
534 }
535
536 537 538 539 540 541 542 543 544 545 546
547 function send( $to, $subject, $message, $headers, $attachments ) {
548 add_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
549 add_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
550 add_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
551
552 $return = wp_mail( $to, $subject, $message, $headers, $attachments );
553
554 remove_filter( 'wp_mail_from', array( $this, 'get_from_address' ) );
555 remove_filter( 'wp_mail_from_name', array( $this, 'get_from_name' ) );
556 remove_filter( 'wp_mail_content_type', array( $this, 'get_content_type' ) );
557
558 return $return;
559 }
560
561 562 563 564 565 566
567 function init_form_fields() {
568 $this->form_fields = array(
569 'enabled' => array(
570 'title' => __( 'Enable/Disable', 'woocommerce' ),
571 'type' => 'checkbox',
572 'label' => __( 'Enable this email notification', 'woocommerce' ),
573 'default' => 'yes'
574 ),
575 'subject' => array(
576 'title' => __( 'Email subject', 'woocommerce' ),
577 'type' => 'text',
578 'description' => sprintf( __( 'Defaults to <code>%s</code>', 'woocommerce' ), $this->subject ),
579 'placeholder' => '',
580 'default' => ''
581 ),
582 'heading' => array(
583 'title' => __( 'Email heading', 'woocommerce' ),
584 'type' => 'text',
585 'description' => sprintf( __( 'Defaults to <code>%s</code>', 'woocommerce' ), $this->heading ),
586 'placeholder' => '',
587 'default' => ''
588 ),
589 'email_type' => array(
590 'title' => __( 'Email type', 'woocommerce' ),
591 'type' => 'select',
592 'description' => __( 'Choose which format of email to send.', 'woocommerce' ),
593 'default' => 'html',
594 'class' => 'email_type',
595 'options' => array(
596 'plain' => __( 'Plain text', 'woocommerce' ),
597 'html' => __( 'HTML', 'woocommerce' ),
598 'multipart' => __( 'Multipart', 'woocommerce' ),
599 )
600 )
601 );
602 }
603
604 605 606 607 608 609 610 611
612 public function process_admin_options() {
613
614
615 parent::process_admin_options();
616
617
618 if ( ! empty( $_POST['template_html_code'] ) && ! empty( $this->template_html ) ) {
619
620 $saved = false;
621 $file = get_stylesheet_directory() . '/woocommerce/' . $this->template_html;
622 $code = stripslashes( $_POST['template_html_code'] );
623
624 if ( is_writeable( $file ) ) {
625 $f = fopen( $file, 'w+' );
626 if ( $f !== FALSE ) {
627 fwrite( $f, $code );
628 fclose( $f );
629 $saved = true;
630 }
631 }
632
633 if ( ! $saved ) {
634 $redirect = add_query_arg( 'wc_error', urlencode( __( 'Could not write to template file.', 'woocommerce' ) ) );
635 wp_redirect( $redirect );
636 exit;
637 }
638 }
639 if ( ! empty( $_POST['template_plain_code'] ) && ! empty( $this->template_plain ) ) {
640
641 $saved = false;
642 $file = get_stylesheet_directory() . '/woocommerce/' . $this->template_plain;
643 $code = stripslashes( $_POST['template_plain_code'] );
644
645 if ( is_writeable( $file ) ) {
646 $f = fopen( $file, 'w+' );
647 if ( $f !== FALSE ) {
648 fwrite( $f, $code );
649 fclose( $f );
650 $saved = true;
651 }
652 }
653
654 if ( ! $saved ) {
655 $redirect = add_query_arg( 'wc_error', __( 'Could not write to template file.', 'woocommerce' ) );
656 wp_redirect( $redirect );
657 exit;
658 }
659 }
660 }
661
662 663 664 665 666 667 668 669 670 671
672 function admin_options() {
673
674
675 if ( ! empty( $this->template_html ) || ! empty( $this->template_plain ) ) {
676
677 if ( ! empty( $_GET['move_template'] ) && ( $template = esc_attr( basename( $_GET['move_template'] ) ) ) ) {
678 if ( ! empty( $this->$template ) ) {
679 if ( wp_mkdir_p( dirname( get_stylesheet_directory() . '/woocommerce/' . $this->$template ) ) && ! file_exists( get_stylesheet_directory() . '/woocommerce/' . $this->$template ) ) {
680
681 $core_file = $this->template_base . $this->$template;
682 $template_file = apply_filters( 'woocommerce_locate_core_template', $core_file, $this->$template, $this->template_base );
683
684
685 copy( $template_file, get_stylesheet_directory() . '/woocommerce/' . $this->$template );
686 echo '<div class="updated fade"><p>' . __( 'Template file copied to theme.', 'woocommerce' ) . '</p></div>';
687 }
688 }
689 }
690
691 if ( ! empty( $_GET['delete_template'] ) && ( $template = esc_attr( basename( $_GET['delete_template'] ) ) ) ) {
692 if ( ! empty( $this->$template ) ) {
693 if ( file_exists( get_stylesheet_directory() . '/woocommerce/' . $this->$template ) ) {
694 unlink( get_stylesheet_directory() . '/woocommerce/' . $this->$template );
695 echo '<div class="updated fade"><p>' . __( 'Template file deleted from theme.', 'woocommerce' ) . '</p></div>';
696 }
697 }
698 }
699
700 }
701
702 ?>
703 <h3><?php echo ( ! empty( $this->title ) ) ? $this->title : __( 'Settings','woocommerce' ) ; ?></h3>
704
705 <?php echo ( ! empty( $this->description ) ) ? wpautop( $this->description ) : ''; ?>
706
707 <table class="form-table">
708 <?php $this->generate_settings_html(); ?>
709 </table>
710
711 <?php if ( ! empty( $this->template_html ) || ! empty( $this->template_plain ) ) { ?>
712 <div id="template">
713 <?php
714 $templates = array(
715 'template_html' => __( 'HTML template', 'woocommerce' ),
716 'template_plain' => __( 'Plain text template', 'woocommerce' )
717 );
718 foreach ( $templates as $template => $title ) :
719 if ( empty( $this->$template ) ) {
720 continue;
721 }
722
723 $local_file = get_stylesheet_directory() . '/woocommerce/' . $this->$template;
724 $core_file = $this->template_base . $this->$template;
725 $template_file = apply_filters( 'woocommerce_locate_core_template', $core_file, $this->$template, $this->template_base );
726 ?>
727 <div class="template <?php echo $template; ?>">
728
729 <h4><?php echo wp_kses_post( $title ); ?></h4>
730
731 <?php if ( file_exists( $local_file ) ) { ?>
732
733 <p>
734 <a href="#" class="button toggle_editor"></a>
735
736 <?php if ( is_writable( $local_file ) ) : ?>
737 <a href="<?php echo remove_query_arg( array( 'move_template', 'saved' ), add_query_arg( 'delete_template', $template ) ); ?>" class="delete_template button"><?php _e( 'Delete template file', 'woocommerce' ); ?></a>
738 <?php endif; ?>
739
740 <?php printf( __( 'This template has been overridden by your theme and can be found in: <code>%s</code>.', 'woocommerce' ), 'yourtheme/woocommerce/' . $this->$template ); ?>
741 </p>
742
743 <div class="editor" style="display:none">
744
745 <textarea class="code" cols="25" rows="20" <?php if ( ! is_writable( $local_file ) ) : ?>readonly="readonly" disabled="disabled"<?php else : ?>data-name="<?php echo $template . '_code'; ?>"<?php endif; ?>><?php echo file_get_contents( $local_file ); ?></textarea>
746
747 </div>
748
749 <?php } elseif ( file_exists( $template_file ) ) { ?>
750
751 <p>
752 <a href="#" class="button toggle_editor"></a>
753
754 <?php if ( ( is_dir( get_stylesheet_directory() . '/woocommerce/emails/' ) && is_writable( get_stylesheet_directory() . '/woocommerce/emails/' ) ) || is_writable( get_stylesheet_directory() ) ) { ?>
755 <a href="<?php echo remove_query_arg( array( 'delete_template', 'saved' ), add_query_arg( 'move_template', $template ) ); ?>" class="button"><?php _e( 'Copy file to theme', 'woocommerce' ); ?></a>
756 <?php } ?>
757
758 <?php printf( __( 'To override and edit this email template copy <code>%s</code> to your theme folder: <code>%s</code>.', 'woocommerce' ), plugin_basename( $template_file ) , 'yourtheme/woocommerce/' . $this->$template ); ?>
759 </p>
760
761 <div class="editor" style="display:none">
762
763 <textarea class="code" readonly="readonly" disabled="disabled" cols="25" rows="20"><?php echo file_get_contents( $template_file ); ?></textarea>
764
765 </div>
766
767 <?php } else { ?>
768
769 <p><?php _e( 'File was not found.', 'woocommerce' ); ?></p>
770
771 <?php } ?>
772
773 </div>
774 <?php
775 endforeach;
776 ?>
777 </div>
778 <?php
779 wc_enqueue_js("
780 jQuery('select.email_type').change(function(){
781
782 var val = jQuery( this ).val();
783
784 jQuery('.template_plain, .template_html').show();
785
786 if ( val != 'multipart' && val != 'html' )
787 jQuery('.template_html').hide();
788
789 if ( val != 'multipart' && val != 'plain' )
790 jQuery('.template_plain').hide();
791
792 }).change();
793
794 var view = '" . esc_js( __( 'View template', 'woocommerce' ) ) . "';
795 var hide = '" . esc_js( __( 'Hide template', 'woocommerce' ) ) . "';
796
797 jQuery('a.toggle_editor').text( view ).toggle( function() {
798 jQuery( this ).text( hide ).closest('.template').find('.editor').slideToggle();
799 return false;
800 }, function() {
801 jQuery( this ).text( view ).closest('.template').find('.editor').slideToggle();
802 return false;
803 } );
804
805 jQuery('a.delete_template').click(function(){
806 var answer = confirm('" . esc_js( __( 'Are you sure you want to delete this template file?', 'woocommerce' ) ) . "');
807
808 if (answer)
809 return true;
810
811 return false;
812 });
813
814 jQuery('.editor textarea').change(function(){
815 var name = jQuery(this).attr( 'data-name' );
816
817 if ( name )
818 jQuery(this).attr( 'name', name );
819 });
820 ");
821 }
822 }
823 }
824