PluginProbe
Friends / 2.7.7
Friends v2.7.7
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-subscription.php

class-subscription.php in Friends 2.7.7, at includes/class-subscription.php

603 lines 18.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Friend Subscription
4 *
5 * This is a virtual user to allow subscriptions without a WordPress user
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 3.0
16 *
17 * @package Friends
18 * @author Alex Kirk
19 */
20 class Subscription extends User {
21 const TAXONOMY = 'friends-virtual-user';
22 private $term;
23 const MIGRATE_USER_OPTIONS = array(
24 'friends_retention_number',
25 'friends_enable_retention_days',
26 'friends_retention_days',
27 'friends_feed_rules',
28 'friends_feed_catch_all',
29 'friends_in_token',
30 'friends_out_token',
31 'friends_starred',
32 'friends_rest_url',
33 'friends_user_icon_url',
34 );
35
36 public function __construct( \WP_Term $term ) {
37 $this->term = $term;
38 $this->ID = 'friends-virtual-user-' . $term->term_id;
39
40 $this->caps = array_fill_keys( get_metadata( 'term', $term->term_id, 'roles' ), true );
41 $this->caps['subscription'] = true;
42 $this->get_role_caps();
43
44 $this->roles = array_values( $this->roles );
45
46 $this->data = (object) array(
47 'ID' => $this->ID,
48 'user_login' => $term->name,
49 'display_name' => get_metadata( 'term', $term->term_id, 'display_name', true ),
50 'user_url' => get_metadata( 'term', $term->term_id, 'user_url', true ),
51 'description' => get_metadata( 'term', $term->term_id, 'description', true ),
52 'user_registered' => get_metadata( 'term', $term->term_id, 'created', true ),
53 );
54 }
55
56 public function get_term_id() {
57 return $this->term->term_id;
58 }
59
60 public function get_object_id() {
61 return $this->get_term_id();
62 }
63
64 public function save() {
65 foreach ( array(
66 'first_name',
67 'display_name',
68 'description',
69 'user_url',
70 ) as $key ) {
71 $this->update_user_option( $key, $this->$key );
72 }
73 return $this->get_object_id();
74 }
75
76 /**
77 * Registers the taxonomy
78 */
79 public static function register_taxonomy() {
80 $args = array(
81 'labels' => array(
82 'name' => _x( 'Virtual User', 'taxonomy general name', 'friends' ),
83 'singular_name' => _x( 'Virtual User', 'taxonomy singular name', 'friends' ),
84 'menu_name' => __( 'Virtual User', 'friends' ),
85 ),
86 'hierarchical' => false,
87 'show_ui' => true,
88 'show_admin_column' => true,
89 'query_var' => true,
90 'rewrite' => false,
91 'public' => false,
92 );
93 register_taxonomy( self::TAXONOMY, 'None', $args );
94 }
95
96 public static function get_by_username( $username ) {
97 if ( 0 === strpos( $username, 'friends-virtual-user-' ) ) {
98 $term_id = substr( $username, strlen( 'friends-virtual-user-' ) );
99 $term = get_term( intval( $term_id ), self::TAXONOMY );
100 if ( $term ) {
101 return new self( $term );
102 }
103 }
104 $term_query = new \WP_Term_Query(
105 array(
106 'taxonomy' => self::TAXONOMY,
107 'name' => $username,
108 'hide_empty' => false,
109 )
110 );
111
112 foreach ( $term_query->get_terms() as $term ) {
113 return new self( $term );
114 }
115
116 return new \WP_Error( 'user-not-found' );
117 }
118
119 public function insert_post( array $postarr, $wp_error = false, $fire_after_hooks = true ) {
120 $post_id = wp_insert_post( $postarr, $wp_error, $fire_after_hooks );
121 if ( ! is_wp_error( $post_id ) ) {
122 wp_set_object_terms( $post_id, $this->get_term_id(), self::TAXONOMY );
123 }
124
125 return $post_id;
126 }
127
128 public function modify_query_by_author( \WP_Query $query ) {
129 $tax_query = $query->get( 'tax_query' );
130 if ( ! $tax_query ) {
131 $tax_query = array();
132 } else {
133 $tax_query['relation'] = 'AND';
134 }
135 $tax_query[] =
136 array(
137 'taxonomy' => self::TAXONOMY,
138 'field' => 'term_id',
139 'terms' => $this->get_term_id(),
140 );
141 $query->set( 'tax_query', $tax_query );
142 return $query;
143 }
144
145 public function modify_get_posts_args_by_author( $args ) {
146 if ( isset( $args['author'] ) ) {
147 unset( $args['author'] );
148 }
149 if ( ! isset( $args['tax_query'] ) ) {
150 $args['tax_query'] = array();
151 } else {
152 $args['tax_query']['relation'] = 'AND';
153 }
154 $args['tax_query'][] =
155 array(
156 'taxonomy' => self::TAXONOMY,
157 'field' => 'term_id',
158 'terms' => $this->get_term_id(),
159 );
160 return $args;
161 }
162
163
164 public static function set_authordata_by_query( $query ) {
165 global $authordata;
166 if ( $query->get( 'tax_query' ) ) {
167 foreach ( $query->get( 'tax_query' ) as $tax_query ) {
168 if ( ! is_array( $tax_query ) || ! isset( $tax_query['taxonomy'] ) || self::TAXONOMY !== $tax_query['taxonomy'] ) {
169 continue;
170 }
171 if ( 'term_id' === $tax_query['field'] ) {
172 $term_id = $tax_query['terms'];
173 if ( is_array( $term_id ) ) {
174 $term_id = reset( $term_id );
175 }
176 $authordata = new Subscription( \get_term( $term_id ) );
177 return;
178 }
179 }
180 }
181 }
182
183
184 /**
185 * Gets the post stats.
186 *
187 * @return object The post stats.
188 */
189 public function get_post_stats() {
190 global $wpdb;
191 $post_types = apply_filters( 'friends_frontend_post_types', array() );
192 $post_stats = $wpdb->get_row(
193 $wpdb->prepare(
194 'SELECT SUM(
195 LENGTH( ID ) +
196 LENGTH( post_author ) +
197 LENGTH( post_date ) +
198 LENGTH( post_date_gmt ) +
199 LENGTH( post_content ) +
200 LENGTH( post_title ) +
201 LENGTH( post_excerpt ) +
202 LENGTH( post_status ) +
203 LENGTH( comment_status ) +
204 LENGTH( ping_status ) +
205 LENGTH( post_password ) +
206 LENGTH( post_name ) +
207 LENGTH( to_ping ) +
208 LENGTH( pinged ) +
209 LENGTH( post_modified ) +
210 LENGTH( post_modified_gmt ) +
211 LENGTH( post_content_filtered ) +
212 LENGTH( post_parent ) +
213 LENGTH( guid ) +
214 LENGTH( menu_order ) +
215 LENGTH( post_type ) +
216 LENGTH( post_mime_type ) +
217 LENGTH( comment_count )
218 ) AS total_size,
219 COUNT(*) as post_count
220 FROM ' . $wpdb->posts . ' p, ' . $wpdb->term_taxonomy . ' t, ' . $wpdb->term_relationships . ' r WHERE r.object_id = p.ID AND r.term_taxonomy_id = t.term_taxonomy_id AND t.term_id = %d AND p.post_type IN ( ' . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
221 array_merge( array( $this->get_term_id() ), $post_types )
222 ),
223 ARRAY_A
224 );
225
226 $post_stats['earliest_post_date'] = mysql2date(
227 'U',
228 $wpdb->get_var(
229 $wpdb->prepare(
230 "SELECT MIN(post_date) FROM $wpdb->posts p, $wpdb->term_taxonomy t, $wpdb->term_relationships r WHERE r.object_id = p.ID AND r.term_taxonomy_id = t.term_taxonomy_id AND t.term_id = %d AND p.post_status = 'publish' AND p.post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' )',
231 array_merge( array( $this->get_term_id() ), $post_types )
232 )
233 )
234 );
235 return $post_stats;
236 }
237
238 public function get_all_post_ids() {
239 global $wpdb;
240 $post_types_to_delete = implode( "', '", apply_filters( 'friends_frontend_post_types', array() ) );
241
242 $post_ids = $wpdb->get_col( $wpdb->prepare( "SELECT p.ID FROM $wpdb->posts p, $wpdb->term_relationships r WHERE r.object_id = p.ID AND r.term_taxonomy_id = %d AND p.post_type IN ('$post_types_to_delete')", $this->get_term_id() ) ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
243 return $post_ids;
244 }
245
246 /**
247 * Gets the post counts by post format.
248 *
249 * @return array The post counts.
250 */
251 public function get_post_count_by_post_format() {
252 $cache_key = 'friends_post_count_by_post_format_author_' . $this->ID;
253
254 $counts = get_transient( $cache_key );
255 if ( false === $counts ) {
256 $counts = array();
257 $post_types = apply_filters( 'friends_frontend_post_types', array() );
258 $post_formats_term_ids = array();
259 foreach ( get_post_format_slugs() as $post_format ) {
260 $term = get_term_by( 'slug', 'post-format-' . $post_format, 'post_format' );
261 if ( $term ) {
262 $post_formats_term_ids[ $term->term_id ] = $post_format;
263 }
264 }
265
266 global $wpdb;
267
268 $counts = array();
269
270 $counts['standard'] = $wpdb->get_var(
271 $wpdb->prepare(
272 sprintf(
273 "SELECT COUNT(DISTINCT posts.ID)
274 FROM %s AS posts
275 JOIN %s AS relationships_post_format
276 JOIN %s AS taxonomy_author
277 JOIN %s AS relationships_author
278
279 WHERE posts.post_status IN ( 'publish', 'private' )
280 AND posts.post_type IN ( %s )
281 AND relationships_post_format.object_id = posts.ID
282 AND relationships_author.object_id = posts.ID
283 AND taxonomy_author.term_taxonomy_id = relationships_author.term_taxonomy_id
284 AND taxonomy_author.term_id = %s",
285 $wpdb->posts,
286 $wpdb->term_relationships,
287 $wpdb->term_taxonomy,
288 $wpdb->term_relationships,
289 implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
290 '%d'
291 ),
292 array_merge(
293 $post_types,
294 array( $this->get_term_id() )
295 )
296 )
297 );
298
299 $post_format_counts = $wpdb->get_results(
300 $wpdb->prepare(
301 sprintf(
302 "SELECT relationships_post_format.term_taxonomy_id AS post_format_id, COUNT(relationships_post_format.term_taxonomy_id) AS count
303 FROM %s AS posts
304 JOIN %s AS relationships_post_format
305 JOIN %s AS taxonomy_author
306 JOIN %s AS relationships_author
307
308 WHERE posts.post_status IN ( 'publish', 'private' )
309 AND posts.post_type IN ( %s )
310 AND relationships_post_format.object_id = posts.ID
311 AND relationships_post_format.term_taxonomy_id IN ( %s )
312 AND relationships_author.object_id = posts.ID
313 AND taxonomy_author.term_taxonomy_id = relationships_author.term_taxonomy_id
314 AND taxonomy_author.term_id = %s
315 GROUP BY relationships_post_format.term_taxonomy_id",
316 $wpdb->posts,
317 $wpdb->term_relationships,
318 $wpdb->term_taxonomy,
319 $wpdb->term_relationships,
320 implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
321 implode( ',', array_fill( 0, count( $post_formats_term_ids ), '%d' ) ),
322 '%d'
323 ),
324 array_merge(
325 $post_types,
326 array_keys( $post_formats_term_ids ),
327 array( $this->get_term_id() )
328 )
329 )
330 );
331
332 foreach ( $post_format_counts as $row ) {
333 $counts[ $post_formats_term_ids[ $row->post_format_id ] ] = $row->count;
334 $counts['standard'] -= $row->count;
335 }
336
337 $counts = array_filter( $counts );
338
339 set_transient( $cache_key, $counts, HOUR_IN_SECONDS );
340 }
341
342 return $counts;
343 }
344
345 /**
346 * Gets the post counts by post format.
347 *
348 * @return int The post count.
349 */
350 public function get_post_in_trash_count() {
351 global $wpdb;
352 $post_types = apply_filters( 'friends_frontend_post_types', array() );
353
354 $count = $wpdb->get_var(
355 $wpdb->prepare(
356 "SELECT COUNT(*) FROM $wpdb->posts p, $wpdb->term_taxonomy t, $wpdb->term_relationships r WHERE r.object_id = p.ID AND r.term_taxonomy_id = t.term_taxonomy_id AND t.term_id = %d AND post_type IN ( " . implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ) . ' ) AND post_status = "trash"',
357 array_merge( array( $this->get_term_id() ), $post_types )
358 )
359 );
360
361 return intval( $count );
362 }
363
364 /**
365 * Gets the role name (for a specific count).
366 *
367 * @param bool $group_subscriptions Whether to group all types of subscriptions into the name "Subscriptions".
368 * @param int $count The count if more than one.
369 *
370 * @return string The role name.
371 */
372 public function get_role_name( $group_subscriptions = false, $count = 1 ) {
373 return _nx( 'Subscription', 'Subscriptions', $count, 'User role', 'friends' );
374 }
375
376 public function get_avatar_url() {
377 return get_metadata( 'term', $this->get_term_id(), 'avatar_url', true );
378 }
379
380 /**
381 * Determines if starred.
382 *
383 * @return bool True if starred, False otherwise.
384 */
385 public function is_starred() {
386 return get_metadata( 'term', $this->get_term_id(), 'starred', true );
387 }
388
389 /**
390 * Marks a friend as starred or unstarred.
391 *
392 * @param bool $starred Whether to star the friend.
393 *
394 * @return bool The new star status.
395 */
396 public function set_starred( $starred ) {
397 if ( $starred ) {
398 update_metadata( 'term', $this->get_term_id(), 'starred', true );
399 return true;
400 }
401
402 delete_metadata( 'term', $this->get_term_id(), 'starred' );
403 return false;
404 }
405
406 public function delete() {
407 // Allow unsubscribing to all these feeds.
408 foreach ( $this->get_active_feeds() as $feed ) {
409 do_action( 'friends_user_feed_deactivated', $feed );
410 $feed->delete();
411 }
412
413 // Delete the rest.
414 foreach ( $this->get_feeds() as $feed ) {
415 $feed->delete();
416 }
417
418 foreach ( $this->get_all_post_ids() as $post_id ) {
419 wp_delete_post( $post_id );
420 }
421
422 wp_delete_term( $this->get_term_id(), self::TAXONOMY );
423 return true;
424 }
425
426
427 public static function convert_from_user( User $user ) {
428 if ( $user instanceof Subscription ) {
429 return $user;
430 }
431
432 $subscription = self::create( $user->user_login, $user->roles[0], $user->user_url, $user->display_name, $user->get_avatar_url(), $user->description, $user->user_registered );
433
434 if ( is_wp_error( $subscription ) ) {
435 return $subscription;
436 }
437
438 $query = new \WP_Query();
439 $query->set( 'post_type', apply_filters( 'friends_frontend_post_types', array() ) );
440 $query->set( 'post_status', array( 'publish', 'private', 'draft', 'trash' ) );
441 $query->set( 'posts_per_page', -1 );
442 $query = $user->modify_query_by_author( $query );
443
444 foreach ( $query->get_posts() as $post ) {
445 $post->post_author = 0;
446 wp_update_post( $post );
447 wp_set_object_terms( $post->ID, $subscription->get_term_id(), self::TAXONOMY );
448 }
449
450 global $wpdb;
451 // Convert feeds.
452 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->term_relationships JOIN $wpdb->term_taxonomy ON $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id SET object_id = %d WHERE object_id = %d AND $wpdb->term_taxonomy.taxonomy = %s", $subscription->get_term_id(), $user->ID, User_Feed::TAXONOMY ) );
453
454 foreach ( self::MIGRATE_USER_OPTIONS as $option_name ) {
455 $subscription->update_user_option( $option_name, $user->get_user_option( $option_name ) );
456 }
457
458 $user->delete();
459
460 return $user;
461 }
462
463 public static function convert_to_user( Subscription $subscription ) {
464 $user = User::create( $subscription->user_login, $subscription->roles[0], $subscription->user_url, $subscription->display_name, $subscription->get_avatar_url(), $subscription->description, $subscription->user_registered, true );
465
466 if ( is_wp_error( $user ) ) {
467 return $user;
468 }
469
470 $query = new \WP_Query();
471 $query->set( 'post_type', apply_filters( 'friends_frontend_post_types', array() ) );
472 $query->set( 'post_status', array( 'publish', 'private', 'draft', 'trashed' ) );
473 $query->set( 'posts_per_page', -1 );
474 $query = $subscription->modify_query_by_author( $query );
475
476 foreach ( $query->get_posts() as $post ) {
477 $post->post_author = $user->ID;
478 wp_update_post( $post );
479 wp_remove_object_terms( $post->ID, $subscription->get_term_id(), self::TAXONOMY );
480 }
481
482 global $wpdb;
483 // Convert feeds.
484 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->term_relationships JOIN $wpdb->term_taxonomy ON $wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id SET object_id = %d WHERE object_id = %d AND $wpdb->term_taxonomy.taxonomy = %s", $user->ID, $subscription->get_term_id(), User_Feed::TAXONOMY ) );
485
486 foreach ( self::MIGRATE_USER_OPTIONS as $option_name ) {
487 $user->update_user_option( $option_name, $subscription->get_user_option( $option_name ) );
488 }
489
490 $subscription->delete();
491
492 return $user;
493 }
494
495 /**
496 * Create a Subscription (virtual user).
497 *
498 * @param string $user_login The user login.
499 * @param string $role The role: subscription.
500 * @param string $user_url The site URL.
501 * @param string $display_name The user's display name.
502 * @param string $avatar_url The user_icon_url URL.
503 * @param string $description A description for the user.
504 * @param string $user_registered When the user was registered.
505 * @param bool $subscription_override Whether to override the automatic creation of a subscription.
506 *
507 * @return Subscription|\WP_Error The created subscription or an error.
508 */
509 public static function create( $user_login, $role, $user_url, $display_name = null, $avatar_url = null, $description = null, $user_registered = null, $subscription_override = false ) {
510 $term = term_exists( $user_login, self::TAXONOMY );
511
512 if ( ! $term || ! isset( $term['term_id'] ) ) {
513 $term = wp_insert_term( $user_login, self::TAXONOMY );
514 if ( is_wp_error( $term ) ) {
515 return $term;
516 }
517 }
518
519 $term_id = $term['term_id'];
520
521 delete_metadata( 'term', $term_id, 'roles' );
522 add_metadata( 'term', $term_id, 'roles', $role, true );
523 delete_metadata( 'term', $term_id, 'user_url' );
524 add_metadata( 'term', $term_id, 'user_url', $user_url, true );
525
526 delete_metadata( 'term', $term_id, 'display_name' );
527 if ( $display_name ) {
528 add_metadata( 'term', $term_id, 'display_name', $display_name, true );
529 }
530
531 delete_metadata( 'term', $term_id, 'avatar_url' );
532 if ( $avatar_url ) {
533 add_metadata( 'term', $term_id, 'avatar_url', $avatar_url, true );
534 }
535 delete_metadata( 'term', $term_id, 'description' );
536 if ( $description ) {
537 add_metadata( 'term', $term_id, 'description', $description, true );
538 }
539 delete_metadata( 'term', $term_id, 'created' );
540 add_metadata( 'term', $term_id, 'created', $user_registered ? $user_registered : gmdate( 'Y-m-d H:i:s' ), true );
541
542 $term = get_term( $term['term_id'] );
543 if ( is_wp_error( $term ) ) {
544 return $term;
545 }
546
547 return new self( $term );
548 }
549
550 private function map_option( $option_name ) {
551 $option_map = array(
552 'friends_user_icon_url' => 'avatar_url',
553 );
554 if ( isset( $option_map[ $option_name ] ) ) {
555 $option_name = $option_map[ $option_name ];
556 }
557
558 return $option_name;
559 }
560
561 /**
562 * Wrap get_user_option
563 *
564 * @param string $option_name User option name.
565 * @return int|bool User meta ID if the option didn't exist, true on successful update,
566 * false on failure.
567 */
568 public function get_user_option( $option_name ) {
569 $value = get_metadata( 'term', $this->get_term_id(), $option_name, true );
570 if ( false === $value ) {
571 $value = get_metadata( 'term', $this->get_term_id(), $this->map_option( $option_name ), true );
572 }
573
574 return $value;
575 }
576
577 /**
578 * Wrap update_user_option
579 *
580 * @param string $option_name User option name.
581 * @param mixed $new_value User option value.
582 * @param bool $is_global Optional. Whether option name is global or blog specific.
583 * Default false (blog specific).
584 * @return int|bool User meta ID if the option didn't exist, true on successful update,
585 * false on failure.
586 */
587 public function update_user_option( $option_name, $new_value, $is_global = false ) {
588 return update_metadata( 'term', $this->get_term_id(), $this->map_option( $option_name ), $new_value );
589 }
590
591 /**
592 * Wrap delete_user_option
593 *
594 * @param string $option_name User option name.
595 * @param bool $is_global Optional. Whether option name is global or blog specific.
596 * Default false (blog specific).
597 * @return bool True on success, false on failure.
598 */
599 public function delete_user_option( $option_name, $is_global = false ) {
600 return delete_metadata( 'term', $this->get_term_id(), $option_name );
601 }
602 }
603