PluginProbe ʕ •ᴥ•ʔ
Brevo – Email, SMS, Web Push, Chat, and more. / 3.1.98
Brevo – Email, SMS, Web Push, Chat, and more. v3.1.98
2.9.13 2.9.14 2.9.15 2.9.16 2.9.17 2.9.18 2.9.4 2.9.5 2.9.6 2.9.7 2.9.8 2.9.9 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.9 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.2 3.1.20 3.1.21 3.1.22 3.1.23 3.1.24 3.1.25 3.1.26 3.1.27 3.1.28 3.1.29 3.1.3 3.1.30 3.1.31 3.1.32 3.1.33 3.1.34 3.1.35 3.1.36 3.1.37 3.1.38 3.1.39 3.1.4 3.1.40 3.1.41 3.1.42 3.1.43 3.1.44 3.1.45 3.1.46 3.1.47 3.1.48 3.1.49 3.1.5 3.1.50 3.1.51 3.1.52 3.1.53 3.1.54 3.1.55 3.1.56 3.1.57 3.1.58 3.1.59 3.1.6 3.1.60 3.1.61 3.1.62 3.1.63 3.1.64 3.1.65 3.1.66 3.1.67 3.1.68 3.1.69 3.1.7 3.1.70 3.1.71 3.1.72 3.1.73 3.1.74 3.1.75 3.1.76 3.1.77 3.1.78 3.1.79 3.1.8 3.1.80 3.1.81 3.1.82 3.1.83 3.1.84 3.1.85 3.1.86 3.1.87 3.1.88 3.1.89 3.1.9 3.1.90 3.1.91 3.1.92 3.1.93 3.1.94 3.1.95 3.1.96 3.1.97 3.1.98 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 trunk 1.0 1.5 2.0.8 2.9.10 2.9.11 2.9.12
mailin / inc / push-admin.php
mailin / inc Last commit date
templates 1 year ago SendinblueAccount.php 1 year ago SendinblueApiClient.php 1 year ago function.wp_mail.php 8 years ago http-build-url.php 1 year ago index.php 8 years ago mailin.php 3 years ago push-admin.php 1 year ago push-amp.php 1 year ago push-api.php 1 year ago push-httpclient.php 1 year ago push-public.php 1 year ago push-settings.php 1 year ago push-utils.php 1 year ago push-woocommerce.php 1 year ago sendinblue.php 3 years ago sib-api-manager.php 1 year ago sib-form-preview.php 2 years ago sib-sms-code.php 3 years ago table-forms.php 1 year ago
push-admin.php
835 lines
1 <?php
2 if (!defined( 'ABSPATH' )) { http_response_code(403); exit(); }
3
4 if ( ! class_exists( 'SIB_Push_Admin' ) ) {
5 class SIB_Push_Admin {
6
7 const SAVE_POST_NONCE_ACTION = 'sib_push_save_post_nonce_action';
8 const SAVE_POST_NONCE_KEY = 'sib_push_save_post_nonce_key';
9 const META_BOX_ID = 'sib_push_meta_box';
10 const METADATA_MULTIVALUE_SEPARATOR = '<+>';
11 const MAX_NOTIFICATION_DELAY_HOURS = 24;
12 const POST_META_LAST_NOTIFICATION_CONTENT = 'sib_push_last_notification_content';
13 const POST_META_LAST_NOTIFICATION_TIMESTAMP = 'sib_push_last_notification_timestamp';
14 const POST_META_ERROR_MESSAGE = 'sib_push_error_message';
15 const POST_META_INFO_MESSAGE = 'sib_push_info_message';
16 const DEDUPLICATION_SECONDS = 60;
17 const API_RATE_LIMIT_SECONDS = 3;
18
19 public static function add_dashboard_widget() {
20 $settings = SIB_Push_Settings::getSettings();
21 if (!$settings->getShowPush()) return;
22 if (SIB_Push_Utils::is_push_active()) return;
23 wp_add_dashboard_widget(
24 'sib_push_dashboard_widget',
25 __('Web Push Notifications', 'mailin'),
26 array( __CLASS__, 'dashboard_widget_html' ),
27 null,
28 null,
29 'normal',
30 'high'
31 );
32 }
33
34 public static function dashboard_widget_html() {
35 ?>
36 <p>
37 <?php echo __( 'Grow your audience with push notifications', 'mailin' ) ?>
38 </p>
39 <ul>
40 <li style="list-style: inside disc"><?php echo __( 'Notify your readers whenever a new post is published.', 'mailin' ) ?></li>
41 <li style="list-style: inside disc"><?php echo __( 'Let your users subscribe to their favorite topics.', 'mailin' ) ?></li>
42 <!-- NOTE: deactivate woocommerce-->
43 <!-- <li style="list-style: inside disc">--><?php //echo __( 'Set up automated e-commerce notifications for your WooCommerce business.', 'mailin' ) ?>
44 </ul>
45 <p><a class="button button-primary"
46 href="<?php echo admin_url( 'admin.php?page=sib_page_push' ) ?>"><?php echo __( 'Activate web push notifications' ) ?></a>
47 </p>
48 <?php
49 }
50
51 public static function add_post_options() {
52 if (!SIB_Push_Utils::can_send_notifications()) {
53 return;
54 }
55
56 $settings = SIB_Push_Settings::getSettings();
57 if (!$settings->getShowPush()) return;
58 if ($settings->getDisableSendOnPublish()) return;
59
60 // Add the post editor js
61 wp_enqueue_script( 'sib-select2' );
62 wp_enqueue_style( 'sib-select2' );
63 wp_enqueue_script( 'sib-post-editor-js' );
64 wp_enqueue_style('sib-font-face');
65 wp_localize_script( 'sib-post-editor-js', 'brevo_push_notice', array(
66 'nonce' => SIB_Push_API::get_nonce()
67 ));
68 wp_enqueue_style( 'sib-push-admin-css' );
69
70 // Add meta box for the "post" post type (default)
71 add_meta_box(self::META_BOX_ID,
72 'Brevo Push Notifications',
73 array( __CLASS__, 'add_post_html' ),
74 'post',
75 'normal',
76 'high');
77
78 // Add meta box for all other post types that are public but not built in to WordPress
79 $post_types = get_post_types(array('public' => true, '_builtin' => false), 'names', 'and' );
80 foreach ( $post_types as $post_type ) {
81 add_meta_box(
82 self::META_BOX_ID,
83 'Brevo Push Notifications',
84 array( __CLASS__, 'add_post_html' ),
85 $post_type,
86 'side',
87 'high'
88 );
89 }
90 }
91 public static function add_post_html($post) {
92 $post_type = $post->post_type;
93 $settings = SIB_Push_Settings::getSettings();
94 $credentials = $settings->getWonderPushCredentials();
95 try {
96 $app = SIB_Push_Utils::get_push_application(SIB_Push_Utils::DEFAULT_CACHE_TTL);
97 } catch (Exception $e) {
98 return;
99 }
100
101 // Add an nonce field so we can check for it later.
102 wp_nonce_field(self::SAVE_POST_NONCE_ACTION, self::SAVE_POST_NONCE_KEY, true);
103
104 // Our plugin config setting "Automatically send a push notification when I publish a post from the WordPress editor"
105 $disable_send_by_default = $settings->getDisableSendByDefaultOnPublish();
106
107 /* This is a scheduled post and the user checked "Send a notification on post publish/update". */
108 $send_notification_checked = (get_post_meta($post->ID, 'sib_push_send_notification', true) == true);
109 // User explicitely unchecked notification and saved post
110 $send_notification_unchecked = get_post_meta($post->ID, 'sib_push_send_notification', true) === '0';
111 $send_notification_delay_seconds = get_post_meta($post->ID, 'sib_push_send_notification_delay_seconds', true);
112 if ($send_notification_delay_seconds === null || $send_notification_delay_seconds === '') {
113 $send_notification_delay_seconds = $settings->getDeliveryTimeSeconds();
114 }
115 $send_notification_delay_seconds = (int)$send_notification_delay_seconds;
116
117 // Defaults
118 $default_target_brevo_segment_id = $settings->getDefaultTargetSegmentId() ?: '';
119 $default_target_brevo_list_id = $settings->getDefaultTargetListId() ?: '';
120
121 // Brevo segment IDs
122 $target_brevo_segment_ids = get_post_meta($post->ID, 'sib_push_target_brevo_segment_ids', true) ?: '';
123 $target_brevo_segment_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $target_brevo_segment_ids ?: $default_target_brevo_segment_id));
124 // Brevo list IDs
125 $target_brevo_list_ids = get_post_meta($post->ID, 'sib_push_target_brevo_list_ids', true) ?: '';
126 $target_brevo_list_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $target_brevo_list_ids ?: $default_target_brevo_list_id));
127 $target_tags = get_post_meta($post->ID, 'sib_push_target_tags', true) ?: '';
128 $target_tags = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $target_tags));
129 // All segments
130 try {
131 $all_brevo_segments = $credentials ? SIB_API_Manager::get_segments() : null;
132 } catch (Exception $e) {
133 $all_brevo_segments = array();
134 SIB_Push_Utils::log_error('Could not get segment list', $e);
135 }
136 // All lists
137 try {
138 $all_brevo_lists = $credentials ? SIB_API_Manager::get_lists() : null;
139 } catch (Exception $e) {
140 $all_brevo_lists = array();
141 SIB_Push_Utils::log_error('Could not get lists', $e);
142 }
143
144
145 try {
146 $app = SIB_Push_Utils::get_push_application();
147 $all_tags = $app && $credentials
148 ? SIB_Push_Utils::list_tags($credentials)
149 : array();
150
151 } catch (Exception $e) {
152 $all_tags = array();
153 SIB_Push_Utils::log_error('Could not get tags', $e);
154 }
155
156 // UTM params
157 $utm_params = array();
158 $url_parameters = $app ? (array)$app->getUrlParameters() : array();
159 foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter) {
160 $value = get_post_meta($post->ID, "sib_push_$utm_parameter", true);
161 $value = $value ?: (array_key_exists($utm_parameter, $url_parameters) ? $url_parameters[$utm_parameter] : null);
162 if ($value) $utm_params[$utm_parameter] = $value;
163 }
164 $hours = array();
165 for ($i = 1; $i <= self::MAX_NOTIFICATION_DELAY_HOURS; $i++) {
166 $hours []= $i;
167 }
168 $minutes = array(5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55);
169
170 // We check the checkbox if: setting is enabled on Config page, post type is ONLY "post", and the post has not been published (new posts are status "auto-draft")
171 $send_notification = (!$send_notification_unchecked
172 && !$disable_send_by_default
173 && $post->post_type == "post"
174 && in_array($post->post_status, array("future", "draft", "auto-draft", "pending")))
175 || $send_notification_checked;
176
177 $notification_already_sent = !!(get_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_CONTENT, true));
178 $sib_push_audience = 'all';
179 if (count($target_tags)) {
180 $sib_push_audience = 'tags';
181 } else if (!empty($target_brevo_segment_ids)) {
182 $sib_push_audience = 'brevo_segments';
183 } else if (!empty($target_brevo_list_ids)) {
184 $sib_push_audience = 'brevo_lists';
185 }
186 ?>
187 <?php if (!SIB_Push_Utils::is_push_active()): ?>
188 <div id="sib_push_activation">
189 <p>
190 <button class="button button-primary" id="sib_push_activation_button">
191 <?php _e('Activate push notifications', 'mailin') ?>
192 </button>
193 <span class="spinner" style="float: none; margin: 0;"></span>
194 <span style="display: none;" class="sib_push_activating_message"><?php _e('Please wait, activation might take up to a minute.', 'mailin') ?></span>
195 </p>
196 <p>
197 <?php _e('Grow your audience with push notifications:', 'mailin') ?>
198 </p>
199 <ul>
200 <li style="list-style-type: disc; list-style-position: inside;"><?php _e('Notify your readers whenever a new post is published.', 'mailin') ?></li>
201 <li style="list-style-type: disc; list-style-position: inside;"><?php _e('Let your users subscribe to their favorite topics.', 'mailin') ?></li>
202 <?php if (!!SIB_Push_Utils::get_woocommerce()) : ?>
203 <li style="list-style-type: disc; list-style-position: inside;"><?php _e('Set up automated e-commerce notifications for your WooCommerce business.', 'mailin') ?></li>
204 <?php endif; ?>
205 </ul>
206
207 </div>
208 <?php endif; ?>
209 <div id="sib_push_editor">
210 <input type="hidden" name="sib_push_meta_box_present" value="true"/>
211 <?php if ($notification_already_sent) : ?>
212 <input type="hidden" name="sib_push_notification_already_sent" value="true"/>
213 <?php endif; ?>
214 <label>
215 <input type="checkbox" name="send_sib_push_notification" value="true" <?php if ($send_notification) {
216 echo "checked";
217 } ?> />
218 <strong>
219 <?php if ($post->post_status == "publish") {
220 /* translators: %s: Type of post. Usually is the string "post" */
221 printf(__("Send notification on %s update", 'mailin'), $post_type);
222 } else {
223 /* translators: %s: Type of post. Usually is the string "post" */
224 printf(__("Send notification on %s publish", 'mailin'), $post_type);
225 }
226 ?>
227 </strong>
228 </label>
229 <div class="sib_push_audience">
230 <h3 style="margin-bottom: 3px;"><?php echo __('Target audience', 'mailin') ?></h3>
231 <label>
232 <input
233 type="radio"
234 name="sib_push_audience"
235 value="all"
236 <?php echo $sib_push_audience === 'all' ? 'checked' : '' ?>
237 />
238 <?php echo __('Everybody', 'mailin') ?>
239 </label>
240 <div class="sib_push_all">
241 <div class="sib_push_target" style="padding: 0">
242 <input type="hidden" name="sib_push_target_segment_ids[]" value="@ALL" />
243 </div>
244 </div>
245 <label>
246 <input
247 type="radio"
248 name="sib_push_audience"
249 value="brevo_segments"
250 <?php echo $sib_push_audience === 'brevo_segments' ? 'checked' : '' ?>
251 />
252 <?php echo __('Users in segment(s)', 'mailin') ?>
253 </label>
254 <div class="sib_push_segments">
255 <div class="sib_push_target">
256 <label for="sib_push_target_brevo_segment_ids"><?php echo __("We'll notify users that match at least one of these segments:", 'mailin') ?></label>
257 <select name="sib_push_target_brevo_segment_ids[]" multiple
258 id="sib_push_target_brevo_segment_ids"
259 class="sib_push_target_segment_id sib_push_select2">
260 <option value=""><?php echo __("Everyone", 'mailin') ?></option>
261 <?php
262 foreach ($all_brevo_segments as $segment) {
263 ?>
264 <option
265 <?php echo array_search($segment['id'], $target_brevo_segment_ids) !== false ? 'selected="selected"' : '' ?>
266 value="<?php echo $segment['id'] ?>"><?php echo $segment['segmentName'] ?: $segment['id'] ?></option><?php
267 }
268 ?>
269 </select>
270 </div>
271 </div>
272 <label>
273 <input
274 type="radio"
275 name="sib_push_audience"
276 value="brevo_lists"
277 <?php echo $sib_push_audience === 'brevo_lists' ? 'checked' : '' ?>
278 />
279 <?php echo __("Users in list(s)", 'mailin') ?>
280 </label>
281 <div class="sib_push_lists">
282 <div class="sib_push_target">
283 <label for="sib_push_target_brevo_list_ids"><?php echo __("We'll notify users that match at least one of these lists:", 'mailin') ?></label>
284 <select name="sib_push_target_brevo_list_ids[]" multiple
285 id="sib_push_target_brevo_list_ids"
286 class="sib_push_target_list_id sib_push_select2">
287 <option value=""><?php echo __("Everyone", 'mailin') ?></option>
288 <?php
289 foreach ($all_brevo_lists as $list) {
290 ?>
291 <option
292 <?php echo array_search($list['id'], $target_brevo_list_ids) !== false ? 'selected="selected"' : '' ?>
293 value="<?php echo $list['id'] ?>"><?php echo $list['name'] ?: $list['id'] ?></option><?php
294 }
295 ?>
296 </select>
297 </div>
298 </div>
299 <label>
300 <input
301 type="radio"
302 name="sib_push_audience"
303 value="tags"
304 <?php echo $sib_push_audience === 'tags' ? 'checked' : '' ?>
305 />
306 <?php echo __("Users with tag(s)", 'mailin') ?>
307 </label>
308 <div class="sib_push_tags">
309 <div class="sib_push_target">
310 <label for="sib_push_target_tags"><?php echo __("We'll notify users that match at least one of these tags:", 'mailin') ?></label>
311 <select name="sib_push_target_tags[]" multiple
312 id="sib_push_target_tags"
313 class="sib_push_target_tags sib_push_select2">
314 <?php
315 foreach ($all_tags as $tag) {
316 ?>
317 <option
318 <?php echo array_search($tag, $target_tags) !== false ? 'selected="selected"' : '' ?>
319 value="<?php echo $tag ?>"><?php echo $tag ?></option><?php
320 }
321 ?>
322 </select>
323 </div>
324 </div>
325 </div>
326 <?php if ($all_brevo_segments) : ?>
327 <?php endif; ?>
328 <h3 style="margin-bottom: 3px;"><?php echo __("Send later", 'mailin') ?></h3>
329 <small><?php echo __("Delay the notification after this post gets published:", 'mailin') ?></small>
330 <br/>
331 <select name="sib_push_send_notification_delay_seconds">
332 <option value="0"><?php echo __("No delay", 'mailin') ?></option>
333 <?php foreach ($minutes as $minute): ?>
334 <option
335 <?php echo (($minute * 60) === $send_notification_delay_seconds ? 'selected="selected"' : '') ?>
336 value="<?php echo $minute * 60 ?>">
337 <?php echo $minute ?> <?php echo __("minutes", 'mailin') ?>
338 </option>
339 <?php endforeach; ?>
340 <?php foreach ($hours as $hour): ?>
341 <option
342 <?php echo (($hour * 3600) === $send_notification_delay_seconds ? 'selected="selected"' : '') ?>
343 value="<?php echo $hour * 3600 ?>">
344 <?php echo $hour ?><?php echo _n("hour", "hours", $hour, 'mailin') ?>
345 </option>
346 <?php endforeach; ?>
347 </select>
348 <h3 style="margin-bottom: 3px;"><?php echo __("Google campaign parameters", 'mailin') ?></h3>
349 <small><?php echo __("Campaign params help you see push notification traffic in Google Analytics.", "mailin") ?> <a target="_blank" href="https://support.google.com/analytics/answer/1033863#parameters"><?php echo __("Learn more", "mailin") ?></a>.</small>
350 <div class="sib_push_utm_parameters">
351 <?php foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter): ?>
352 <?php $id = 'sib_push_'. $utm_parameter; ?>
353 <div class="sib_push_utm">
354 <label for="<?php echo $id; ?>"><?php echo $utm_parameter; ?>:</label>
355 <input type="text"
356 id="<?php echo $id; ?>" name="<?php echo $id; ?>"
357 value="<?php echo esc_attr(array_key_exists($utm_parameter, $utm_params) ? $utm_params[$utm_parameter] : '') ?>"/>
358 </div>
359 <?php endforeach; ?>
360 </div>
361 </div>
362 <?php
363 }
364 public static function on_save_post($post_id) {
365 // Check nonce
366 if (!isset( $_POST[self::SAVE_POST_NONCE_KEY] ) ) {
367 return $post_id;
368 }
369
370 $nonce = $_POST[self::SAVE_POST_NONCE_KEY];
371
372 // Verify nonce
373 if (!wp_verify_nonce($nonce, self::SAVE_POST_NONCE_ACTION)) {
374 return $post_id;
375 }
376
377 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
378 return $post_id;
379 }
380
381 $sib_push_meta_box_present = array_key_exists('sib_push_meta_box_present', $_POST);
382 update_post_meta($post_id, 'sib_push_meta_box_present', $sib_push_meta_box_present ? true : false);
383
384 if (array_key_exists('send_sib_push_notification', $_POST)) {
385 $notification_already_sent = !!(get_post_meta($post_id, self::POST_META_LAST_NOTIFICATION_CONTENT, true));
386 if (
387 !$notification_already_sent // Notification wasn't sent
388 || ($notification_already_sent && array_key_exists('sib_push_notification_already_sent', $_POST)) // Notification was sent and the UI reflected this
389 ) {
390 update_post_meta($post_id, 'sib_push_send_notification', true);
391 }
392 } else {
393 // If meta box present, user explicitely unchecked
394 $sib_push_send_notification = $sib_push_meta_box_present ? '0' : false;
395 update_post_meta($post_id, 'sib_push_send_notification', $sib_push_send_notification);
396 }
397
398 $settings = SIB_Push_Settings::getSettings();
399 if (array_key_exists('sib_push_send_notification_delay_seconds', $_POST)) {
400 $meta_value = trim(sanitize_text_field($_POST['sib_push_send_notification_delay_seconds']));
401 if (SIB_Push_Utils::is_int_string($meta_value) && (int)$meta_value <= self::MAX_NOTIFICATION_DELAY_HOURS * 3600) {
402 update_post_meta($post_id, 'sib_push_send_notification_delay_seconds', (int)$meta_value);
403 }
404 } else {
405 update_post_meta($post_id, 'sib_push_send_notification_delay_seconds', null);
406 }
407
408 if (array_key_exists('sib_push_target_tags', $_POST)) {
409 $meta_values = array_filter(array_map(function($elt) {
410 return trim(sanitize_text_field($elt));
411 }, $_POST['sib_push_target_tags']));
412 update_post_meta($post_id, 'sib_push_target_tags', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
413 } else {
414 update_post_meta($post_id, 'sib_push_target_tags', null);
415 }
416
417 if (array_key_exists('sib_push_target_segment_ids', $_POST)) {
418 $meta_values = array_filter(array_map(function ($elt) {
419 return trim(sanitize_text_field($elt));
420 }, $_POST['sib_push_target_segment_ids']));
421 update_post_meta($post_id, 'sib_push_target_segment_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
422 } else {
423 update_post_meta($post_id, 'sib_push_target_segment_ids', null);
424 }
425
426 if (array_key_exists('sib_push_target_brevo_segment_ids', $_POST)) {
427 $meta_values = array_filter(array_map(function ($elt) {
428 return trim(sanitize_text_field($elt));
429 }, $_POST['sib_push_target_brevo_segment_ids']));
430 update_post_meta($post_id, 'sib_push_target_brevo_segment_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
431 } else {
432 update_post_meta($post_id, 'sib_push_target_brevo_segment_ids', null);
433 }
434
435 if (array_key_exists('sib_push_target_brevo_list_ids', $_POST)) {
436 $meta_values = array_filter(array_map(function ($elt) {
437 return trim(sanitize_text_field($elt));
438 }, $_POST['sib_push_target_brevo_list_ids']));
439 update_post_meta($post_id, 'sib_push_target_brevo_list_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
440 } else {
441 update_post_meta($post_id, 'sib_push_target_brevo_list_ids', null);
442 }
443
444 foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter) {
445 $key = "sib_push_$utm_parameter";
446 if (array_key_exists($key, $_POST)) {
447 $meta_value = trim(sanitize_text_field($_POST[$key]));
448 update_post_meta($post_id, $key, $meta_value && strlen($meta_value) ? $meta_value : null);
449 }
450 }
451 }
452
453 public static function on_transition_post_status( $new_status, $old_status, $post ) {
454 if ($old_status === 'trash' && $new_status === 'publish') {
455 return;
456 }
457 if (!empty($post)
458 && $new_status === "publish"
459 && get_post_status($post->ID) === "publish"
460 && $post->post_type !== 'page') {
461 self::send_notification_on_post($new_status, $old_status, $post);
462 }
463 }
464
465 public static function send_notification_on_post($new_status, $old_status, $post) {
466 try {
467 if (!SIB_Push_Utils::is_push_active()) return;
468 if (!SIB_Push_Utils::is_curl_installed()) {
469 return;
470 }
471 $settings = SIB_Push_Settings::getSettings();
472 $credentials = $settings->getWonderPushCredentials();
473 if (!$credentials || $settings->getDisableSendOnPublish()) return;
474
475 // quirk of Gutenberg editor leads to two passes if meta box is added
476 // conditional removes first pass
477 if( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
478 return;
479 }
480
481 // Returns true if there is POST data
482 $was_posted = !empty($_POST);
483
484 // When this post was created or updated, the meta box in the WordPress post editor screen was visible
485 $sib_push_meta_box_present = $was_posted && array_key_exists('sib_push_meta_box_present', $_POST) && $_POST['sib_push_meta_box_present'] === 'true';
486
487 // The checkbox "Send notification on post publish/update" on the meta box is checked
488 $sib_push_meta_box_send_notification_checked = $was_posted && array_key_exists('send_sib_push_notification', $_POST) && $_POST['send_sib_push_notification'] === 'true';
489
490 // The notification date was filled
491 $sib_push_meta_send_notification_delay_seconds = null;
492 if ($was_posted && array_key_exists('sib_push_send_notification_delay_seconds', $_POST)) {
493 $meta_value = trim(sanitize_text_field($_POST['sib_push_send_notification_delay_seconds']));
494 if (SIB_Push_Utils::is_int_string($meta_value) && (int)$meta_value < self::MAX_NOTIFICATION_DELAY_HOURS * 3600) {
495 $sib_push_meta_send_notification_delay_seconds = (int)$meta_value;
496 }
497 }
498
499 // Target WonderPush segment IDs - This is REQUIRED to handle @ALL
500 // We currently will store "@ALL" in the `sib_push_target_segment_ids` key of the postmeta
501 $target_segment_ids = array();
502 if ($was_posted && array_key_exists('sib_push_target_segment_ids', $_POST)) {
503 $target_segment_ids = array_filter(array_map(function($elt) {
504 return trim(sanitize_text_field($elt));
505 }, $_POST['sib_push_target_segment_ids']));
506 } else {
507 $meta_value = get_post_meta($post->ID, 'sib_push_target_segment_ids', true) ?: '';
508 $target_segment_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
509 }
510
511 // Target Brevo segment IDs
512 $target_brevo_segment_ids = array();
513
514 if ($was_posted && array_key_exists('sib_push_target_brevo_segment_ids', $_POST)) {
515 $target_brevo_segment_ids = array_filter(array_map(function($elt) {
516 return trim(sanitize_text_field($elt));
517 }, $_POST['sib_push_target_brevo_segment_ids']));
518 } else {
519 $meta_value = get_post_meta($post->ID, 'sib_push_target_brevo_segment_ids', true) ?: '';
520 $target_brevo_segment_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
521 }
522
523 // Target Brevo list IDs
524 $target_brevo_list_ids = array();
525
526 if ($was_posted && array_key_exists('sib_push_target_brevo_list_ids', $_POST)) {
527 $target_brevo_list_ids = array_filter(array_map(function($elt) {
528 return trim(sanitize_text_field($elt));
529 }, $_POST['sib_push_target_brevo_list_ids']));
530 } else {
531 $meta_value = get_post_meta($post->ID, 'sib_push_target_brevo_list_ids', true) ?: '';
532 $target_brevo_list_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
533 }
534
535 // Target tags
536 $target_tags = array();
537 if ($was_posted && array_key_exists('sib_push_target_tags', $_POST)) {
538 $target_tags = array_filter(array_map(function($elt) {
539 return trim(sanitize_text_field($elt));
540 }, $_POST['sib_push_target_tags']));
541 } else {
542 $meta_value = get_post_meta($post->ID, 'sib_push_target_tags', true) ?: '';
543 $target_tags = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
544 }
545
546 // utm parameters
547 $utm_params = array();
548 foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter) {
549 $value = null;
550 $key = "sib_push_$utm_parameter";
551 if ($was_posted) {
552 if (array_key_exists($key, $_POST)) {
553 $value = $_POST[$key];
554 }
555 } else {
556 $value = get_post_meta($post->ID, $key, true);
557 }
558 $value = $value ? trim(sanitize_text_field($value)) : $value;
559 $value = $value && strlen($value) > 256 ? substr($value, 0, 256) : $value;
560 $value = $value && strlen($value) ? $value : null;
561 if ($value) $utm_params[$utm_parameter] = $value;
562 }
563 // This is a scheduled post and the meta box was present.
564 $post_metadata_was_sib_push_meta_box_present = (get_post_meta($post->ID, 'sib_push_meta_box_present', true) == true);
565
566 // This is a scheduled post and the user checked "Send a notification on post publish/update".
567 $post_metadata_was_send_notification_checked = (get_post_meta($post->ID, 'sib_push_send_notification', true) == true);
568
569 // This is a scheduled post and the user filled notification delay
570 $post_metadata_send_notification_delay_seconds = get_post_meta($post->ID, 'sib_push_send_notification_delay_seconds', true);
571 if ($post_metadata_send_notification_delay_seconds === null
572 || $post_metadata_send_notification_delay_seconds === '') {
573 // Backwards compat: set this to the settings value for those who saved the post with a previous version of the plugin
574 // The current plugin version always sets a $post_metadata_send_notification_delay_seconds
575 $post_metadata_send_notification_delay_seconds = $settings->getDeliveryTimeSeconds();
576 }
577 $post_metadata_send_notification_delay_seconds = (int)$post_metadata_send_notification_delay_seconds;
578
579 // Either we were just posted from the WordPress post editor form, or this is a scheduled notification and it was previously submitted from the post editor form
580 $posted_from_wordpress_editor = $sib_push_meta_box_present || $post_metadata_was_sib_push_meta_box_present;
581
582 $last_sent_title = get_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_CONTENT, true);
583
584 $send_notification_delay_seconds = null;
585
586 $settings_send_notification_on_non_editor_post_publish = $settings->getSendOnThirdPartyPublish();
587 $additional_custom_post_types_string = str_replace(' ', '', $settings->getAdditionalCustomPostTypes() ?: '');
588 $additional_custom_post_types_array = array_filter(explode(',', $additional_custom_post_types_string));
589 $non_editor_post_publish_do_send_notification = $settings_send_notification_on_non_editor_post_publish &&
590 ($post->post_type === 'post' || in_array($post->post_type, $additional_custom_post_types_array, true)) &&
591 $old_status !== 'publish';
592
593 if ($posted_from_wordpress_editor) {
594 $do_send_notification = ($was_posted && $sib_push_meta_box_send_notification_checked) ||
595 (!$was_posted && $post_metadata_was_send_notification_checked);
596
597 if ($was_posted) {
598 // When posting and the notification has already been sent, make sure the 'sib_push_notification_already_sent' key was sent along
599 // Otherwise, this may be a page that wasn't refreshed as the post was published in the background.
600 if ($last_sent_title && !array_key_exists('sib_push_notification_already_sent', $_POST)) {
601 $do_send_notification = false;
602 }
603
604 $send_notification_delay_seconds = $sib_push_meta_send_notification_delay_seconds;
605 } else {
606 $send_notification_delay_seconds = $post_metadata_send_notification_delay_seconds;
607 }
608 } else {
609 // This was not submitted via the WordPress editor
610 $do_send_notification = $non_editor_post_publish_do_send_notification;
611 }
612
613 if (!$do_send_notification) return;
614
615 // Create WonderPush client
616 $management_api_client = SIB_Push_Utils::management_api_client($credentials);
617 $default_target_segment_id = $settings->getDefaultTargetSegmentId();
618 $default_target_list_id = $settings->getDefaultTargetListId();
619
620 update_post_meta($post->ID, 'sib_push_meta_box_present', false);
621 update_post_meta($post->ID, 'sib_push_send_notification', false);
622
623 // Some WordPress environments seem to be inconsistent about whether on_save_post is called before transition_post_status
624 // This sets the metadata back to true, and will cause a post to be sent even if the checkbox is not checked the next time
625 // We remove all related $_POST data to prevent this
626 if ($was_posted) {
627 if (array_key_exists('sib_push_meta_box_present', $_POST)) {
628 unset($_POST['sib_push_meta_box_present']);
629 }
630 if (array_key_exists('send_sib_push_notification', $_POST)) {
631 unset($_POST['send_sib_push_notification']);
632 }
633 }
634
635 $title = SIB_Push_Utils::decode_entities(get_the_title($post->ID));
636
637 $site_title = "";
638 if ($settings->getNotificationTitle()) {
639 $site_title = SIB_Push_Utils::decode_entities($settings->getNotificationTitle());
640 } else {
641 $site_title = SIB_Push_Utils::decode_entities(get_bloginfo('name'));
642 }
643
644 $icon_image = null;
645 $big_picture = null;
646 if (has_post_thumbnail($post->ID)) {
647
648 $post_thumbnail_id = get_post_thumbnail_id($post->ID);
649
650 // Higher resolution (2x retina, + a little more) for the notification small icon
651 $thumbnail_sized_images_array = wp_get_attachment_image_src($post_thumbnail_id, 'medium', false);
652 $thumbnail_image = $thumbnail_sized_images_array && count($thumbnail_sized_images_array) > 0 ? $thumbnail_sized_images_array[0] : null;
653
654 // Much higher resolution for the notification large image
655 $large_sized_images_array = wp_get_attachment_image_src($post_thumbnail_id, 'large', false);
656 $large_image = $large_sized_images_array && count($large_sized_images_array) > 0 ? $large_sized_images_array[0] : null;
657
658 $config_use_featured_image_as_icon = !($settings->getDisableUsePostImageForNotification());
659 $config_use_featured_image_as_image = !($settings->getDisableUsePostImageForNotification());
660 $use_large_image = $settings->getPreferLargeImageForNotification();
661
662 // Use the same image in any case
663 $image = $use_large_image ? ($large_image ?: $thumbnail_image) : ($thumbnail_image ?: $large_image);
664
665 // WPRocket support
666 if ( function_exists( 'get_rocket_cdn_url' ) && $image ) {
667 try {
668 $rocket_url = get_rocket_cdn_url($image);
669 if ($rocket_url) {
670 $image = $rocket_url;
671 }
672 } catch (Exception $e) {
673 SIB_Push_Utils::log_warn('Rocket cdn function get_rocket_cdn_url threw', $e);
674 }
675 }
676
677 if ($config_use_featured_image_as_icon) {
678 $icon_image = $image;
679 }
680 if ($config_use_featured_image_as_image) {
681 $big_picture = $image;
682 }
683 }
684
685 // Send the notification
686 $notification = new \WonderPush\Obj\Notification();
687 $alert = new \WonderPush\Obj\NotificationAlert();
688 $notification->setAlert($alert);
689 $permalink = get_permalink($post->ID);
690 $target_url = SIB_Push_Utils::inject_query_string_params($permalink, $utm_params);
691 $alert->setTargetUrl($target_url);
692 $alert->setTitle($site_title);
693 $alert->setText($title);
694
695 // Android
696 $android = new \WonderPush\Obj\NotificationAlertAndroid();
697 $alert->setAndroid($android);
698 if ($big_picture) {
699 $android->setBigPicture($big_picture);
700 $android->setType('bigPicture');
701 }
702 $ios = new \WonderPush\Obj\NotificationAlertIos();
703 $alert->setIos($ios);
704 if ($big_picture) {
705 $attachment = new \WonderPush\Obj\NotificationAlertIosAttachment();
706 $attachment->setUrl($big_picture);
707 $attachment->setType('image/png'); // Valid for all image types
708 $ios->setAttachments(array($attachment));
709 }
710 $ios->setSound('default');
711 $web = new \WonderPush\Obj\NotificationAlertWeb();
712 $alert->setWeb($web);
713 if ($icon_image) $web->setIcon($icon_image);
714 if ($big_picture) $web->setImage($big_picture);
715 $params = new \WonderPush\Params\DeliveriesCreateParams();
716 $params->setInheritUrlParameters(true);
717 $params->setNotification($notification);
718 $brevoSegmentIds = array();
719 $brevoListIds = array();
720 $segmentIds = array();
721 if (count($target_tags)) {
722 $params->setTargetTags($target_tags);
723 } else if (count($target_brevo_segment_ids)) {
724 $brevoSegmentIds = $target_brevo_segment_ids;
725 $params->setTargetBrevoSegmentIds( array_map(function ($x) { return (int)$x; }, $brevoSegmentIds) );
726 } else if (count($target_brevo_list_ids)) {
727 $brevoListIds = $target_brevo_list_ids;
728 $params->setTargetBrevoListIds( $target_brevo_list_ids );
729 } else if (count($target_segment_ids)) {
730 $segmentIds = $target_segment_ids;
731 $params->setTargetSegmentIds($segmentIds);
732 } else if ($default_target_segment_id) {
733 $brevoSegmentIds = array($default_target_segment_id);
734 $params->setTargetBrevoSegmentIds( $brevoSegmentIds );
735 } else if ($default_target_list_id) {
736 $brevoListIds = array($default_target_list_id);
737 $params->setTargetBrevoListIds( $brevoListIds );
738 } else {
739 $segmentIds = array('@ALL');
740 $params->setTargetSegmentIds($segmentIds);
741 }
742 if ($send_notification_delay_seconds !== null && $send_notification_delay_seconds > 0) {
743 $params->setDeliveryTime('' . $send_notification_delay_seconds . 's');
744 }
745 // Deduplicate notifications
746 $last_sent_timestamp = get_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_TIMESTAMP, true);
747 $elapsed = current_time('timestamp') - ($last_sent_timestamp ? $last_sent_timestamp : 0);
748 if ($elapsed < self::DEDUPLICATION_SECONDS && $last_sent_title === $title) {
749 SIB_Push_Utils::log_debug('Discarding duplicate notification', $params);
750 return;
751 }
752
753 // Rate limit
754 $wait_time = self::get_sending_rate_limit_wait_time();
755 if ($wait_time) {
756 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, 'You must wait ' . $wait_time . 's before sending another notification');
757 return;
758 }
759
760 // Remember last notification content and timestamp
761 update_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_CONTENT, $title);
762 update_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_TIMESTAMP, current_time('timestamp'));
763
764 // Send the notification
765 SIB_Push_Utils::log_debug('Sending Brevo push notification', $params);
766 self::update_last_sent_timestamp();
767 $response = $management_api_client->deliveries()->create($params);
768
769 // Handle success/failure
770 if ($response->isSuccess()) {
771 if (count($brevoListIds) || count($brevoSegmentIds) || $settings->getDisableFeedbackOnPublish()) {
772 update_post_meta($post->ID, self::POST_META_INFO_MESSAGE, __('Brevo push notification sent.', 'mailin'));
773 } else {
774 // Fetch the number of subscribers
775 try {
776 $countResponse = $management_api_client->installations()->all(array(
777 'limit' => 1,
778 'reachability' => 'optIn',
779 'segmentIds' => $segmentIds,
780 'tags' => $target_tags,
781 ));
782 $count = $countResponse->getCount();
783 if ($count) {
784 if ($send_notification_delay_seconds) {
785 $dt = new DateTime();
786 $dt->setTimestamp($send_notification_delay_seconds + $dt->getTimestamp());
787 $formatted_date = $dt->format(DateTime::RFC850);
788 // translators: %d is the number of subscribers, %s is the date and time
789 update_post_meta($post->ID, self::POST_META_INFO_MESSAGE, sprintf(__("Brevo will send a notification to %d subscribers on %s.", "mailin"), $count, $formatted_date));
790 } else {
791 // translators: %d is the number of subscribers
792 update_post_meta($post->ID, self::POST_META_INFO_MESSAGE, sprintf(__("Brevo notification sent to %d subscribers.", "mailin"), $count));
793 }
794 } else {
795 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, __("Brevo notification sent but the target audience is empty.", "mailin"));
796 }
797 } catch (\WonderPush\Errors\Base $e) {}
798 }
799 } else {
800 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, __("Brevo notification could not be sent.", "mailin"));
801 }
802 } catch (\WonderPush\Errors\Base $e) {
803 switch ($e->getCode()) {
804 default:
805 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, $e->getMessage());
806 break;
807 }
808 } catch (Exception $e) {
809 SIB_Push_Utils::log_error('Caught Exception', $e);
810 }
811 }
812
813 public static function get_sending_rate_limit_wait_time() {
814 $last_send_time = get_option('sib_push.last_send_time');
815 if ($last_send_time) {
816 $current_time = current_time('timestamp');
817 $time_elapsed_since_last_send = self::API_RATE_LIMIT_SECONDS - ($current_time - intval($last_send_time));
818 if ($time_elapsed_since_last_send > 0) {
819 return $time_elapsed_since_last_send;
820 }
821 }
822 return false;
823 }
824
825 /**
826 * Updates the last sent timestamp, used in rate limiting notifications sent more than 1 per minute.
827 */
828 public static function update_last_sent_timestamp() {
829 $current_time = current_time('timestamp');
830 update_option('sib_push.last_send_time', $current_time);
831 }
832
833 }
834
835 }