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-feed.php +127 -4 4.2.14.3.2 View file →
@@ -254,9 +254,9 @@
254 254 $fulltext = '';
255 255 foreach ( apply_filters( 'friends_keyword_search_fields', array( 'post_title', 'post_content' ) ) as $field ) {
256 256 $fulltext .= PHP_EOL . $post->$field;
257 257 }
258 - $fulltext = wp_strip_all_tags( $fulltext );
258 + $fulltext = self::prepare_keyword_search_text( $fulltext );
259 259 foreach ( $keywords as $keyword ) {
260 260 if ( preg_match( '/' . str_replace( '/', '\\/', $keyword ) . '/ius', $fulltext ) ) {
261 261 $keyword_match = $keyword;
262 262 break;
@@ -480,8 +480,113 @@
480 480 return $catch_all;
481 481 }
482 482
483 483 /**
484 + * Prepares post fields for keyword notification matching.
485 + *
486 + * @param string $text The text to search.
487 + * @return string The prepared text.
488 + */
489 + public static function prepare_keyword_search_text( $text ) {
490 + $text = wp_strip_all_tags( $text );
491 +
492 + return preg_replace_callback(
493 + '#https?://[^\s<>"\']+#i',
494 + function ( $matches ) {
495 + return self::remove_tracking_url_query_args_from_keyword_search_text( $matches[0] );
496 + },
497 + $text
498 + );
499 + }
500 +
501 + /**
502 + * Removes tracking query args from URLs before keyword notification matching.
503 + *
504 + * @param string $url The URL to normalize.
505 + * @return string The URL without known tracking query args.
506 + */
507 + private static function remove_tracking_url_query_args_from_keyword_search_text( $url ) {
508 + $parsed_url = wp_parse_url( $url );
509 + if ( ! is_array( $parsed_url ) || empty( $parsed_url['host'] ) ) {
510 + return $url;
511 + }
512 +
513 + $query_args = array();
514 + if ( isset( $parsed_url['query'] ) ) {
515 + wp_parse_str( html_entity_decode( $parsed_url['query'], ENT_QUOTES ), $query_args );
516 + }
517 +
518 + foreach ( array_keys( $query_args ) as $query_arg ) {
519 + if ( self::is_tracking_query_arg( $query_arg ) ) {
520 + unset( $query_args[ $query_arg ] );
521 + }
522 + }
523 +
524 + $normalized_url = $parsed_url['scheme'] . '://';
525 + if ( isset( $parsed_url['user'] ) ) {
526 + $normalized_url .= $parsed_url['user'];
527 + if ( isset( $parsed_url['pass'] ) ) {
528 + $normalized_url .= ':' . $parsed_url['pass'];
529 + }
530 + $normalized_url .= '@';
531 + }
532 + $normalized_url .= $parsed_url['host'];
533 + if ( isset( $parsed_url['port'] ) ) {
534 + $normalized_url .= ':' . $parsed_url['port'];
535 + }
536 + if ( isset( $parsed_url['path'] ) ) {
537 + $normalized_url .= $parsed_url['path'];
538 + }
539 + if ( $query_args ) {
540 + $normalized_url .= '?' . http_build_query( $query_args, '', '&' );
541 + }
542 + if ( isset( $parsed_url['fragment'] ) ) {
543 + $normalized_url .= '#' . $parsed_url['fragment'];
544 + }
545 +
546 + return $normalized_url;
547 + }
548 +
549 + /**
550 + * Checks whether a query arg is used for tracking.
551 + *
552 + * @param string $query_arg The query arg.
553 + * @return bool Whether the query arg is used for tracking.
554 + */
555 + private static function is_tracking_query_arg( $query_arg ) {
556 + if ( preg_match( '/^(?:utm|mtm|hsa)_/i', $query_arg ) ) {
557 + return true;
558 + }
559 +
560 + return in_array(
561 + strtolower( $query_arg ),
562 + array(
563 + '_hsenc',
564 + '_hsmi',
565 + 'dclid',
566 + 'fbclid',
567 + 'gclid',
568 + 'gbraid',
569 + 'igshid',
570 + 'li_fat_id',
571 + 'mc_cid',
572 + 'mc_eid',
573 + 'mkt_tok',
574 + 'msclkid',
575 + 'oly_anon_id',
576 + 'oly_enc_id',
577 + 'pk_campaign',
578 + 'pk_kwd',
579 + 'twclid',
580 + 'vero_id',
581 + 'wbraid',
582 + 'yclid',
583 + ),
584 + true
585 + );
586 + }
587 +
588 + /**
484 589 * Gets the notification keywords.
485 590 *
486 591 * @return array The notification keywords.
487 592 */
@@ -1019,8 +1124,22 @@
1019 1124 $available_feeds[ $link_url ]['autoselect'] = true;
1020 1125 }
1021 1126 }
1022 1127
1128 + // Prefer the ActivityPub actor feed over RSS when both are available.
1129 + $activitypub_feed = null;
1130 + foreach ( $available_feeds as $link_url => $feed ) {
1131 + if ( 'activitypub' === $feed['parser'] ) {
1132 + $activitypub_feed = $link_url;
1133 + break;
1134 + }
1135 + }
1136 + if ( $activitypub_feed ) {
1137 + foreach ( $available_feeds as $link_url => $feed ) {
1138 + $available_feeds[ $link_url ]['autoselect'] = $link_url === $activitypub_feed;
1139 + }
1140 + }
1141 +
1023 1142 $feed_sort_order = array( 'self', 'alternate', 'me' );
1024 1143 if ( $has_friends_plugin ) {
1025 1144 // If we have the Friends plugin, we prefer an (augmented) RSS feed over, for example, microformats.
1026 1145 $feed_sort_order = array( 'alternate', 'self', 'me' );
@@ -1160,14 +1279,16 @@
1160 1279 * @param int $author_id The id of the author.
1161 1280 * @return int Post ID, or 0 on failure.
1162 1281 */
1163 1282 public static function url_to_postid( $url, $author_id = false ) {
1164 - $cache_key = 'friends_url_to_postid_' . md5( $url ) . ( $author_id ? '_' . $author_id : '' );
1283 + $post_types = apply_filters( 'friends_frontend_post_types', array() );
1284 +
1285 + // The post types are part of the cache key since they can be filtered per lookup.
1286 + $cache_key = 'friends_url_to_postid_' . md5( $url . '|' . implode( ',', $post_types ) ) . ( $author_id ? '_' . $author_id : '' );
1165 1287 $post_id = wp_cache_get( $cache_key, 'friends' );
1166 1288 if ( false !== $post_id ) {
1167 1289 return $post_id;
1168 1290 }
1169 - $post_types = apply_filters( 'friends_frontend_post_types', array() );
1170 1291 $args = $post_types;
1171 1292
1172 1293 global $wpdb;
1173 1294 $sql = sprintf(
@@ -1190,9 +1311,11 @@
1190 1311 $args
1191 1312 )
1192 1313 );
1193 1314
1194 - wp_cache_set( $cache_key, $post_id, 'friends' );
1315 + if ( $post_id ) {
1316 + wp_cache_set( $cache_key, $post_id, 'friends' );
1317 + }
1195 1318 return $post_id;
1196 1319 }
1197 1320
1198 1321 public function oembed_request_post_id( $post_id, $url ) {