PluginProbe
ActivityPub / 7.0.0
ActivityPub v7.0.0
9.3.1 9.3.0 9.2.2 9.2.1 9.2.0 9.1.0 9.0.2 9.0.1 9.0.0 8.3.0 8.2.1 8.2.0 8.1.1 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.2.0 1.3.0 2.0.0 2.0.1 2.1.0 2.1.1 All 160 releases
activitypub / includes / collection / class-replies.php

class-replies.php in ActivityPub 7.0.0, at includes/collection/class-replies.php

227 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Replies collection file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Collection;
9
10 use WP_Post;
11 use WP_Comment;
12 use WP_Error;
13
14 use Activitypub\Comment;
15 use Activitypub\Model\Blog;
16 use Activitypub\Transformer\Post as PostTransformer;
17 use Activitypub\Transformer\Comment as CommentTransformer;
18
19 use function Activitypub\is_post_disabled;
20 use function Activitypub\is_local_comment;
21 use function Activitypub\get_rest_url_by_path;
22 use function Activitypub\is_user_type_disabled;
23
24 /**
25 * Class containing code for getting replies Collections and CollectionPages of posts and comments.
26 */
27 class Replies {
28 /**
29 * Build base arguments for fetching the comments of either a WordPress post or comment.
30 *
31 * @param WP_Post|WP_Comment|WP_Error $wp_object The post or comment to fetch replies for on success.
32 */
33 private static function build_args( $wp_object ) {
34 $args = array(
35 'status' => 'approve',
36 'orderby' => 'comment_date_gmt',
37 'order' => 'ASC',
38 'type' => 'comment',
39 );
40
41 if ( $wp_object instanceof WP_Post ) {
42 $args['parent'] = 0; // TODO: maybe this is unnecessary.
43 $args['post_id'] = $wp_object->ID;
44 } elseif ( $wp_object instanceof WP_Comment ) {
45 $args['parent'] = $wp_object->comment_ID;
46 } else {
47 return new WP_Error();
48 }
49
50 return $args;
51 }
52
53 /**
54 * Get the replies collections ID.
55 *
56 * @param WP_Post|WP_Comment $wp_object The post or comment to fetch replies for.
57 *
58 * @return string|WP_Error The rest URL of the replies collection or WP_Error if the object is not a post or comment.
59 */
60 private static function get_id( $wp_object ) {
61 if ( $wp_object instanceof WP_Post ) {
62 return get_rest_url_by_path( sprintf( 'posts/%d/replies', $wp_object->ID ) );
63 } elseif ( $wp_object instanceof WP_Comment ) {
64 return get_rest_url_by_path( sprintf( 'comments/%d/replies', $wp_object->comment_ID ) );
65 } else {
66 return new WP_Error( 'unsupported_object', 'The object is not a post or comment.' );
67 }
68 }
69
70 /**
71 * Get the Replies collection.
72 *
73 * @param WP_Post|WP_Comment $wp_object The post or comment to fetch replies for.
74 *
75 * @return array|\WP_Error|null An associative array containing the replies collection without JSON-LD context on success.
76 */
77 public static function get_collection( $wp_object ) {
78 $id = self::get_id( $wp_object );
79
80 if ( is_wp_error( $id ) ) {
81 return \wp_is_serving_rest_request() ? $id : null;
82 }
83
84 $replies = array(
85 'id' => $id,
86 'type' => 'Collection',
87 );
88
89 $replies['first'] = self::get_collection_page( $wp_object, 1, $replies['id'] );
90
91 return $replies;
92 }
93
94 /**
95 * Returns a replies collection page as an associative array.
96 *
97 * @link https://www.w3.org/TR/activitystreams-vocabulary/#dfn-collectionpage
98 *
99 * @param WP_Post|WP_Comment $wp_object The post of comment the replies are for.
100 * @param int $page The current pagination page.
101 * @param string $part_of Optional. The collection id/url the returned CollectionPage belongs to. Default null.
102 *
103 * @return array|WP_Error|null A CollectionPage as an associative array on success, WP_Error or null on failure.
104 */
105 public static function get_collection_page( $wp_object, $page, $part_of = null ) {
106 // Build initial arguments for fetching approved comments.
107 $args = self::build_args( $wp_object );
108 if ( is_wp_error( $args ) ) {
109 return \wp_is_serving_rest_request() ? $args : null;
110 }
111
112 // Retrieve the partOf if not already given.
113 $part_of = $part_of ?? self::get_id( $wp_object );
114
115 // If the collection page does not exist.
116 if ( is_wp_error( $part_of ) ) {
117 return \wp_is_serving_rest_request() ? $part_of : null;
118 }
119
120 // Get to total replies count.
121 $total_replies = \get_comments( array_merge( $args, array( 'count' => true ) ) );
122
123 // If set to zero, we get errors below. You need at least one comment per page, here.
124 $args['number'] = max( (int) \get_option( 'comments_per_page' ), 1 );
125 $args['offset'] = intval( $page - 1 ) * $args['number'];
126
127 // Get the ActivityPub ID's of the comments, without local-only comments.
128 $comment_ids = self::get_reply_ids( \get_comments( $args ) );
129
130 // Build the associative CollectionPage array.
131 $collection_page = array(
132 'id' => \add_query_arg( 'page', $page, $part_of ),
133 'type' => 'CollectionPage',
134 'partOf' => $part_of,
135 'items' => $comment_ids,
136 );
137
138 if ( ( $total_replies / $args['number'] ) > $page ) {
139 $collection_page['next'] = \add_query_arg( 'page', $page + 1, $part_of );
140 }
141
142 if ( $page > 1 ) {
143 $collection_page['prev'] = \add_query_arg( 'page', $page - 1, $part_of );
144 }
145
146 return $collection_page;
147 }
148
149 /**
150 * Get the context collection for a post.
151 *
152 * @param int $post_id The post ID.
153 *
154 * @return array|false The context for the post or false if the post is not found or disabled.
155 */
156 public static function get_context_collection( $post_id ) {
157 $post = \get_post( $post_id );
158
159 if ( ! $post || is_post_disabled( $post_id ) ) {
160 return false;
161 }
162
163 $comments = \get_comments(
164 array(
165 'post_id' => $post_id,
166 'type' => 'comment',
167 'status' => 'approve',
168 'orderby' => 'comment_date_gmt',
169 'order' => 'ASC',
170 )
171 );
172 $ids = self::get_reply_ids( $comments, true );
173 $post_uri = ( new PostTransformer( $post ) )->to_id();
174 \array_unshift( $ids, $post_uri );
175
176 $author = Actors::get_by_id( $post->post_author );
177 if ( is_wp_error( $author ) ) {
178 if ( is_user_type_disabled( 'blog' ) ) {
179 return false;
180 }
181
182 $author = new Blog();
183 }
184
185 return array(
186 'type' => 'OrderedCollection',
187 'url' => \get_permalink( $post_id ),
188 'attributedTo' => $author->get_id(),
189 'totalItems' => count( $ids ),
190 'items' => $ids,
191 );
192 }
193
194 /**
195 * Get the ActivityPub ID's from a list of comments.
196 *
197 * It takes only federated/non-local comments into account, others also do not have an
198 * ActivityPub ID available.
199 *
200 * @param WP_Comment[] $comments The comments to retrieve the ActivityPub ids from.
201 * @param boolean $include_blog_comments Optional. Include blog comments in the returned array. Default false.
202 *
203 * @return string[] A list of the ActivityPub ID's.
204 */
205 private static function get_reply_ids( $comments, $include_blog_comments = false ) {
206 $comment_ids = array();
207
208 foreach ( $comments as $comment ) {
209 if ( is_local_comment( $comment ) ) {
210 continue;
211 }
212
213 $public_comment_id = Comment::get_source_id( $comment->comment_ID );
214 if ( $public_comment_id ) {
215 $comment_ids[] = $public_comment_id;
216 continue;
217 }
218
219 if ( $include_blog_comments ) {
220 $comment_ids[] = ( new CommentTransformer( $comment ) )->to_id();
221 }
222 }
223
224 return \array_unique( $comment_ids );
225 }
226 }
227