id = 'email'; $this->label = __( 'Emails', 'propertyhive' ); add_filter( 'propertyhive_settings_tabs_array', array( $this, 'add_settings_page' ), 20 ); add_action( 'propertyhive_sections_' . $this->id, array( $this, 'output_sections' ) ); add_action( 'propertyhive_settings_' . $this->id, array( $this, 'output' ) ); add_action( 'propertyhive_settings_save_' . $this->id, array( $this, 'save' ) ); add_action( 'propertyhive_admin_field_email_queue', array( $this, 'email_queue_setting' ) ); } /** * Get sections. * * @return array */ public function get_sections() { $sections = array( '' => __( 'Email Options', 'propertyhive' ), 'enquiry-auto-responder' => __( 'Enquiry Auto-Responder', 'propertyhive' ), ); if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' ) { $sections['match'] = __( 'Property Match', 'propertyhive' ); } if ( get_option('propertyhive_module_disabled_viewings', '') != 'yes' || get_option('propertyhive_module_disabled_appraisals', '') != 'yes' ) { $sections['booking-confirmation'] = __( 'Booking Confirmations & Cancellations', 'propertyhive' ); } if ( get_option('propertyhive_module_disabled_contacts', '') != 'yes' ) { $sections['log'] = __( 'Email Queue', 'propertyhive' ); } return apply_filters( 'propertyhive_get_sections_' . $this->id, $sections ); } /** * Get settings array. * * @return array */ public function get_settings() { $settings = array( array( 'title' => __( 'Email Sender Settings', 'propertyhive' ), 'type' => 'title', 'id' => 'email_sender_options' ), array( 'title' => __( '"From" Email Address', 'propertyhive' ), 'id' => 'propertyhive_email_from_address', 'type' => 'text', 'css' => 'min-width:300px;', 'default' => get_option('admin_email'), 'autoload' => false, 'desc_tip' => false, ), array( 'type' => 'sectionend', 'id' => 'email_sender_options' ), array( 'title' => __( 'Email Template Settings', 'propertyhive' ), 'type' => 'title', 'id' => 'email_template_options' ), array( 'title' => __( 'Header Image URL', 'propertyhive' ), 'desc' => __( 'URL to an image you want to show in the email header. Upload images using the media uploader (Admin > Media).', 'propertyhive' ), 'id' => 'propertyhive_email_header_image', 'type' => 'text', 'css' => 'min-width:300px;', 'placeholder' => 'http://', 'default' => '', 'autoload' => false, 'desc_tip' => true, ), array( 'title' => __( 'Email Background Colour', 'propertyhive' ), 'desc' => __( 'The background colour for Property Hive email templates.', 'propertyhive' ), 'id' => 'propertyhive_email_background_color', 'type' => 'color', 'css' => 'width:6em;', 'default' => '#f7f7f7', 'autoload' => false, 'desc_tip' => true, ), array( 'title' => __( 'Body Background Colour', 'propertyhive' ), 'desc' => __( 'The main body background colour.', 'propertyhive' ), 'id' => 'propertyhive_email_body_background_color', 'type' => 'color', 'css' => 'width:6em;', 'default' => '#ffffff', 'autoload' => false, 'desc_tip' => true, ), array( 'title' => __( 'Body Text Colour', 'propertyhive' ), 'desc' => __( 'The main body text colour.', 'propertyhive' ), 'id' => 'propertyhive_email_text_color', 'type' => 'color', 'css' => 'width:6em;', 'default' => '#333333', 'autoload' => false, 'desc_tip' => true, ), array( 'type' => 'sectionend', 'id' => 'email_template_options' ), ); $settings = apply_filters( 'propertyhive_email_settings', $settings ); return apply_filters( 'propertyhive_get_settings_' . $this->id, $settings ); } /** * Get enquiry auto-responder settings array * * @return array */ public function get_enquiry_autoresponder_settings() { return apply_filters( 'propertyhive_enquiry_autoresponder_settings', array( array( 'title' => __( 'Enquiry Auto-Responder Settings', 'propertyhive' ), 'type' => 'title', 'id' => 'enquiry_auto_responder_email_options' ), array( 'title' => __( 'Auto-Responder Enabled', 'propertyhive' ), 'id' => 'propertyhive_enquiry_auto_responder', 'type' => 'checkbox', 'default' => '', ), array( 'title' => __( 'Auto-Responder Email Subject', 'propertyhive' ), 'id' => 'propertyhive_enquiry_auto_responder_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ), array( 'title' => __( 'Auto-Responder Email Body', 'propertyhive' ), 'id' => 'propertyhive_enquiry_auto_responder_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ), array( 'type' => 'sectionend', 'id' => 'enquiry_auto_responder_email_options' ) ) ); // End settings } /** * Get property match settings settings array * * @return array */ public function get_property_match_settings() { $settings = array(); $settings[] = array( 'title' => __( 'Property Match Email Settings', 'propertyhive' ), 'type' => 'title', 'id' => 'applicant_match_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_property_match_default_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_property_match_default_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'title' => __( 'Default From Email Address', 'propertyhive' ), 'id' => 'propertyhive_property_match_default_from', 'type' => 'select', 'default' => '', 'css' => 'min-width:300px;', 'options' => array( '' => __( 'User Email Address', 'propertyhive' ), 'default_from_email' => __( 'Default "From" Email Address', 'propertyhive' ), ), 'desc' => '

' . __( 'This sets the email address that manual matches will be sent from by default. This can still be edited when you go to send the match.
Automatic matches, if enabled, will still be sent from the email address of the office that most of the properties in the match belong to.', 'propertyhive' ) . '

', ); $options = array(); $args = array( 'hide_empty' => false, 'parent' => 0 ); $terms = get_terms( array_merge( wp_parse_args( $args ), array( 'taxonomy' => 'availability' ) ) ); if ( !empty( $terms ) && !is_wp_error( $terms ) ) { foreach ($terms as $term) { $options[$term->term_id] = $term->name; } } $settings[] = array( 'title' => __( 'Only Include Properties With Statuses', 'propertyhive' ), 'id' => 'propertyhive_property_match_statuses', 'type' => 'multiselect', 'css' => 'min-width:300px; height:110px;', 'options' => $options, 'desc' => '

' . __( 'By default, all on market properties will come back in matches when sending properties to applicants. If you wish to only send properties with a certain status you can choose this here. For example, maybe you don\'t want Sold STC properties to be sent. Hold ctrl/cmd whilst clicking to select multiple.
This will also affect the Similar Properties included in the Auto Responder above, if applicable.', 'propertyhive' ) . '

', ); $time_offset = (int) get_option('gmt_offset') * 60 * 60; $settings[] = array( 'title' => __( 'Automatically Send Matching Properties To Applicants', 'propertyhive' ), 'desc' => __( 'Enabling this setting will mean applicants will automatically get sent properties.

- This will only apply to properties added from the moment this option is activated.
- When enabled, this can be disabled on a per-applicant basis by going into their record.
- When sending out lots of emails we recommend using a plugin to send them out using SMTP. Your web developer or hosting company should be able to advise on this.', 'propertyhive' ) . ( ( get_option( 'propertyhive_auto_property_match', '' ) == 'yes' && get_option( 'propertyhive_auto_property_match_enabled_date', '' ) != '' ) ? '

Enabled on ' . gmdate("jS F Y H:i", strtotime(get_option( 'propertyhive_auto_property_match_enabled_date', '' )) + $time_offset) : '' ), 'id' => 'propertyhive_auto_property_match', 'type' => 'checkbox', 'default' => '', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'applicant_match_email_options' ); return apply_filters( 'propertyhive_property_match_settings', $settings ); // End settings } /** * Get booking confirmation email settings array * * @return array */ public function get_booking_confirmation_settings() { $settings = array(); if ( get_option('propertyhive_module_disabled_viewings', '') != 'yes' ) { //Applicant $settings[] = array( 'title' => __( 'Applicant Viewing Booking Confirmations', 'propertyhive' ), 'type' => 'title', 'id' => 'applicant_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_applicant_booking_confirmation_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_applicant_booking_confirmation_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'applicant_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Applicant Viewing Cancellation Notifications', 'propertyhive' ), 'type' => 'title', 'id' => 'applicant_viewing_cancellation_notification_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_applicant_cancellation_notification_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_applicant_cancellation_notification_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'applicant_viewing_cancellation_notification_email_options' ); // Owner $settings[] = array( 'title' => __( 'Owner/Landlord Viewing Booking Confirmations', 'propertyhive' ), 'type' => 'title', 'id' => 'owner_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_owner_booking_confirmation_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_owner_booking_confirmation_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'owner_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Owner/Landlord Viewing Cancellation Notifications', 'propertyhive' ), 'type' => 'title', 'id' => 'owner_viewing_cancellation_notification_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_owner_cancellation_notification_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_owner_cancellation_notification_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'owner_viewing_cancellation_notification_email_options' ); // Attending Negotiator $settings[] = array( 'title' => __( 'Attending Negotiator Viewing Booking Confirmations', 'propertyhive' ), 'type' => 'title', 'id' => 'attending_negotiator_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_attending_negotiator_booking_confirmation_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_attending_negotiator_booking_confirmation_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'attending_negotiator_viewing_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Attending Negotiator Viewing Cancellation Notifications', 'propertyhive' ), 'type' => 'title', 'id' => 'attending_negotiator_viewing_cancellation_notifications_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_viewing_attending_negotiator_cancellation_notification_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_viewing_attending_negotiator_cancellation_notification_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'attending_negotiator_viewing_cancellation_notifications_email_options' ); } if ( get_option('propertyhive_module_disabled_appraisals', '') != 'yes' ) { // Owner $settings[] = array( 'title' => __( 'Owner/Landlord Appraisal Booking Confirmations', 'propertyhive' ), 'type' => 'title', 'id' => 'owner_appraisal_booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Default Email Subject', 'propertyhive' ), 'id' => 'propertyhive_appraisal_owner_booking_confirmation_email_subject', 'type' => 'text', 'css' => 'min-width:300px;', ); $settings[] = array( 'title' => __( 'Default Email Body', 'propertyhive' ), 'id' => 'propertyhive_appraisal_owner_booking_confirmation_email_body', 'type' => 'textarea', 'css' => 'min-width:300px; height:110px;', ); $settings[] = array( 'type' => 'sectionend', 'id' => 'owner_appraisal_booking_confirmation_email_options' ); } if ( get_option('propertyhive_module_disabled_appraisals', '') != 'yes' || get_option('propertyhive_module_disabled_viewings', '') != 'yes' ) { // Owner $settings[] = array( 'title' => __( 'Booking Confirmations & Cancellations', 'propertyhive' ), 'type' => 'title', 'id' => 'booking_confirmation_email_options' ); $settings[] = array( 'title' => __( 'Sent From Email Address', 'propertyhive' ), 'id' => 'propertyhive_confirmations_default_from', 'type' => 'select', 'default' => '', 'css' => 'min-width:300px;', 'options' => array( '' => __( 'Default "From" Email Address', 'propertyhive' ), 'office' => __( 'Office Email Address', 'propertyhive' ), 'user' => __( 'User Email Address', 'propertyhive' ), ), 'desc' => '

' . __( 'This sets the email address that booking confirmations and cancellation notifications come from and that will receive the response should someone reply.', 'propertyhive' ) . '

', ); $settings[] = array( 'title' => __( 'Customise Emails Before Sending', 'propertyhive' ), 'id' => 'propertyhive_customise_confirmation_emails', 'type' => 'checkbox', 'desc' => 'With this ticked you\'ll be able to customise the subject and body of any emails before they get sent. This can be useful for adding any appraisal/viewing-specific details to the email. If left unticked, the default subject and body set above will be used.' ); $settings[] = array( 'type' => 'sectionend', 'id' => 'booking_confirmation_email_options' ); } return apply_filters( 'propertyhive_booking_confirmation_settings', $settings ); // End general map settings } /** * Get email queue settings array * * @return array */ public function get_email_queue_settings() { return apply_filters( 'propertyhive_email_queue_settings', array( array( 'title' => __( 'Email Queue', 'propertyhive' ), 'type' => 'title', 'desc' => '', 'id' => 'email_queue_options' ), array( 'type' => 'email_queue' ), array( 'type' => 'sectionend', 'id' => 'email_queue_options'), ) ); // End general map settings } /** * Output email queue * * @access public * @return void */ public function email_queue_setting() { global $wpdb, $post; $date_from = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The email queue date filter is a read-only GET parameter; the separate Run Now action has its own capability and nonce gate. if ( isset( $_GET['date_from'] ) && is_string( $_GET['date_from'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The email queue date filter is a read-only GET parameter; the separate Run Now action has its own capability and nonce gate. $date_from = sanitize_text_field( wp_unslash( $_GET['date_from'] ) ); } $date = DateTime::createFromFormat( 'Y-m-d', $date_from ); if ( 'all' !== $date_from && ( ! $date || $date->format( 'Y-m-d' ) !== $date_from ) ) { $date_from = gmdate( 'Y-m-d', strtotime( '-30 days' ) ); } $status = ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The email queue status filter is a read-only GET parameter; the separate Run Now action has its own capability and nonce gate. if ( isset( $_GET['status'] ) && is_string( $_GET['status'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The email queue status filter is a read-only GET parameter; the separate Run Now action has its own capability and nonce gate. $status = sanitize_key( wp_unslash( $_GET['status'] ) ); } $additional_query_string = '&date_from=' . rawurlencode( $date_from ); ?>

Some processes, such as property matching, can result in a lot of emails being sent at once. To cater for this we queue emails and send them out in batches at regular intervals.

Using this screen you can see which emails have been sent, which have failed, and how many are queued to be sent.


Run Now


prefix}ph_email_log WHERE %s = %s"; $query_args = array( '1', '1' ); if ( 'all' !== $date_from ) { $query .= ' AND send_at >= %s'; $query_args[] = $date_from . ' 00:00:00'; } switch ( $status ) { case 'queued': $query .= ' AND status = %s'; $query_args[] = ''; break; case 'failed': $query .= " AND status IN ('fail1', 'fail2')"; break; case 'sent': $query .= ' AND status = %s'; $query_args[] = 'sent'; break; } $query .= ' ORDER BY send_at DESC LIMIT 250'; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- The email queue is stored in Property Hive's custom table, which has no WP_Query API; this live filtered log must reflect asynchronous queue changes immediately. The query contains only fixed SQL branches and passes all date/status values through $wpdb->prepare(). $emails = $wpdb->get_results( $wpdb->prepare( $query, $query_args ) ); if ( is_array($emails) && !empty($emails) ) { foreach ( $emails as $email ) { ?>
 
send_at))); ?> contact_id)) . '">' . esc_html(get_the_title($email->contact_id)) . '
' . esc_html($email->to_email_address); ?>
subject); ?> status) { case "fail1": { echo 'First attempt failed. Will retry'; break; } case "fail2": { echo 'Failed after 2 attempts'; break; } case "sent": { echo 'Sent'; break; } default: { echo 'Queued'; } } ?> View Email
No emails found
get_enquiry_autoresponder_settings(); break; } case "match": { $settings = $this->get_property_match_settings(); break; } case "booking-confirmation": { $settings = $this->get_booking_confirmation_settings(); break; } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- Shared admin settings-view state; this global is intentionally used to control the common settings template and is not an arbitrary application global. case "log": { $settings = $this->get_email_queue_settings(); $hide_save_button = true; break; } default: { die("Unknown setting section"); } } } else { $settings = $this->get_settings(); } PH_Admin_Settings::output_fields( $settings ); } /** * Save settings. */ public function save() { if ( ! current_user_can( 'manage_options' ) || ! isset( $_REQUEST['_wpnonce'] ) || ! is_string( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'propertyhive-settings' ) ) { return; } global $current_section; if ( $current_section != '' ) { switch ($current_section) { case 'enquiry-auto-responder': { $settings = $this->get_enquiry_autoresponder_settings(); PH_Admin_Settings::save_fields( $settings ); break; } case 'match': { $settings = $this->get_property_match_settings(); $previous_auto_property_match = get_option( 'propertyhive_auto_property_match', '' ); PH_Admin_Settings::save_fields( $settings ); if ( isset($_POST['propertyhive_auto_property_match']) && $_POST['propertyhive_auto_property_match'] == '1' ) { if ( $previous_auto_property_match != 'yes' ) { // it's been activated. Stored in UTC update_option( 'propertyhive_auto_property_match_enabled_date', gmdate("Y-m-d H:i:s"), FALSE); } $timestamp = wp_next_scheduled( 'propertyhive_auto_email_match' ); wp_unschedule_event($timestamp, 'propertyhive_auto_email_match' ); wp_clear_scheduled_hook('propertyhive_auto_email_match'); $recurrence = apply_filters( 'propertyhive_auto_email_match_cron_recurrence', 'daily' ); if ( $recurrence != 'hourly' ) { $timestamp = strtotime( 'tomorrow +2hours' ) - ( (int)get_option( 'gmt_offset' ) * HOUR_IN_SECONDS ); } else { $timestamp = strtotime( '+1 hours' ); } wp_schedule_event( apply_filters( 'propertyhive_auto_email_match_cron_timestamp', $timestamp ), $recurrence, 'propertyhive_auto_email_match' ); } else { wp_clear_scheduled_hook( 'propertyhive_auto_email_match' ); } break; } case 'booking-confirmation': { $settings = $this->get_booking_confirmation_settings(); PH_Admin_Settings::save_fields( $settings ); break; } default: { die("Unknown setting section"); } } } else { PH_Admin_Settings::save_fields( $this->get_settings() ); } } } endif; return new PH_Settings_Emails();