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-extra-fields.php

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

312 lines 8.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Extra Fields collection file.
4 *
5 * @package Activitypub
6 */
7
8 namespace Activitypub\Collection;
9
10 use Activitypub\Link;
11
12 use function Activitypub\site_supports_blocks;
13
14 /**
15 * Extra Fields collection.
16 */
17 class Extra_Fields {
18
19 const USER_POST_TYPE = 'ap_extrafield';
20 const BLOG_POST_TYPE = 'ap_extrafield_blog';
21
22 /**
23 * Get the extra fields for a user.
24 *
25 * @param int $user_id The user ID.
26 *
27 * @return \WP_Post[] The extra fields.
28 */
29 public static function get_actor_fields( $user_id ) {
30 $is_blog = self::is_blog( $user_id );
31 $post_type = $is_blog ? self::BLOG_POST_TYPE : self::USER_POST_TYPE;
32 $args = array(
33 'post_type' => $post_type,
34 'nopaging' => true,
35 'orderby' => 'menu_order',
36 'order' => 'ASC',
37 );
38 if ( ! $is_blog ) {
39 $args['author'] = $user_id;
40 }
41
42 // Limit to 20 fields to prevent response size issues.
43 if ( ! is_admin() ) {
44 /**
45 * Filters the number of extra fields to retrieve for an ActivityPub actor.
46 *
47 * @param int $limit The number of extra fields to retrieve. Default 20.
48 */
49 $args['posts_per_page'] = apply_filters( 'activitypub_actor_extra_fields_limit', 20 );
50 $args['nopaging'] = false;
51 }
52
53 $query = new \WP_Query( $args );
54 $fields = $query->posts ?? array();
55
56 /**
57 * Filters the extra fields for an ActivityPub actor.
58 *
59 * This filter allows developers to modify or add custom fields to an actor's
60 * profile.
61 *
62 * @param \WP_Post[] $fields Array of WP_Post objects representing the extra fields.
63 * @param int $user_id The ID of the user whose fields are being retrieved.
64 */
65 return apply_filters( 'activitypub_get_actor_extra_fields', $fields, $user_id );
66 }
67
68 /**
69 * Get formatted content for an extra field.
70 *
71 * @param \WP_Post $post The post.
72 *
73 * @return string The formatted content.
74 */
75 public static function get_formatted_content( $post ) {
76 $content = \get_the_content( null, false, $post );
77 $content = Link::the_content( $content );
78 if ( site_supports_blocks() ) {
79 $content = \do_blocks( $content );
80 }
81 $content = \wptexturize( $content );
82 $content = \wp_filter_content_tags( $content );
83
84 // Replace script and style elements.
85 $content = \preg_replace( '@<(script|style)[^>]*?>.*?</\\1>@si', '', $content );
86 $content = \strip_shortcodes( $content );
87 $content = \trim( \preg_replace( '/[\n\r\t]/', '', $content ) );
88
89 /**
90 * Filters the content of an extra field.
91 *
92 * @param string $content The content.
93 * @param \WP_Post $post The post.
94 */
95 return \apply_filters( 'activitypub_extra_field_content', $content, $post );
96 }
97
98 /**
99 * Transforms the Extra Fields (Custom Post Types) to ActivityPub Actor-Attachments.
100 *
101 * @param \WP_Post[] $fields The extra fields.
102 *
103 * @return array ActivityPub attachments.
104 */
105 public static function fields_to_attachments( $fields ) {
106 $attachments = array();
107 \add_filter( 'activitypub_link_rel', array( self::class, 'add_rel_me' ) );
108
109 foreach ( $fields as $post ) {
110 $content = self::get_formatted_content( $post );
111 $attachments[] = array(
112 'type' => 'PropertyValue',
113 'name' => \get_the_title( $post ),
114 'value' => \html_entity_decode(
115 $content,
116 \ENT_QUOTES,
117 'UTF-8'
118 ),
119 );
120
121 $attachment = false;
122
123 // Add support for FEP-fb2a, for more information see FEDERATION.md.
124 $link_content = \trim( \strip_tags( $content, '<a>' ) );
125 if (
126 \stripos( $link_content, '<a' ) === 0 &&
127 \stripos( $link_content, '<a', 3 ) === false &&
128 \stripos( $link_content, '</a>', \strlen( $link_content ) - 4 ) !== false &&
129 \class_exists( '\WP_HTML_Tag_Processor' )
130 ) {
131 $tags = new \WP_HTML_Tag_Processor( $link_content );
132 $tags->next_tag( 'A' );
133
134 if ( 'A' === $tags->get_tag() ) {
135 $attachment = array(
136 'type' => 'Link',
137 'name' => \get_the_title( $post ),
138 'href' => \esc_url( $tags->get_attribute( 'href' ) ),
139 );
140
141 $rel = $tags->get_attribute( 'rel' );
142
143 if ( $rel && \is_string( $rel ) ) {
144 $attachment['rel'] = \explode( ' ', $rel );
145 }
146 }
147 }
148
149 if ( ! $attachment ) {
150 $attachment = array(
151 'type' => 'Note',
152 'name' => \get_the_title( $post ),
153 'content' => \html_entity_decode(
154 $content,
155 \ENT_QUOTES,
156 'UTF-8'
157 ),
158 );
159 }
160
161 $attachments[] = $attachment;
162 }
163
164 \remove_filter( 'activitypub_link_rel', array( self::class, 'add_rel_me' ) );
165
166 return $attachments;
167 }
168
169 /**
170 * Check if a post type is an extra fields post type.
171 *
172 * @param string $post_type The post type.
173 *
174 * @return bool True if the post type is an extra fields post type, otherwise false.
175 */
176 public static function is_extra_fields_post_type( $post_type ) {
177 return \in_array( $post_type, array( self::USER_POST_TYPE, self::BLOG_POST_TYPE ), true );
178 }
179
180 /**
181 * Check if a post type is the `ap_extrafield` post type.
182 *
183 * @param string $post_type The post type.
184 *
185 * @return bool True if the post type is `ap_extrafield`, otherwise false.
186 */
187 public static function is_extra_field_post_type( $post_type ) {
188 return self::USER_POST_TYPE === $post_type;
189 }
190
191 /**
192 * Check if a post type is the `ap_extrafield_blog` post type.
193 *
194 * @param string $post_type The post type.
195 *
196 * @return bool True if the post type is `ap_extrafield_blog`, otherwise false.
197 */
198 public static function is_extra_field_blog_post_type( $post_type ) {
199 return self::BLOG_POST_TYPE === $post_type;
200 }
201
202 /**
203 * Add default extra fields to an actor.
204 *
205 * @param array $extra_fields The extra fields.
206 * @param int $user_id The User-ID.
207 *
208 * @return array The extra fields.
209 */
210 public static function default_actor_extra_fields( $extra_fields, $user_id ) {
211 // We'll only take action when there are none yet.
212 if ( ! empty( $extra_fields ) ) {
213 return $extra_fields;
214 }
215
216 $is_blog = self::is_blog( $user_id );
217 $already_migrated = $is_blog
218 ? \get_option( 'activitypub_default_extra_fields' )
219 : \get_user_meta( $user_id, 'activitypub_default_extra_fields', true );
220
221 if ( $already_migrated ) {
222 return $extra_fields;
223 }
224
225 \add_filter(
226 'activitypub_link_rel',
227 function ( $rel ) {
228 $rel .= ' me';
229
230 return $rel;
231 }
232 );
233
234 $defaults = array(
235 \__( 'Blog', 'activitypub' ) => \home_url( '/' ),
236 );
237
238 if ( ! $is_blog ) {
239 $author_url = \get_the_author_meta( 'user_url', $user_id );
240 $author_posts_url = \get_author_posts_url( $user_id );
241
242 $defaults[ \__( 'Profile', 'activitypub' ) ] = $author_posts_url;
243 if ( $author_url !== $author_posts_url ) {
244 $defaults[ \__( 'Homepage', 'activitypub' ) ] = $author_url;
245 }
246 }
247
248 $post_type = $is_blog ? self::BLOG_POST_TYPE : self::USER_POST_TYPE;
249 $menu_order = 10;
250
251 foreach ( $defaults as $title => $url ) {
252 if ( ! $url ) {
253 continue;
254 }
255
256 $extra_field = array(
257 'post_type' => $post_type,
258 'post_title' => $title,
259 'post_status' => 'publish',
260 'post_author' => $user_id,
261 'post_content' => self::make_paragraph_block( Link::the_content( $url ) ),
262 'comment_status' => 'closed',
263 'menu_order' => $menu_order,
264 );
265
266 $menu_order += 10;
267 $extra_field_id = wp_insert_post( $extra_field );
268 $extra_fields[] = get_post( $extra_field_id );
269 }
270
271 $is_blog
272 ? \update_option( 'activitypub_default_extra_fields', true )
273 : \update_user_meta( $user_id, 'activitypub_default_extra_fields', true );
274
275 return $extra_fields;
276 }
277
278 /**
279 * Create a paragraph block.
280 *
281 * @param string $content The content.
282 *
283 * @return string The paragraph block.
284 */
285 public static function make_paragraph_block( $content ) {
286 if ( ! site_supports_blocks() ) {
287 return $content;
288 }
289 return '<!-- wp:paragraph --><p>' . $content . '</p><!-- /wp:paragraph -->';
290 }
291
292 /**
293 * Add the 'me' rel to the link.
294 *
295 * @param string $rel The rel attribute.
296 * @return string The modified rel attribute.
297 */
298 public static function add_rel_me( $rel ) {
299 return $rel . ' me';
300 }
301
302 /**
303 * Checks if the user is the blog user.
304 *
305 * @param int $user_id The user ID.
306 * @return bool True if the user is the blog user, otherwise false.
307 */
308 private static function is_blog( $user_id ) {
309 return Actors::BLOG_USER_ID === $user_id;
310 }
311 }
312