PluginProbe
Friends / 2.8.8
Friends v2.8.8
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.8.8, at includes/class-subscription.php

605 lines 18.9 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 if ( ! empty( $post_formats_term_ids ) ) {
300 $post_format_counts = $wpdb->get_results(
301 $wpdb->prepare(
302 sprintf(
303 "SELECT relationships_post_format.term_taxonomy_id AS post_format_id, COUNT(relationships_post_format.term_taxonomy_id) AS count
304 FROM %s AS posts
305 JOIN %s AS relationships_post_format
306 JOIN %s AS taxonomy_author
307 JOIN %s AS relationships_author
308
309 WHERE posts.post_status IN ( 'publish', 'private' )
310 AND posts.post_type IN ( %s )
311 AND relationships_post_format.object_id = posts.ID
312 AND relationships_post_format.term_taxonomy_id IN ( %s )
313 AND relationships_author.object_id = posts.ID
314 AND taxonomy_author.term_taxonomy_id = relationships_author.term_taxonomy_id
315 AND taxonomy_author.term_id = %s
316 GROUP BY relationships_post_format.term_taxonomy_id",
317 $wpdb->posts,
318 $wpdb->term_relationships,
319 $wpdb->term_taxonomy,
320 $wpdb->term_relationships,
321 implode( ',', array_fill( 0, count( $post_types ), '%s' ) ),
322 implode( ',', array_fill( 0, count( $post_formats_term_ids ), '%d' ) ),
323 '%d'
324 ),
325 array_merge(
326 $post_types,
327 array_keys( $post_formats_term_ids ),
328 array( $this->get_term_id() )
329 )
330 )
331 );
332
333 foreach ( $post_format_counts as $row ) {
334 $counts[ $post_formats_term_ids[ $row->post_format_id ] ] = $row->count;
335 $counts['standard'] -= $row->count;
336 }
337 }
338
339 $counts = array_filter( $counts );
340
341 set_transient( $cache_key, $counts, HOUR_IN_SECONDS );
342 }
343
344 return $counts;
345 }
346
347 /**
348 * Gets the post counts by post format.
349 *
350 * @return int The post count.
351 */
352 public function get_post_in_trash_count() {
353 global $wpdb;
354 $post_types = apply_filters( 'friends_frontend_post_types', array() );
355
356 $count = $wpdb->get_var(
357 $wpdb->prepare(
358 "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"',
359 array_merge( array( $this->get_term_id() ), $post_types )
360 )
361 );
362
363 return intval( $count );
364 }
365
366 /**
367 * Gets the role name (for a specific count).
368 *
369 * @param bool $group_subscriptions Whether to group all types of subscriptions into the name "Subscriptions".
370 * @param int $count The count if more than one.
371 *
372 * @return string The role name.
373 */
374 public function get_role_name( $group_subscriptions = false, $count = 1 ) {
375 return _nx( 'Subscription', 'Subscriptions', $count, 'User role', 'friends' );
376 }
377
378 public function get_avatar_url() {
379 return get_metadata( 'term', $this->get_term_id(), 'avatar_url', true );
380 }
381
382 /**
383 * Determines if starred.
384 *
385 * @return bool True if starred, False otherwise.
386 */
387 public function is_starred() {
388 return get_metadata( 'term', $this->get_term_id(), 'starred', true );
389 }
390
391 /**
392 * Marks a friend as starred or unstarred.
393 *
394 * @param bool $starred Whether to star the friend.
395 *
396 * @return bool The new star status.
397 */
398 public function set_starred( $starred ) {
399 if ( $starred ) {
400 update_metadata( 'term', $this->get_term_id(), 'starred', true );
401 return true;
402 }
403
404 delete_metadata( 'term', $this->get_term_id(), 'starred' );
405 return false;
406 }
407
408 public function delete() {
409 // Allow unsubscribing to all these feeds.
410 foreach ( $this->get_active_feeds() as $feed ) {
411 do_action( 'friends_user_feed_deactivated', $feed );
412 $feed->delete();
413 }
414
415 // Delete the rest.
416 foreach ( $this->get_feeds() as $feed ) {
417 $feed->delete();
418 }
419
420 foreach ( $this->get_all_post_ids() as $post_id ) {
421 wp_delete_post( $post_id );
422 }
423
424 wp_delete_term( $this->get_term_id(), self::TAXONOMY );
425 return true;
426 }
427
428
429 public static function convert_from_user( User $user ) {
430 if ( $user instanceof Subscription ) {
431 return $user;
432 }
433
434 $subscription = self::create( $user->user_login, $user->roles[0], $user->user_url, $user->display_name, $user->get_avatar_url(), $user->description, $user->user_registered );
435
436 if ( is_wp_error( $subscription ) ) {
437 return $subscription;
438 }
439
440 $query = new \WP_Query();
441 $query->set( 'post_type', apply_filters( 'friends_frontend_post_types', array() ) );
442 $query->set( 'post_status', array( 'publish', 'private', 'draft', 'trash' ) );
443 $query->set( 'posts_per_page', -1 );
444 $query = $user->modify_query_by_author( $query );
445
446 foreach ( $query->get_posts() as $post ) {
447 $post->post_author = 0;
448 wp_update_post( $post );
449 wp_set_object_terms( $post->ID, $subscription->get_term_id(), self::TAXONOMY );
450 }
451
452 global $wpdb;
453 // Convert feeds.
454 $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 ) );
455
456 foreach ( self::MIGRATE_USER_OPTIONS as $option_name ) {
457 $subscription->update_user_option( $option_name, $user->get_user_option( $option_name ) );
458 }
459
460 $user->delete();
461
462 return $user;
463 }
464
465 public static function convert_to_user( Subscription $subscription ) {
466 $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 );
467
468 if ( is_wp_error( $user ) ) {
469 return $user;
470 }
471
472 $query = new \WP_Query();
473 $query->set( 'post_type', apply_filters( 'friends_frontend_post_types', array() ) );
474 $query->set( 'post_status', array( 'publish', 'private', 'draft', 'trashed' ) );
475 $query->set( 'posts_per_page', -1 );
476 $query = $subscription->modify_query_by_author( $query );
477
478 foreach ( $query->get_posts() as $post ) {
479 $post->post_author = $user->ID;
480 wp_update_post( $post );
481 wp_remove_object_terms( $post->ID, $subscription->get_term_id(), self::TAXONOMY );
482 }
483
484 global $wpdb;
485 // Convert feeds.
486 $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 ) );
487
488 foreach ( self::MIGRATE_USER_OPTIONS as $option_name ) {
489 $user->update_user_option( $option_name, $subscription->get_user_option( $option_name ) );
490 }
491
492 $subscription->delete();
493
494 return $user;
495 }
496
497 /**
498 * Create a Subscription (virtual user).
499 *
500 * @param string $user_login The user login.
501 * @param string $role The role: subscription.
502 * @param string $user_url The site URL.
503 * @param string $display_name The user's display name.
504 * @param string $avatar_url The user_icon_url URL.
505 * @param string $description A description for the user.
506 * @param string $user_registered When the user was registered.
507 * @param bool $subscription_override Whether to override the automatic creation of a subscription.
508 *
509 * @return Subscription|\WP_Error The created subscription or an error.
510 */
511 public static function create( $user_login, $role, $user_url, $display_name = null, $avatar_url = null, $description = null, $user_registered = null, $subscription_override = false ) {
512 $term = term_exists( $user_login, self::TAXONOMY );
513
514 if ( ! $term || ! isset( $term['term_id'] ) ) {
515 $term = wp_insert_term( $user_login, self::TAXONOMY );
516 if ( is_wp_error( $term ) ) {
517 return $term;
518 }
519 }
520
521 $term_id = $term['term_id'];
522
523 delete_metadata( 'term', $term_id, 'roles' );
524 add_metadata( 'term', $term_id, 'roles', $role, true );
525 delete_metadata( 'term', $term_id, 'user_url' );
526 add_metadata( 'term', $term_id, 'user_url', $user_url, true );
527
528 delete_metadata( 'term', $term_id, 'display_name' );
529 if ( $display_name ) {
530 add_metadata( 'term', $term_id, 'display_name', $display_name, true );
531 }
532
533 delete_metadata( 'term', $term_id, 'avatar_url' );
534 if ( $avatar_url ) {
535 add_metadata( 'term', $term_id, 'avatar_url', $avatar_url, true );
536 }
537 delete_metadata( 'term', $term_id, 'description' );
538 if ( $description ) {
539 add_metadata( 'term', $term_id, 'description', $description, true );
540 }
541 delete_metadata( 'term', $term_id, 'created' );
542 add_metadata( 'term', $term_id, 'created', $user_registered ? $user_registered : gmdate( 'Y-m-d H:i:s' ), true );
543
544 $term = get_term( $term['term_id'] );
545 if ( is_wp_error( $term ) ) {
546 return $term;
547 }
548
549 return new self( $term );
550 }
551
552 private function map_option( $option_name ) {
553 $option_map = array(
554 'friends_user_icon_url' => 'avatar_url',
555 );
556 if ( isset( $option_map[ $option_name ] ) ) {
557 $option_name = $option_map[ $option_name ];
558 }
559
560 return $option_name;
561 }
562
563 /**
564 * Wrap get_user_option
565 *
566 * @param string $option_name User option name.
567 * @return int|bool User meta ID if the option didn't exist, true on successful update,
568 * false on failure.
569 */
570 public function get_user_option( $option_name ) {
571 $value = get_metadata( 'term', $this->get_term_id(), $option_name, true );
572 if ( false === $value ) {
573 $value = get_metadata( 'term', $this->get_term_id(), $this->map_option( $option_name ), true );
574 }
575
576 return $value;
577 }
578
579 /**
580 * Wrap update_user_option
581 *
582 * @param string $option_name User option name.
583 * @param mixed $new_value User option value.
584 * @param bool $is_global Optional. Whether option name is global or blog specific.
585 * Default false (blog specific).
586 * @return int|bool User meta ID if the option didn't exist, true on successful update,
587 * false on failure.
588 */
589 public function update_user_option( $option_name, $new_value, $is_global = false ) {
590 return update_metadata( 'term', $this->get_term_id(), $this->map_option( $option_name ), $new_value );
591 }
592
593 /**
594 * Wrap delete_user_option
595 *
596 * @param string $option_name User option name.
597 * @param bool $is_global Optional. Whether option name is global or blog specific.
598 * Default false (blog specific).
599 * @return bool True on success, false on failure.
600 */
601 public function delete_user_option( $option_name, $is_global = false ) {
602 return delete_metadata( 'term', $this->get_term_id(), $option_name );
603 }
604 }
605