PluginProbe
Property Hive / 1.4.53
Property Hive v1.4.53
2.3.0 2.2.6 2.2.5 2.2.4 2.2.3 2.2.2 1.4.46 1.4.47 1.4.48 1.4.49 1.4.5 1.4.50 1.4.51 1.4.52 1.4.53 1.4.54 1.4.55 1.4.56 1.4.57 1.4.58 1.4.59 1.4.6 1.4.60 1.4.61 1.4.62 All 260 releases
propertyhive / includes / class-ph-emails.php

class-ph-emails.php in Property Hive 1.4.53, at includes/class-ph-emails.php

680 lines 21.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 /**
8 * Transactional Emails Controller
9 *
10 * Property Hive Emails Class which handles the sending on transactional emails and email templates. This class loads in available emails.
11 *
12 * @class PH_Emails
13 * @version 1.0.0
14 * @package PropertyHive/Classes/Emails
15 * @category Class
16 * @author PropertyHive
17 */
18 class PH_Emails {
19
20 /** @var PH_Emails The single instance of the class */
21 protected static $_instance = null;
22
23 /**
24 * Main PH_Emails Instance.
25 *
26 * Ensures only one instance of PH_Emails is loaded or can be loaded.
27 *
28 * @since 1.0.0
29 * @static
30 * @return PH_Emails Main instance
31 */
32 public static function instance() {
33 if ( is_null( self::$_instance ) ) {
34 self::$_instance = new self();
35 }
36 return self::$_instance;
37 }
38
39 /**
40 * Cloning is forbidden.
41 *
42 * @since 1.0.0
43 */
44 public function __clone() {
45 _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'propertyhive' ), '1.0.0' );
46 }
47
48 /**
49 * Unserializing instances of this class is forbidden.
50 *
51 * @since 1.0.0
52 */
53 public function __wakeup() {
54 _doing_it_wrong( __FUNCTION__, __( 'Cheatin&#8217; huh?', 'propertyhive' ), '1.0.0' );
55 }
56
57 /**
58 * Constructor for the email class hooks in all emails that can be sent.
59 *
60 */
61 public function __construct() {
62 $this->init();
63
64 // Email Header, Footer
65 add_action( 'propertyhive_email_header', array( $this, 'email_header' ), 10, 1 );
66 add_action( 'propertyhive_email_footer', array( $this, 'email_footer' ), 10, 1 );
67
68 add_action( 'propertyhive_process_email_log', array( $this, 'ph_process_email_log' ) );
69 add_action( 'propertyhive_auto_email_match', array( $this, 'ph_auto_email_match' ) );
70
71 // Send applicant registration email
72 add_action( 'propertyhive_applicant_registered', array( $this, 'send_applicant_registration_alert' ), 10, 2 );
73
74 add_action( 'admin_init', array( $this, 'run_custom_email_cron' ), 10, 1 );
75 }
76
77 public function run_custom_email_cron()
78 {
79 if (isset($_GET['custom_email_log_cron']) && in_array($_GET['custom_email_log_cron'], array('propertyhive_process_email_log', 'propertyhive_auto_email_match')) )
80 {
81 do_action($_GET['custom_email_log_cron']);
82 }
83 }
84
85 public function send_applicant_registration_alert( $contact_post_id, $user_id )
86 {
87 if (
88 get_option( 'propertyhive_new_registration_alert', '' ) == 'yes' &&
89 isset($_POST['office_id']) && // in the future we should have office stored against contact and use that
90 $_POST['office_id'] != '' &&
91 isset($_POST['department']) && // Should really take department from contacts requirements
92 $_POST['department'] != ''
93 )
94 {
95 $to = get_post_meta( (int)$_POST['office_id'], '_office_email_address_' . str_replace("residential-", "", ph_clean($_POST['department'])), TRUE );
96
97 if ( $to == '' )
98 {
99 $to = get_option( 'admin_email', '' );
100 }
101
102 $subject = sprintf( __( 'A new applicant, %s, has registered through your website', 'propertyhive' ), get_the_title($contact_post_id) );
103
104 $message = __( "A new applicant has registered through your website. Please find details of the applicant below:", 'propertyhive' ) . "\n\n";
105
106 $message = apply_filters( 'propertyhive_applicant_registration_email_pre_body', $message, $contact_post_id );
107
108 $form_controls = ph_get_user_details_form_fields();
109
110 $form_controls = apply_filters( 'propertyhive_user_details_form_fields', $form_controls );
111
112 $form_controls_2 = ph_get_applicant_requirements_form_fields();
113
114 $form_controls_2 = apply_filters( 'propertyhive_applicant_requirements_form_fields', $form_controls_2 );
115
116 $form_controls = array_merge( $form_controls, $form_controls_2 );
117
118 $form_controls = apply_filters( 'propertyhive_applicant_registration_form_fields', $form_controls );
119
120 unset($form_controls['office_id']);
121
122 foreach ($form_controls as $key => $control)
123 {
124 if ( isset($control['type']) && $control['type'] == 'password' )
125 {
126 continue;
127 }
128
129 $value = ph_clean($_POST[$key]);
130 if ( taxonomy_exists($key) )
131 {
132 $term = get_term( ph_clean($_POST[$key]), $key );
133
134 if ( isset($term->name) )
135 {
136 $value = $term->name;
137 }
138 }
139
140 if ( ph_clean($value) == '' )
141 {
142 continue;
143 }
144
145 $label = ( isset($control['label']) ) ? $control['label'] : $key;
146 $message .= $label . ": " . $value . "\n";
147 }
148
149 wp_mail($to, $subject, $message);
150 }
151 }
152
153 /**
154 * Process ph_email_log table. Handle failed, hung and pending emails
155 */
156 public function ph_process_email_log()
157 {
158 global $wpdb;
159
160 $lock_id = uniqid( "", true );
161
162 $wpdb->query("
163 UPDATE " . $wpdb->prefix . "ph_email_log
164 SET
165 status = 'fail2',
166 lock_id = ''
167 WHERE
168 status = 'fail1'
169 AND
170 lock_id <> ''
171 AND
172 locked_at <= '" . date("Y-m-d H:i:s", strtotime('24 hours ago')) . "'
173 ");
174
175 $wpdb->query("
176 UPDATE " . $wpdb->prefix . "ph_email_log
177 SET
178 status = 'fail1',
179 lock_id = ''
180 WHERE
181 status = ''
182 AND
183 lock_id <> ''
184 AND
185 locked_at <= '" . date("Y-m-d H:i:s", strtotime('24 hours ago')) . "'
186 ");
187
188 // Lock/reserve all emails in log that are status blank or 'fail1' and lock_id blank and send_at in the past
189 // Only grab 25 at a time to prevent hanging/being seen as spamming
190 $wpdb->query("
191 UPDATE " . $wpdb->prefix . "ph_email_log
192 SET
193 lock_id = '" . $lock_id . "',
194 locked_at = '" . date("Y-m-d H:i:s") . "'
195 WHERE
196 (status = '' OR status = 'fail1')
197 AND
198 lock_id = ''
199 AND
200 send_at <= '" . date("Y-m-d H:i:s") . "'
201 LIMIT 25
202 ");
203
204 // We now have up to 25 emails locked. Get this 25 and attempt to send
205 $emails_to_send = $wpdb->get_results("
206 SELECT *
207 FROM " . $wpdb->prefix . "ph_email_log
208 WHERE
209 lock_id = '" . $lock_id . "'
210 ");
211
212 foreach ( $emails_to_send as $email_to_send )
213 {
214 $email_id = $email_to_send->email_id;
215
216 $headers = array();
217 $headers[] = 'From: ' . $email_to_send->from_name . ' <' . $email_to_send->from_email_address . '>';
218 $headers[] = 'Content-Type: text/html; charset=UTF-8';
219
220 $body = apply_filters( 'propertyhive_mail_content', $this->style_inline( $this->wrap_message( $email_to_send->body, $email_to_send->contact_id ) ) );
221
222 $sent = wp_mail(
223 $email_to_send->to_email_address,
224 $email_to_send->subject,
225 $body,
226 $headers/*,
227 string|array $attachments = array() */
228 );
229
230 $new_status = '';
231 if ( $sent )
232 {
233 // Sent successfully
234 $new_status = 'sent';
235 }
236 else
237 {
238 // Failed to send
239 if ($email_to_send->status == '')
240 {
241 $new_status = 'fail1';
242 }
243 else
244 {
245 $new_status = 'fail2';
246 }
247 }
248 $wpdb->query("
249 UPDATE " . $wpdb->prefix . "ph_email_log
250 SET
251 status = '" . $new_status . "',
252 lock_id = ''
253 WHERE
254 email_id = '" . $email_id . "'
255 ");
256 }
257 }
258
259 /*
260 * Automatically send new properties to registered applicants
261 */
262 public function ph_auto_email_match()
263 {
264 global $post;
265
266 // Auto emails enabled in settings
267 // Auto emails not disabled in applicant record
268 // Property added more recently that setting enabled in settings
269 // Property not already previously sent
270 // Valid email address
271 // 'Do not email' not selected
272
273 $auto_property_match_enabled = get_option( 'propertyhive_auto_property_match', '' );
274
275 if ( $auto_property_match_enabled == '' )
276 {
277 return false;
278 }
279
280 $auto_property_match_enabled_date = get_option( 'propertyhive_auto_property_match_enabled_date', '' );
281
282 if ( $auto_property_match_enabled_date == '' )
283 {
284 return false;
285 }
286
287 // Get all of the office email addresses and store them in an array to save having to query them for every email
288 // Get all contacts that have a type of applicant
289 $args = array(
290 'post_type' => 'office',
291 'nopaging' => true
292 );
293
294 $office_email_addresses = array();
295 $office_query = new WP_Query( $args );
296
297 if ( $office_query->have_posts() )
298 {
299 while ( $office_query->have_posts() )
300 {
301 $office_query->the_post();
302
303 $office_email_addresses['residential-sales'][get_the_ID()] = get_post_meta( get_the_ID(), '_office_email_address_sales', TRUE );
304 $office_email_addresses['residential-lettings'][get_the_ID()] = get_post_meta( get_the_ID(), '_office_email_address_lettings', TRUE );
305 $office_email_addresses['commercial'][get_the_ID()] = get_post_meta( get_the_ID(), '_office_email_address_commercial', TRUE );
306 }
307 }
308
309 wp_reset_postdata();
310
311 include_once( dirname(__FILE__) . '/admin/class-ph-admin-matching-properties.php' );
312 $ph_admin_matching_properties = new PH_Admin_Matching_Properties();
313
314 // Get all contacts that have a type of applicant
315 $args = array(
316 'post_type' => 'contact',
317 'nopaging' => true,
318 'meta_query' => array(
319 array(
320 'key' => '_contact_types',
321 'value' => 'applicant',
322 'compare' => 'LIKE'
323 )
324 ),
325 'fields' => 'ids'
326 );
327
328 $contact_query = new WP_Query( $args );
329
330 if ( $contact_query->have_posts() )
331 {
332 $default_subject = get_option( 'propertyhive_property_match_default_email_subject', '' );
333 $default_body = get_option( 'propertyhive_property_match_default_email_body', '' );
334
335 while ( $contact_query->have_posts() )
336 {
337 $contact_query->the_post();
338
339 $contact_id = get_the_ID();
340
341 // invalid email address
342 if ( strpos( get_post_meta( $contact_id, '_email_address', TRUE ), '@' ) === FALSE )
343 {
344 continue;
345 }
346
347 // email in the list of forbidden contact methods
348 $forbidden_contact_methods = get_post_meta( $contact_id, '_forbidden_contact_methods', TRUE );
349 if ( is_array($forbidden_contact_methods) && in_array('email', $forbidden_contact_methods) )
350 {
351 continue;
352 }
353
354 $applicant_profiles = get_post_meta( $contact_id, '_applicant_profiles', TRUE );
355
356 if ( $applicant_profiles != '' && $applicant_profiles > 0 )
357 {
358 $dismissed_properties = get_post_meta( $contact_id, '_dismissed_properties', TRUE );
359 if ( $dismissed_properties == '' )
360 {
361 $dismissed_properties = array();
362 }
363
364 for ( $i = 0; $i < $applicant_profiles; ++$i )
365 {
366 $applicant_profile = get_post_meta( $contact_id, '_applicant_profile_' . $i, TRUE );
367
368 if ( $applicant_profile == '' || !is_array($applicant_profile) || !isset($applicant_profile['department']) )
369 {
370 continue;
371 }
372
373 if ( !isset($applicant_profile['send_matching_properties']) || ( isset($applicant_profile['send_matching_properties']) && $applicant_profile['send_matching_properties'] != 'yes' ) )
374 {
375 continue;
376 }
377
378 if ( isset($applicant_profile['auto_match_disabled']) && $applicant_profile['auto_match_disabled'] == 'yes' )
379 {
380 continue;
381 }
382
383 $matching_properties = $ph_admin_matching_properties->get_matching_properties( $contact_id, $i, $auto_property_match_enabled_date );
384
385 if ( !empty($matching_properties) )
386 {
387 $already_sent_properties = get_post_meta( $contact_id, '_applicant_profile_' . $i . '_match_history', TRUE );
388
389 // Remove from this array if on market changed or price changed
390 if ( is_array($already_sent_properties) )
391 {
392 foreach ( $already_sent_properties as $already_sent_property_id => $sends )
393 {
394 $highest_send = $sends[count($sends) - 1]['date'];
395
396 if ( $highest_send != '' )
397 {
398 $on_market_change_date = get_post_meta( $already_sent_property_id, '_on_market_change_date', TRUE );
399 $price_change_date = get_post_meta( $already_sent_property_id, '_price_change_date', TRUE );
400
401 if ( $on_market_change_date > $highest_send || $price_change_date > $highest_send )
402 {
403 // This property has changed since it was last sent. Remove from already sent list so it gets sent again
404 unset($already_sent_properties[$already_sent_property_id]);
405 }
406 }
407 }
408 }
409
410 // Check properties haven't already been sent and not marked as 'not interested'
411 $new_matching_properties = array();
412 foreach ($matching_properties as $matching_property)
413 {
414 if ( !isset($already_sent_properties[$matching_property->id]) && !in_array($matching_property->id, $dismissed_properties) )
415 {
416 $new_matching_properties[] = $matching_property->id;
417 }
418 }
419
420 if ( !empty($new_matching_properties) )
421 {
422 $subject = str_replace("[property_count]", count($new_matching_properties) . ' propert' . ( ( count($new_matching_properties) != 1 ) ? 'ies' : 'y' ), $default_subject);
423
424 $body = str_replace("[contact_name]", get_the_title($contact_id), $default_body);
425 $body = str_replace("[property_count]", count($new_matching_properties) . ' propert' . ( ( count($new_matching_properties) != 1 ) ? 'ies' : 'y' ), $body);
426
427 if ( strpos($body, '[properties]') !== FALSE )
428 {
429 ob_start();
430
431 $office_counts = array();
432 if ( !empty($new_matching_properties) )
433 {
434 foreach ( $new_matching_properties as $email_property_id )
435 {
436 $property = new PH_Property((int)$email_property_id);
437
438 if ( $property->office_id != '' && $property->office_id != 0 )
439 {
440 if ( !isset($office_counts[$property->office_id]) ) { $office_counts[$property->office_id] = 0; }
441 ++$office_counts[$property->office_id];
442 }
443
444 ph_get_template( 'emails/applicant-match-property.php', array( 'property' => $property ) );
445 }
446 }
447 $body = str_replace("[properties]", ob_get_clean(), $body);
448 }
449
450 // Get email address of office with most properties
451 $highest_office_email_address = '';
452 if ( !empty($office_counts) )
453 {
454 arsort($office_counts);
455 reset($office_counts);
456 $highest_office_id = key($office_counts);
457 $highest_office_email_address = ( isset($office_email_addresses[$applicant_profile['department']][$highest_office_id]) ? $office_email_addresses[$applicant_profile['department']][$highest_office_id] : '' );
458 }
459 if ( $highest_office_email_address == '' )
460 {
461 // fallback to admin email address
462 $highest_office_email_address = get_option('admin_email');
463 }
464
465 $ph_admin_matching_properties->send_emails(
466 $contact_id,
467 $i,
468 $new_matching_properties,
469 get_bloginfo('name'),
470 $highest_office_email_address,
471 $subject,
472 $body
473 );
474 }
475 }
476 }
477 }
478 }
479 }
480
481 wp_reset_postdata();
482 }
483
484 /**
485 * Init email classes.
486 */
487 public function init() {
488
489 }
490
491 /**
492 * Apply inline styles to dynamic content.
493 *
494 * @param string|null $content
495 * @return string
496 */
497 public function style_inline( $content ) {
498 // make sure we only inline CSS for html emails
499 if ( class_exists( 'DOMDocument' ) ) {
500 ob_start();
501 ph_get_template( 'emails/email-styles.php' );
502 $css = apply_filters( 'propertyhive_email_styles', ob_get_clean() );
503
504 // include css inliner
505 if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
506 include_once( dirname( __FILE__ ) . '/libraries/class-emogrifier.php' );
507 }
508
509 // apply CSS styles inline for picky email clients
510 try {
511 $emogrifier = new Emogrifier( $content, $css );
512 $content = $emogrifier->emogrify();
513 } catch ( Exception $e ) {
514 die("Error converting CSS styles to be inline. Error as follows: " . $e->getMessage());
515 }
516 }
517 return $content;
518 }
519
520 /**
521 * Get the email header.
522 */
523 public function email_header( $contact_id = '' ) {
524 ph_get_template( 'emails/email-header.php' );
525 }
526
527 /**
528 * Get the email footer.
529 */
530 public function email_footer( $contact_id = '' ) {
531 $unsubscribe_link = '';
532 if ($contact_id != '')
533 {
534 $unsubscribe_link = site_url() .'?ph_unsubscribe=' . base64_encode($contact_id . '|' . md5( get_post_meta( $contact_id, '_email_address', TRUE ) ) );
535 }
536
537 ph_get_template( 'emails/email-footer.php', array( 'unsubscribe_link' => $unsubscribe_link ) );
538 }
539
540 /**
541 * Wraps a message in the Property Hive mail template.
542 *
543 * @param mixed $email_heading
544 * @param string $message
545 * @return string
546 */
547 public function wrap_message( $message, $contact_id = '', $plain_text = false ) {
548 // Buffer
549 ob_start();
550
551 do_action( 'propertyhive_email_header', $contact_id );
552
553 echo wpautop( wptexturize( $message ) );
554
555 do_action( 'propertyhive_email_footer', $contact_id );
556
557 // Get contents
558 $message = ob_get_clean();
559
560 return $message;
561 }
562
563 public function send_enquiry_auto_responder( $data = array() )
564 {
565 if ( isset($data['property_id']) && sanitize_text_field($data['property_id']) != '' )
566 {
567 $property_id = $data['property_id'];
568 $to = sanitize_email( $_POST['email_address'] );
569 $subject = get_option( 'propertyhive_enquiry_auto_responder_email_subject', '' );
570 $body = get_option( 'propertyhive_enquiry_auto_responder_email_body', '' );
571
572 if ( $to != '' && $subject != '' && $body != '' )
573 {
574 $headers = array();
575 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . get_option( 'propertyhive_email_from_address', get_option( 'admin_email' ) ) . '>';
576 $headers[] = 'Content-Type: text/html; charset=UTF-8';
577
578 $body = str_replace( "[name]", ( isset($_POST['name']) ? ph_clean($_POST['name']) : '' ), $body );
579
580 $body = str_replace( "[property_address_hyperlinked]", '<a href="' . get_permalink($property_id) . '">' . get_the_title($property_id) . '</a>', $body );
581
582 if ( strpos( $body, '[similar_properties]' ) !== FALSE )
583 {
584 $similar_html = '';
585
586 $department = get_post_meta( $property_id, '_department', TRUE );
587 $bedrooms = get_post_meta( $property_id, '_bedrooms', TRUE );
588 $price = get_post_meta( $property_id, '_price_actual', true );
589 $lower_price = $price - ($price / 10);
590 $higher_price = $price + ($price / 10);
591
592 // Get two similar properties
593 $args = array(
594 'post_type' => 'property',
595 'post_status' => 'publish',
596 'posts_per_page' => 3,
597 'orderby' => 'rand',
598 'post__not_in' => array($property_id),
599 );
600
601 $meta_query = array();
602
603 $meta_query[] = array(
604 'key' => '_department',
605 'value' => $department,
606 );
607
608 $meta_query[] = array(
609 'key' => '_on_market',
610 'value' => 'yes',
611 );
612
613 $meta_query[] = array(
614 'key' => '_bedrooms',
615 'value' => $bedrooms,
616 'type' => 'NUMERIC'
617 );
618
619 $meta_query[] = array(
620 'key' => '_price_actual',
621 'value' => $lower_price,
622 'compare' => '>=',
623 'type' => 'NUMERIC'
624 );
625
626 $meta_query[] = array(
627 'key' => '_price_actual',
628 'value' => $higher_price,
629 'compare' => '<=',
630 'type' => 'NUMERIC'
631 );
632
633 $args['meta_query'] = $meta_query;
634
635 $properties_query = new WP_Query( apply_filters( 'propertyhive_auto_responder_similar_properties_query', $args, $property_id ) );
636
637 if ( $properties_query->have_posts() )
638 {
639 $similar_html = '<br><hr><br><h3>Similar Properties You Might Like:</h3>';
640
641 while ( $properties_query->have_posts() )
642 {
643 $properties_query->the_post();
644
645 $property = new PH_Property( get_the_ID() );
646
647 $similar_html .= '<table width="100%" cellpadding="5" cellspacing="0">';
648 $similar_html .= '<tr>';
649 $similar_html .= '<td width="20%" valign="top">';
650 $image = $property->get_main_photo_src();
651 if ( $image !== false )
652 {
653 $similar_html .= '<a href="' . get_permalink() . '"><img src="' . $image . '" alt="' . get_the_title() . '"></a>';
654 }
655 $similar_html .= '</td>';
656 $similar_html .= '<td valign="top" class="text">';
657 $similar_html .= '<p style="margin-bottom:8px !important;"><strong><a href="' . get_permalink() . '">' . get_the_title() . '</a></strong></p>';
658 $similar_html .= '<p style="margin-bottom:8px !important; font-size:14px;"><strong>' . $property->get_formatted_price() . '</strong></p>';
659 $similar_html .= '<p style="margin-bottom:8px !important; font-size:14px;">' . $property->bedrooms . ' bed ' . $property->property_type . ' ' . $property->availability . '</p>';
660 if ( strip_tags($property->post_excerpt) != '' )
661 {
662 $similar_html .= '<p style="margin-bottom:0 !important; font-size:14px;">' . substr(strip_tags($property->post_excerpt), 0, 300);
663 if ( strlen(strip_tags($property->post_excerpt)) > 300 ) { $similar_html .= '...'; }
664 $similar_html .= '</p>';
665 }
666 $similar_html .= '</td>';
667 $similar_html .= '</tr>';
668 $similar_html .= '</table><br>';
669 }
670 }
671 $body = str_replace( "[similar_properties]", $similar_html, $body );
672 }
673
674 $body = apply_filters( 'propertyhive_mail_content', $this->style_inline( $this->wrap_message( $body ) ) );
675
676 wp_mail( $to, $subject, $body, $headers );
677 }
678 }
679 }
680 }