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-user.php +388 -357 2.8.34.3.2 View file →
@@ -32,8 +32,10 @@
32 32 */
33 33 public static $feed_catch_all = array();
34 34
35 35 public static function get_by_username( $username ) {
36 + $username = self::sanitize_username( $username );
37 +
36 38 $subscription = Subscription::get_by_username( $username );
37 39 if ( $subscription && ! is_wp_error( $subscription ) ) {
38 40 return $subscription;
39 41 }
@@ -45,14 +47,23 @@
45 47 return $user;
46 48 }
47 49
48 50 public static function get_post_author( \WP_Post $post ) {
51 + static $cache = array();
52 +
49 53 $subscriptions = wp_get_object_terms( $post->ID, Subscription::TAXONOMY );
50 54 if ( empty( $subscriptions ) ) {
51 - return new self( $post->post_author );
55 + if ( ! isset( $cache[ 'u_' . $post->post_author ] ) ) {
56 + $cache[ 'u_' . $post->post_author ] = new self( $post->post_author );
57 + }
58 + return $cache[ 'u_' . $post->post_author ];
52 59 }
53 60
54 - return new Subscription( reset( $subscriptions ) );
61 + $term = reset( $subscriptions );
62 + if ( ! isset( $cache[ 't_' . $term->term_id ] ) ) {
63 + $cache[ 't_' . $term->term_id ] = new Subscription( $term );
64 + }
65 + return $cache[ 't_' . $term->term_id ];
55 66 }
56 67
57 68 /**
58 69 * Create a User with a specific Friends-related role
@@ -57,11 +68,9 @@
57 68 /**
58 69 * Create a User with a specific Friends-related role
59 70 *
60 71 * @param string $user_login The user login.
61 - * @param string $role The role: subscription,
62 - * pending_friend_request,
63 - * or friend_request.
72 + * @param string $role The role: subscription.
64 73 * @param string $url The site URL for which
65 74 * to create the user.
66 75 * @param string $display_name The user's display name.
67 76 * @param string $avatar_url The user_avatar_url URL.
@@ -66,76 +75,14 @@
66 75 * @param string $display_name The user's display name.
67 76 * @param string $avatar_url The user_avatar_url URL.
68 77 * @param string $description A description for the user.
69 78 * @param string $user_registered When the user was registered.
70 - * @param bool $subscription_override Whether to override the automatic creation of a subscription.
71 79 *
72 80 * @return User|\WP_Error The created user or an error.
73 81 */
74 - public static function create( $user_login, $role, $url, $display_name = null, $avatar_url = null, $description = null, $user_registered = null, $subscription_override = false ) {
75 - if ( 'subscription' === $role && ! $subscription_override ) {
76 - return Subscription::create( $user_login, $role, $url, $display_name, $avatar_url, $description );
77 - }
78 -
79 - $role_rank = array_flip(
80 - array(
81 - 'subscription',
82 - 'pending_friend_request',
83 - 'friend_request',
84 - )
85 - );
86 - if ( ! isset( $role_rank[ $role ] ) ) {
87 - return new \WP_Error( 'invalid_role', 'Invalid role for creation specified' );
88 - }
89 -
90 - if ( is_multisite() ) {
91 - $user = get_user_by( 'login', $user_login );
92 - if ( $user && ! self::is_friends_plugin_user( $user ) ) {
93 - if ( ! is_user_member_of_blog( $user->ID, get_current_blog_id() ) ) {
94 - add_user_to_blog( get_current_blog_id(), $user->ID, $role );
95 - }
96 - }
97 - }
98 -
99 - $friend_user = self::get_user( $user_login );
100 - if ( $friend_user && ! is_wp_error( $friend_user ) ) {
101 -
102 - foreach ( $role_rank as $_role => $rank ) {
103 - if ( $rank > $role_rank[ $role ] ) {
104 - break;
105 - }
106 - if ( $friend_user->has_cap( $_role ) ) {
107 - // Upgrade user role.
108 - $friend_user->set_role( $role );
109 - break;
110 - }
111 - }
112 - return $friend_user;
113 - }
114 -
115 - $userdata = array(
116 - 'user_login' => $user_login,
117 - 'display_name' => $display_name,
118 - 'first_name' => $display_name,
119 - 'nickname' => $display_name,
120 - 'description' => $description,
121 - 'user_url' => $url,
122 - 'user_pass' => wp_generate_password( 256 ),
123 - 'role' => $role,
124 - );
125 -
126 - if ( $user_registered ) {
127 - $userdata['user_registered'] = $user_registered;
128 - }
129 -
130 - $friend_id = wp_insert_user( $userdata );
131 -
132 - $friend_user = new User( $friend_id );
133 - $friend_user->update_user_option( 'friends_new_friend', true );
134 - $friend_user->update_user_icon_url( $avatar_url );
135 -
136 - do_action( 'friends_after_create_friend_user', $friend_user );
137 - return $friend_user;
82 + public static function create( $user_login, $role, $url, $display_name = null, $avatar_url = null, $description = null, $user_registered = null ) {
83 + $user_login = self::sanitize_username( $user_login );
84 + return Subscription::create( $user_login, $role, $url, $display_name, $avatar_url, $description, $user_registered );
138 85 }
139 86
140 87 public static function register_wrapper_hooks() {
141 88 add_filter( 'friends_get_user_feeds', array( 'Friends\User', 'friends_get_user_feeds' ), 10, 2 );
@@ -162,8 +109,13 @@
162 109 * @param bool $multisite_shortname Whether to use the multisite shortname.
163 110 * @return string The corresponding username.
164 111 */
165 112 public static function get_user_login_for_url( $url, $multisite_shortname = true ) {
113 + $pre_user_login = apply_filters( 'friends_pre_get_user_login_for_url', false, $url );
114 + if ( $pre_user_login ) {
115 + return $pre_user_login;
116 + }
117 +
166 118 $multisite_user = self::get_multisite_user( $url );
167 119 if ( $multisite_user && $multisite_shortname ) {
168 120 return $multisite_user->user_login;
169 121 }
@@ -192,8 +144,27 @@
192 144 return $display_name;
193 145 }
194 146
195 147 /**
148 + * Discover a user login from feeds
149 + *
150 + * @param array $feeds A list of feeds.
151 + * @return string The corresponding user login.
152 + */
153 + public static function get_user_login_from_feeds( $feeds ) {
154 + foreach ( $feeds as $feed ) {
155 + if ( isset( $feed['suggested-username'] ) ) {
156 + return sanitize_text_field( $feed['suggested-username'] );
157 + }
158 + }
159 + $display_name = self::get_display_name_from_feeds( $feeds );
160 + if ( $display_name ) {
161 + return self::sanitize_username( $display_name );
162 + }
163 +
164 + return false;
165 + }
166 + /**
196 167 * Discover a display name from feeds
197 168 *
198 169 * @param array $feeds A list of feeds.
199 170 * @return string The corresponding display name.
@@ -199,10 +170,11 @@
199 170 * @return string The corresponding display name.
200 171 */
201 172 public static function get_display_name_from_feeds( $feeds ) {
202 173 foreach ( $feeds as $feed ) {
203 - if ( 'self' === $feed['rel'] ) {
204 - return sanitize_text_field( $feed['title'] );
174 + if ( 'self' === $feed['rel'] && ! empty( $feed['title'] ) ) {
175 + $name = trim( preg_replace( '/(\s[–—|-]|[:,])\s.*$/u', '', $feed['title'] ) );
176 + return sanitize_text_field( $name );
205 177 }
206 178 }
207 179
208 180 return false;
@@ -223,8 +195,11 @@
223 195 if ( ! $host ) {
224 196 return false;
225 197 }
226 198 $path = wp_parse_url( $url, PHP_URL_PATH );
199 + if ( ! $path ) {
200 + $path = '';
201 + }
227 202
228 203 $site_id = get_blog_id_from_url( $host, trailingslashit( $path ) );
229 204 if ( ! $site_id ) {
230 205 return false;
@@ -245,9 +220,9 @@
245 220 *
246 221 * @return string The sanitized username.
247 222 */
248 223 public static function sanitize_username( $username ) {
249 - $username = preg_replace( '/[^a-z0-9.]+/', '-', strtolower( $username ) );
224 + $username = preg_replace( '/[^a-z0-9.]+/', '-', strtolower( remove_accents( $username ) ) );
250 225 $username = sanitize_user( $username );
251 226 return $username;
252 227 }
253 228
@@ -258,9 +233,9 @@
258 233 *
259 234 * @return bool True if the specified user is a friends plugin user, False otherwise.
260 235 */
261 236 public static function is_friends_plugin_user( \WP_User $user ) {
262 - return $user->has_cap( 'friend' ) || $user->has_cap( 'pending_friend_request' ) || $user->has_cap( 'friend_request' ) || $user->has_cap( 'subscription' );
237 + return $user->has_cap( 'subscription' );
263 238 }
264 239
265 240 /**
266 241 * Get a friend user for a user_login.
@@ -286,12 +261,11 @@
286 261 * @param string $user_id The user ID.
287 262 * @return User|false The friend user or false.
288 263 */
289 264 public static function get_user_by_id( $user_id ) {
290 - if ( 0 === strpos( $user_id, 'friends-virtual-user-' ) ) {
291 - $term_id = substr( $user_id, strlen( 'friends-virtual-user-' ) );
292 - $term = get_term( intval( $term_id ), Subscription::TAXONOMY );
293 - if ( $term ) {
265 + if ( is_numeric( $user_id ) && $user_id > 1e10 ) {
266 + $term = get_term( $user_id - 1e10, Subscription::TAXONOMY );
267 + if ( $term && ! is_wp_error( $term ) ) {
294 268 return new Subscription( $term );
295 269 }
296 270 }
297 271
@@ -296,9 +270,9 @@
296 270 }
297 271
298 272 $user = get_user_by( 'ID', $user_id );
299 273 if ( $user ) {
300 - if ( $user->has_cap( 'friend' ) || $user->has_cap( 'pending_friend_request' ) || $user->has_cap( 'friend_request' ) || $user->has_cap( 'subscription' ) ) {
274 + if ( $user->has_cap( 'subscription' ) ) {
301 275 return new self( $user );
302 276 }
303 277
304 278 return false;
@@ -317,21 +291,10 @@
317 291 }
318 292
319 293 return parent::__get( $key );
320 294 }
321 - /**
322 - * Sends a message to the friend..
323 - *
324 - * @param string $message The message.
325 - * @param string $subject The subject.
326 - *
327 - * @return \WP_Error|bool True if the message was sent successfully.
328 - */
329 - public function send_message( $message, $subject = null ) {
330 - $friends = Friends::get_instance();
331 - return $friends->messages->send_message( $this, $message, $subject );
332 - }
333 295
296 +
334 297 public function insert_post( array $postarr, $wp_error = false, $fire_after_hooks = true ) {
335 298 $current_user = wp_get_current_user();
336 299
337 300 // Posts and revisions should be associated with this user.
@@ -356,9 +319,9 @@
356 319
357 320 /**
358 321 * Save multiple feeds for a user.
359 322 *
360 - * @param string $feeds The feed URLs to subscribe to.
323 + * @param array $feeds The feed URLs to subscribe to.
361 324 *
362 325 * @return array(\WP_Term)|\WP_error $user The new associated user or an error object.
363 326 */
364 327 public function save_feeds( $feeds = array() ) {
@@ -364,9 +327,9 @@
364 327 public function save_feeds( $feeds = array() ) {
365 328 $errors = new \WP_Error();
366 329 foreach ( $feeds as $feed_url => $options ) {
367 330 if ( ! is_string( $feed_url ) || ! Friends::check_url( $feed_url ) ) {
368 - $errors->add( 'invalid-url', 'An invalid URL was provided' );
331 + $errors->add( 'invalid-url', 'An invalid URL was provided', $feed_url );
369 332 unset( $feeds[ $feed_url ] );
370 333 continue;
371 334 }
372 335
@@ -382,9 +345,10 @@
382 345 }
383 346
384 347 $all_urls = array();
385 348 foreach ( wp_get_object_terms( $this->get_object_id(), User_Feed::TAXONOMY ) as $term ) {
386 - $all_urls[ $term->name ] = $term->term_id;
349 + $url = str_replace( '&', '&', $term->name );
350 + $all_urls[ $url ] = $term->term_id;
387 351 }
388 352
389 353 $user_feeds = wp_set_object_terms( $this->get_object_id(), array_keys( array_merge( $all_urls, $feeds ) ), User_Feed::TAXONOMY );
390 354 if ( is_wp_error( $user_feeds ) ) {
@@ -391,9 +355,10 @@
391 355 return $user_feeds;
392 356 }
393 357
394 358 foreach ( wp_get_object_terms( $this->get_object_id(), User_Feed::TAXONOMY ) as $term ) {
395 - $all_urls[ $term->name ] = $term->term_id;
359 + $url = str_replace( '&', '&', $term->name );
360 + $all_urls[ $url ] = $term->term_id;
396 361 }
397 362
398 363 foreach ( $feeds as $url => $feed_options ) {
399 364 if ( ! isset( $all_urls[ $url ] ) ) {
@@ -438,9 +403,10 @@
438 403 return new \WP_Error(
439 404 'error-saving-feed',
440 405 sprintf(
441 406 // translators: %s is a URL.
442 - __( 'The feed %s could not be saved', 'friends' )
407 + __( 'The feed %s could not be saved', 'friends' ),
408 + $feed_url
443 409 )
444 410 );
445 411 }
446 412
@@ -483,19 +449,28 @@
483 449 $new_posts = array();
484 450 foreach ( $feeds as $feed ) {
485 451 $posts = $friends->feed->retrieve_feed( $feed );
486 452 if ( ! is_wp_error( $posts ) ) {
487 - $new_posts = array_merge( $new_posts, $posts );
453 + foreach ( $posts as $post_id => $item ) {
454 + $new_posts[ $post_id ] = $item;
455 + }
488 456 }
489 457 }
490 -
491 - $deleted_posts = $this->delete_outdated_posts();
492 -
493 - return array_values( array_diff( $new_posts, $deleted_posts ) );
458 + return $new_posts;
494 459 }
495 460
496 461 public function modify_query_by_author( \WP_Query $query ) {
497 462 $query->set( 'author', $this->ID );
463 +
464 + $_post_type = apply_filters( 'friends_author_post_type', $query->get( 'post_type' ), $this );
465 + if ( $_post_type ) {
466 + $query->set( 'post_type', $_post_type );
467 + }
468 +
469 + if ( ! user_can( $this->ID, 'friends_plugin' ) || user_can( $this->ID, 'manage_options' ) ) {
470 + // If the user doesn't belong to the friends plugin, only show their local posts so that subcriptions don't spill in.
471 + $query->set( 'post_type', 'post' );
472 + }
498 473 return $query;
499 474 }
500 475
501 476 public function modify_get_posts_args_by_author( $args ) {
@@ -518,9 +493,12 @@
518 493 public function delete_outdated_posts() {
519 494 $deleted_posts = array();
520 495
521 496 $args = array(
522 - 'post_type' => Friends::CPT,
497 + 'post_type' => Friends::CPT,
498 + 'post_status' => array( 'publish', 'trash' ),
499 + 'fields' => 'ids',
500 + 'posts_per_page' => 10,
523 501 );
524 502
525 503 if ( $this->is_retention_days_enabled() ) {
526 504 $args['date_query'] = array(
@@ -525,15 +503,9 @@
525 503 if ( $this->is_retention_days_enabled() ) {
526 504 $args['date_query'] = array(
527 505 'before' => gmdate( 'Y-m-d H:i:s', strtotime( '-' . ( $this->get_retention_days() * 24 ) . 'hours' ) ),
528 506 );
529 - } elseif ( get_option( 'friends_enable_retention_days' ) ) {
530 - $args['date_query'] = array(
531 - 'before' => gmdate( 'Y-m-d H:i:s', strtotime( '-' . ( Friends::get_retention_days() * 24 ) . 'hours' ) ),
532 - );
533 - }
534 507
535 - if ( isset( $args['date_query'] ) ) {
536 508 $query = new \WP_Query();
537 509 foreach ( $args as $key => $value ) {
538 510 $query->set( $key, $value );
539 511 }
@@ -538,20 +510,19 @@
538 510 $query->set( $key, $value );
539 511 }
540 512 $query = $this->modify_query_by_author( $query );
541 513
542 - foreach ( $query->get_posts() as $post ) {
543 - if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
544 - echo 'Deleting ', esc_html( $post->ID ), '<br/>';
514 + foreach ( $query->get_posts() as $post_id ) {
515 + $post_id = Friends::maybe_delete_outdated_post( $post_id, 'date overflow' );
516 + if ( $post_id ) {
517 + $deleted_posts[] = $post_id;
545 518 }
546 - wp_delete_post( $post->ID, true );
547 - $deleted_posts[] = $post->ID;
548 519 }
549 520 }
550 521
551 522 unset( $args['date_query'] );
552 523 $args['orderby'] = 'date';
553 - $args['order'] = 'asc';
524 + $args['order'] = 'desc';
554 525 if ( $this->is_retention_number_enabled() ) {
555 526 $args['offset'] = $this->get_retention_number();
556 527 $query = new \WP_Query();
557 528 foreach ( $args as $key => $value ) {
@@ -557,58 +528,16 @@
557 528 foreach ( $args as $key => $value ) {
558 529 $query->set( $key, $value );
559 530 }
560 531 $query = $this->modify_query_by_author( $query );
561 -
562 - foreach ( $query->get_posts() as $post ) {
563 - if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
564 - echo 'Deleting ', esc_html( $post->ID ), '<br/>';
532 + foreach ( $query->get_posts() as $post_id ) {
533 + $post_id = Friends::maybe_delete_outdated_post( $post_id, 'local number overflow' );
534 + if ( $post_id ) {
535 + $deleted_posts[] = $post_id;
565 536 }
566 - wp_delete_post( $post->ID, true );
567 - $deleted_posts[] = $post->ID;
568 537 }
569 538 }
570 539
571 - // Global setting.
572 - if ( get_option( 'friends_enable_retention_number' ) ) {
573 - unset( $args['author'] );
574 - $args['offset'] = Friends::get_retention_number();
575 - $query = new \WP_Query();
576 - foreach ( $args as $key => $value ) {
577 - $query->set( $key, $value );
578 - }
579 - $query = $this->modify_query_by_author( $query );
580 -
581 - foreach ( $query->get_posts() as $post ) {
582 - if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
583 - echo 'Deleting ', esc_html( $post->ID ), '<br/>';
584 - }
585 - wp_delete_post( $post->ID, true );
586 - $deleted_posts[] = $post->ID;
587 - }
588 - }
589 -
590 - // In any case, don't overflow the trash.
591 - $args = array(
592 - 'post_type' => Friends::CPT,
593 - 'post_status' => 'trash',
594 - 'offset' => 30,
595 - );
596 -
597 - $query = new \WP_Query();
598 - foreach ( $args as $key => $value ) {
599 - $query->set( $key, $value );
600 - }
601 - $query = $this->modify_query_by_author( $query );
602 -
603 - foreach ( $query->get_posts() as $post ) {
604 - if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
605 - echo 'Deleting ', esc_html( $post->ID ), '<br/>';
606 - }
607 - wp_delete_post( $post->ID, true );
608 - $deleted_posts[ $post->ID ] = $post->ID;
609 - }
610 -
611 540 return $deleted_posts;
612 541 }
613 542
614 543 /**
@@ -698,9 +627,8 @@
698 627 */
699 628 public function set_retention_days( $days ) {
700 629 $days = max( 1, intval( $days ) );
701 630 return $this->update_user_option( 'friends_retention_days', $days );
702 - return $days;
703 631 }
704 632
705 633 /**
706 634 * Gets the post counts by post format.
@@ -710,15 +638,32 @@
710 638 public function get_post_in_trash_count() {
711 639 global $wpdb;
712 640 $post_types = apply_filters( 'friends_frontend_post_types', array() );
713 641
714 - $count = $wpdb->get_var(
642 + $cache_key = 'get_post_in_trash_count_' . $this->get_term_id() . '_' . implode( '_', $post_types );
643 + if ( false !== wp_cache_get( $cache_key, 'friends' ) ) {
644 + return wp_cache_get( $cache_key, 'friends' );
645 + }
646 +
647 + $count = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
715 648 $wpdb->prepare(
716 - "SELECT COUNT(*) FROM $wpdb->posts WHERE post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' ) AND post_status = "trash" AND post_author = %d',
717 - array_merge( $post_types, array( $this->ID ) )
649 + sprintf(
650 + 'SELECT COUNT(*)
651 + FROM %s
652 + WHERE post_author = %%d
653 + AND post_type IN ( %s )
654 + AND post_status = "trash"',
655 + $wpdb->posts,
656 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
657 + ),
658 + array_merge(
659 + array( $this->ID ),
660 + $post_types
661 + )
718 662 )
719 663 );
720 664
665 + wp_cache_set( $cache_key, intval( $count ), 'friends', HOUR_IN_SECONDS - 60 );
721 666 return intval( $count );
722 667 }
723 668
724 669 /**
@@ -726,87 +671,90 @@
726 671 *
727 672 * @return array The post counts.
728 673 */
729 674 public function get_post_count_by_post_format() {
730 - $cache_key = 'friends_post_count_by_post_format_author_' . $this->ID;
675 + $cache_key = 'get_post_count_by_post_format_' . $this->ID;
731 676
677 + $counts = wp_cache_get( $cache_key, 'friends' );
678 + if ( false !== $counts ) {
679 + return $counts;
680 + }
732 681 $counts = get_transient( $cache_key );
733 - if ( true || false === $counts ) {
734 - $counts = array();
735 - $post_types = apply_filters( 'friends_frontend_post_types', array() );
736 - $post_formats_term_ids = array();
737 - foreach ( get_post_format_slugs() as $post_format ) {
738 - $term = get_term_by( 'slug', 'post-format-' . $post_format, 'post_format' );
739 - if ( $term ) {
740 - $post_formats_term_ids[ $term->term_id ] = $post_format;
741 - }
682 + if ( false !== $counts ) {
683 + return $counts;
684 + }
685 + $counts = array();
686 + $post_types = apply_filters( 'friends_frontend_post_types', array() );
687 + $post_formats_term_ids = array();
688 + foreach ( get_post_format_slugs() as $post_format ) {
689 + $term = get_term_by( 'slug', 'post-format-' . $post_format, 'post_format' );
690 + if ( $term ) {
691 + $post_formats_term_ids[ $term->term_taxonomy_id ] = $post_format;
742 692 }
693 + }
743 694
744 - global $wpdb;
695 + global $wpdb;
745 696
746 - $counts = array();
747 - $counts['standard'] = $wpdb->get_var(
697 + $counts = array();
698 + $counts['standard'] = $wpdb->get_var(// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
699 + $wpdb->prepare(
700 + sprintf(
701 + "SELECT COUNT(DISTINCT posts.ID)
702 + FROM %s AS posts
703 + JOIN %s AS relationships_post_format
704 +
705 + WHERE posts.post_author = %%d
706 + AND posts.post_status IN ( 'publish', 'private' )
707 + AND posts.post_type IN ( %s )
708 + AND relationships_post_format.object_id = posts.ID",
709 + $wpdb->posts,
710 + $wpdb->term_relationships,
711 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
712 + ),
713 + array_merge(
714 + array( $this->ID ),
715 + $post_types
716 + )
717 + )
718 + );
719 +
720 + if ( ! empty( $post_formats_term_ids ) ) {
721 + $post_format_counts = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
748 722 $wpdb->prepare(
749 723 sprintf(
750 - "SELECT COUNT(DISTINCT posts.ID)
724 + "SELECT relationships_post_format.term_taxonomy_id AS post_format_id, COUNT(relationships_post_format.term_taxonomy_id) AS count
751 725 FROM %s AS posts
752 726 JOIN %s AS relationships_post_format
753 727
754 - WHERE posts.post_author = %s
728 + WHERE posts.post_author = %%d
755 729 AND posts.post_status IN ( 'publish', 'private' )
756 730 AND posts.post_type IN ( %s )
757 - AND relationships_post_format.object_id = posts.ID",
731 + AND relationships_post_format.object_id = posts.ID
732 + AND relationships_post_format.term_taxonomy_id IN ( %s )
733 + GROUP BY relationships_post_format.term_taxonomy_id",
758 734 $wpdb->posts,
759 735 $wpdb->term_relationships,
760 - '%d',
761 - implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
736 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
737 + implode( ',', array_fill( 0, count( $post_formats_term_ids ), '%d' ) )
762 738 ),
763 739 array_merge(
764 740 array( $this->ID ),
765 - $post_types
741 + $post_types,
742 + array_keys( $post_formats_term_ids )
766 743 )
767 744 )
768 745 );
769 746
770 - if ( ! empty( $post_formats_term_ids ) ) {
771 - $post_format_counts = $wpdb->get_results(
772 - $wpdb->prepare(
773 - sprintf(
774 - "SELECT relationships_post_format.term_taxonomy_id AS post_format_id, COUNT(relationships_post_format.term_taxonomy_id) AS count
775 - FROM %s AS posts
776 - JOIN %s AS relationships_post_format
777 -
778 - WHERE posts.post_author = %s
779 - AND posts.post_status IN ( 'publish', 'private' )
780 - AND posts.post_type IN ( %s )
781 - AND relationships_post_format.object_id = posts.ID
782 - AND relationships_post_format.term_taxonomy_id IN ( %s )
783 - GROUP BY relationships_post_format.term_taxonomy_id",
784 - $wpdb->posts,
785 - $wpdb->term_relationships,
786 - '%d',
787 - implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
788 - implode( ',', array_fill( 0, count( $post_formats_term_ids ), '%d' ) )
789 - ),
790 - array_merge(
791 - array( $this->ID ),
792 - $post_types,
793 - array_keys( $post_formats_term_ids )
794 - )
795 - )
796 - );
797 -
798 - foreach ( $post_format_counts as $row ) {
799 - $counts[ $post_formats_term_ids[ $row->post_format_id ] ] = $row->count;
800 - $counts['standard'] -= $row->count;
801 - }
747 + foreach ( $post_format_counts as $row ) {
748 + $counts[ $post_formats_term_ids[ $row->post_format_id ] ] = $row->count;
749 + $counts['standard'] -= $row->count;
802 750 }
751 + }
803 752
804 - $counts = array_filter( $counts );
753 + $counts = array_filter( $counts );
805 754
806 - set_transient( $cache_key, $counts, HOUR_IN_SECONDS );
807 - }
808 -
755 + set_transient( $cache_key, $counts, HOUR_IN_SECONDS - 60 );
756 + wp_cache_set( $cache_key, $counts, 'friends', HOUR_IN_SECONDS - 60 );
809 757 return $counts;
810 758 }
811 759
812 760 /**
@@ -815,12 +763,18 @@
815 763 * @return object The post stats.
816 764 */
817 765 public function get_post_stats() {
818 766 global $wpdb;
767 + $cache_key = 'post_stats_author_' . $this->ID;
768 + $post_stats = wp_cache_get( $cache_key, 'friends' );
769 + if ( false !== $post_stats ) {
770 + return $post_stats;
771 + }
819 772 $post_types = apply_filters( 'friends_frontend_post_types', array() );
820 - $post_stats = $wpdb->get_row(
773 + $post_stats = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
821 774 $wpdb->prepare(
822 - 'SELECT SUM(
775 + sprintf(
776 + 'SELECT SUM(
823 777 LENGTH( ID ) +
824 778 LENGTH( post_author ) +
825 779 LENGTH( post_date ) +
826 780 LENGTH( post_date_gmt ) +
@@ -844,9 +798,12 @@
844 798 LENGTH( post_mime_type ) +
845 799 LENGTH( comment_count )
846 800 ) AS total_size,
847 801 COUNT(*) as post_count
848 - FROM ' . $wpdb->posts . ' WHERE post_author = %d AND post_type IN ( ' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
802 + FROM %s WHERE post_author = %%d AND post_type IN ( %s )',
803 + $wpdb->posts,
804 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
805 + ),
849 806 array_merge( array( $this->ID ), $post_types )
850 807 ),
851 808 ARRAY_A
852 809 );
@@ -851,23 +808,49 @@
851 808 ARRAY_A
852 809 );
853 810 $post_stats['earliest_post_date'] = mysql2date(
854 811 'U',
855 - $wpdb->get_var(
812 + $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
856 813 $wpdb->prepare(
857 - "SELECT MIN(post_date) FROM $wpdb->posts WHERE post_author = %d AND post_status = 'publish' AND post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
814 + sprintf(
815 + 'SELECT MIN(post_date) FROM %s WHERE post_author = %%d AND post_status = "publish" AND post_type IN ( %s )',
816 + $wpdb->posts,
817 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
818 + ),
858 819 array_merge( array( $this->ID ), $post_types )
859 820 )
860 821 )
861 822 );
823 +
824 + wp_cache_set( $cache_key, $post_stats, 'friends', HOUR_IN_SECONDS );
862 825 return $post_stats;
863 826 }
864 827
865 828 public function get_all_post_ids() {
866 829 global $wpdb;
867 - $post_types_to_delete = implode( "', '", apply_filters( 'friends_frontend_post_types', array() ) );
830 + $post_types = apply_filters( 'friends_frontend_post_types', array() );
868 831
869 - $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE post_author = %d AND post_type IN ('$post_types_to_delete')", $this->ID ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
832 + $cache_key = 'get_all_post_ids_' . $this->ID . '_' . implode( '_', $post_types );
833 + $post_ids = wp_cache_get( $cache_key, 'friends' );
834 + if ( false !== $post_ids ) {
835 + return $post_ids;
836 + }
837 +
838 + $post_ids = $wpdb->get_col( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
839 + $wpdb->prepare(
840 + sprintf(
841 + 'SELECT ID FROM %s WHERE post_author = %%d AND post_type IN ( %s )',
842 + $wpdb->posts,
843 + implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
844 + ),
845 + array_merge(
846 + array( $this->ID ),
847 + $post_types
848 + )
849 + )
850 + );
851 +
852 + wp_cache_set( $cache_key, $post_ids, 'friends', HOUR_IN_SECONDS - 60 );
870 853 return $post_ids;
871 854 }
872 855
873 856 /**
@@ -907,10 +890,9 @@
907 890 * @param array $rules The rules to set for this feed.
908 891 * @return array The rules set by the user for this feed.
909 892 */
910 893 public function set_feed_rules( $rules ) {
911 - $friends = Friends::get_instance();
912 - self::$feed_rules[ $this->ID ] = $friends->feed->validate_feed_rules( $rules );
894 + self::$feed_rules[ $this->ID ] = Feed::validate_feed_rules( $rules );
913 895 return self::$feed_rules[ $this->ID ];
914 896 }
915 897
916 898
@@ -933,10 +915,9 @@
933 915 * @param array $catchall The catchall rule to set for this feed.
934 916 * @return array The catchall rukle set by the user for this feed.
935 917 */
936 918 public function set_feed_catch_all( $catchall ) {
937 - $friends = Friends::get_instance();
938 - self::$feed_catch_all[ $this->ID ] = $friends->feed->validate_feed_catch_all( $catchall );
919 + self::$feed_catch_all[ $this->ID ] = Feed::validate_feed_catch_all( $catchall );
939 920 return self::$feed_catch_all[ $this->ID ];
940 921 }
941 922
942 923 /**
@@ -945,31 +926,31 @@
945 926 * @return array A mapping of the remote post ids.
946 927 */
947 928 public function get_remote_post_ids() {
948 929 $remote_post_ids = array();
949 - $existing_posts = new \WP_Query(
950 - array(
951 - 'post_type' => Friends::CPT,
952 - 'post_status' => array( 'publish', 'private', 'trash' ),
953 - 'author' => $this->ID,
954 - 'nopaging' => true,
955 - )
956 - );
957 -
958 - if ( $existing_posts->have_posts() ) {
959 - while ( $existing_posts->have_posts() ) {
960 - $post = $existing_posts->next_post();
961 - $remote_post_id = get_post_meta( $post->ID, 'remote_post_id', true );
962 - if ( $remote_post_id ) {
963 - $remote_post_ids[ $remote_post_id ] = $post->ID;
964 - }
965 - $permalink = get_permalink( $post );
966 - $remote_post_ids[ $permalink ] = $post->ID;
967 - $permalink = str_replace( array( '&#38;', '&#038;' ), '&', ent2ncr( $permalink ) );
968 - $remote_post_ids[ $permalink ] = $post->ID;
930 + $existing_posts = new \WP_Query();
931 + foreach ( array(
932 + 'post_type' => Friends::CPT,
933 + 'post_status' => array( 'publish', 'private', 'trash', 'future' ),
934 + 'nopaging' => true,
935 + 'fields' => 'ids',
936 + ) as $key => $value ) {
937 + $existing_posts->set( $key, $value );
938 + }
939 + $existing_posts = $this->modify_query_by_author( $existing_posts );
940 + foreach ( $existing_posts->get_posts() as $post_id ) {
941 + $post_id = $existing_posts->next_post();
942 + $remote_post_id = get_post_meta( $post_id, 'remote_post_id', true );
943 + if ( $remote_post_id ) {
944 + $remote_post_ids[ $remote_post_id ] = $post_id;
969 945 }
946 + $permalink = get_permalink( $post_id );
947 + $remote_post_ids[ $permalink ] = $post_id;
948 + $permalink = str_replace( array( '&#38;', '&#038;' ), '&', ent2ncr( $permalink ) );
949 + $remote_post_ids[ $permalink ] = $post_id;
970 950 }
971 951
952 + unset( $existing_posts );
972 953 do_action( 'friends_remote_post_ids', $remote_post_ids );
973 954 return $remote_post_ids;
974 955 }
975 956
@@ -978,8 +959,12 @@
978 959 *
979 960 * @return array An array of User_Feed items.
980 961 */
981 962 public function get_feeds() {
963 + if ( isset( $this->cached_feeds ) ) {
964 + return $this->cached_feeds;
965 + }
966 +
982 967 $term_query = new \WP_Term_Query(
983 968 array(
984 969 'taxonomy' => User_Feed::TAXONOMY,
985 970 'object_ids' => $this->get_object_id(),
@@ -990,8 +975,9 @@
990 975 foreach ( $term_query->get_terms() as $term ) {
991 976 $feeds[ $term->term_id ] = new User_Feed( $term, $this );
992 977 }
993 978
979 + $this->cached_feeds = $feeds;
994 980 return $feeds;
995 981 }
996 982
997 983 /**
@@ -1030,54 +1016,12 @@
1030 1016 *
1031 1017 * @return bool True if able to refresh feeds, False otherwise.
1032 1018 */
1033 1019 public function can_refresh_feeds() {
1034 - return $this->has_cap( 'subscription' ) ||
1035 - $this->has_cap( 'acquaintance' ) ||
1036 - $this->has_cap( 'friend' ) ||
1037 - $this->has_cap( 'pending_friend_request' );
1020 + return $this->has_cap( 'subscription' );
1038 1021 }
1039 1022
1040 1023 /**
1041 - * Convert a user to a friend
1042 - *
1043 - * @param string $out_token The token to authenticate against the remote.
1044 - * @param string $in_token The token the remote needs to use to authenticate to us.
1045 - */
1046 - public function make_friend( $out_token, $in_token ) {
1047 - $this->update_user_option( 'friends_out_token', $out_token );
1048 - if ( $this->update_user_option( 'friends_in_token', $in_token ) ) {
1049 - update_option( 'friends_in_token_' . $in_token, $this->ID );
1050 - }
1051 - $this->set_role( get_option( 'friends_default_friend_role', 'friend' ) );
1052 - }
1053 -
1054 - /**
1055 - * Check whether this is a valid friend
1056 - *
1057 - * @return boolean Whether the user has valid friend data.
1058 - */
1059 - public function is_valid_friend() {
1060 - if ( ! $this->has_cap( 'friend' ) ) {
1061 - return false;
1062 - }
1063 -
1064 - if ( ! $this->data->user_url ) {
1065 - return false;
1066 - }
1067 -
1068 - if ( ! $this->get_user_option( 'friends_in_token' ) ) {
1069 - return false;
1070 - }
1071 -
1072 - if ( ! $this->get_user_option( 'friends_out_token' ) ) {
1073 - return false;
1074 - }
1075 -
1076 - return true;
1077 - }
1078 -
1079 - /**
1080 1024 * Gets the role name (for a specific count).
1081 1025 *
1082 1026 * @param bool $group_subscriptions Whether to group all types of subscriptions into the name "Subscriptions".
1083 1027 * @param int $count The count if more than one.
@@ -1084,36 +1028,14 @@
1084 1028 *
1085 1029 * @return string The role name.
1086 1030 */
1087 1031 public function get_role_name( $group_subscriptions = false, $count = 1 ) {
1088 - $name = false;
1032 + $name = apply_filters( 'friend_user_role_name', false, $this );
1089 1033
1090 - if ( ! $name && in_array( 'acquaintance', $this->roles ) ) {
1091 - return _nx( 'Acquaintance', 'Acquaintances', $count, 'User role', 'friends' );
1034 + if ( empty( $name ) ) {
1035 + $name = _nx( 'Subscription', 'Subscriptions', $count, 'User role', 'friends' );
1092 1036 }
1093 1037
1094 - if ( ! $name && in_array( 'friend', $this->roles ) && $this->is_valid_friend() ) {
1095 - return _nx( 'Friend', 'Friends', $count, 'User role', 'friends' );
1096 - }
1097 -
1098 - if ( ! $name && in_array( 'subscription', $this->roles ) || ( $group_subscriptions && ( in_array( 'friend_request', $this->roles ) || in_array( 'pending_friend_request', $this->roles ) ) ) ) {
1099 - return _nx( 'Subscription', 'Subscriptions', $count, 'User role', 'friends' );
1100 - }
1101 -
1102 - if ( ! $name && in_array( 'friend_request', $this->roles ) ) {
1103 - return _nx( 'Friend Request', 'Friend Requests', $count, 'User role', 'friends' );
1104 - }
1105 -
1106 - if ( ! $name && in_array( 'pending_friend_request', $this->roles ) ) {
1107 - return _nx( 'Pending Friend Request', 'Pending Friend Requests', $count, 'User role', 'friends' );
1108 - }
1109 -
1110 - $name = apply_filters( 'friend_user_role_name', $name, $this );
1111 -
1112 - if ( ! $name ) {
1113 - $name = _x( 'Unknown', 'User role', 'friends' );
1114 - }
1115 -
1116 1038 return $name;
1117 1039 }
1118 1040
1119 1041 /**
@@ -1150,12 +1072,18 @@
1150 1072 * @return string The local friends page url.
1151 1073 */
1152 1074 public function get_local_friends_page_url( $post_id = null ) {
1153 1075 $path = '/';
1154 - if ( $post_id ) {
1076 + if ( $post_id && ! is_wp_error( $post_id ) ) {
1155 1077 $path = '/' . $post_id . '/';
1156 1078 }
1157 - return home_url( '/friends/' . self::get_user_login_for_url( $this->user_login ) . $path );
1079 +
1080 + $user_login = self::get_user_login_for_url( $this->user_login );
1081 + if ( ! $user_login || is_wp_error( $user_login ) ) {
1082 + return home_url( '/friends/' . $path );
1083 + }
1084 +
1085 + return home_url( '/friends/' . $user_login . $path );
1158 1086 }
1159 1087
1160 1088 /**
1161 1089 * Gets the local friends page url for a post format.
@@ -1182,24 +1110,8 @@
1182 1110 return home_url( '/friends/' . $this->user_login . '/reaction' . $slug . '/' );
1183 1111 }
1184 1112
1185 1113 /**
1186 - * Gets the friend auth to be used as a GET parameter.
1187 - *
1188 - * @param integer $validity The validity in seconds.
1189 - *
1190 - * @return string The friend auth.
1191 - */
1192 - public function get_friend_auth( $validity = 3600 ) {
1193 - $friends = Friends::get_instance();
1194 - $friend_auth = $friends->access_control->get_friend_auth( $this, $validity );
1195 - if ( empty( $friend_auth ) ) {
1196 - return '';
1197 - }
1198 - return $friend_auth['me'] . '-' . $friend_auth['until'] . '-' . $friend_auth['auth'];
1199 - }
1200 -
1201 - /**
1202 1114 * Determines whether the specified url is friend url.
1203 1115 *
1204 1116 * @param string $url The url.
1205 1117 *
@@ -1214,29 +1126,8 @@
1214 1126 }
1215 1127 return true;
1216 1128 }
1217 1129
1218 - /**
1219 - * Get the REST URL for the friend
1220 - *
1221 - * @return string The REST URL.
1222 - */
1223 - public function get_rest_url() {
1224 - $friends = Friends::get_instance();
1225 - $rest_url = $this->get_user_option( 'friends_rest_url' );
1226 - if ( ! $rest_url || false === strpos( $rest_url, REST::PREFIX ) ) {
1227 - $rest_url = $friends->rest->discover_rest_url( $this->user_url );
1228 - if ( is_wp_error( $rest_url ) ) {
1229 - return null;
1230 - }
1231 -
1232 - if ( $rest_url ) {
1233 - $this->update_user_option( 'friends_rest_url', $rest_url );
1234 - }
1235 - }
1236 - return $rest_url;
1237 - }
1238 -
1239 1130 public function get_avatar_url() {
1240 1131 return $this->get_user_option( 'friends_user_icon_url' );
1241 1132 }
1242 1133
@@ -1274,6 +1165,146 @@
1274 1165 * @return bool True on success, false on failure.
1275 1166 */
1276 1167 public function delete_user_option( $option_name, $is_global = false ) {
1277 1168 return delete_user_option( $this->ID, $option_name, $is_global );
1169 + }
1170 +
1171 + public static function mastodon_api_account( $account, $user_id, $request = null, $post = null ) {
1172 + if ( $account instanceof \Enable_Mastodon_Apps\Entity\Account && $user_id ) {
1173 + return $account;
1174 + }
1175 +
1176 + $user = false;
1177 + if ( $user_id && class_exists( Feed_Parser_ActivityPub::class ) ) {
1178 + $user = Feed_Parser_ActivityPub::determine_mastodon_api_user( $user_id );
1179 + }
1180 +
1181 + if ( ! $user ) {
1182 + if ( ! $post instanceof \WP_Post ) {
1183 + return $account;
1184 + }
1185 + $user = self::get_post_author( $post );
1186 + }
1187 + if ( $user instanceof self ) {
1188 + if ( ! self::is_friends_plugin_user( $user ) ) {
1189 + return $account;
1190 + }
1191 + if ( ! $account instanceof \Enable_Mastodon_Apps\Entity\Account ) {
1192 + $account = new \Enable_Mastodon_Apps\Entity\Account();
1193 + }
1194 + $note = $user->description;
1195 + if ( ! $note ) {
1196 + $note = '';
1197 + }
1198 + $ap_actor_id = null;
1199 + if ( $post instanceof \WP_Post && class_exists( '\Activitypub\Collection\Remote_Actors' ) ) {
1200 + $ap_meta = get_post_meta( $post->ID, 'activitypub', true );
1201 + if ( ! empty( $ap_meta['attributedTo']['ap_actor_id'] ) ) {
1202 + $ap_actor_id = (int) $ap_meta['attributedTo']['ap_actor_id'];
1203 + }
1204 + }
1205 +
1206 + if ( ! $ap_actor_id ) {
1207 + foreach ( $user->get_active_feeds() as $user_feed ) {
1208 + if ( $user_feed->is_activitypub_feed() ) {
1209 + $ap_actor_id = $user_feed->get_ap_actor_id();
1210 + break;
1211 + }
1212 + }
1213 + }
1214 +
1215 + if ( $ap_actor_id ) {
1216 + $account->id = \strval( $ap_actor_id );
1217 + $acct = \Activitypub\Collection\Remote_Actors::get_acct( $ap_actor_id );
1218 + $account->username = $acct ? $acct : $user->user_login;
1219 + $account->acct = $account->username;
1220 + } else {
1221 + $account->id = apply_filters( 'friends_mastodon_api_username', $user->ID );
1222 + $account->username = is_string( $account->id ) && ! is_numeric( $account->id ) ? $account->id : $user->user_login;
1223 + $account->acct = $account->username;
1224 + }
1225 + $account->display_name = $user->display_name;
1226 + $account->avatar = $user->get_avatar_url();
1227 + $account->avatar_static = $user->get_avatar_url();
1228 + $account->note = wpautop( $note );
1229 + $account->created_at = new \DateTime( $user->user_registered );
1230 + $account->statuses_count = $user->get_post_stats()['post_count'];
1231 + if ( ! $post instanceof \WP_Post ) {
1232 + $account->last_status_at = new \DateTime( 'now' );
1233 + } else {
1234 + $account->last_status_at = new \DateTime( $post->post_date_gmt );
1235 + }
1236 + $account->url = $user->get_local_friends_page_url();
1237 +
1238 + $account->source = array(
1239 + 'privacy' => 'public',
1240 + 'sensitive' => false,
1241 + 'language' => get_user_locale( $user->ID ),
1242 + 'note' => $note,
1243 + 'fields' => array(),
1244 + );
1245 + }
1246 +
1247 + return $account;
1248 + }
1249 +
1250 + public static function mastodon_api_account_id( $user_id, $post_id ) {
1251 + if ( $user_id ) {
1252 + return $user_id;
1253 + }
1254 + $user = false;
1255 + // The ActivityPub parser is only loaded when the ActivityPub plugin is active.
1256 + if ( class_exists( Feed_Parser_ActivityPub::class ) ) {
1257 + $user = Feed_Parser_ActivityPub::determine_mastodon_api_user( $user_id );
1258 + }
1259 + if ( ! $user ) {
1260 + $user = self::get_post_author( get_post( $post_id ) );
1261 + }
1262 + if ( $user instanceof self ) {
1263 + return $user->ID;
1264 + }
1265 +
1266 + return $user_id;
1267 + }
1268 +
1269 + public static function mastodon_api_get_posts_query_args( $args ) {
1270 + if ( ! isset( $args['author'] ) ) {
1271 + return $args;
1272 + }
1273 + $author = false;
1274 + if ( is_string( $args['author'] ) ) {
1275 + $author = self::get_by_username( $args['author'] );
1276 + } elseif ( is_numeric( $args['author'] ) ) {
1277 + $author = self::get_user_by_id( $args['author'] );
1278 + }
1279 +
1280 + if ( $author instanceof User ) {
1281 + $args['post_type'][] = Friends::CPT;
1282 + return $author->modify_get_posts_args_by_author( $args );
1283 + }
1284 +
1285 + return $args;
1286 + }
1287 +
1288 + public static function mastodon_entity_relationship( $relationship, $user_id ) {
1289 + if ( ! class_exists( 'Friends\Feed_Parser_ActivityPub' ) ) {
1290 + if ( ! is_wp_error( $user_id ) ) {
1291 + $user = User::get_user_by_id( $user_id );
1292 + }
1293 + } else {
1294 + $user = Feed_Parser_ActivityPub::determine_mastodon_api_user( $user_id );
1295 + }
1296 + if ( $user instanceof self ) {
1297 + if ( ! $relationship instanceof \Enable_Mastodon_Apps\Entity\Relationship ) {
1298 + $relationship = new \Enable_Mastodon_Apps\Entity\Relationship();
1299 + }
1300 + foreach ( $user->get_active_feeds() as $feed ) {
1301 + // Not Feed_Parser_ActivityPub::SLUG: this is reached above without the ActivityPub plugin, so that class may not exist.
1302 + if ( 'activitypub' === $feed->get_parser() ) {
1303 + $relationship->following = true;
1304 + break;
1305 + }
1306 + }
1307 + }
1308 + return $relationship;
1278 1309 }
1279 1310 }