Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

location reminder emails #1410

Merged
Merged
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
064a975
location reminders for bookings starting/ending soon
Nov 11, 2023
d6fd0fb
added translations to location reminder email settings
Nov 14, 2023
3353f5c
improved time picker for location reminders & added missing scheduler
Nov 16, 2023
e5fc4bf
reverted language files back to state of master
Nov 16, 2023
49a49c9
Merge remote-tracking branch 'origin/master' into feature/location-re…
Nov 16, 2023
fdde1ef
* fixed issue when sending location reminder for current day
Nov 20, 2023
1ea79ce
removed roles to ignore for location reminder emails
Nov 20, 2023
543ebc9
changed option values for the days of location reminder emails
Nov 28, 2023
d2ce1a9
Merge remote-tracking branch 'origin/master' into feature/location-re…
Dec 5, 2023
7aca9f2
location reminder email sanitizing & description for activate checkbox
Dec 5, 2023
134565c
* additional checkbox to activate location emails
Feb 23, 2024
ef19188
Revert "* additional checkbox to activate location emails"
Feb 27, 2024
4496d62
Merge branch 'master' into feature/location-reminder-emails
hansmorb Mar 17, 2024
d5b3022
check action before sending booking reminder messages to location
Mar 19, 2024
dfcafa0
refactor: introduce recipient class to avoid improperly using \WP_Use…
hansmorb Mar 19, 2024
1228ac9
refactor: add tests for two location emails
hansmorb Mar 19, 2024
4d5c000
add tests for LocationBookingReminderMessage
hansmorb Mar 19, 2024
457bde3
formatting
hansmorb Mar 19, 2024
8497b41
refactor: omit two step message creation
hansmorb Mar 19, 2024
44de61a
refactor similar functions
hansmorb Mar 19, 2024
244e2de
added failing test (TODO)
hansmorb Mar 19, 2024
b66b522
fixed test using mockery
hansmorb Mar 19, 2024
7337cf4
fix tests
hansmorb Mar 19, 2024
5f333d0
getEnding & beginningBookings scrutinized
hansmorb Mar 20, 2024
27cb8dd
remove failing tests
hansmorb Mar 20, 2024
25d25d4
fixed accessors
hansmorb Mar 20, 2024
d132593
improved default messages
hansmorb Mar 20, 2024
c2717af
Merge branch 'master' into feature/location-reminder-emails
hansmorb Mar 20, 2024
86e1b1a
added refactor todo
hansmorb Mar 20, 2024
ef498a1
Merge remote-tracking branch 'upstream/feature/location-reminder-emai…
hansmorb Mar 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 138 additions & 1 deletion includes/OptionsArray.php
Original file line number Diff line number Diff line change
Expand Up @@ -879,7 +879,7 @@
<br>The email will be sent around midnight after the booking day has ended.'
, 'commonsbooking' ) ),
'fields' => array(
// settings pre booking reminder -- activate reminder
// settings post booking reminder -- activate reminder
array(
'name' => esc_html__( 'Activate', 'commonsbooking' ),
'id' => 'post-booking-notice-activate',
Expand All @@ -906,6 +906,143 @@
),
),
/* field group post booking reminder settings end */

/* field group booking start reminder for locations */
'booking-start-location-reminder' => array(
'title' => commonsbooking_sanitizeHTML( __( 'Reminder for locations before booking starts', 'commonsbooking' ) ),
'id' => 'booking-start-location-reminder',
'desc' => commonsbooking_sanitizeHTML( __(
'You can set here whether locations should receive a reminder email before the start of a booking.<br><a href="https://commonsbooking.org/?p=1763" target="_blank">More Information in the documentation</a>'
, 'commonsbooking' ) ),
'fields' => array(
// settings booking start reminder -- activate reminder
array(
'name' => esc_html__( 'Activate', 'commonsbooking' ),
hansmorb marked this conversation as resolved.
Show resolved Hide resolved
'id' => 'booking-start-location-reminder-activate',
'type' => 'checkbox',
'desc' => esc_html__( 'The reminders need to be enabled for all locations individually. This is only the main on/off switch.', 'commonsbooking' ),
),
// E-Mail booking start reminder for locations
array(
'name' => commonsbooking_sanitizeHTML( __( 'E-mail subject', 'commonsbooking' ) ),
'id' => 'booking-start-location-reminder-subject',
'type' => 'text',
'default' => commonsbooking_sanitizeHTML( __( 'Upcoming booking of {{item:post_title}} {{booking:formattedBookingDate}}', 'commonsbooking' ) ),
),
array(
'name' => commonsbooking_sanitizeHTML( __( 'email body', 'commonsbooking' ) ),
'id' => 'booking-start-location-reminder-body',
'type' => 'textarea',
'default' => commonsbooking_sanitizeHTML( __( '<h2>Hi,</h2>
<p>The booking period for the item {{item:post_title}} will start soon.<br>
The booking period: {{booking:formattedBookingDate}}<br><br>

{{booking:getEmailSignature}}', 'commonsbooking' ) ),
),
// settings booking start reminder -- set sending time
array(
'name' => esc_html__( 'Time', 'commonsbooking' ),
'id' => 'booking-start-location-reminder-time',
'desc' => '<br>' . commonsbooking_sanitizeHTML( __(
'Define when the reminder should be sent. The actual sending may differ from the defined value by a few hours, depending on how your WordPress is configured.'
, 'commonsbooking' ) ),
'type' => 'text_time',
'attributes' => array(
'data-timepicker' => wp_json_encode(
array(
'stepMinute' => 60,
'timeFormat' => 'HH:mm',
)
),
),
'time_format' => esc_html(get_option( 'time_format' )),
),
array(
'name' => esc_html__( 'Bookings of', 'commonsbooking' ),
'id' => 'booking-start-location-reminder-day',
'desc' => '<br>' . commonsbooking_sanitizeHTML( __(
'Define for which booking start day the notifications should be sent'
, 'commonsbooking' ) ),
'type' => 'select',
'show_option_none' => false,
'default' => '1',
'options' => array(
'1' => esc_html__( 'current day', 'commonsbooking' ),
'2' => esc_html__( 'next day', 'commonsbooking' ),
),
),
),
),
/* field group booking start reminder for locations end */

/* field group booking end reminder for locations */
'booking-end-location-reminder' => array(
'title' => commonsbooking_sanitizeHTML( __( 'Reminder for locations before booking ends', 'commonsbooking' ) ),
'id' => 'booking-end-location-reminder',
'desc' => commonsbooking_sanitizeHTML( __(
'You can set here whether locations should receive a reminder email before the end of a booking.<br><a href="https://commonsbooking.org/?p=1763" target="_blank">More Information in the documentation</a>'
, 'commonsbooking' ) ),
'fields' => array(
// settings booking end reminder -- activate reminder
array(
'name' => esc_html__( 'Activate', 'commonsbooking' ),
'id' => 'booking-end-location-reminder-activate',
'type' => 'checkbox',
'desc' => esc_html__( 'The reminders need to be enabled for all locations individually. This is only the main on/off switch.', 'commonsbooking' ),
),
// E-Mail booking end reminder for locations
array(
'name' => commonsbooking_sanitizeHTML( __( 'E-mail subject', 'commonsbooking' ) ),
'id' => 'booking-end-location-reminder-subject',
'type' => 'text',
'default' => commonsbooking_sanitizeHTML( __( 'Booking of {{item:post_title}} {{booking:formattedBookingDate}}', 'commonsbooking' ) ),
),
array(
'name' => commonsbooking_sanitizeHTML( __( 'email body', 'commonsbooking' ) ),
'id' => 'booking-end-location-reminder-body',
'type' => 'textarea',
'default' => commonsbooking_sanitizeHTML( __( '<h2>Hi,</h2>
<p>The booking period for the item {{item:post_title}} will end soon.<br>
The booking period: {{booking:formattedBookingDate}}<br><br>

{{booking:getEmailSignature}}', 'commonsbooking' ) ),
),
// settings booking end reminder -- set sending time
array(
'name' => esc_html__( 'Time', 'commonsbooking' ),
'id' => 'booking-end-location-reminder-time',
'desc' => '<br>' . commonsbooking_sanitizeHTML( __(
'Define when the reminder should be sent. The actual sending may differ from the defined value by a few hours, depending on how your WordPress is configured.'
, 'commonsbooking' ) ),
'type' => 'text_time',
'default' => '1',
'attributes' => array(
'data-timepicker' => wp_json_encode(
array(
'stepMinute' => 60,
'timeFormat' => 'HH:mm',
)
),
),
'time_format' => esc_html(get_option( 'time_format' )),
),
array(
'name' => esc_html__( 'Bookings of', 'commonsbooking' ),
'id' => 'booking-end-location-reminder-day',
'desc' => '<br>' . commonsbooking_sanitizeHTML( __(
'Define for which booking end day the notifications should be sent'
, 'commonsbooking' ) ),
'type' => 'select',
'show_option_none' => false,
'default' => '1',
'options' => array(
'1' => esc_html__( 'current day', 'commonsbooking' ),
'2' => esc_html__( 'next day', 'commonsbooking' ),
),
),
),
),
/* field group booking end reminder for locations end */
),
/* field group container end */
),
Expand Down
85 changes: 85 additions & 0 deletions src/Messages/LocationBookingReminderMessage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

namespace CommonsBooking\Messages;

use CommonsBooking\CB\CB;
use CommonsBooking\Repository\Booking;
use CommonsBooking\Service\Scheduler;
use CommonsBooking\Settings\Settings;
use CommonsBooking\Wordpress\CustomPostType\Location;

/**
* This message is sent out to locations to remind them of bookings starting soon.
* This is sent using a cron job.
* @see \CommonsBooking\Service\Scheduler
*/
class LocationBookingReminderMessage extends Message {

/**
* @var array|string[]
*/
protected $validActions = [ "booking-start-location-reminder", "booking-end-location-reminder" ];

/**
* Prepares reminder message
*/
public function prepareMessage() {
/** @var \CommonsBooking\Model\Booking $booking */
$booking = Booking::getPostById( $this->getPostId() );
$booking_user = get_userdata( $this->getPost()->post_author );

// get location email adresses to send them bcc copies
$location = get_post($booking->getMeta('location-id'));
$location_emails_option = CB::get( Location::$postType, COMMONSBOOKING_METABOX_PREFIX . 'location_email', $location ) ; /* email addresses, comma-seperated */
if(empty($location_emails_option)) {
return;
}

$location_emails_option = str_replace(' ','',$location_emails_option);
$location_emails = explode(',', $location_emails_option);

// get templates from Admin Options
$template_body = Settings::getOption( 'commonsbooking_options_reminder',
$this->action . '-body' );
$template_subject = Settings::getOption( 'commonsbooking_options_reminder',
$this->action . '-subject', 'sanitize_text_field' );

// Setup email: From
$fromHeaders = sprintf(
"From: %s <%s>",
Settings::getOption( 'commonsbooking_options_templates', 'emailheaders_from-name', 'sanitize_text_field' ),
sanitize_email( Settings::getOption( 'commonsbooking_options_templates', 'emailheaders_from-email' ) )
);

if(!is_array($location_emails)) {
return;
}

$recipientUser = new \WP_User();
$recipientUser->user_nicename = $booking->getLocation()->post_title;
$recipientUser->user_email = array_shift($location_emails);
$bcc_adresses = implode(',',$location_emails);

$this->prepareMail(
$recipientUser,
$template_body,
$template_subject,
$fromHeaders,
$bcc_adresses,
[
'booking' => $booking,
'item' => $booking->getItem(),
'location' => $booking->getLocation(),
'user' => $booking_user,
]
);
}

/**
* Sends reminder message.
* @throws \Exception
*/
public function sendMessage() {
$this->SendNotificationMail();
}
}
61 changes: 61 additions & 0 deletions src/Service/Booking.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace CommonsBooking\Service;

use CommonsBooking\Messages\BookingReminderMessage;
use CommonsBooking\Messages\LocationBookingReminderMessage;
use CommonsBooking\Settings\Settings;
use CommonsBooking\Wordpress\CustomPostType\Timeframe;
use WP_Query;
Expand Down Expand Up @@ -119,4 +120,64 @@ public static function sendFeedbackMessage() {
}
}

public static function sendBookingStartLocationReminderMessage() {
self::sendLocationBookingReminderMessage('start');
}

public static function sendBookingEndLocationReminderMessage() {
hansmorb marked this conversation as resolved.
Show resolved Hide resolved
self::sendLocationBookingReminderMessage('end');
}

protected static function sendLocationBookingReminderMessage(string $type) {

if (Settings::getOption('commonsbooking_options_reminder', 'booking-'.$type.'-location-reminder-activate') != 'on') {
return;
}

$daysBeforeStart = (int) Settings::getOption( 'commonsbooking_options_reminder', 'booking-'.$type.'-location-reminder-day' ) - 1;
$startDate = strtotime( '+' . $daysBeforeStart . ' days midnight' );

// start day of booking at 23:59
$endDate = strtotime( '+23 Hours +59 Minutes +59 Seconds', $startDate );

$key = '';
switch($type) {
case 'start':
$key = \CommonsBooking\Model\Booking::REPETITION_START;
break;
case 'end':
$key = \CommonsBooking\Model\Booking::REPETITION_END;
break;
}

$bookings = \CommonsBooking\Repository\Booking::getByTimerange(
0, //overwritten by customArgs metaquery
0, //overwritten by customArgs metaquery
null,
null,
[
'meta_query' => [
[
'key' => $key,
'value' => array( $startDate, $endDate ),
'compare' => 'BETWEEN',
'type' => 'numeric'
]
]
],
['confirmed']
);

if ( count( $bookings ) ) {
foreach ( $bookings as $booking ) {
$reminderMessage = new LocationBookingReminderMessage( $booking->getPost()->ID, 'booking-'.$type.'-location-reminder' );
$reminderMessage->prepareMessage();
$reminderMessage = apply_filters( 'commonsbooking_before_send_location_reminder_mail', $reminderMessage );

if($reminderMessage) {
$reminderMessage->sendMessage();
hansmorb marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
}
20 changes: 20 additions & 0 deletions src/Service/Scheduler.php
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,26 @@ public static function initHooks() {
'update_option_commonsbooking_options_reminder'
);

// Init booking start reminder job for locations
New Scheduler(
'location-reminder-booking-start',
hansmorb marked this conversation as resolved.
Show resolved Hide resolved
array( \CommonsBooking\Service\Booking::class, 'sendBookingStartLocationReminderMessage' ),
'daily',
'today ' . Settings::getOption( 'commonsbooking_options_reminder', 'booking-start-location-reminder-time' ) . ':00',
array( 'commonsbooking_options_reminder', 'booking-start-location-reminder-activate'),
'update_option_commonsbooking_options_reminder'
);

// Init booking end reminder job for locations
New Scheduler(
'location-reminder-booking-end',
array( \CommonsBooking\Service\Booking::class, 'sendBookingEndLocationReminderMessage' ),
'daily',
'today ' . Settings::getOption( 'commonsbooking_options_reminder', 'booking-end-location-reminder-time' ) . ':00',
array( 'commonsbooking_options_reminder', 'booking-end-location-reminder-activate'),
'update_option_commonsbooking_options_reminder'
);

// Init booking feedback job
New Scheduler(
'feedback',
Expand Down
14 changes: 14 additions & 0 deletions src/Wordpress/CustomPostType/Location.php
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,20 @@ public function registerMetabox() {
$cmb->add_field( $metabox );
}

$cmb->add_field( array(
'name' => esc_html__( 'Receive booking start reminder', 'commonsbooking' ),
'desc' => commonsbooking_sanitizeHTML( __( 'If selected, this location receives reminder emails of bookings starting soon. The notifications are sent to all addresses specified in the location email list (first as receiver, all following as BCC). This type of reminder needs to be activated in the <a href="admin.php?page=commonsbooking_options_reminder"> general CommonsBooking settings</a>.', 'commonsbooking' ) ),
'id' => COMMONSBOOKING_METABOX_PREFIX . 'receive_booking_start_reminder',
'type' => 'checkbox',
) );

$cmb->add_field( array(
'name' => esc_html__( 'Receive booking end reminder', 'commonsbooking' ),
'desc' => commonsbooking_sanitizeHTML( __( 'If selected, this location receives reminder emails of bookings ending soon. The notifications are sent to all addresses specified in the location email list (first as receiver, all following as BCC). This type of reminder needs to be activated in the <a href="admin.php?page=commonsbooking_options_reminder"> general CommonsBooking settings</a>.', 'commonsbooking' ) ),
'id' => COMMONSBOOKING_METABOX_PREFIX . 'receive_booking_end_reminder',
'type' => 'checkbox',
) );

// Check if custom meta fields are set in CB Options and generate MetaData-Box and fields
if ( is_array( self::getCMB2FieldsArrayFromCustomMetadata( 'location' ) ) ) {
$customMetaData = self::getCMB2FieldsArrayFromCustomMetadata( 'location' );
Expand Down
Loading