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