PluginProbe ʕ •ᴥ•ʔ
Brevo – Email, SMS, Web Push, Chat, and more. / trunk
Brevo – Email, SMS, Web Push, Chat, and more. vtrunk
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 week 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 5 months ago push-amp.php 1 year ago push-api.php 3 months ago push-httpclient.php 1 year ago push-public.php 1 year ago push-settings.php 3 months ago push-utils.php 5 months ago push-woocommerce.php 11 months ago sendinblue.php 3 years ago sib-api-manager.php 1 year ago sib-form-preview.php 2 years ago sib-sms-code.php 5 months ago table-forms.php 1 year ago
push-admin.php
893 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 = (string)$settings->getDefaultTargetSegmentId() ?: '';
143 $default_target_brevo_list_id = (string)$settings->getDefaultTargetListId() ?: '';
144
145 // Brevo segment IDs
146 $target_brevo_segment_ids = (string)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 = (string)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 $contactSyncMessage = SIB_Push_Utils::is_contact_sync_active()
211 ? null
212 : sprintf(
213 // translators: %1$s: advanced settings
214 __( 'To use Brevo segments and lists, enable contact creation from push subscribers %1$s.', 'mailin' ),
215 '<a href="'.add_query_arg( 'page', SIB_Page_Push::PAGE_ID, admin_url( 'admin.php' ) ).'#/settings/advanced" style="font-size:12px;">' . __( 'in Advanced settings', 'mailin' ) . '</a>',
216 );
217 ?>
218 <div id="sib_notification_preview"></div>
219 <div id="sib_push_config" style="display:none"><?php
220 echo json_encode(SIB_Push_API::get_push_configuration());
221 ?></div>
222 <?php if (!SIB_Push_Utils::is_push_active()): ?>
223 <div id="sib_push_activation">
224 <p>
225 <?php _e('Notify your readers:', 'mailin');?>
226 </p>
227 <p>
228 <label>
229 <input type="checkbox" id="sib_push_activation_button" value="true" />
230 <strong>
231 <?php if ($post->post_status == "publish") {
232 /* translators: %s: Type of post. Usually is the string "post" */
233 printf(__("Send web push on %s update", 'mailin'), $post_type);
234 } else {
235 /* translators: %s: Type of post. Usually is the string "post" */
236 printf(__("Send web push on %s publish", 'mailin'), $post_type);
237 }
238 ?>
239 <span class="new-sticker"><?php _e('New', 'mailin') ?></span>
240 </strong>
241 </label>
242 <span class="spinner" style="float: none; margin: 0;"></span>
243 <span style="display: none;" class="sib_push_activating_message"><?php _e('Please wait a few seconds...', 'mailin') ?></span>
244 </p>
245 </div>
246 <?php endif; ?>
247 <div id="sib_push_editor">
248 <input type="hidden" name="sib_push_meta_box_present" value="true"/>
249 <?php if ($notification_already_sent) : ?>
250 <input type="hidden" name="sib_push_notification_already_sent" value="true"/>
251 <?php endif; ?>
252 <label>
253 <input type="checkbox" name="send_sib_push_notification" value="true" <?php if ($send_notification) {
254 echo "checked";
255 } ?> />
256 <strong>
257 <?php if ($post->post_status == "publish") {
258 /* translators: %s: Type of post. Usually is the string "post" */
259 printf(__("Send web push on %s update", 'mailin'), $post_type);
260 } else {
261 /* translators: %s: Type of post. Usually is the string "post" */
262 printf(__("Send web push on %s publish", 'mailin'), $post_type);
263 }
264 ?>
265 </strong>
266 </label>
267 <div class="sib_push_audience">
268 <h3 style="margin-bottom: 3px;"><?php echo __('Target audience', 'mailin') ?></h3>
269 <label>
270 <input
271 type="radio"
272 name="sib_push_audience"
273 value="all"
274 <?php echo $sib_push_audience === 'all' ? 'checked' : '' ?>
275 />
276 <?php echo __('Everybody', 'mailin') ?>
277 </label>
278 <div class="sib_push_all">
279 <div class="sib_push_target" style="padding: 0">
280 <input type="hidden" name="sib_push_target_segment_ids[]" value="@ALL" />
281 </div>
282 </div>
283 <label>
284 <input
285 type="radio"
286 name="sib_push_audience"
287 value="brevo_segments"
288 <?php echo $sib_push_audience === 'brevo_segments' ? 'checked' : '' ?>
289 />
290 <?php echo __('Users in segment(s)', 'mailin') ?>
291 </label>
292 <div class="sib_push_segments">
293 <div class="sib_push_target">
294 <label for="sib_push_target_brevo_segment_ids"><?php echo __("We'll notify users that match at least one of these segments:", 'mailin') ?></label>
295 <?php if ($contactSyncMessage): ?>
296 <p style="padding: 8px; background-color: #fdf5f1; border-radius: 12px;"><?php echo $contactSyncMessage; ?></p>
297 <?php endif; ?>
298 <select name="sib_push_target_brevo_segment_ids[]" multiple
299 id="sib_push_target_brevo_segment_ids"
300 class="sib_push_target_segment_id sib_push_select2">
301 <option value=""><?php echo __("Everyone", 'mailin') ?></option>
302 <?php
303 foreach ($all_brevo_segments as $segment) {
304 ?>
305 <option
306 <?php echo array_search($segment['id'], $target_brevo_segment_ids) !== false ? 'selected="selected"' : '' ?>
307 value="<?php echo $segment['id'] ?>"><?php echo $segment['segmentName'] ?: $segment['id'] ?></option><?php
308 }
309 ?>
310 </select>
311 </div>
312 </div>
313 <label>
314 <input
315 type="radio"
316 name="sib_push_audience"
317 value="brevo_lists"
318 <?php echo $sib_push_audience === 'brevo_lists' ? 'checked' : '' ?>
319 />
320 <?php echo __("Users in list(s)", 'mailin') ?>
321 </label>
322 <div class="sib_push_lists">
323 <div class="sib_push_target">
324 <?php if ($contactSyncMessage): ?>
325 <p style="padding: 8px; background-color: #fdf5f1; border-radius: 12px;"><?php echo $contactSyncMessage; ?></p>
326 <?php endif; ?>
327 <label for="sib_push_target_brevo_list_ids"><?php echo __("We'll notify users that match at least one of these lists:", 'mailin') ?></label>
328 <select name="sib_push_target_brevo_list_ids[]" multiple
329 id="sib_push_target_brevo_list_ids"
330 class="sib_push_target_list_id sib_push_select2">
331 <option value=""><?php echo __("Everyone", 'mailin') ?></option>
332 <?php
333 foreach ($all_brevo_lists as $list) {
334 ?>
335 <option
336 <?php echo array_search($list['id'], $target_brevo_list_ids) !== false ? 'selected="selected"' : '' ?>
337 value="<?php echo $list['id'] ?>"><?php echo $list['name'] ?: $list['id'] ?></option><?php
338 }
339 ?>
340 </select>
341 </div>
342 </div>
343 <label>
344 <input
345 type="radio"
346 name="sib_push_audience"
347 value="tags"
348 <?php echo $sib_push_audience === 'tags' ? 'checked' : '' ?>
349 />
350 <?php echo __("Users with tag(s)", 'mailin') ?>
351 </label>
352 <div class="sib_push_tags">
353 <div class="sib_push_target">
354 <label for="sib_push_target_tags"><?php echo __("We'll notify users that match at least one of these tags:", 'mailin') ?></label>
355 <select name="sib_push_target_tags[]" multiple
356 id="sib_push_target_tags"
357 class="sib_push_target_tags sib_push_select2">
358 <?php
359 foreach ($all_tags as $tag) {
360 ?>
361 <option
362 <?php echo array_search($tag, $target_tags) !== false ? 'selected="selected"' : '' ?>
363 value="<?php echo $tag ?>"><?php echo $tag ?></option><?php
364 }
365 ?>
366 </select>
367 </div>
368 </div>
369 </div>
370 <?php if ($all_brevo_segments) : ?>
371 <?php endif; ?>
372 <h3 style="margin-bottom: 3px;"><?php echo __("Send later", 'mailin') ?></h3>
373 <small><?php echo __("Delay the notification after this post gets published:", 'mailin') ?></small>
374 <br/>
375 <select name="sib_push_send_notification_delay_seconds">
376 <option value="0"><?php echo __("No delay", 'mailin') ?></option>
377 <?php foreach ($minutes as $minute): ?>
378 <option
379 <?php echo (($minute * 60) === $send_notification_delay_seconds ? 'selected="selected"' : '') ?>
380 value="<?php echo $minute * 60 ?>">
381 <?php echo $minute ?> <?php echo __("minutes", 'mailin') ?>
382 </option>
383 <?php endforeach; ?>
384 <?php foreach ($hours as $hour): ?>
385 <option
386 <?php echo (($hour * 3600) === $send_notification_delay_seconds ? 'selected="selected"' : '') ?>
387 value="<?php echo $hour * 3600 ?>">
388 <?php echo $hour ?><?php echo _n("hour", "hours", $hour, 'mailin') ?>
389 </option>
390 <?php endforeach; ?>
391 </select>
392 <h3 style="margin-bottom: 3px;"><?php echo __("Google campaign parameters", 'mailin') ?></h3>
393 <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>
394 <div class="sib_push_utm_parameters">
395 <?php foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter): ?>
396 <?php $id = 'sib_push_'. $utm_parameter; ?>
397 <div class="sib_push_utm">
398 <label for="<?php echo $id; ?>"><?php echo $utm_parameter; ?>:</label>
399 <input type="text"
400 id="<?php echo $id; ?>" name="<?php echo $id; ?>"
401 value="<?php echo esc_attr(array_key_exists($utm_parameter, $utm_params) ? $utm_params[$utm_parameter] : '') ?>"/>
402 </div>
403 <?php endforeach; ?>
404 </div>
405 </div>
406 <?php
407 }
408 public static function on_save_post($post_id) {
409 // Check nonce
410 if (!isset( $_POST[self::SAVE_POST_NONCE_KEY] ) ) {
411 return $post_id;
412 }
413
414 $nonce = $_POST[self::SAVE_POST_NONCE_KEY];
415
416 // Verify nonce
417 if (!wp_verify_nonce($nonce, self::SAVE_POST_NONCE_ACTION)) {
418 return $post_id;
419 }
420
421 if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
422 return $post_id;
423 }
424
425 $sib_push_meta_box_present = array_key_exists('sib_push_meta_box_present', $_POST);
426 update_post_meta($post_id, 'sib_push_meta_box_present', $sib_push_meta_box_present ? true : false);
427
428 if (array_key_exists('send_sib_push_notification', $_POST)) {
429 $notification_already_sent = !!(get_post_meta($post_id, self::POST_META_LAST_NOTIFICATION_CONTENT, true));
430 if (
431 !$notification_already_sent // Notification wasn't sent
432 || ($notification_already_sent && array_key_exists('sib_push_notification_already_sent', $_POST)) // Notification was sent and the UI reflected this
433 ) {
434 update_post_meta($post_id, 'sib_push_send_notification', true);
435 }
436 } else {
437 // If meta box present, user explicitely unchecked
438 $sib_push_send_notification = $sib_push_meta_box_present ? '0' : false;
439 update_post_meta($post_id, 'sib_push_send_notification', $sib_push_send_notification);
440 }
441
442 $settings = SIB_Push_Settings::getSettings();
443 if (array_key_exists('sib_push_send_notification_delay_seconds', $_POST)) {
444 $meta_value = trim(sanitize_text_field($_POST['sib_push_send_notification_delay_seconds']));
445 if (SIB_Push_Utils::is_int_string($meta_value) && (int)$meta_value <= self::MAX_NOTIFICATION_DELAY_HOURS * 3600) {
446 update_post_meta($post_id, 'sib_push_send_notification_delay_seconds', (int)$meta_value);
447 }
448 } else {
449 update_post_meta($post_id, 'sib_push_send_notification_delay_seconds', null);
450 }
451
452 if (array_key_exists('sib_push_target_tags', $_POST)) {
453 $meta_values = array_filter(array_map(function($elt) {
454 return trim(sanitize_text_field($elt));
455 }, $_POST['sib_push_target_tags']));
456 update_post_meta($post_id, 'sib_push_target_tags', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
457 } else {
458 update_post_meta($post_id, 'sib_push_target_tags', null);
459 }
460
461 if (array_key_exists('sib_push_target_segment_ids', $_POST)) {
462 $meta_values = array_filter(array_map(function ($elt) {
463 return trim(sanitize_text_field($elt));
464 }, $_POST['sib_push_target_segment_ids']));
465 update_post_meta($post_id, 'sib_push_target_segment_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
466 } else {
467 update_post_meta($post_id, 'sib_push_target_segment_ids', null);
468 }
469
470 if (array_key_exists('sib_push_target_brevo_segment_ids', $_POST)) {
471 $meta_values = array_filter(array_map(function ($elt) {
472 return trim(sanitize_text_field($elt));
473 }, $_POST['sib_push_target_brevo_segment_ids']));
474 update_post_meta($post_id, 'sib_push_target_brevo_segment_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
475 } else {
476 update_post_meta($post_id, 'sib_push_target_brevo_segment_ids', null);
477 }
478
479 if (array_key_exists('sib_push_target_brevo_list_ids', $_POST)) {
480 $meta_values = array_filter(array_map(function ($elt) {
481 return trim(sanitize_text_field($elt));
482 }, $_POST['sib_push_target_brevo_list_ids']));
483 update_post_meta($post_id, 'sib_push_target_brevo_list_ids', count($meta_values) ? implode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_values) : null);
484 } else {
485 update_post_meta($post_id, 'sib_push_target_brevo_list_ids', null);
486 }
487
488 foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter) {
489 $key = "sib_push_$utm_parameter";
490 if (array_key_exists($key, $_POST)) {
491 $meta_value = trim(sanitize_text_field($_POST[$key]));
492 update_post_meta($post_id, $key, $meta_value && strlen($meta_value) ? $meta_value : null);
493 }
494 }
495 }
496
497 public static function on_transition_post_status( $new_status, $old_status, $post ) {
498 if ($old_status === 'trash' && $new_status === 'publish') {
499 return;
500 }
501 if (!empty($post)
502 && $new_status === "publish"
503 && get_post_status($post->ID) === "publish"
504 && $post->post_type !== 'page') {
505 self::send_notification_on_post($new_status, $old_status, $post);
506 }
507 }
508
509 public static function send_notification_on_post($new_status, $old_status, $post) {
510 try {
511 if (!SIB_Push_Utils::is_push_active()) return;
512 if (!SIB_Push_Utils::is_curl_installed()) {
513 return;
514 }
515 $settings = SIB_Push_Settings::getSettings();
516 $credentials = $settings->getWonderPushCredentials();
517 if (!$credentials || $settings->getDisableSendOnPublish()) return;
518
519 // quirk of Gutenberg editor leads to two passes if meta box is added
520 // conditional removes first pass
521 if( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
522 return;
523 }
524
525 // Returns true if there is POST data
526 $was_posted = !empty($_POST);
527
528 // When this post was created or updated, the meta box in the WordPress post editor screen was visible
529 $sib_push_meta_box_present = $was_posted && array_key_exists('sib_push_meta_box_present', $_POST) && $_POST['sib_push_meta_box_present'] === 'true';
530
531 // The checkbox "Send notification on post publish/update" on the meta box is checked
532 $sib_push_meta_box_send_notification_checked = $was_posted && array_key_exists('send_sib_push_notification', $_POST) && $_POST['send_sib_push_notification'] === 'true';
533
534 // The notification date was filled
535 $sib_push_meta_send_notification_delay_seconds = null;
536 if ($was_posted && array_key_exists('sib_push_send_notification_delay_seconds', $_POST)) {
537 $meta_value = trim(sanitize_text_field($_POST['sib_push_send_notification_delay_seconds']));
538 if (SIB_Push_Utils::is_int_string($meta_value) && (int)$meta_value < self::MAX_NOTIFICATION_DELAY_HOURS * 3600) {
539 $sib_push_meta_send_notification_delay_seconds = (int)$meta_value;
540 }
541 }
542
543 // Target WonderPush segment IDs - This is REQUIRED to handle @ALL
544 // We currently will store "@ALL" in the `sib_push_target_segment_ids` key of the postmeta
545 $target_segment_ids = array();
546 if ($was_posted && array_key_exists('sib_push_target_segment_ids', $_POST)) {
547 $target_segment_ids = array_filter(array_map(function($elt) {
548 return trim(sanitize_text_field($elt));
549 }, $_POST['sib_push_target_segment_ids']));
550 } else {
551 $meta_value = get_post_meta($post->ID, 'sib_push_target_segment_ids', true) ?: '';
552 $target_segment_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
553 }
554
555 // Target Brevo segment IDs
556 $target_brevo_segment_ids = array();
557
558 if ($was_posted && array_key_exists('sib_push_target_brevo_segment_ids', $_POST)) {
559 $target_brevo_segment_ids = array_filter(array_map(function($elt) {
560 return trim(sanitize_text_field($elt));
561 }, $_POST['sib_push_target_brevo_segment_ids']));
562 } else {
563 $meta_value = get_post_meta($post->ID, 'sib_push_target_brevo_segment_ids', true) ?: '';
564 $target_brevo_segment_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
565 }
566
567 // Target Brevo list IDs
568 $target_brevo_list_ids = array();
569
570 if ($was_posted && array_key_exists('sib_push_target_brevo_list_ids', $_POST)) {
571 $target_brevo_list_ids = array_filter(array_map(function($elt) {
572 return trim(sanitize_text_field($elt));
573 }, $_POST['sib_push_target_brevo_list_ids']));
574 } else {
575 $meta_value = get_post_meta($post->ID, 'sib_push_target_brevo_list_ids', true) ?: '';
576 $target_brevo_list_ids = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
577 }
578
579 // Target tags
580 $target_tags = array();
581 if ($was_posted && array_key_exists('sib_push_target_tags', $_POST)) {
582 $target_tags = array_filter(array_map(function($elt) {
583 return trim(sanitize_text_field($elt));
584 }, $_POST['sib_push_target_tags']));
585 } else {
586 $meta_value = get_post_meta($post->ID, 'sib_push_target_tags', true) ?: '';
587 $target_tags = array_filter(explode(self::METADATA_MULTIVALUE_SEPARATOR, $meta_value));
588 }
589
590 // utm parameters
591 $utm_params = array();
592 foreach (SIB_Push_Utils::utm_parameters() as $utm_parameter) {
593 $value = null;
594 $key = "sib_push_$utm_parameter";
595 if ($was_posted) {
596 if (array_key_exists($key, $_POST)) {
597 $value = $_POST[$key];
598 }
599 } else {
600 $value = get_post_meta($post->ID, $key, true);
601 }
602 $value = $value ? trim(sanitize_text_field($value)) : $value;
603 $value = $value && strlen($value) > 256 ? substr($value, 0, 256) : $value;
604 $value = $value && strlen($value) ? $value : null;
605 if ($value) $utm_params[$utm_parameter] = $value;
606 }
607 // This is a scheduled post and the meta box was present.
608 $post_metadata_was_sib_push_meta_box_present = (get_post_meta($post->ID, 'sib_push_meta_box_present', true) == true);
609
610 // This is a scheduled post and the user checked "Send a notification on post publish/update".
611 $post_metadata_was_send_notification_checked = (get_post_meta($post->ID, 'sib_push_send_notification', true) == true);
612
613 // This is a scheduled post and the user filled notification delay
614 $post_metadata_send_notification_delay_seconds = get_post_meta($post->ID, 'sib_push_send_notification_delay_seconds', true);
615 if ($post_metadata_send_notification_delay_seconds === null
616 || $post_metadata_send_notification_delay_seconds === '') {
617 // Backwards compat: set this to the settings value for those who saved the post with a previous version of the plugin
618 // The current plugin version always sets a $post_metadata_send_notification_delay_seconds
619 $post_metadata_send_notification_delay_seconds = $settings->getDeliveryTimeSeconds();
620 }
621 $post_metadata_send_notification_delay_seconds = (int)$post_metadata_send_notification_delay_seconds;
622
623 // 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
624 $posted_from_wordpress_editor = $sib_push_meta_box_present || $post_metadata_was_sib_push_meta_box_present;
625
626 $last_sent_title = get_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_CONTENT, true);
627
628 $send_notification_delay_seconds = null;
629
630 $settings_send_notification_on_non_editor_post_publish = $settings->getSendOnThirdPartyPublish();
631 $additional_custom_post_types_string = str_replace(' ', '', $settings->getAdditionalCustomPostTypes() ?: '');
632 $additional_custom_post_types_array = array_filter(explode(',', $additional_custom_post_types_string));
633 $non_editor_post_publish_do_send_notification = $settings_send_notification_on_non_editor_post_publish &&
634 ($post->post_type === 'post' || in_array($post->post_type, $additional_custom_post_types_array, true)) &&
635 $old_status !== 'publish';
636
637 if ($posted_from_wordpress_editor) {
638 $do_send_notification = ($was_posted && $sib_push_meta_box_send_notification_checked) ||
639 (!$was_posted && $post_metadata_was_send_notification_checked);
640
641 if ($was_posted) {
642 // When posting and the notification has already been sent, make sure the 'sib_push_notification_already_sent' key was sent along
643 // Otherwise, this may be a page that wasn't refreshed as the post was published in the background.
644 if ($last_sent_title && !array_key_exists('sib_push_notification_already_sent', $_POST)) {
645 $do_send_notification = false;
646 }
647
648 $send_notification_delay_seconds = $sib_push_meta_send_notification_delay_seconds;
649 } else {
650 $send_notification_delay_seconds = $post_metadata_send_notification_delay_seconds;
651 }
652 } else {
653 // This was not submitted via the WordPress editor
654 $do_send_notification = $non_editor_post_publish_do_send_notification;
655 }
656
657 if (!$do_send_notification) return;
658
659 // Create WonderPush client
660 $management_api_client = SIB_Push_Utils::management_api_client($credentials);
661 $default_target_segment_id = $settings->getDefaultTargetSegmentId();
662 $default_target_list_id = $settings->getDefaultTargetListId();
663
664 update_post_meta($post->ID, 'sib_push_meta_box_present', false);
665 update_post_meta($post->ID, 'sib_push_send_notification', false);
666
667 // Some WordPress environments seem to be inconsistent about whether on_save_post is called before transition_post_status
668 // 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
669 // We remove all related $_POST data to prevent this
670 if ($was_posted) {
671 if (array_key_exists('sib_push_meta_box_present', $_POST)) {
672 unset($_POST['sib_push_meta_box_present']);
673 }
674 if (array_key_exists('send_sib_push_notification', $_POST)) {
675 unset($_POST['send_sib_push_notification']);
676 }
677 }
678
679 $title = SIB_Push_Utils::decode_entities(get_the_title($post->ID));
680
681 $site_title = "";
682 if ($settings->getNotificationTitle()) {
683 $site_title = SIB_Push_Utils::decode_entities($settings->getNotificationTitle());
684 } else {
685 $site_title = SIB_Push_Utils::decode_entities(get_bloginfo('name'));
686 }
687
688 $icon_image = null;
689 $big_picture = null;
690 if (has_post_thumbnail($post->ID)) {
691
692 $post_thumbnail_id = get_post_thumbnail_id($post->ID);
693
694 // Higher resolution (2x retina, + a little more) for the notification small icon
695 $thumbnail_sized_images_array = wp_get_attachment_image_src($post_thumbnail_id, 'medium', false);
696 $thumbnail_image = $thumbnail_sized_images_array && count($thumbnail_sized_images_array) > 0 ? $thumbnail_sized_images_array[0] : null;
697
698 // Much higher resolution for the notification large image
699 $large_sized_images_array = wp_get_attachment_image_src($post_thumbnail_id, 'large', false);
700 $large_image = $large_sized_images_array && count($large_sized_images_array) > 0 ? $large_sized_images_array[0] : null;
701
702 $config_use_featured_image_as_icon = !($settings->getDisableUsePostImageForNotification());
703 $config_use_featured_image_as_image = !($settings->getDisableUsePostImageForNotification());
704 $use_large_image = $settings->getPreferLargeImageForNotification();
705
706 // Use the same image in any case
707 $image = $use_large_image ? ($large_image ?: $thumbnail_image) : ($thumbnail_image ?: $large_image);
708
709 // WPRocket support
710 if ( function_exists( 'get_rocket_cdn_url' ) && $image ) {
711 try {
712 $rocket_url = get_rocket_cdn_url($image);
713 if ($rocket_url) {
714 $image = $rocket_url;
715 }
716 } catch (Exception $e) {
717 SIB_Push_Utils::log_warn('Rocket cdn function get_rocket_cdn_url threw', $e);
718 }
719 }
720
721 if ($config_use_featured_image_as_icon) {
722 $icon_image = $image;
723 }
724 if ($config_use_featured_image_as_image) {
725 $big_picture = $image;
726 }
727 }
728
729 // Send the notification
730 $notification = new \WonderPush\Obj\Notification();
731 $alert = new \WonderPush\Obj\NotificationAlert();
732 $notification->setAlert($alert);
733 $permalink = get_permalink($post->ID);
734 $target_url = SIB_Push_Utils::inject_query_string_params($permalink, $utm_params);
735 $alert->setTargetUrl($target_url);
736 $alert->setTitle($site_title);
737 $alert->setText($title);
738
739 // Android
740 $android = new \WonderPush\Obj\NotificationAlertAndroid();
741 $alert->setAndroid($android);
742 if ($big_picture) {
743 $android->setBigPicture($big_picture);
744 $android->setType('bigPicture');
745 }
746 $ios = new \WonderPush\Obj\NotificationAlertIos();
747 $alert->setIos($ios);
748 if ($big_picture) {
749 $attachment = new \WonderPush\Obj\NotificationAlertIosAttachment();
750 $attachment->setUrl($big_picture);
751 $attachment->setType('image/png'); // Valid for all image types
752 $ios->setAttachments(array($attachment));
753 }
754 $ios->setSound('default');
755 $web = new \WonderPush\Obj\NotificationAlertWeb();
756 $alert->setWeb($web);
757 if ($icon_image) $web->setIcon($icon_image);
758 if ($big_picture) $web->setImage($big_picture);
759 $params = new \WonderPush\Params\DeliveriesCreateParams();
760 $params->setDeliverySource('brevoWordPressPlugin');
761 $params->setInheritUrlParameters(true);
762 $params->setNotification($notification);
763 $brevoSegmentIds = array();
764 $brevoListIds = array();
765 $segmentIds = array();
766 if (count($target_tags)) {
767 $params->setTargetTags($target_tags);
768 } else if (count($target_brevo_segment_ids)) {
769 $brevoSegmentIds = $target_brevo_segment_ids;
770 $params->setTargetBrevoSegmentIds( array_map(function ($x) { return (int)$x; }, $brevoSegmentIds) );
771 } else if (count($target_brevo_list_ids)) {
772 $brevoListIds = $target_brevo_list_ids;
773 $params->setTargetBrevoListIds( $target_brevo_list_ids );
774 } else if (count($target_segment_ids)) {
775 $segmentIds = $target_segment_ids;
776 $params->setTargetSegmentIds($segmentIds);
777 } else if ($default_target_segment_id) {
778 $brevoSegmentIds = array($default_target_segment_id);
779 $params->setTargetBrevoSegmentIds( $brevoSegmentIds );
780 } else if ($default_target_list_id) {
781 $brevoListIds = array($default_target_list_id);
782 $params->setTargetBrevoListIds( $brevoListIds );
783 } else {
784 $segmentIds = array('@ALL');
785 $params->setTargetSegmentIds($segmentIds);
786 }
787 if ($send_notification_delay_seconds !== null && $send_notification_delay_seconds > 0) {
788 $params->setDeliveryTime('' . $send_notification_delay_seconds . 's');
789 }
790
791 // Set filterWebDomains if sendOnlyToThisDomain is enabled
792 $settings = SIB_Push_Settings::getSettings();
793 if ($settings->getSendOnlyToThisDomain()) {
794 $current_site_url = home_url();
795 $parsed_current = parse_url($current_site_url);
796 if ($parsed_current) {
797 $current_origin = $parsed_current['scheme'] . '://' . $parsed_current['host'] . (isset($parsed_current['port']) ? (':' . $parsed_current['port']) : '');
798 $params->setFilterWebDomains(array($current_origin));
799 }
800 }
801
802 // Deduplicate notifications
803 $last_sent_timestamp = get_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_TIMESTAMP, true);
804 $elapsed = current_time('timestamp') - ($last_sent_timestamp ? $last_sent_timestamp : 0);
805 if ($elapsed < self::DEDUPLICATION_SECONDS && $last_sent_title === $title) {
806 SIB_Push_Utils::log_debug('Discarding duplicate notification', $params);
807 return;
808 }
809
810 // Rate limit
811 $wait_time = self::get_sending_rate_limit_wait_time();
812 if ($wait_time) {
813 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, 'You must wait ' . $wait_time . 's before sending another notification');
814 return;
815 }
816
817 // Remember last notification content and timestamp
818 update_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_CONTENT, $title);
819 update_post_meta($post->ID, self::POST_META_LAST_NOTIFICATION_TIMESTAMP, current_time('timestamp'));
820
821 // Send the notification
822 SIB_Push_Utils::log_debug('Sending Brevo push notification', $params);
823 self::update_last_sent_timestamp();
824 $response = $management_api_client->deliveries()->create($params);
825
826 // Handle success/failure
827 if ($response->isSuccess()) {
828 if (count($brevoListIds) || count($brevoSegmentIds) || $settings->getDisableFeedbackOnPublish()) {
829 update_post_meta($post->ID, self::POST_META_INFO_MESSAGE, __('Brevo push notification sent.', 'mailin'));
830 } else {
831 // Fetch the number of subscribers
832 try {
833 $countResponse = $management_api_client->installations()->all(array(
834 'limit' => 1,
835 'reachability' => 'optIn',
836 'segmentIds' => $segmentIds,
837 'tags' => $target_tags,
838 ));
839 $count = $countResponse->getCount();
840 if ($count) {
841 if ($send_notification_delay_seconds) {
842 $dt = new DateTime();
843 $dt->setTimestamp($send_notification_delay_seconds + $dt->getTimestamp());
844 $formatted_date = $dt->format(DateTime::RFC850);
845 // translators: %d is the number of subscribers, %s is the date and time
846 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));
847 } else {
848 // translators: %d is the number of subscribers
849 update_post_meta($post->ID, self::POST_META_INFO_MESSAGE, sprintf(__("Brevo notification sent to %d subscribers.", "mailin"), $count));
850 }
851 } else {
852 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, __("Brevo notification sent but the target audience is empty.", "mailin"));
853 }
854 } catch (\WonderPush\Errors\Base $e) {}
855 }
856 } else {
857 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, __("Brevo notification could not be sent.", "mailin"));
858 }
859 } catch (\WonderPush\Errors\Base $e) {
860 switch ($e->getCode()) {
861 default:
862 update_post_meta($post->ID, self::POST_META_ERROR_MESSAGE, $e->getMessage());
863 break;
864 }
865 } catch (Exception $e) {
866 SIB_Push_Utils::log_warn('Caught Exception', $e);
867 }
868 }
869
870 public static function get_sending_rate_limit_wait_time() {
871 $last_send_time = get_option('sib_push.last_send_time');
872 if ($last_send_time) {
873 $current_time = current_time('timestamp');
874 $time_elapsed_since_last_send = self::API_RATE_LIMIT_SECONDS - ($current_time - intval($last_send_time));
875 if ($time_elapsed_since_last_send > 0) {
876 return $time_elapsed_since_last_send;
877 }
878 }
879 return false;
880 }
881
882 /**
883 * Updates the last sent timestamp, used in rate limiting notifications sent more than 1 per minute.
884 */
885 public static function update_last_sent_timestamp() {
886 $current_time = current_time('timestamp');
887 update_option('sib_push.last_send_time', $current_time);
888 }
889
890 }
891
892 }
893