PluginProbe
Property Hive / 1.4.6
Property Hive v1.4.6
2.3.1 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 All 261 releases
propertyhive / includes / class-ph-emails.php

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

584 lines 17.5 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_log_cron' ), 10, 1 );
75 }
76
77 public function run_custom_email_log_cron()
78 {
79 if( isset($_GET['custom_email_log_cron']) )
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( $_POST['office_id'], '_office_email_address_' . str_replace("residential-", "", $_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 unset($form_controls['office_id']);
119
120 foreach ($form_controls as $key => $control)
121 {
122 if ( isset($control['type']) && $control['type'] == 'password' )
123 {
124 continue;
125 }
126
127 $label = ( isset($control['label']) ) ? $control['label'] : $key;
128 $message .= $label . ": " . $_POST[$key] . "\n";
129 }
130
131 wp_mail($to, $subject, $message);
132 }
133 }
134
135 /**
136 * Process ph_email_log table. Handle failed, hung and pending emails
137 */
138 public function ph_process_email_log()
139 {
140 global $wpdb;
141
142 $lock_id = uniqid( "", true );
143
144 $wpdb->query("
145 UPDATE " . $wpdb->prefix . "ph_email_log
146 SET
147 status = 'fail2',
148 lock_id = ''
149 WHERE
150 status = 'fail1'
151 AND
152 lock_id <> ''
153 AND
154 locked_at <= '" . date("Y-m-d H:i:s", strtotime('24 hours ago')) . "'
155 ");
156
157 $wpdb->query("
158 UPDATE " . $wpdb->prefix . "ph_email_log
159 SET
160 status = 'fail1',
161 lock_id = ''
162 WHERE
163 status = ''
164 AND
165 lock_id <> ''
166 AND
167 locked_at <= '" . date("Y-m-d H:i:s", strtotime('24 hours ago')) . "'
168 ");
169
170 // Lock/reserve all emails in log that are status blank or 'fail1' and lock_id blank and send_at in the past
171 // Only grab 5 at a time to prevent hanging/being seen as spamming
172 $wpdb->query("
173 UPDATE " . $wpdb->prefix . "ph_email_log
174 SET
175 lock_id = '" . $lock_id . "',
176 locked_at = '" . date("Y-m-d H:i:s") . "'
177 WHERE
178 (status = '' OR status = 'fail1')
179 AND
180 lock_id = ''
181 AND
182 send_at <= '" . date("Y-m-d H:i:s") . "'
183 LIMIT 5
184 ");
185
186 // We now have up to 5 emails locked. Get this 5 and attempt to send
187 $emails_to_send = $wpdb->get_results("
188 SELECT *
189 FROM " . $wpdb->prefix . "ph_email_log
190 WHERE
191 lock_id = '" . $lock_id . "'
192 ");
193
194 foreach ( $emails_to_send as $email_to_send )
195 {
196 $email_id = $email_to_send->email_id;
197
198 $headers = array();
199 $headers[] = 'From: ' . $email_to_send->from_name . ' <' . $email_to_send->from_email_address . '>';
200 $headers[] = 'Content-Type: text/html; charset=UTF-8';
201
202 $body = apply_filters( 'propertyhive_mail_content', $this->style_inline( $this->wrap_message( $email_to_send->body, $email_to_send->contact_id ) ) );
203
204 $sent = wp_mail(
205 $email_to_send->to_email_address,
206 $email_to_send->subject,
207 $body,
208 $headers/*,
209 string|array $attachments = array() */
210 );
211
212 $new_status = '';
213 if ( $sent )
214 {
215 // Sent successfully
216 $new_status = 'sent';
217 }
218 else
219 {
220 // Failed to send
221 if ($email_to_send->status == '')
222 {
223 $new_status = 'fail1';
224 }
225 else
226 {
227 $new_status = 'fail2';
228 }
229 }
230 $wpdb->query("
231 UPDATE " . $wpdb->prefix . "ph_email_log
232 SET
233 status = '" . $new_status . "',
234 lock_id = ''
235 WHERE
236 email_id = '" . $email_id . "'
237 ");
238 }
239 }
240
241 /*
242 * Automatically send new properties to registered applicants
243 */
244 public function ph_auto_email_match()
245 {
246 global $post;
247
248 // Auto emails enabled in settings
249 // Auto emails not disabled in applicant record
250 // Property added more recently that setting enabled in settings
251 // Property not already previously sent
252 // Valid email address
253 // 'Do not email' not selected
254
255 $auto_property_match_enabled = get_option( 'propertyhive_auto_property_match', '' );
256
257 if ( $auto_property_match_enabled == '' )
258 {
259 return false;
260 }
261
262 $auto_property_match_enabled_date = get_option( 'propertyhive_auto_property_match_enabled_date', '' );
263
264 if ( $auto_property_match_enabled_date == '' )
265 {
266 return false;
267 }
268
269 include_once( dirname(__FILE__) . '/admin/class-ph-admin-matching-properties.php' );
270 $ph_admin_matching_properties = new PH_Admin_Matching_Properties();
271
272 // Get all contacts that have a type of applicant
273 $args = array(
274 'post_type' => 'contact',
275 'nopaging' => true,
276 'meta_query' => array(
277 array(
278 'key' => '_contact_types',
279 'value' => 'applicant',
280 'compare' => 'LIKE'
281 )
282 ),
283 'fields' => 'ids'
284 );
285
286 $contact_query = new WP_Query( $args );
287
288 if ( $contact_query->have_posts() )
289 {
290 $default_subject = get_option( 'propertyhive_property_match_default_email_subject', '' );
291 $default_body = get_option( 'propertyhive_property_match_default_email_body', '' );
292
293 while ( $contact_query->have_posts() )
294 {
295 $contact_query->the_post();
296
297 $contact_id = get_the_ID();
298
299 // invalid email address
300 if ( strpos( get_post_meta( $contact_id, '_email_address', TRUE ), '@' ) === FALSE )
301 {
302 continue;
303 }
304
305 // email in the list of forbidden contact methods
306 $forbidden_contact_methods = get_post_meta( $contact_id, '_forbidden_contact_methods', TRUE );
307 if ( is_array($forbidden_contact_methods) && in_array('email', $forbidden_contact_methods) )
308 {
309 continue;
310 }
311
312 $applicant_profiles = get_post_meta( $contact_id, '_applicant_profiles', TRUE );
313
314 if ( $applicant_profiles != '' && $applicant_profiles > 0 )
315 {
316 $dismissed_properties = get_post_meta( $contact_id, '_dismissed_properties', TRUE );
317
318 for ( $i = 0; $i < $applicant_profiles; ++$i )
319 {
320 $applicant_profile = get_post_meta( $contact_id, '_applicant_profile_' . $i, TRUE );
321
322 if ( $applicant_profile == '' || !is_array($applicant_profile) || !isset($applicant_profile['department']) )
323 {
324 continue;
325 }
326
327 if ( isset($applicant_profile['send_matching_properties']) && $applicant_profile['send_matching_properties'] == '' )
328 {
329 continue;
330 }
331
332 if ( isset($applicant_profile['auto_match_disabled']) && $applicant_profile['auto_match_disabled'] == 'yes' )
333 {
334 continue;
335 }
336
337 $matching_properties = $ph_admin_matching_properties->get_matching_properties( $contact_id, $i, $auto_property_match_enabled_date );
338
339 if ( !empty($matching_properties) )
340 {
341 $already_sent_properties = get_post_meta( $contact_id, '_applicant_profile_' . $i . '_match_history', TRUE );
342
343 // Check properties haven't already been sent and not marked as 'not interested'
344 $new_matching_properties = array();
345 foreach ($matching_properties as $matching_property)
346 {
347 if ( !isset($already_sent_properties[$matching_property->id]) && !in_array($matching_property->id, $dismissed_properties) )
348 {
349 $new_matching_properties[] = $matching_property->id;
350 }
351 }
352
353 if ( !empty($new_matching_properties) )
354 {
355 $subject = str_replace("[property_count]", count($new_matching_properties) . ' propert' . ( ( count($new_matching_properties) != 1 ) ? 'ies' : 'y' ), $default_subject);
356
357 $body = str_replace("[contact_name]", get_the_title($contact_id), $default_body);
358 $body = str_replace("[property_count]", count($new_matching_properties) . ' propert' . ( ( count($new_matching_properties) != 1 ) ? 'ies' : 'y' ), $body);
359
360 if ( strpos($body, '[properties]') !== FALSE )
361 {
362 ob_start();
363 if ( !empty($new_matching_properties) )
364 {
365 foreach ( $new_matching_properties as $email_property_id )
366 {
367 $property = new PH_Property((int)$email_property_id);
368 ph_get_template( 'emails/applicant-match-property.php', array( 'property' => $property ) );
369 }
370 }
371 $body = str_replace("[properties]", ob_get_clean(), $body);
372 }
373
374 $ph_admin_matching_properties->send_emails(
375 $contact_id,
376 $i,
377 $new_matching_properties,
378 get_bloginfo('name'),
379 get_option('admin_email'),
380 $subject,
381 $body
382 );
383 }
384 }
385 }
386 }
387 }
388 }
389
390 wp_reset_postdata();
391 }
392
393 /**
394 * Init email classes.
395 */
396 public function init() {
397 // include css inliner
398 if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
399 include_once( dirname( __FILE__ ) . '/libraries/class-emogrifier.php' );
400 }
401 }
402
403 /**
404 * Apply inline styles to dynamic content.
405 *
406 * @param string|null $content
407 * @return string
408 */
409 public function style_inline( $content ) {
410 // make sure we only inline CSS for html emails
411 if ( class_exists( 'DOMDocument' ) ) {
412 ob_start();
413 ph_get_template( 'emails/email-styles.php' );
414 $css = apply_filters( 'propertyhive_email_styles', ob_get_clean() );
415 // apply CSS styles inline for picky email clients
416 try {
417 $emogrifier = new Emogrifier( $content, $css );
418 $content = $emogrifier->emogrify();
419 } catch ( Exception $e ) {
420 die("Error converting CSS styles to be inline. Error as follows: " . $e->getMessage());
421 }
422 }
423 return $content;
424 }
425
426 /**
427 * Get the email header.
428 */
429 public function email_header( $contact_id = '' ) {
430 ph_get_template( 'emails/email-header.php' );
431 }
432
433 /**
434 * Get the email footer.
435 */
436 public function email_footer( $contact_id = '' ) {
437 $unsubscribe_link = '';
438 if ($contact_id != '')
439 {
440 $unsubscribe_link = site_url() .'?ph_unsubscribe=' . base64_encode($contact_id . '|' . md5( get_post_meta( $contact_id, '_email_address', TRUE ) ) );
441 }
442
443 ph_get_template( 'emails/email-footer.php', array( 'unsubscribe_link' => $unsubscribe_link ) );
444 }
445
446 /**
447 * Wraps a message in the Property Hive mail template.
448 *
449 * @param mixed $email_heading
450 * @param string $message
451 * @return string
452 */
453 public function wrap_message( $message, $contact_id = '', $plain_text = false ) {
454 // Buffer
455 ob_start();
456
457 do_action( 'propertyhive_email_header', $contact_id );
458
459 echo wpautop( wptexturize( $message ) );
460
461 do_action( 'propertyhive_email_footer', $contact_id );
462
463 // Get contents
464 $message = ob_get_clean();
465
466 return $message;
467 }
468
469 public function send_enquiry_auto_responder( $data = array() )
470 {
471 if ( isset($data['property_id']) && sanitize_text_field($data['property_id']) != '' )
472 {
473 $property_id = $data['property_id'];
474 $to = sanitize_email( $_POST['email_address'] );
475 $subject = get_option( 'propertyhive_enquiry_auto_responder_email_subject', '' );
476 $body = get_option( 'propertyhive_enquiry_auto_responder_email_body', '' );
477
478 if ( $to != '' && $subject != '' && $body != '' )
479 {
480 $headers = array();
481 $headers[] = 'From: ' . get_bloginfo('name') . ' <' . get_option( 'propertyhive_email_from_address', get_option( 'admin_email' ) ) . '>';
482 $headers[] = 'Content-Type: text/html; charset=UTF-8';
483
484 $body = str_replace( "[property_address_hyperlinked]", '<a href="' . get_permalink($property_id) . '">' . get_the_title($property_id) . '</a>', $body );
485
486 if ( strpos( $body, '[similar_properties]' ) !== FALSE )
487 {
488 $similar_html = '';
489
490 $department = get_post_meta( $property_id, '_department', TRUE );
491 $bedrooms = get_post_meta( $property_id, '_bedrooms', TRUE );
492 $price = get_post_meta( $property_id, '_price_actual', true );
493 $lower_price = $price - ($price / 10);
494 $higher_price = $price + ($price / 10);
495
496 // Get two similar properties
497 $args = array(
498 'post_type' => 'property',
499 'post_status' => 'publish',
500 'posts_per_page' => 3,
501 'orderby' => 'rand',
502 'post__not_in' => array($property_id),
503 );
504
505 $meta_query = array();
506
507 $meta_query[] = array(
508 'key' => '_department',
509 'value' => $department,
510 );
511
512 $meta_query[] = array(
513 'key' => '_on_market',
514 'value' => 'yes',
515 );
516
517 $meta_query[] = array(
518 'key' => '_bedrooms',
519 'value' => $bedrooms,
520 'type' => 'NUMERIC'
521 );
522
523 $meta_query[] = array(
524 'key' => '_price_actual',
525 'value' => $lower_price,
526 'compare' => '>=',
527 'type' => 'NUMERIC'
528 );
529
530 $meta_query[] = array(
531 'key' => '_price_actual',
532 'value' => $higher_price,
533 'compare' => '<=',
534 'type' => 'NUMERIC'
535 );
536
537 $args['meta_query'] = $meta_query;
538
539 $properties_query = new WP_Query( apply_filters( 'propertyhive_auto_responder_similar_properties_query', $args, $property_id ) );
540
541 if ( $properties_query->have_posts() )
542 {
543 $similar_html = '<br><hr><br><h3>Similar Properties You Might Like:</h3>';
544
545 while ( $properties_query->have_posts() )
546 {
547 $properties_query->the_post();
548
549 $property = new PH_Property( get_the_ID() );
550
551 $similar_html .= '<table width="100%" cellpadding="5" cellspacing="0">';
552 $similar_html .= '<tr>';
553 $similar_html .= '<td width="20%" valign="top">';
554 $image = $property->get_main_photo_src();
555 if ( $image !== false )
556 {
557 $similar_html .= '<a href="' . get_permalink() . '"><img src="' . $image . '" alt="' . get_the_title() . '"></a>';
558 }
559 $similar_html .= '</td>';
560 $similar_html .= '<td valign="top" class="text">';
561 $similar_html .= '<p style="margin-bottom:8px !important;"><strong><a href="' . get_permalink() . '">' . get_the_title() . '</a></strong></p>';
562 $similar_html .= '<p style="margin-bottom:8px !important; font-size:14px;"><strong>' . $property->get_formatted_price() . '</strong></p>';
563 $similar_html .= '<p style="margin-bottom:8px !important; font-size:14px;">' . $property->bedrooms . ' bed ' . $property->property_type . ' ' . $property->availability . '</p>';
564 if ( strip_tags($property->post_excerpt) != '' )
565 {
566 $similar_html .= '<p style="margin-bottom:0 !important; font-size:14px;">' . substr(strip_tags($property->post_excerpt), 0, 300);
567 if ( strlen(strip_tags($property->post_excerpt)) > 300 ) { $similar_html .= '...'; }
568 $similar_html .= '</p>';
569 }
570 $similar_html .= '</td>';
571 $similar_html .= '</tr>';
572 $similar_html .= '</table><br>';
573 }
574 }
575 $body = str_replace( "[similar_properties]", $similar_html, $body );
576 }
577
578 $body = apply_filters( 'propertyhive_mail_content', $this->style_inline( $this->wrap_message( $body ) ) );
579
580 wp_mail( $to, $subject, $body, $headers );
581 }
582 }
583 }
584 }