Delay Booking Completed Notifications

Delay one or more “Booking Completed” notifications so they send a set amount of time after a booking ends (e.g. a feedback request two days later) instead of immediately when the booking is completed.

Instructions

  1. Install this snippet by following the steps here: https://gravitywiz.com/documentation/how-do-i-install-a-snippet/

  2. Update the configuration at the bottom of the snippet.

Notes:

  • The delay is measured from when the booking would have notified (within ~an hour of the booking ending), not the exact end time.
  • The listed notifications are sent only by this snippet’s scheduled job, so manually resending them from the entry screen will not send while the snippet is active.

Code

Filename: gpb-delay-booking-completed-notifications.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
<?php
/**
 * Gravity Perks // Bookings // Delay Booking Completed Notifications
 * https://gravitywiz.com/documentation/gravity-forms-bookings/
 *
 * Delay one or more "Booking Completed" notifications so they send a set amount of time
 * after a booking ends (e.g. a feedback request two days later) instead of immediately
 * when the booking is completed.
 *
 * Instructions:
 *
 * 1. Install this snippet by following the steps here:
 *    https://gravitywiz.com/documentation/how-do-i-install-a-snippet/
 *
 * 2. Update the configuration at the bottom of the snippet.
 *
 * Notes:
 *  - The delay is measured from when the booking would have notified (within ~an hour
 *    of the booking ending), not the exact end time.
 *  - The listed notifications are sent only by this snippet's scheduled job, so manually
 *    resending them from the entry screen will not send while the snippet is active.
 */
class GPB_Delay_Completed_Notification {

	private $notification_ids;
	private $delay;
	private $delay_unit;
	private $action_hook    = 'gpb_send_delayed_completed_notification';
	private $is_dispatching = false;

	private static $allowed_units = array( 'hours', 'days', 'weeks', 'months' );

	public function __construct( array $args ) {
		$args = wp_parse_args( $args, array(
			'notification_ids' => array(),
			'delay'            => 1,
			'delay_unit'       => 'days',
		));

		$this->notification_ids = array_filter( array_map( 'strval', (array) $args['notification_ids'] ) );
		$this->delay            = (float) $args['delay'];
		$this->delay_unit       = in_array( $args['delay_unit'], self::$allowed_units, true ) ? $args['delay_unit'] : 'days';

		if ( empty( $this->notification_ids ) || $this->delay <= 0 || ! function_exists( 'as_schedule_single_action' ) ) {
			return;
		}

		add_filter( 'gform_disable_notification', array( $this, 'reschedule_notification' ), 10, 4 );
		add_action( $this->action_hook, array( $this, 'send_notification' ), 10, 2 );
	}

	public function reschedule_notification( $is_disabled, $notification, $form, $entry ) {
		if ( $is_disabled || $this->is_dispatching ) {
			return $is_disabled;
		}

		if ( empty( $notification['id'] ) || ! in_array( (string) $notification['id'], $this->notification_ids, true ) ) {
			return $is_disabled;
		}

		$args = array( (int) $entry['id'], (string) $notification['id'] );

		if ( ! as_next_scheduled_action( $this->action_hook, $args ) && ! $this->already_sent( $args[0], $args[1] ) ) {
			as_schedule_single_action( strtotime( "+{$this->delay} {$this->delay_unit}" ), $this->action_hook, $args );
		}

		return true;
	}

	public function send_notification( $entry_id, $notification_id ) {
		if ( ! class_exists( '\GFCommon' ) || $this->already_sent( $entry_id, $notification_id ) ) {
			return;
		}

		if ( ! $this->booking_still_confirmed( $entry_id ) ) {
			return;
		}

		$entry = \GFAPI::get_entry( (int) $entry_id );
		if ( ! $entry || is_wp_error( $entry ) ) {
			return;
		}

		$form = \GFAPI::get_form( $entry['form_id'] );
		if ( ! $form ) {
			return;
		}

		// Record before dispatching so the notification cannot be sent twice.
		gform_update_meta( $entry_id, $this->sent_meta_key( $notification_id ), true );

		$this->is_dispatching = true;
		\GFCommon::send_notifications( array( $notification_id ), $form, $entry, true, 'gpb_booking_completed' );
		$this->is_dispatching = false;
	}

	private function booking_still_confirmed( $entry_id ): bool {
		global $wpdb;

		if ( ! class_exists( '\GP_Bookings\Database' ) ) {
			return false;
		}

		$table_name = \GP_Bookings\Database::table_bookings();

		$booking_id = $wpdb->get_var(
			$wpdb->prepare(
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Table name is provided by GP Bookings.
				"SELECT booking_id FROM {$table_name}
				 WHERE gf_entry_id = %d
				 AND object_type = 'service'
				 AND status = 'confirmed'
				 LIMIT 1",
				(int) $entry_id
			)
		);

		return ! empty( $booking_id );
	}

	private function already_sent( $entry_id, $notification_id ): bool {
		return (bool) gform_get_meta( (int) $entry_id, $this->sent_meta_key( $notification_id ) );
	}

	private function sent_meta_key( $notification_id ): string {
		return 'gpb_delayed_completed_sent_' . $notification_id;
	}

}

# Configuration

new GPB_Delay_Completed_Notification(
	array(
		'notification_ids' => array( '6a3f4210238ed' ), // Booking Completed notification ID(s) to delay
		'delay'            => 2, // How long after the booking completes
		'delay_unit'       => 'days', // hours | days | weeks | months
	)
);

Leave a Reply

Your email address will not be published. Required fields are marked *

  • Trouble installing this snippet? See our troubleshooting tips.
  • Need to include code? Create a gist and link to it in your comment.
  • Reporting a bug? Provide a URL where this issue can be recreated.

By commenting, I understand that I may receive emails related to Gravity Wiz and can unsubscribe at any time.