PluginProbe
Friends / 4.3.2
Friends v4.3.2
4.3.2 4.3.1 4.3.0 4.2.2 4.2.1 4.2.0 4.1.0 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.0 2.9.1 All 88 releases
← All changes | includes/class-notifications.php +343 -48 2.8.64.3.2 View file →
@@ -38,14 +38,17 @@
38 38 /**
39 39 * Register the WordPress hooks
40 40 */
41 41 private function register_hooks() {
42 - add_action( 'friends_rewrite_mail_html', array( $this, 'rewrite_mail_html' ) );
43 - add_action( 'notify_new_friend_post', array( $this, 'notify_new_friend_post' ), 10, 2 );
44 - add_filter( 'notify_keyword_match_post', array( $this, 'notify_keyword_match_post' ), 10, 3 );
45 - add_action( 'notify_new_friend_request', array( $this, 'notify_new_friend_request' ) );
46 - add_action( 'notify_accepted_friend_request', array( $this, 'notify_accepted_friend_request' ) );
47 - add_action( 'notify_friend_message_received', array( $this, 'notify_friend_message_received' ), 10, 3 );
42 + add_filter( 'friends_rewrite_mail_html', array( $this, 'rewrite_mail_html' ) );
43 + add_filter( 'friends_rewrite_mail_html', array( $this, 'highlight_keywords' ), 10, 2 );
44 + add_action( 'notify_new_friend_post', array( $this, 'notify_new_friend_post' ), 10, 3 );
45 + add_filter( 'friends_notify_keyword_match_post', array( $this, 'notify_keyword_match_post' ), 10, 3 );
46 + add_action( 'notify_friend_message_received', array( $this, 'notify_friend_message_received' ), 10, 5 );
47 + add_action( 'notify_unknown_friend_message_received', array( $this, 'notify_unknown_friend_message_received' ), 10, 4 );
48 + add_action( 'activitypub_new_follower_email', array( $this, 'activitypub_new_follower_email' ), 10, 3 );
49 + add_action( 'activitypub_followers_post_follow', array( $this, 'activitypub_followers_post_follow' ), 10, 4 );
50 + add_action( 'activitypub_followers_pre_remove_follower', array( $this, 'activitypub_followers_pre_remove_follower' ), 10, 3 );
48 51 }
49 52
50 53 /**
51 54 * Sets the friends plugin from email address when sending mail.
@@ -81,15 +84,18 @@
81 84
82 85 /**
83 86 * Notify the users of this site about a new friend post
84 87 *
85 - * @param \WP_Post $post The new post by a friend or subscription.
86 - * @param User_Feed $user_feed The feed where the post came from.
88 + * @param \WP_Post $post The new post by a friend or subscription.
89 + * @param User_Feed $user_feed The feed where the post came from.
90 + * @param string|false $keyword If a post matched a keyword, the keyword is specified.
87 91 */
88 - public function notify_new_friend_post( \WP_Post $post, User_Feed $user_feed ) {
92 + public function notify_new_friend_post( \WP_Post $post, User_Feed $user_feed, $keyword ) {
89 93 if (
90 94 // Post might be trashed through rules.
91 95 'trash' === $post->post_status
96 + // Don't notify about posts that WordPress scheduled for future publishing.
97 + || 'future' === $post->post_status
92 98 // Don't notify about posts older than a week.
93 99 || strtotime( $post->post_date_gmt ) + WEEK_IN_SECONDS < time()
94 100 ) {
95 101 return;
@@ -94,20 +100,38 @@
94 100 ) {
95 101 return;
96 102 }
97 103 $user = new User( Friends::get_main_friend_user_id() );
104 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
105 + $user->user_email = WP_TESTS_EMAIL;
106 + }
98 107 if ( ! $user->user_email ) {
99 108 return;
100 109 }
101 110 $author = $user_feed->get_friend_user();
102 111
112 + if ( ! get_post_format( $post ) ) {
113 + $post_format = 'standard';
114 + } else {
115 + $post_format = get_post_format( $post );
116 + }
117 +
103 118 $notify_user = ! get_user_option( 'friends_no_new_post_notification', $user->ID );
104 119 $notify_user = $notify_user && ! get_user_option( 'friends_no_new_post_notification_' . $author->user_login, $user->ID );
120 + $notify_user = $notify_user && ! get_user_option( 'friends_no_new_post_format_notification_' . $post_format, $user->ID );
121 + $notify_user = $notify_user && ! get_user_option( 'friends_no_new_post_by_parser_notification_' . $user_feed->get_parser(), $user->ID );
105 122
123 + // If the post would notify anyway and it was a keyword match, notify that way.
124 + if ( $notify_user && $keyword && get_user_option( 'friends_keyword_notification_override_disabled', $user->ID ) ) {
125 + add_filter( 'get_user_option_friends_keyword_notification_override_disabled', '__return_false' );
126 + $this->notify_keyword_match_post( false, $post, $keyword );
127 + remove_filter( 'get_user_option_friends_keyword_notification_override_disabled', '__return_false' );
128 + return;
129 + }
130 +
106 131 if ( ! apply_filters( 'notify_user_about_friend_post', $notify_user, $user, $post, $author ) ) {
107 132 return;
108 133 }
109 -
110 134 $email_title = $post->post_title;
111 135
112 136 $params = array(
113 137 'author' => $author,
@@ -143,18 +167,26 @@
143 167 return $notified;
144 168 }
145 169
146 170 $user = new User( Friends::get_main_friend_user_id() );
171 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
172 + $user->user_email = WP_TESTS_EMAIL;
173 + }
147 174 if ( ! $user->user_email ) {
148 175 return $notified;
149 176 }
150 177 $notify_user = ! get_user_option( 'friends_no_keyword_notification_' . $post->post_author, $user->ID );
178 + // If the override was disabled, don't notify. This could be temporarily disabled later.
151 179
180 + if ( $notify_user && get_user_option( 'friends_keyword_notification_override_disabled', $user->ID ) ) {
181 + return $notified;
182 + }
183 +
152 184 if ( ! apply_filters( 'notify_user_about_keyword_post', $notify_user, $user, $post, $keyword ) ) {
153 185 return $notified;
154 186 }
155 187
156 - $author = new User( $post->post_author );
188 + $author = User::get_post_author( $post );
157 189 // translators: %s is a keyword string specified by the user.
158 190 $email_title = sprintf( __( 'Keyword matched: %s', 'friends' ), $keyword );
159 191
160 192 $params = array(
@@ -182,45 +214,50 @@
182 214 return true;
183 215 }
184 216
185 217 /**
186 - * Notify the users of this site about a new friend request
218 + * Notify the users of this site about a received message
187 219 *
188 - * @param User $friend_user The user requesting friendship.
220 + * @param User $friend_user The user who sent the message.
221 + * @param string $message The message.
222 + * @param string $subject The subject.
223 + * @param string $_feed_url The feed URL.
224 + * @param string $remote_url The remote message URL.
189 225 */
190 - public function notify_new_friend_request( User $friend_user ) {
191 - if ( ! $friend_user->has_cap( 'friend_request' ) ) {
192 - return;
226 + public function notify_friend_message_received( User $friend_user, $message, $subject, $_feed_url = null, $remote_url = null ) {
227 + $user = new User( Friends::get_main_friend_user_id() );
228 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
229 + $user->user_email = WP_TESTS_EMAIL;
193 230 }
194 - $user = new User( Friends::get_main_friend_user_id() );
195 -
196 231 if ( ! $user->user_email ) {
197 232 return;
198 233 }
199 234
200 - $notify_user = ! get_user_option( 'friends_no_friend_request_notification', $user->ID );
201 - if ( ! apply_filters( 'notify_user_about_friend_request', $notify_user, $user, $friend_user ) ) {
235 + if ( ! apply_filters( 'notify_user_about_friend_message', true, $user, $friend_user ) ) {
202 236 return;
203 237 }
204 238
205 239 // translators: %s is a user display name.
206 - $email_title = sprintf( __( '%s sent a Friend Request', 'friends' ), $friend_user->display_name );
240 + $email_title = sprintf( __( '%s sent you a message', 'friends' ), $friend_user->display_name );
207 241
208 242 $params = array(
209 243 'user' => $user,
210 244 'friend_user' => $friend_user,
245 + 'subject' => $subject,
246 + 'message' => $message,
247 + 'message_url' => $this->get_friend_message_url( $friend_user, $remote_url ),
211 248 );
212 249
213 250 $email_message = array();
214 251 ob_start();
215 252 Friends::template_loader()->get_template_part( 'email/header', null, array( 'email_title' => $email_title ) );
216 - Friends::template_loader()->get_template_part( 'email/new-friend-request', null, $params );
253 + Friends::template_loader()->get_template_part( 'email/friend-message-received', null, $params );
217 254 Friends::template_loader()->get_template_part( 'email/footer' );
218 255 $email_message['html'] = ob_get_contents();
219 256 ob_end_clean();
220 257
221 258 ob_start();
222 - Friends::template_loader()->get_template_part( 'email/new-friend-request-text', null, $params );
259 + Friends::template_loader()->get_template_part( 'email/friend-message-received-text', null, $params );
223 260 Friends::template_loader()->get_template_part( 'email/footer-text' );
224 261 $email_message['text'] = ob_get_contents();
225 262 ob_end_clean();
226 263
@@ -227,40 +264,88 @@
227 264 $this->send_mail( $user->user_email, $email_title, $email_message );
228 265 }
229 266
230 267 /**
231 - * Notify the users of this site about an accepted friend request
268 + * Get the URL for replying to a received direct message.
232 269 *
233 - * @param User $friend_user The user who accepted friendship.
270 + * @param User $friend_user The message sender.
271 + * @param string|null $remote_url The remote ActivityPub message URL.
272 + * @return string The reply URL.
234 273 */
235 - public function notify_accepted_friend_request( User $friend_user ) {
274 + private function get_friend_message_url( User $friend_user, $remote_url = null ) {
275 + if ( $remote_url ) {
276 + add_filter( 'friends_frontend_post_types', array( $this, 'friends_frontend_post_types_only_messages' ), 999 );
277 + $message_id = Feed::url_to_postid( $remote_url );
278 + remove_filter( 'friends_frontend_post_types', array( $this, 'friends_frontend_post_types_only_messages' ), 999 );
279 +
280 + if ( $message_id ) {
281 + $message = get_post( $message_id );
282 + if ( $message ) {
283 + while ( $message && $message->post_parent ) {
284 + $message = get_post( $message->post_parent );
285 + }
286 +
287 + if ( $message ) {
288 + return add_query_arg( 'conversation', $message->ID, home_url( '/friends/messages/' ) );
289 + }
290 + }
291 + }
292 + }
293 +
294 + return $friend_user->get_local_friends_page_url();
295 + }
296 +
297 + /**
298 + * Limit frontend post type lookups to messages.
299 + *
300 + * @return array The message post type.
301 + */
302 + public function friends_frontend_post_types_only_messages() {
303 + return array( Messages::CPT );
304 + }
305 +
306 + /**
307 + * Notify the users of this site about a received message
308 + *
309 + * @param string $sender_name The user who sent the message.
310 + * @param string $message The message.
311 + * @param string $subject The subject.
312 + * @param string $feed_url The url of the user who sent the message.
313 + */
314 + public function notify_unknown_friend_message_received( $sender_name, $message, $subject, $feed_url ) {
236 315 $user = new User( Friends::get_main_friend_user_id() );
316 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
317 + $user->user_email = WP_TESTS_EMAIL;
318 + }
237 319 if ( ! $user->user_email ) {
238 320 return;
239 321 }
240 322
241 - if ( ! apply_filters( 'notify_user_about_accepted_friend_request', true, $user, $friend_user ) ) {
323 + if ( ! apply_filters( 'notify_user_about_friend_message', true, $user ) ) {
242 324 return;
243 325 }
244 326
245 327 // translators: %s is a user display name.
246 - $email_title = sprintf( __( '%s accepted your Friend Request', 'friends' ), $friend_user->display_name );
328 + $email_title = sprintf( __( '%s sent you a message', 'friends' ), $sender_name );
247 329
248 330 $params = array(
249 331 'user' => $user,
250 - 'friend_user' => $friend_user,
332 + 'sender_name' => $sender_name,
333 + 'feed_url' => $feed_url,
334 + 'subject' => $subject,
335 + 'message' => $message,
251 336 );
252 337
253 338 $email_message = array();
254 339 ob_start();
255 340 Friends::template_loader()->get_template_part( 'email/header', null, array( 'email_title' => $email_title ) );
256 - Friends::template_loader()->get_template_part( 'email/accepted-friend-request', null, $params );
341 + Friends::template_loader()->get_template_part( 'email/unknown-friend-message-received', null, $params );
257 342 Friends::template_loader()->get_template_part( 'email/footer' );
258 343 $email_message['html'] = ob_get_contents();
259 344 ob_end_clean();
260 345
261 346 ob_start();
262 - Friends::template_loader()->get_template_part( 'email/accepted-friend-request-text', null, $params );
347 + Friends::template_loader()->get_template_part( 'email/unknown-friend-message-received-text', null, $params );
263 348 Friends::template_loader()->get_template_part( 'email/footer-text' );
264 349 $email_message['text'] = ob_get_contents();
265 350 ob_end_clean();
266 351
@@ -267,50 +352,122 @@
267 352 $this->send_mail( $user->user_email, $email_title, $email_message );
268 353 }
269 354
270 355 /**
271 - * Notify the users of this site about a received message
356 + * Augment the ActivityPub new follower e-mail
272 357 *
273 - * @param User $friend_user The user who sent the message.
358 + * @param array $actor The actor.
274 359 */
360 + public function activitypub_new_follower_email( $actor ) {
361 + if ( isset( $actor['id'] ) ) {
362 + $url = $actor['id'];
363 + } elseif ( isset( $actor['url'] ) ) {
364 + $url = $actor['url'];
365 + } else {
366 + return;
367 + }
275 368
369 + $url = \ActivityPub\object_to_uri( $url );
370 + $server = wp_parse_url( $url, PHP_URL_HOST );
371 + $following = User_Feed::get_by_url( $url );
372 + if ( ! $following || is_wp_error( $following ) ) {
373 + $following = User_Feed::get_by_url( str_replace( '/users/', '/@', $url ) );
374 + }
375 + if ( $following && ! is_wp_error( $following ) ) {
376 + $following = $following->get_friend_user();
377 + } else {
378 + $following = false;
379 + }
380 + echo '<p>';
381 + if ( $following ) {
382 + echo esc_html__( 'You are already following them!', 'friends' );
383 + echo ' ';
384 + // translators: %s is a URL.
385 + echo wp_kses( sprintf( __( 'Go to their <a href="%s">friends page</a> to see what they recently posted about.', 'friends' ), esc_url( $following->get_local_friends_page_url() ) ), array( 'a' => array( 'href' => array() ) ) );
386 + } else {
387 + // translators: %s is a URL.
388 + echo wp_kses( sprintf( __( 'Maybe you want to <a href="%s">follow them back</a> using the Friends plugin?', 'friends' ), esc_url( add_query_arg( 'url', $url, admin_url( 'admin.php?page=add-friend' ) ) ) ), array( 'a' => array( 'href' => array() ) ) );
389 + }
390 + echo '</p>';
391 + }
392 +
276 393 /**
277 - * Notify the users of this site about a received message
394 + * Notify of a follower
278 395 *
279 - * @param User $friend_user The user who sent the message.
280 - * @param string $message The message.
281 - * @param string $subject The subject.
396 + * @param string $actor The Actor URL.
397 + * @param array $activitypub_object The Activity object.
398 + * @param int $user_id The ID of the WordPress User.
399 + * @param \WP_Post|\Activitypub\Activity\Actor $follower The Actor post (since ActivityPub 7.5.0) or Actor object.
400 + *
401 + * @return void
282 402 */
283 - public function notify_friend_message_received( User $friend_user, $message, $subject ) {
284 - $user = new User( Friends::get_main_friend_user_id() );
403 + public function activitypub_followers_post_follow( $actor, $activitypub_object, $user_id, $follower ) {
404 + if ( ! get_user_option( 'friends_no_friend_follower_notification', $user_id ) ) {
405 + return;
406 + }
407 + $user = new User( $user_id );
408 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
409 + $user->user_email = WP_TESTS_EMAIL;
410 + }
285 411 if ( ! $user->user_email ) {
286 412 return;
287 413 }
288 414
289 - if ( ! apply_filters( 'notify_user_about_friend_message', true, $user, $friend_user ) ) {
415 + if ( is_wp_error( $follower ) ) {
290 416 return;
291 417 }
292 418
419 + $follower_post = null;
420 + if ( $follower instanceof \WP_Post ) {
421 + $follower_post = $follower;
422 + $follower = \Activitypub\Collection\Remote_Actors::get_actor( $follower_post );
423 + if ( is_wp_error( $follower ) ) {
424 + return;
425 + }
426 + }
427 +
428 + if ( ! apply_filters( 'notify_user_about_new_follower', true, $user, $actor, $activitypub_object, $follower ) ) {
429 + return;
430 + }
431 +
432 + $url = \ActivityPub\object_to_uri( $follower->get( 'id' ) );
433 + $server = wp_parse_url( $url, PHP_URL_HOST );
434 + $following = User_Feed::get_by_url( $url );
435 + if ( ! $following || is_wp_error( $following ) ) {
436 + $following = User_Feed::get_by_url( $follower->get_url() );
437 + }
438 + if ( $following && ! is_wp_error( $following ) ) {
439 + $following = $following->get_friend_user();
440 + } else {
441 + $following = false;
442 + }
443 +
444 + $icon_url = $follower_post
445 + ? \Activitypub\Collection\Remote_Actors::get_avatar_url( $follower_post->ID )
446 + : \ActivityPub\object_to_uri( $follower->get_icon() );
447 +
293 448 // translators: %s is a user display name.
294 - $email_title = sprintf( __( '%s sent you a message', 'friends' ), $friend_user->display_name );
449 + $email_title = sprintf( __( 'New Follower: %s', 'friends' ), $follower->get_name() . '@' . $server );
295 450
296 451 $params = array(
297 - 'user' => $user,
298 - 'friend_user' => $friend_user,
299 - 'subject' => $subject,
300 - 'message' => $message,
452 + 'user' => $user,
453 + 'url' => $url,
454 + 'follower' => $follower,
455 + 'icon_url' => $icon_url,
456 + 'server' => $server,
457 + 'following' => $following,
301 458 );
302 459
303 460 $email_message = array();
304 461 ob_start();
305 462 Friends::template_loader()->get_template_part( 'email/header', null, array( 'email_title' => $email_title ) );
306 - Friends::template_loader()->get_template_part( 'email/friend-message-received', null, $params );
463 + Friends::template_loader()->get_template_part( 'email/new-follower', null, $params );
307 464 Friends::template_loader()->get_template_part( 'email/footer' );
308 465 $email_message['html'] = ob_get_contents();
309 466 ob_end_clean();
310 467
311 468 ob_start();
312 - Friends::template_loader()->get_template_part( 'email/friend-message-received-text', null, $params );
469 + Friends::template_loader()->get_template_part( 'email/new-follower-text', null, $params );
313 470 Friends::template_loader()->get_template_part( 'email/footer-text' );
314 471 $email_message['text'] = ob_get_contents();
315 472 ob_end_clean();
316 473
@@ -317,8 +474,91 @@
317 474 $this->send_mail( $user->user_email, $email_title, $email_message );
318 475 }
319 476
320 477 /**
478 + * Notify of a lost follower
479 + *
480 + * @param \WP_Post|\Activitypub\Activity\Actor $follower The Actor post (since ActivityPub 7.5.0) or Actor object.
481 + * @param int $user_id The ID of the WordPress User.
482 + * @param string|\Activitypub\Activity\Actor $actor The Actor URL or Actor object.
483 + *
484 + * @return void
485 + */
486 + public function activitypub_followers_pre_remove_follower( $follower, $user_id, $actor ) {
487 + if ( ! get_user_option( 'friends_no_friend_follower_notification', $user_id ) ) {
488 + return;
489 + }
490 + $user = new User( $user_id );
491 + if ( defined( 'WP_TESTS_EMAIL' ) ) {
492 + $user->user_email = WP_TESTS_EMAIL;
493 + }
494 + if ( ! $user->user_email ) {
495 + return;
496 + }
497 +
498 + $follower_post = null;
499 + $published = null;
500 + if ( $follower instanceof \WP_Post ) {
501 + $follower_post = $follower;
502 + $published = $follower_post->post_date_gmt;
503 + if ( $actor instanceof \Activitypub\Activity\Actor ) {
504 + $follower = $actor;
505 + } else {
506 + $follower = \Activitypub\Collection\Remote_Actors::get_actor( $follower_post );
507 + if ( is_wp_error( $follower ) ) {
508 + return;
509 + }
510 + }
511 + } else {
512 + $published = $follower->get_published();
513 + }
514 +
515 + if ( ! apply_filters( 'notify_user_about_lost_follower', true, $user, $actor, $follower ) ) {
516 + return;
517 + }
518 +
519 + $url = \ActivityPub\object_to_uri( $follower->get( 'id' ) );
520 + $server = wp_parse_url( $url, PHP_URL_HOST );
521 +
522 + $icon_url = $follower_post
523 + ? \Activitypub\Collection\Remote_Actors::get_avatar_url( $follower_post->ID )
524 + : \ActivityPub\object_to_uri( $follower->get_icon() );
525 +
526 + // translators: %s is a user display name.
527 + $email_title = sprintf( __( 'Lost Follower: %s', 'friends' ), $follower->get_name() . '@' . $server );
528 +
529 + $params = array(
530 + 'user' => $user,
531 + 'url' => $url,
532 + 'follower' => $follower,
533 + 'icon_url' => $icon_url,
534 + 'server' => $server,
535 + 'duration' => human_time_diff( strtotime( $published ) ) . ' (' . sprintf(
536 + // translators: %s is a time duration.
537 + __( 'since %s', 'friends' ),
538 + $published
539 + ) . ')',
540 +
541 + );
542 +
543 + $email_message = array();
544 + ob_start();
545 + Friends::template_loader()->get_template_part( 'email/header', null, array( 'email_title' => $email_title ) );
546 + Friends::template_loader()->get_template_part( 'email/lost-follower', null, $params );
547 + Friends::template_loader()->get_template_part( 'email/footer' );
548 + $email_message['html'] = ob_get_contents();
549 + ob_end_clean();
550 +
551 + ob_start();
552 + Friends::template_loader()->get_template_part( 'email/lost-follower-text', null, $params );
553 + Friends::template_loader()->get_template_part( 'email/footer-text' );
554 + $email_message['text'] = ob_get_contents();
555 + ob_end_clean();
556 +
557 + $this->send_mail( $user->user_email, $email_title, $email_message );
558 + }
559 +
560 + /**
321 561 * Rewrite HTML for e-mail (by inlining some CSS styles)
322 562 *
323 563 * @param string $html The HTML.
324 564 *
@@ -331,8 +571,63 @@
331 571 $html = preg_replace( '/(' . $img_regex . '.*?)height=[\'"]\d+[\'"]/i', '$1', $html );
332 572 return $html;
333 573 }
334 574
575 + public function highlight_keywords( $the_content, $args ) {
576 + if ( ! isset( $args['keyword'] ) ) {
577 + return $the_content;
578 + }
579 +
580 + $tag_stack = array();
581 + $protected_tags = array(
582 + 'pre',
583 + 'code',
584 + 'textarea',
585 + 'style',
586 + );
587 + $new_content = '';
588 + $in_protected_tag = false;
589 + foreach ( wp_html_split( $the_content ) as $chunk ) {
590 + if ( preg_match( '#^<!--[\s\S]*-->$#i', $chunk, $m ) ) {
591 + $new_content .= $chunk;
592 + continue;
593 + }
594 +
595 + if ( preg_match( '#^<(/)?([a-z-]+)\b[^>]*>$#i', $chunk, $m ) ) {
596 + $tag = strtolower( $m[2] );
597 + if ( '/' === $m[1] ) {
598 + // Closing tag.
599 + $i = array_search( $tag, $tag_stack );
600 + // We can only remove the tag from the stack if it is in the stack.
601 + if ( false !== $i ) {
602 + $tag_stack = array_slice( $tag_stack, 0, $i );
603 + }
604 + } else {
605 + // Opening tag, add it to the stack.
606 + $tag_stack[] = $tag;
607 + }
608 +
609 + // If we're in a protected tag, the tag_stack contains at least one protected tag string.
610 + // The protected tag state can only change when we encounter a start or end tag.
611 + $in_protected_tag = array_intersect( $tag_stack, $protected_tags );
612 +
613 + // Never inspect tags.
614 + $new_content .= $chunk;
615 + continue;
616 + }
617 +
618 + if ( $in_protected_tag ) {
619 + // Don't inspect a chunk inside an inspected tag.
620 + $new_content .= $chunk;
621 + continue;
622 + }
623 + // Only reachable when there is no protected tag in the stack.
624 + $new_content .= preg_replace( '/(' . preg_quote( $args['keyword'], '/' ) . ')/i', '<mark>$1</mark>', $chunk );
625 + }
626 +
627 + return $new_content;
628 + }
629 +
335 630 /**
336 631 * Wrapper for wp_mail to be overridden in unit tests
337 632 *
338 633 * @param string|array $to Array or comma-separated list of email addresses to send message.
@@ -363,9 +658,9 @@
363 658 if ( isset( $message['html'] ) ) {
364 659 if ( isset( $message['text'] ) ) {
365 660 $plain_text = $message['text'];
366 661 } else {
367 - $plain_text = strip_tags( $message['html'] );
662 + $plain_text = wp_strip_all_tags( $message['html'] );
368 663 }
369 664
370 665 $headers[] = 'Content-type: text/html';
371 666 $alt_function = function ( $mailer ) use ( $plain_text ) {