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