PluginProbe
Friends / 2.7.5
Friends v2.7.5
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
friends / includes / class-user.php

class-user.php in Friends 2.7.5, at includes/class-user.php

1,276 lines 35.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Friend User
4 *
5 * This wraps \WP_User and adds friend specific functions.
6 *
7 * @package Friends
8 */
9
10 namespace Friends;
11
12 /**
13 * This is the class for the User part of the Friends Plugin.
14 *
15 * @since 0.21
16 *
17 * @package Friends
18 * @author Alex Kirk
19 */
20 class User extends \WP_User {
21 /**
22 * Caches the feed rules.
23 *
24 * @var array
25 */
26 public static $feed_rules = array();
27
28 /**
29 * Caches the feed catch all action.
30 *
31 * @var array
32 */
33 public static $feed_catch_all = array();
34
35 public static function get_by_username( $username ) {
36 $subscription = Subscription::get_by_username( $username );
37 if ( $subscription && ! is_wp_error( $subscription ) ) {
38 return $subscription;
39 }
40
41 $user = get_user_by( 'login', $username );
42 if ( $user && ! is_wp_error( $user ) ) {
43 return new self( $user );
44 }
45 return $user;
46 }
47
48 public static function get_post_author( \WP_Post $post ) {
49 $subscriptions = wp_get_object_terms( $post->ID, Subscription::TAXONOMY );
50 if ( empty( $subscriptions ) ) {
51 return new self( $post->post_author );
52 }
53
54 return new Subscription( reset( $subscriptions ) );
55 }
56
57 /**
58 * Create a User with a specific Friends-related role
59 *
60 * @param string $user_login The user login.
61 * @param string $role The role: subscription,
62 * pending_friend_request,
63 * or friend_request.
64 * @param string $url The site URL for which
65 * to create the user.
66 * @param string $display_name The user's display name.
67 * @param string $avatar_url The user_avatar_url URL.
68 * @param string $description A description for the user.
69 * @param string $user_registered When the user was registered.
70 * @param bool $subscription_override Whether to override the automatic creation of a subscription.
71 *
72 * @return User|\WP_Error The created user or an error.
73 */
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;
138 }
139
140 public static function register_wrapper_hooks() {
141 add_filter( 'friends_get_user_feeds', array( 'Friends\User', 'friends_get_user_feeds' ), 10, 2 );
142 }
143
144 /**
145 * Get the feeds for a user.
146 *
147 * @param array $feeds The feeds.
148 * @param \WP_User $user The user.
149 */
150 public static function friends_get_user_feeds( $feeds, $user ) {
151 $user_feeds = $user->get_feeds();
152 if ( is_array( $user_feeds ) ) {
153 $feeds = array_merge( $feeds, $user_feeds );
154 }
155 return $feeds;
156 }
157
158 /**
159 * Convert a site URL to a username
160 *
161 * @param string $url The site URL in question.
162 * @return string The corresponding username.
163 */
164 public static function get_user_login_for_url( $url ) {
165 $multisite_user = self::get_multisite_user( $url );
166 if ( $multisite_user ) {
167 return $multisite_user->user_login;
168 }
169
170 $user_login = self::sanitize_username( self::get_display_name_for_url( $url ) );
171 return $user_login;
172 }
173
174 /**
175 * Convert a site URL to a display name
176 *
177 * @param string $url The site URL in question.
178 * @return string The corresponding display name.
179 */
180 public static function get_display_name_for_url( $url ) {
181 $multisite_user = self::get_multisite_user( $url );
182 if ( $multisite_user ) {
183 return $multisite_user->display_name;
184 }
185
186 $host = wp_parse_url( $url, PHP_URL_HOST );
187 $path = wp_parse_url( $url, PHP_URL_PATH );
188
189 $display_name = sanitize_text_field( preg_replace( '#^www\.#', '', preg_replace( '#[^a-z0-9.-]+#i', ' ', strtolower( $host . ' ' . $path ) ) ) );
190 return $display_name;
191 }
192
193 /**
194 * Discover a display name from feeds
195 *
196 * @param array $feeds A list of feeds.
197 * @return string The corresponding display name.
198 */
199 public static function get_display_name_from_feeds( $feeds ) {
200 foreach ( $feeds as $feed ) {
201 if ( 'self' === $feed['rel'] ) {
202 return sanitize_text_field( $feed['title'] );
203 }
204 }
205
206 return false;
207 }
208
209 /**
210 * If the URL is on the same multisite, get the main user.
211 *
212 * @param string $url The site URL in question.
213 * @return bool|WP_User false or the user.
214 */
215 public static function get_multisite_user( $url ) {
216 if ( ! is_multisite() ) {
217 return false;
218 }
219
220 $host = wp_parse_url( $url, PHP_URL_HOST );
221 if ( ! $host ) {
222 return false;
223 }
224 $path = wp_parse_url( $url, PHP_URL_PATH );
225
226 $site_id = get_blog_id_from_url( $host, trailingslashit( $path ) );
227 if ( ! $site_id ) {
228 return false;
229 }
230
231 // Let's find the user that is associated with that blog.
232 switch_to_blog( $site_id );
233 $friend_user_id = Friends::get_main_friend_user_id();
234 restore_current_blog();
235
236 return get_user_by( 'id', $friend_user_id );
237 }
238
239 /**
240 * Sanitize the username according to some more rules than just sanitize_user()
241 *
242 * @param string $username The username.
243 *
244 * @return string The sanitized username.
245 */
246 public static function sanitize_username( $username ) {
247 $username = preg_replace( '/[^a-z0-9.]+/', '-', strtolower( $username ) );
248 $username = sanitize_user( $username );
249 return $username;
250 }
251
252 /**
253 * Determines whether the specified user is a friends plugin user.
254 *
255 * @param \WP_User $user The user.
256 *
257 * @return bool True if the specified user is a friends plugin user, False otherwise.
258 */
259 public static function is_friends_plugin_user( \WP_User $user ) {
260 return $user->has_cap( 'friend' ) || $user->has_cap( 'pending_friend_request' ) || $user->has_cap( 'friend_request' ) || $user->has_cap( 'subscription' );
261 }
262
263 /**
264 * Get a friend user for a user_login.
265 *
266 * @param string $user_login The user login.
267 * @return User|false The friend user or false.
268 */
269 public static function get_user( $user_login ) {
270 $user = get_user_by( 'login', $user_login );
271 if ( $user ) {
272 if ( self::is_friends_plugin_user( $user ) ) {
273 return new self( $user );
274 }
275
276 return false;
277 }
278 return $user;
279 }
280
281 /**
282 * Get a friend user for a user_id.
283 *
284 * @param string $user_id The user ID.
285 * @return User|false The friend user or false.
286 */
287 public static function get_user_by_id( $user_id ) {
288 if ( 0 === strpos( $user_id, 'friends-virtual-user-' ) ) {
289 $term_id = substr( $user_id, strlen( 'friends-virtual-user-' ) );
290 $term = get_term( intval( $term_id ), Subscription::TAXONOMY );
291 if ( $term ) {
292 return new Subscription( $term );
293 }
294 }
295
296 $user = get_user_by( 'ID', $user_id );
297 if ( $user ) {
298 if ( $user->has_cap( 'friend' ) || $user->has_cap( 'pending_friend_request' ) || $user->has_cap( 'friend_request' ) || $user->has_cap( 'subscription' ) ) {
299 return new self( $user );
300 }
301
302 return false;
303 }
304 return $user;
305 }
306
307 public function __get( $key ) {
308 if ( 'user_url' === $key && empty( $this->data->user_url ) && is_multisite() ) {
309 $site = get_active_blog_for_user( $this->ID );
310 if ( $site ) {
311 // Ensure we're using the same URL protocol.
312 $this->data->user_url = set_url_scheme( $site->siteurl );
313 return $this->data->user_url;
314 }
315 }
316
317 return parent::__get( $key );
318 }
319 /**
320 * Sends a message to the friend..
321 *
322 * @param string $message The message.
323 * @param string $subject The subject.
324 *
325 * @return \WP_Error|bool True if the message was sent successfully.
326 */
327 public function send_message( $message, $subject = null ) {
328 $friends = Friends::get_instance();
329 return $friends->messages->send_message( $this, $message, $subject );
330 }
331
332 public function insert_post( array $postarr, $wp_error = false, $fire_after_hooks = true ) {
333 $current_user = wp_get_current_user();
334
335 // Posts and revisions should be associated with this user.
336 wp_set_current_user( $this->ID );
337
338 $post = wp_insert_post( $postarr, $wp_error, $fire_after_hooks );
339
340 if ( $current_user ) {
341 wp_set_current_user( $current_user->ID );
342 }
343
344 return $post;
345 }
346
347 public function get_object_id() {
348 return $this->ID;
349 }
350
351 public function save() {
352 return wp_update_user( $this );
353 }
354
355 /**
356 * Save multiple feeds for a user.
357 *
358 * @param string $feeds The feed URLs to subscribe to.
359 *
360 * @return array(\WP_Term)|\WP_error $user The new associated user or an error object.
361 */
362 public function save_feeds( $feeds = array() ) {
363 $errors = new \WP_Error();
364 foreach ( $feeds as $feed_url => $options ) {
365 if ( ! is_string( $feed_url ) || ! Friends::check_url( $feed_url ) ) {
366 $errors->add( 'invalid-url', 'An invalid URL was provided' );
367 unset( $feeds[ $feed_url ] );
368 continue;
369 }
370
371 $default_options = array(
372 'active' => false,
373 'parser' => 'simplepie',
374 'post-format' => 'standard',
375 'mime-type' => 'application/rss+xml',
376 'title' => $this->display_name . ' RSS Feed',
377 );
378
379 $feeds[ $feed_url ] = array_merge( $default_options, $options );
380 }
381
382 $all_urls = array();
383 foreach ( wp_get_object_terms( $this->get_object_id(), User_Feed::TAXONOMY ) as $term ) {
384 $all_urls[ $term->name ] = $term->term_id;
385 }
386
387 $user_feeds = wp_set_object_terms( $this->get_object_id(), array_keys( array_merge( $all_urls, $feeds ) ), User_Feed::TAXONOMY );
388 if ( is_wp_error( $user_feeds ) ) {
389 return $user_feeds;
390 }
391
392 foreach ( wp_get_object_terms( $this->get_object_id(), User_Feed::TAXONOMY ) as $term ) {
393 $all_urls[ $term->name ] = $term->term_id;
394 }
395
396 foreach ( $feeds as $url => $feed_options ) {
397 if ( ! isset( $all_urls[ $url ] ) ) {
398 continue;
399 }
400 $term_id = $all_urls[ $url ];
401 foreach ( $feed_options as $key => $value ) {
402 if ( in_array( $key, array( 'active', 'parser', 'post-format', 'mime-type', 'title', 'interval', 'modifier' ) ) ) {
403
404 if ( metadata_exists( 'term', $term_id, $key ) ) {
405 update_metadata( 'term', $term_id, $key, $value );
406 } else {
407 add_metadata( 'term', $term_id, $key, $value, true );
408 }
409 }
410 }
411 }
412
413 if ( $errors->has_errors() ) {
414 return $errors;
415 }
416
417 return $all_urls;
418 }
419
420 /**
421 * Save a feed url for a user.
422 *
423 * @param string $feed_url The feed URL to subscribe to.
424 * @param array $options The options.
425 *
426 * @return User_Feed|\WP_Error $user The new feed or an error object.
427 */
428 public function save_feed( $feed_url, $options = array() ) {
429 $all_urls = $this->save_feeds( array( $feed_url => $options ) );
430
431 if ( is_wp_error( $all_urls ) ) {
432 return $all_urls;
433 }
434
435 if ( ! isset( $all_urls[ $feed_url ] ) ) {
436 return new \WP_Error(
437 'error-saving-feed',
438 sprintf(
439 // translators: %s is a URL.
440 __( 'The feed %s could not be saved', 'friends' )
441 )
442 );
443 }
444
445 $term = get_term( $all_urls[ $feed_url ], User_Feed::TAXONOMY );
446
447 return new User_Feed( $term );
448 }
449
450 /**
451 * Subscribe to a friends site without becoming a friend
452 *
453 * @param string $feed_url The feed URL to subscribe to.
454 * @param array $options The options.
455 *
456 * @return User_Feed|\WP_error $user The new associated user or an error object.
457 */
458 public function subscribe( $feed_url, $options = array() ) {
459 $options['active'] = true;
460 return $this->save_feed( $feed_url, $options );
461 }
462
463 /**
464 * Retrieve the posts for this user
465 *
466 * @return array The new posts.
467 */
468 public function retrieve_posts_from_active_feeds() {
469 return $this->retrieve_posts_from_feeds( $this->get_active_feeds() );
470 }
471
472 /**
473 * Retrieve the posts for these user feeds
474 *
475 * @param array $feeds The feeds to retrieve from.
476 *
477 * @return array The new posts.
478 */
479 public function retrieve_posts_from_feeds( array $feeds ) {
480 $friends = Friends::get_instance();
481 $new_posts = array();
482 foreach ( $feeds as $feed ) {
483 $posts = $friends->feed->retrieve_feed( $feed );
484 if ( ! is_wp_error( $posts ) ) {
485 $new_posts = array_merge( $new_posts, $posts );
486 }
487 }
488
489 $deleted_posts = $this->delete_outdated_posts();
490
491 return array_values( array_diff( $new_posts, $deleted_posts ) );
492 }
493
494 public function modify_query_by_author( \WP_Query $query ) {
495 $query->set( 'author', $this->ID );
496 return $query;
497 }
498
499 public function modify_get_posts_args_by_author( $args ) {
500 $args['author'] = $this->ID;
501 return $args;
502 }
503
504 public function delete() {
505 if ( is_multisite() ) {
506 remove_user_from_blog( $this->ID, get_current_blog_id() );
507 } else {
508 wp_delete_user( $this->ID );
509 }
510 // The content (posts and feeds) will be deleted with the 'delete_user' hook.
511 }
512
513 /**
514 * Delete posts the user decided to automatically delete.
515 */
516 public function delete_outdated_posts() {
517 $deleted_posts = array();
518
519 $args = array(
520 'post_type' => Friends::CPT,
521 );
522
523 if ( $this->is_retention_days_enabled() ) {
524 $args['date_query'] = array(
525 'before' => gmdate( 'Y-m-d H:i:s', strtotime( '-' . ( $this->get_retention_days() * 24 ) . 'hours' ) ),
526 );
527 } elseif ( get_option( 'friends_enable_retention_days' ) ) {
528 $args['date_query'] = array(
529 'before' => gmdate( 'Y-m-d H:i:s', strtotime( '-' . ( Friends::get_retention_days() * 24 ) . 'hours' ) ),
530 );
531 }
532
533 if ( isset( $args['date_query'] ) ) {
534 $query = new \WP_Query();
535 foreach ( $args as $key => $value ) {
536 $query->set( $key, $value );
537 }
538 $query = $this->modify_query_by_author( $query );
539
540 foreach ( $query->get_posts() as $post ) {
541 if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
542 echo 'Deleting ', esc_html( $post->ID ), '<br/>';
543 }
544 wp_delete_post( $post->ID, true );
545 $deleted_posts[] = $post->ID;
546 }
547 }
548
549 unset( $args['date_query'] );
550 $args['orderby'] = 'date';
551 $args['order'] = 'asc';
552 if ( $this->is_retention_number_enabled() ) {
553 $args['offset'] = $this->get_retention_number();
554 $query = new \WP_Query();
555 foreach ( $args as $key => $value ) {
556 $query->set( $key, $value );
557 }
558 $query = $this->modify_query_by_author( $query );
559
560 foreach ( $query->get_posts() as $post ) {
561 if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
562 echo 'Deleting ', esc_html( $post->ID ), '<br/>';
563 }
564 wp_delete_post( $post->ID, true );
565 $deleted_posts[] = $post->ID;
566 }
567 }
568
569 // Global setting.
570 if ( get_option( 'friends_enable_retention_number' ) ) {
571 unset( $args['author'] );
572 $args['offset'] = Friends::get_retention_number();
573 $query = new \WP_Query();
574 foreach ( $args as $key => $value ) {
575 $query->set( $key, $value );
576 }
577 $query = $this->modify_query_by_author( $query );
578
579 foreach ( $query->get_posts() as $post ) {
580 if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
581 echo 'Deleting ', esc_html( $post->ID ), '<br/>';
582 }
583 wp_delete_post( $post->ID, true );
584 $deleted_posts[] = $post->ID;
585 }
586 }
587
588 // In any case, don't overflow the trash.
589 $args = array(
590 'post_type' => Friends::CPT,
591 'post_status' => 'trash',
592 'offset' => 30,
593 );
594
595 $query = new \WP_Query();
596 foreach ( $args as $key => $value ) {
597 $query->set( $key, $value );
598 }
599 $query = $this->modify_query_by_author( $query );
600
601 foreach ( $query->get_posts() as $post ) {
602 if ( apply_filters( 'friends_debug', false ) && ! wp_doing_cron() ) {
603 echo 'Deleting ', esc_html( $post->ID ), '<br/>';
604 }
605 wp_delete_post( $post->ID, true );
606 $deleted_posts[ $post->ID ] = $post->ID;
607 }
608
609 return $deleted_posts;
610 }
611
612 /**
613 * Check whether the retention by number of posts is enabled.
614 *
615 * @return boolean Whether the retention by number of posts is enabled.
616 */
617 public function is_retention_number_enabled() {
618 return $this->get_user_option( 'friends_enable_retention_number' );
619 }
620
621 /**
622 * Enable or disable the retention by number of posts.
623 *
624 * @param boolean $enabled Whether the retention by number of posts should be enabled.
625 * @return boolean Whether the retention by number of posts is enabled.
626 */
627 public function set_retention_number_enabled( $enabled ) {
628 $this->update_user_option( 'friends_enable_retention_number', boolval( $enabled ) );
629 return boolval( $enabled );
630 }
631
632 /**
633 * Get the retention by number of posts.
634 *
635 * @return int The retention by number of posts.
636 */
637 public function get_retention_number() {
638 $number = $this->get_user_option( 'friends_retention_number' );
639 if ( $number <= 0 ) {
640 return 200;
641 }
642
643 return $number;
644 }
645
646 /**
647 * Set the retention by number of posts.
648 *
649 * @param int $number The retention by number of posts.
650 * @return int The retention by number of posts.
651 */
652 public function set_retention_number( $number ) {
653 $number = max( 1, $number );
654 $this->update_user_option( 'friends_retention_number', $number );
655 return $number;
656 }
657 /**
658 * Check whether the retention by days of posts is enabled.
659 *
660 * @return boolean Whether the retention by days of posts is enabled.
661 */
662 public function is_retention_days_enabled() {
663 return $this->get_user_option( 'friends_enable_retention_days' );
664 }
665
666 /**
667 * Enable or disable the retention by days of posts.
668 *
669 * @param boolean $enabled Whether the retention by days of posts should be enabled.
670 * @return boolean Whether the retention by days of posts is enabled.
671 */
672 public function set_retention_days_enabled( $enabled ) {
673 $this->update_user_option( 'friends_enable_retention_days', boolval( $enabled ) );
674 return boolval( $enabled );
675 }
676
677 /**
678 * Get the retention by days of posts.
679 *
680 * @return int The retention by days of posts.
681 */
682 public function get_retention_days() {
683 $days = $this->get_user_option( 'friends_retention_days' );
684 if ( $days <= 0 ) {
685 return 14;
686 }
687
688 return $days;
689 }
690
691 /**
692 * Set the retention by days of posts.
693 *
694 * @param int $days The retention by days of posts.
695 * @return int The retention by days of posts.
696 */
697 public function set_retention_days( $days ) {
698 $days = max( 1, intval( $days ) );
699 return $this->update_user_option( 'friends_retention_days', $days );
700 return $days;
701 }
702
703 /**
704 * Gets the post counts by post format.
705 *
706 * @return int The post count.
707 */
708 public function get_post_in_trash_count() {
709 global $wpdb;
710 $post_types = apply_filters( 'friends_frontend_post_types', array() );
711
712 $count = $wpdb->get_var(
713 $wpdb->prepare(
714 "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',
715 array_merge( $post_types, array( $this->ID ) )
716 )
717 );
718
719 return intval( $count );
720 }
721
722 /**
723 * Gets the post counts by post format.
724 *
725 * @return array The post counts.
726 */
727 public function get_post_count_by_post_format() {
728 $cache_key = 'friends_post_count_by_post_format_author_' . $this->ID;
729
730 $counts = get_transient( $cache_key );
731 if ( true || false === $counts ) {
732 $counts = array();
733 $post_types = apply_filters( 'friends_frontend_post_types', array() );
734 $post_formats_term_ids = array();
735 foreach ( get_post_format_slugs() as $post_format ) {
736 $term = get_term_by( 'slug', 'post-format-' . $post_format, 'post_format' );
737 if ( $term ) {
738 $post_formats_term_ids[ $term->term_id ] = $post_format;
739 }
740 }
741
742 global $wpdb;
743
744 $counts = array();
745 $counts['standard'] = $wpdb->get_var(
746 $wpdb->prepare(
747 sprintf(
748 "SELECT COUNT(DISTINCT posts.ID)
749 FROM %s AS posts
750 JOIN %s AS relationships_post_format
751
752 WHERE posts.post_author = %s
753 AND posts.post_status IN ( 'publish', 'private' )
754 AND posts.post_type IN ( %s )
755 AND relationships_post_format.object_id = posts.ID",
756 $wpdb->posts,
757 $wpdb->term_relationships,
758 '%d',
759 implode( ',', array_fill( 0, count( $post_types ), '%s' ) )
760 ),
761 array_merge(
762 array( $this->ID ),
763 $post_types
764 )
765 )
766 );
767
768 $post_format_counts = $wpdb->get_results(
769 $wpdb->prepare(
770 sprintf(
771 "SELECT relationships_post_format.term_taxonomy_id AS post_format_id, COUNT(relationships_post_format.term_taxonomy_id) AS count
772 FROM %s AS posts
773 JOIN %s AS relationships_post_format
774
775 WHERE posts.post_author = %s
776 AND posts.post_status IN ( 'publish', 'private' )
777 AND posts.post_type IN ( %s )
778 AND relationships_post_format.object_id = posts.ID
779 AND relationships_post_format.term_taxonomy_id IN ( %s )
780 GROUP BY relationships_post_format.term_taxonomy_id",
781 $wpdb->posts,
782 $wpdb->term_relationships,
783 '%d',
784 implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
785 implode( ',', array_fill( 0, count( $post_formats_term_ids ), '%d' ) )
786 ),
787 array_merge(
788 array( $this->ID ),
789 $post_types,
790 array_keys( $post_formats_term_ids )
791 )
792 )
793 );
794
795 foreach ( $post_format_counts as $row ) {
796 $counts[ $post_formats_term_ids[ $row->post_format_id ] ] = $row->count;
797 $counts['standard'] -= $row->count;
798 }
799
800 $counts = array_filter( $counts );
801
802 set_transient( $cache_key, $counts, HOUR_IN_SECONDS );
803 }
804
805 return $counts;
806 }
807
808 /**
809 * Gets the post stats.
810 *
811 * @return object The post stats.
812 */
813 public function get_post_stats() {
814 global $wpdb;
815 $post_types = apply_filters( 'friends_frontend_post_types', array() );
816 $post_stats = $wpdb->get_row(
817 $wpdb->prepare(
818 'SELECT SUM(
819 LENGTH( ID ) +
820 LENGTH( post_author ) +
821 LENGTH( post_date ) +
822 LENGTH( post_date_gmt ) +
823 LENGTH( post_content ) +
824 LENGTH( post_title ) +
825 LENGTH( post_excerpt ) +
826 LENGTH( post_status ) +
827 LENGTH( comment_status ) +
828 LENGTH( ping_status ) +
829 LENGTH( post_password ) +
830 LENGTH( post_name ) +
831 LENGTH( to_ping ) +
832 LENGTH( pinged ) +
833 LENGTH( post_modified ) +
834 LENGTH( post_modified_gmt ) +
835 LENGTH( post_content_filtered ) +
836 LENGTH( post_parent ) +
837 LENGTH( guid ) +
838 LENGTH( menu_order ) +
839 LENGTH( post_type ) +
840 LENGTH( post_mime_type ) +
841 LENGTH( comment_count )
842 ) AS total_size,
843 COUNT(*) as post_count
844 FROM ' . $wpdb->posts . ' WHERE post_author = %d AND post_type IN ( ' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
845 array_merge( array( $this->ID ), $post_types )
846 ),
847 ARRAY_A
848 );
849 $post_stats['earliest_post_date'] = mysql2date(
850 'U',
851 $wpdb->get_var(
852 $wpdb->prepare(
853 "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' ) ) . ' )',
854 array_merge( array( $this->ID ), $post_types )
855 )
856 )
857 );
858 return $post_stats;
859 }
860
861 public function get_all_post_ids() {
862 global $wpdb;
863 $post_types_to_delete = implode( "', '", apply_filters( 'friends_frontend_post_types', array() ) );
864
865 $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
866 return $post_ids;
867 }
868
869 /**
870 * Update a friend's avatar URL
871 *
872 * @param string $user_icon_url The user icon URL.
873 * @return string|false The URL that was set or false.
874 */
875 public function update_user_icon_url( $user_icon_url ) {
876 if ( ! $user_icon_url ) {
877 $user_icon_url = Mf2\resolveUrl( $this->user_url, '/favicon.ico' );
878 }
879
880 if ( $user_icon_url && Friends::check_url( $user_icon_url ) ) {
881 $this->update_user_option( 'friends_user_icon_url', $user_icon_url );
882 return $user_icon_url;
883 }
884
885 return false;
886 }
887
888 /**
889 * Retrieve the rules for this feed.
890 *
891 * @return array The rules set by the user for this feed.
892 */
893 public function get_feed_rules() {
894 if ( ! isset( self::$feed_rules[ $this->ID ] ) ) {
895 $this->set_feed_rules( $this->get_user_option( 'friends_feed_rules' ) );
896 }
897 return self::$feed_rules[ $this->ID ];
898 }
899
900 /**
901 * Set the rules for this feed.
902 *
903 * @param array $rules The rules to set for this feed.
904 * @return array The rules set by the user for this feed.
905 */
906 public function set_feed_rules( $rules ) {
907 $friends = Friends::get_instance();
908 self::$feed_rules[ $this->ID ] = $friends->feed->validate_feed_rules( $rules );
909 return self::$feed_rules[ $this->ID ];
910 }
911
912
913 /**
914 * Retrieve the catch_all value for this feed.
915 *
916 * @return array The rules set by the user for this feed.
917 */
918 public function get_feed_catch_all() {
919 if ( ! isset( self::$feed_catch_all[ $this->ID ] ) ) {
920 $this->set_feed_catch_all( $this->get_user_option( 'friends_feed_catch_all' ) );
921 }
922 return self::$feed_catch_all[ $this->ID ];
923 }
924
925
926 /**
927 * Set the catch_all value for this feed.
928 *
929 * @param array $catchall The catchall rule to set for this feed.
930 * @return array The catchall rukle set by the user for this feed.
931 */
932 public function set_feed_catch_all( $catchall ) {
933 $friends = Friends::get_instance();
934 self::$feed_catch_all[ $this->ID ] = $friends->feed->validate_feed_catch_all( $catchall );
935 return self::$feed_catch_all[ $this->ID ];
936 }
937
938 /**
939 * Retrieve the remote post ids.
940 *
941 * @return array A mapping of the remote post ids.
942 */
943 public function get_remote_post_ids() {
944 $remote_post_ids = array();
945 $existing_posts = new \WP_Query(
946 array(
947 'post_type' => Friends::CPT,
948 'post_status' => array( 'publish', 'private', 'trash' ),
949 'author' => $this->ID,
950 'nopaging' => true,
951 )
952 );
953
954 if ( $existing_posts->have_posts() ) {
955 while ( $existing_posts->have_posts() ) {
956 $post = $existing_posts->next_post();
957 $remote_post_id = get_post_meta( $post->ID, 'remote_post_id', true );
958 if ( $remote_post_id ) {
959 $remote_post_ids[ $remote_post_id ] = $post->ID;
960 }
961 $permalink = get_permalink( $post );
962 $remote_post_ids[ $permalink ] = $post->ID;
963 $permalink = str_replace( array( '&#38;', '&#038;' ), '&', ent2ncr( $permalink ) );
964 $remote_post_ids[ $permalink ] = $post->ID;
965 }
966 }
967
968 do_action( 'friends_remote_post_ids', $remote_post_ids );
969 return $remote_post_ids;
970 }
971
972 /**
973 * Get the user's feeds (and potentially convert old-style feed URL).
974 *
975 * @return array An array of User_Feed items.
976 */
977 public function get_feeds() {
978 $term_query = new \WP_Term_Query(
979 array(
980 'taxonomy' => User_Feed::TAXONOMY,
981 'object_ids' => $this->get_object_id(),
982 )
983 );
984
985 $feeds = array();
986 foreach ( $term_query->get_terms() as $term ) {
987 $feeds[ $term->term_id ] = new User_Feed( $term, $this );
988 }
989
990 return $feeds;
991 }
992
993 /**
994 * Get just the user's active feeds.
995 *
996 * @return array An array of active User_Feed items.
997 */
998 public function get_active_feeds() {
999 $active_feeds = array();
1000 foreach ( $this->get_feeds() as $feed ) {
1001 if ( $feed->is_active() ) {
1002 $active_feeds[] = $feed;
1003 }
1004 }
1005 return $active_feeds;
1006 }
1007
1008 /**
1009 * Get just the user's active feeds.
1010 *
1011 * @return array An array of active User_Feed items.
1012 */
1013 public function get_due_feeds() {
1014 $due_feeds = array();
1015 foreach ( $this->get_active_feeds() as $feed ) {
1016 // Explicitly use time() to allow mocking it inside the namespace.
1017 if ( gmdate( 'Y-m-d H:i:s', time() ) >= $feed->get_next_poll() ) {
1018 $due_feeds[] = $feed;
1019 }
1020 }
1021 return $due_feeds;
1022 }
1023
1024 /**
1025 * Determines whether the user can have feeds refreshed.
1026 *
1027 * @return bool True if able to refresh feeds, False otherwise.
1028 */
1029 public function can_refresh_feeds() {
1030 return $this->has_cap( 'subscription' ) ||
1031 $this->has_cap( 'acquaintance' ) ||
1032 $this->has_cap( 'friend' ) ||
1033 $this->has_cap( 'pending_friend_request' );
1034 }
1035
1036 /**
1037 * Convert a user to a friend
1038 *
1039 * @param string $out_token The token to authenticate against the remote.
1040 * @param string $in_token The token the remote needs to use to authenticate to us.
1041 */
1042 public function make_friend( $out_token, $in_token ) {
1043 $this->update_user_option( 'friends_out_token', $out_token );
1044 if ( $this->update_user_option( 'friends_in_token', $in_token ) ) {
1045 update_option( 'friends_in_token_' . $in_token, $this->ID );
1046 }
1047 $this->set_role( get_option( 'friends_default_friend_role', 'friend' ) );
1048 }
1049
1050 /**
1051 * Check whether this is a valid friend
1052 *
1053 * @return boolean Whether the user has valid friend data.
1054 */
1055 public function is_valid_friend() {
1056 if ( ! $this->has_cap( 'friend' ) ) {
1057 return false;
1058 }
1059
1060 if ( ! $this->data->user_url ) {
1061 return false;
1062 }
1063
1064 if ( ! $this->get_user_option( 'friends_in_token' ) ) {
1065 return false;
1066 }
1067
1068 if ( ! $this->get_user_option( 'friends_out_token' ) ) {
1069 return false;
1070 }
1071
1072 return true;
1073 }
1074
1075 /**
1076 * Gets the role name (for a specific count).
1077 *
1078 * @param bool $group_subscriptions Whether to group all types of subscriptions into the name "Subscriptions".
1079 * @param int $count The count if more than one.
1080 *
1081 * @return string The role name.
1082 */
1083 public function get_role_name( $group_subscriptions = false, $count = 1 ) {
1084 $name = false;
1085
1086 if ( ! $name && in_array( 'acquaintance', $this->roles ) ) {
1087 return _nx( 'Acquaintance', 'Acquaintances', $count, 'User role', 'friends' );
1088 }
1089
1090 if ( ! $name && in_array( 'friend', $this->roles ) && $this->is_valid_friend() ) {
1091 return _nx( 'Friend', 'Friends', $count, 'User role', 'friends' );
1092 }
1093
1094 if ( ! $name && in_array( 'subscription', $this->roles ) || ( $group_subscriptions && ( in_array( 'friend_request', $this->roles ) || in_array( 'pending_friend_request', $this->roles ) ) ) ) {
1095 return _nx( 'Subscription', 'Subscriptions', $count, 'User role', 'friends' );
1096 }
1097
1098 if ( ! $name && in_array( 'friend_request', $this->roles ) ) {
1099 return _nx( 'Friend Request', 'Friend Requests', $count, 'User role', 'friends' );
1100 }
1101
1102 if ( ! $name && in_array( 'pending_friend_request', $this->roles ) ) {
1103 return _nx( 'Pending Friend Request', 'Pending Friend Requests', $count, 'User role', 'friends' );
1104 }
1105
1106 $name = apply_filters( 'friend_user_role_name', $name, $this );
1107
1108 if ( ! $name ) {
1109 $name = _x( 'Unknown', 'User role', 'friends' );
1110 }
1111
1112 return $name;
1113 }
1114
1115 /**
1116 * Determines if starred.
1117 *
1118 * @return bool True if starred, False otherwise.
1119 */
1120 public function is_starred() {
1121 return $this->get_user_option( 'friends_starred' );
1122 }
1123
1124 /**
1125 * Marks a friend as starred or unstarred.
1126 *
1127 * @param bool $starred Whether to star the friend.
1128 *
1129 * @return bool The new star status.
1130 */
1131 public function set_starred( $starred ) {
1132 if ( $starred ) {
1133 $this->update_user_option( 'friends_starred', true );
1134 return true;
1135 }
1136
1137 $this->delete_user_option( 'friends_starred' );
1138 return false;
1139 }
1140
1141 /**
1142 * Gets the local friends page url.
1143 *
1144 * @param integer $post_id The post identifier.
1145 *
1146 * @return string The local friends page url.
1147 */
1148 function get_local_friends_page_url( $post_id = null ) {
1149 $path = '/';
1150 if ( $post_id ) {
1151 $path = '/' . $post_id . '/';
1152 }
1153 return home_url( '/friends/' . self::get_user_login_for_url( $this->user_login ) . $path );
1154 }
1155
1156 /**
1157 * Gets the local friends page url for a post format.
1158 *
1159 * @param string|array $post_format The post format.
1160 *
1161 * @return string The local friends page url.
1162 */
1163 function get_local_friends_page_post_format_url( $post_format ) {
1164 if ( is_array( $post_format ) ) {
1165 $post_format = implode( ',', $post_format );
1166 }
1167 return home_url( '/friends/' . $this->user_login . '/type/' . $post_format . '/' );
1168 }
1169
1170 /**
1171 * Gets the local friends page url for a reaction.
1172 *
1173 * @param string $slug The reaction slug.
1174 *
1175 * @return string The local friends page url.
1176 */
1177 function get_local_friends_page_reaction_url( $slug ) {
1178 return home_url( '/friends/' . $this->user_login . '/reaction' . $slug . '/' );
1179 }
1180
1181 /**
1182 * Gets the friend auth to be used as a GET parameter.
1183 *
1184 * @param integer $validity The validity in seconds.
1185 *
1186 * @return string The friend auth.
1187 */
1188 function get_friend_auth( $validity = 3600 ) {
1189 $friends = Friends::get_instance();
1190 $friend_auth = $friends->access_control->get_friend_auth( $this, $validity );
1191 if ( empty( $friend_auth ) ) {
1192 return '';
1193 }
1194 return $friend_auth['me'] . '-' . $friend_auth['until'] . '-' . $friend_auth['auth'];
1195 }
1196
1197 /**
1198 * Determines whether the specified url is friend url.
1199 *
1200 * @param string $url The url.
1201 *
1202 * @return bool True if the specified url is friend url, False otherwise.
1203 */
1204 function is_friend_url( $url ) {
1205 if ( ! $this->user_url ) {
1206 return false;
1207 }
1208 if ( 0 !== strpos( $url, $this->user_url ) ) {
1209 return false;
1210 }
1211 return true;
1212 }
1213
1214 /**
1215 * Get the REST URL for the friend
1216 *
1217 * @return string The REST URL.
1218 */
1219 public function get_rest_url() {
1220 $friends = Friends::get_instance();
1221 $rest_url = $this->get_user_option( 'friends_rest_url' );
1222 if ( ! $rest_url || false === strpos( $rest_url, REST::PREFIX ) ) {
1223 $rest_url = $friends->rest->discover_rest_url( $this->user_url );
1224 if ( is_wp_error( $rest_url ) ) {
1225 return null;
1226 }
1227
1228 if ( $rest_url ) {
1229 $this->update_user_option( 'friends_rest_url', $rest_url );
1230 }
1231 }
1232 return $rest_url;
1233 }
1234
1235 public function get_avatar_url() {
1236 return $this->get_user_option( 'friends_user_icon_url' );
1237 }
1238
1239 /**
1240 * Wrap get_user_option
1241 *
1242 * @param string $option_name User option name.
1243 * @return int|bool User meta ID if the option didn't exist, true on successful update,
1244 * false on failure.
1245 */
1246 function get_user_option( $option_name ) {
1247 return get_user_option( $option_name, $this->ID );
1248 }
1249
1250 /**
1251 * Wrap update_user_option
1252 *
1253 * @param string $option_name User option name.
1254 * @param mixed $new_value User option value.
1255 * @param bool $global Optional. Whether option name is global or blog specific.
1256 * Default false (blog specific).
1257 * @return int|bool User meta ID if the option didn't exist, true on successful update,
1258 * false on failure.
1259 */
1260 function update_user_option( $option_name, $new_value, $global = false ) {
1261 return update_user_option( $this->ID, $option_name, $new_value, $global );
1262 }
1263
1264 /**
1265 * Wrap delete_user_option
1266 *
1267 * @param string $option_name User option name.
1268 * @param bool $global Optional. Whether option name is global or blog specific.
1269 * Default false (blog specific).
1270 * @return bool True on success, false on failure.
1271 */
1272 function delete_user_option( $option_name, $global = false ) {
1273 return delete_user_option( $this->ID, $option_name, $global );
1274 }
1275 }
1276