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