PageRenderTime 50ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 1ms

/wp-content/plugins/wp-e-commerce-style-email/mail.class.php

https://github.com/AaronFernandes/aquestionof
PHP | 587 lines | 270 code | 140 blank | 177 comment | 47 complexity | b4ace0de03da46e5ce49136799d4e3ef MD5 | raw file
Possible License(s): AGPL-1.0, GPL-2.0
  1. <?php
  2. /**
  3. * This file supports formatting and outputting of styled emails
  4. */
  5. //TODO: support WPEC subjects being modified slightly by testing for presence of subjects, rather than exact matches
  6. global $ecse_email_content;
  7. global $ecse_email_subject;
  8. global $ecse_email_type;
  9. /* TEMPLATE TAGS FOR THE STYLE TEMPLATES */
  10. /**
  11. * Returns the content of the email as formatted by WP E-Commerce.
  12. * @return String as generated by WP e-Commerce
  13. */
  14. function ecse_get_email_content() {
  15. global $ecse_email_content;
  16. if(!is_string($ecse_email_content)) $ecse_email_content=''; //just to make sure it's a string
  17. return $ecse_email_content;
  18. }
  19. /**
  20. * Returns the subject of the email as formatted by WP E-Commerce.
  21. * @return String as generated by WP e-Commerce
  22. */
  23. function ecse_get_email_subject() {
  24. global $ecse_email_subject;
  25. if(!is_string($ecse_email_subject)) $ecse_email_subject=''; //just to make sure it's a string
  26. return $ecse_email_subject;
  27. }
  28. /* TEMPLATE TAGS FOR THE CONTENT TEMPLATES */
  29. function ecse_get_the_product_list() {
  30. return ECSE_mail::get_product_rows_part();
  31. }
  32. function ecse_get_the_totals() {
  33. return ECSE_mail::get_totals_part();
  34. }
  35. function ecse_get_the_addresses() {
  36. return ECSE_mail::get_address_part();
  37. }
  38. /* CONDITIONAL TAGS FOR USE IN ANY EMAIL TEMPLATE */
  39. /**
  40. * Conditional tag
  41. * @return bool
  42. */
  43. function ecse_is_purchase_report_email() {
  44. global $ecse_email_subject;
  45. return ($ecse_email_subject==__( 'Purchase Report', 'wpsc' )) || ($ecse_email_subject==__( 'Transaction Report', 'wpsc' ));
  46. }
  47. /**
  48. * Conditional tag
  49. * @return bool
  50. */
  51. function ecse_is_purchase_receipt_email() {
  52. global $ecse_email_subject;
  53. return ($ecse_email_subject==__( 'Purchase Receipt', 'wpsc' ));
  54. }
  55. /**
  56. * Conditional tag
  57. * @return bool
  58. */
  59. function ecse_is_order_pending_email() {
  60. global $ecse_email_subject;
  61. return ($ecse_email_subject==__( 'Order Pending', 'wpsc' ));
  62. }
  63. /**
  64. * Conditional tag
  65. * @return bool
  66. */
  67. function ecse_is_order_pending_payment_required_email() {
  68. global $ecse_email_subject;
  69. return ($ecse_email_subject==__( 'Order Pending: Payment Required', 'wpsc' ));
  70. }
  71. /**
  72. * Conditional tag
  73. * @return bool
  74. */
  75. function ecse_is_tracking_email() {
  76. global $ecse_email_subject;
  77. return ($ecse_email_subject==get_option( 'wpsc_trackingid_subject' ));
  78. }
  79. /**
  80. * Conditional tag
  81. * @return bool
  82. */
  83. function ecse_is_unlocked_file_email() {
  84. global $ecse_email_subject;
  85. return ($ecse_email_subject==__( 'The administrator has unlocked your file', 'wpsc' ));
  86. }
  87. /**
  88. * Conditional tag
  89. * @return bool
  90. */
  91. function ecse_is_out_of_stock_email() {
  92. global $ecse_email_subject;
  93. //this is a bit more involved than the rest, because WPEC uses a wildcard in the internationalisation
  94. $needle = __('%s is out of stock', 'wpsc');
  95. $needle = str_replace('%s ', '', $needle);
  96. $haystack = 'x'.$ecse_email_subject;
  97. return (stripos($haystack, $needle)>0);
  98. }
  99. /**
  100. * Conditional tag
  101. * @return bool
  102. */
  103. function ecse_is_test_email() {
  104. global $ecse_email_subject;
  105. return ($ecse_email_subject=='ECSE test email');
  106. }
  107. /**
  108. * Conditional tag
  109. * @return bool
  110. */
  111. function ecse_is_other_email() {
  112. global $ecse_email_type;
  113. return ( isset($ecse_email_type) && ($ecse_email_type == 'other email') ) ;
  114. }
  115. class ECSE_mail {
  116. /* GLOBAL SETTERS */
  117. // Use at beginning of application of style, before style template heirarchy calls.
  118. static function set_content($content) {
  119. global $ecse_email_content;
  120. $ecse_email_content = $content;
  121. }
  122. static function set_subject($subject) {
  123. global $ecse_email_subject;
  124. $ecse_email_subject = $subject;
  125. }
  126. /**
  127. * Set the email type. Type is only used to check for 'other email', the catch-all.
  128. */
  129. static function set_type_other() {
  130. global $ecse_email_type;
  131. $ecse_email_type = 'other email';
  132. }
  133. /* INTELLIGENCE */
  134. /**
  135. * Decide whether or not to modify mail, given an email subject and recipient
  136. * @param string $subject
  137. * @param string $to (email address)
  138. * @return bool
  139. */
  140. static function should_modify_mail($subject,$to) {
  141. $returner = false;
  142. if(!self::is_excempt($subject)) {
  143. if(get_option('ecse_is_active')) {
  144. $user_can_receive = true;
  145. } else {
  146. $user_can_receive = false;
  147. //but wait, admin recipients CAN be styled!
  148. require_once(ABSPATH . WPINC . '/registration.php');
  149. $to_user_ID = email_exists($to);
  150. if( $to_user_ID && user_can($to_user_ID,'activate_plugins') ) $user_can_receive = true;
  151. }
  152. switch($subject) {
  153. case __( 'Purchase Report', 'wpsc' ):
  154. case __( 'Transaction Report', 'wpsc' ):
  155. case __( 'Purchase Receipt', 'wpsc' ):
  156. case __( 'Order Pending', 'wpsc' ):
  157. case __( 'Order Pending: Payment Required', 'wpsc' ):
  158. case get_option( 'wpsc_trackingid_subject' ):
  159. case __( 'The administrator has unlocked your file', 'wpsc' ):
  160. if($user_can_receive) $returner=true;
  161. break;
  162. case 'ECSE test email':
  163. //even with styling turned off, test emails can be sent to anyone, not just admins
  164. $returner=true;
  165. break;
  166. default:
  167. if($user_can_receive && get_option('ecse_is_other_active') ) $returner=true;
  168. }
  169. }
  170. return $returner;
  171. }
  172. /**
  173. * Determine whether subject line is in the excempt list
  174. * @param string $subject
  175. * @return bool
  176. */
  177. static function is_excempt($subject) {
  178. $my_list = get_option('ecse_subjects_to_ignore');
  179. $returner = false;
  180. if(!empty($my_list)) {
  181. $my_list = unserialize($my_list);
  182. $my_list[] = 'ECSE plugin wish'; //never style plugin wishes.
  183. foreach($my_list as $row) {
  184. if( trim($subject) == trim($row) ) $returner=true;
  185. }
  186. }
  187. return $returner;
  188. }
  189. /* TEMPLATE ACCESS */
  190. /**
  191. * Output the style template, based on the template heirarchy.
  192. * Requires the global setters be used first, so that email type can be determined.
  193. * If no style template file can be found, outputs an empty string.
  194. * @return none.
  195. */
  196. static function the_style_part() {
  197. /*
  198. *
  199. * wpsc-email_style_unlocked_file.php
  200. * wpsc-email_style_tracking.php
  201. * wpsc-email_style_order_pending_payment_required.php
  202. * wpsc-email_style_out_of_stock.php wpsc-email_style_order_pending.php
  203. * wpsc-email_style_purchase_report.php wpsc-email_style_purchase_receipt.php
  204. *
  205. * | |
  206. *
  207. * wpsc-email_style_manager.php wpsc-email_style_customer.php
  208. * (includes any uncaught emails such as "test" and "other")
  209. *
  210. * \ /
  211. *
  212. * wpsc-email_style.php
  213. *
  214. */
  215. $base = 'wpsc';
  216. $name = 'email_style';
  217. $pref = $base.'-'.$name;
  218. $suf = '';
  219. //first, manager email templates
  220. if(ecse_is_purchase_report_email()) {
  221. if( ecse_is_purchase_report_email() && (locate_template($pref.'_purchase_report.php')!='') ) {
  222. $suf = '_purchase_report';
  223. } elseif( ecse_is_out_of_stock_email() && (locate_template($pref.'_out_of_stock.php')!='') ) {
  224. $suf = '_out_of_stock';
  225. //fallback manager
  226. } elseif( locate_template($pref.'_manager.php')!='' ) {
  227. $suf = '_manager';
  228. }
  229. //next, customer/public email templates
  230. } else {
  231. if(ecse_is_purchase_receipt_email() && (locate_template($pref.'_purchase_receipt.php')!='') ) {
  232. $suf = '_purchase_receipt';
  233. } elseif(ecse_is_order_pending_email() && (locate_template($pref.'_purchase_order_pending.php')!='')) {
  234. $suf = '_order_pending';
  235. } elseif(ecse_is_order_pending_payment_required_email() && (locate_template($pref.'_purchase_order_pending_payment_required.php')!='')) {
  236. $suf = '_order_pending_payment_required';
  237. } elseif(ecse_is_tracking_email() && (locate_template($pref.'_purchase_tracking.php')!='')) {
  238. $suf = '_tracking';
  239. } elseif(ecse_is_unlocked_file_email() && (locate_template($pref.'_unlocked_file.php')!='')) {
  240. $suf = '_unlocked_file';
  241. //fallback customer, including test and all other emails
  242. } elseif( locate_template($pref.'_customer.php')!='' ) {
  243. $suf = '_customer';
  244. }
  245. }
  246. //general fallback goes to wpsc-email_style.php template because $suf is empty
  247. get_template_part($base,$name.$suf);
  248. }
  249. /**
  250. * Get replacement content for a type of WPEC email
  251. * @param string $type {'receipt'}
  252. * @param int $purch_id
  253. * @return string (html) or (empty)
  254. */
  255. static function get_content_part($type, $purch_id) {
  256. $returner='';
  257. require_once 'purchase.class.php';
  258. switch($type) {
  259. case 'receipt':
  260. if( ECSE_purchase::get_purchase($purch_id)!=null ) {
  261. ob_start();
  262. get_template_part('wpsc','email_content-receipt'); //the template page should output some stuff, and probably include some uses of the ECSE_purchase class.
  263. $returner = ob_get_clean();
  264. }
  265. }
  266. return $returner;
  267. }
  268. /**
  269. * Output result of same call on get_content_part().
  270. * If no content replacement can be found, outputs an empty string.
  271. * @param string $type
  272. * @param int $purch_id
  273. */
  274. static function the_content_part($type,$purch_id) {
  275. echo self::get_content_part($type, $purch_id);
  276. }
  277. /**
  278. * To be used within purchase transaction emails to get the product rows.
  279. * @return string html the product rows
  280. */
  281. static function get_product_rows_part() {
  282. ob_start();
  283. while(ECSE_purchase::have_products()) { ECSE_purchase::the_product();
  284. get_template_part('wpsc','email_content_part-product_row'); //the theme file
  285. }
  286. return ob_get_clean();
  287. }
  288. /**
  289. * To be used within purchase transaction emails to get the totals.
  290. * @return string html the totals
  291. */
  292. static function get_totals_part() {
  293. ob_start();
  294. get_template_part('wpsc','email_content_part-totals'); //the theme file
  295. return ob_get_clean();
  296. }
  297. /**
  298. * To be used within purchase transaction emails to get the shipping & billing addresses.
  299. * @return string html the addresses
  300. */
  301. static function get_address_part() {
  302. ob_start();
  303. get_template_part('wpsc','email_content_part-addresses'); //the theme file
  304. return ob_get_clean();
  305. }
  306. /* STYLE & CONTENT APPLICATION */
  307. /**
  308. * Filter. Modify the variables of an email, to add style wrapping and convert to HTML.
  309. * Only modifies the email if a style template is found. Content template is optional.
  310. * Note that content replacement functionality in this plugin is not enough to convert the email to HTML, this function is needed to modify the email's header etc.
  311. * Used by self::modify_mail_operation(), which applies rules before deciding to apply style.
  312. * Used during wp_mail filter.
  313. * @param $vars - refer to the wp_mail filter
  314. * @return (array) refer to the wp_mail filter
  315. */
  316. static function filter_for_style($vars) {
  317. extract($vars);
  318. ECSE_mail::set_content($message);
  319. ECSE_mail::set_subject($subject);
  320. //content replacement
  321. if( (ecse_is_purchase_receipt_email() || ecse_is_order_pending_email() || ecse_is_order_pending_payment_required_email() ) && (locate_template('wpsc-email_content-receipt.php')!='') ) {
  322. $purch_id = self::read_pid_tag($message);
  323. if($purch_id!=0) {
  324. $replacement_content = ECSE_mail::get_content_part('receipt', $purch_id);
  325. if(!empty($replacement_content)) ECSE_mail::set_content($replacement_content);
  326. }
  327. }
  328. //keep line-breaks in wp-e-commerce & wordpress content when moving to HTML (not applicable when using content replacement)
  329. if( !isset($replacement_content) && ( (stripos($message,'<br') + stripos($message,'<body') + stripos($message,'<table') + stripos($message,'<div')) ==false) ) {
  330. // There is no HTML or BR linebreaks, so probably originally a plain-text content.
  331. // Let's convert all plain-text linebreaks to html linebreaks.
  332. // We needed to check, because we don't want to double-linebreak the email!
  333. ECSE_mail::set_content( str_ireplace("\n",'<br />',$message) );
  334. }
  335. //do the styling
  336. ob_start();
  337. self::the_style_part(); //the template file should output some stuff, and probabaly include a call to ecse_get_email_content()
  338. $message_formatted = ob_get_clean();
  339. if(!empty($message_formatted)) {
  340. $message=$message_formatted;
  341. //make sure content-type isn't already specified in the header.
  342. if(stripos('x'.$headers, 'Content-Type: text/html;')==false) {
  343. $ecse_charset = get_option('ecse_charset'); //not sure if anyone still uses this. Legacy since fixed charset mangling.
  344. if(empty($ecse_charset)) $ecse_charset = get_bloginfo( 'charset' ); //by default, WP assigns the charset of the blog to the emails. Not sure we need to do this. Not even sure anyone would want to override it.
  345. if(empty($ecse_charset)) $ecse_charset = 'UTF-8';
  346. $headers .= "\r\nContent-Type: text/html; charset=".$ecse_charset.";\r\n";
  347. }
  348. if(ecse_is_test_email() || ecse_is_other_email()) { //set the 'from' to be same as WPEC emails. Note that this can still be overridden by plugins and WP itself, like in user registrations.
  349. $reply_address = get_option( 'return_email' );
  350. $reply_name = get_option( 'return_name' );
  351. if(!empty($reply_address) && !empty($reply_name)) $headers .= "from: ".$reply_name." <".$reply_address.">\r\n";
  352. }
  353. }
  354. //clean up to reduce opportunities for data leakage outside the formatting template
  355. ECSE_mail::set_content('');
  356. ECSE_mail::set_subject('');
  357. return compact( 'to', 'subject', 'message', 'headers', 'attachments' );
  358. }
  359. /**
  360. * Filter that adds a temporary tag, storing the purchase ID for use in content rewriting.
  361. * @param string $message The body of the email
  362. * @param string $report_id The report_id snippet generated by WPEC during transactions, or a purchase number on it's own as a string
  363. * @return string the filtered message body with HTML-commented pid inserted
  364. */
  365. static function add_pid_tag($message,$report_id) {
  366. //narrow down the purchase ID from the report_id string
  367. $purch_id = intval(preg_replace("/[^0-9]/", '', $report_id));
  368. $message = '<!-- !ecse! '.$purch_id.' !ecse! --> '.$message;
  369. return $message;
  370. }
  371. /**
  372. * Extract the purchase ID from the pid tag
  373. * @param unknown_type $message
  374. * @return int purchase_id (or) 0 if not found
  375. */
  376. static function read_pid_tag($message) {
  377. $pid_start = stripos($message, '<!-- !ecse!') + 12;
  378. $pid_end = stripos($message, '!ecse! -->', $purch_id_start+1) - 1;
  379. $id = substr($message, $pid_start, $pid_end-$pid_start);
  380. return intval(preg_replace("/[^0-9]/", '', $id));
  381. }
  382. /**
  383. * Filter that strips the temporary tag added with add_pid_tag().
  384. * Used when we've added our temporary tag but aren't applying style
  385. * @param unknown_type $message
  386. */
  387. static function strip_pid_tag($message) {
  388. $pid_start = stripos($message, '<!-- !ecse!');
  389. $pid_end = stripos($message, '!ecse! -->', $pid_start+1) + 10;
  390. if(stripos($message, '!ecse! -->')>0) $message = substr_replace($message, '', $pid_start, $pid_end-$pid_start);
  391. return $message;
  392. }
  393. /* CONTROL */
  394. /**
  395. * Decide whether or not to style emails. Apply style if so. Should only be called by the wp_mail filter.
  396. * @param array $vars - refer to the wp_mail filter
  397. * @return array - refer to the wp_mail filter
  398. */
  399. static function modify_mail_operation($vars) {
  400. extract($vars);
  401. if(self::should_modify_mail($subject, $to)) {
  402. //just so we know if it's an "other" email.
  403. switch($subject) {
  404. case __( 'Purchase Report', 'wpsc' ):
  405. case __( 'Transaction Report', 'wpsc' ):
  406. case __( 'Purchase Receipt', 'wpsc' ):
  407. case __( 'Order Pending', 'wpsc' ):
  408. case __( 'Order Pending: Payment Required', 'wpsc' ):
  409. case get_option( 'wpsc_trackingid_subject' ):
  410. case __( 'The administrator has unlocked your file', 'wpsc' ):
  411. case 'ECSE test email':
  412. break;
  413. default:
  414. self::set_type_other();
  415. }
  416. //Apply the style!
  417. extract(self::filter_for_style($vars));
  418. }
  419. $message = self::strip_pid_tag($message);
  420. return compact( 'to', 'subject', 'message', 'headers', 'attachments' );
  421. }
  422. /**
  423. * Output a preview email. Used in the options page via page load.
  424. * @param array $options containing any or all of the defaults to be overridden
  425. * @return none
  426. */
  427. static function render_preview($options = array()) {
  428. require_once 'purchase.class.php';
  429. $pid = ECSE_purchase::get_recent_purchase_id();
  430. $defaults = array(
  431. 'to' => '',
  432. 'subject' => 'ECSE test email',
  433. 'message' => self::add_pid_tag('[email content as generated]', $pid),
  434. 'headers' => '',
  435. 'attachments' => ''
  436. );
  437. $vars = array_merge($defaults,$options);
  438. if($subject=='other email') self::set_type_other();
  439. //apply style
  440. $vars = self::filter_for_style($vars);
  441. //remove the pid tag added during the 'wpsc_email_message' filter
  442. //not needed for the browser preview, because even if the styling didn't happen, browsers still hide HTML comments
  443. //$vars['message'] = ECSE_mail::strip_pid_tag($vars['message']);
  444. echo $vars['message'];
  445. }
  446. }
  447. ?>