PluginProbe
ActivityPub / 7.8.0
ActivityPub v7.8.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.8.0, at includes/collection/class-extra-fields.php

305 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 $title = \html_entity_decode( \get_the_title( $post ), \ENT_QUOTES, 'UTF-8' );
111 $content = self::get_formatted_content( $post );
112 $attachments[] = array(
113 'type' => 'PropertyValue',
114 'name' => $title,
115 'value' => \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' ),
116 );
117
118 $attachment = false;
119
120 // Add support for FEP-fb2a, for more information see FEDERATION.md.
121 $link_content = \trim( \strip_tags( $content, '<a>' ) );
122 if (
123 \stripos( $link_content, '<a' ) === 0 &&
124 \stripos( $link_content, '<a', 3 ) === false &&
125 \stripos( $link_content, '</a>', \strlen( $link_content ) - 4 ) !== false &&
126 \class_exists( '\WP_HTML_Tag_Processor' )
127 ) {
128 $tags = new \WP_HTML_Tag_Processor( $link_content );
129 $tags->next_tag( 'A' );
130
131 if ( 'A' === $tags->get_tag() ) {
132 $attachment = array(
133 'type' => 'Link',
134 'name' => $title,
135 'href' => \esc_url( $tags->get_attribute( 'href' ) ),
136 );
137
138 $rel = $tags->get_attribute( 'rel' );
139
140 if ( $rel && \is_string( $rel ) ) {
141 $attachment['rel'] = \explode( ' ', $rel );
142 }
143 }
144 }
145
146 if ( ! $attachment ) {
147 $attachment = array(
148 'type' => 'Note',
149 'name' => $title,
150 'content' => \html_entity_decode( $content, \ENT_QUOTES, 'UTF-8' ),
151 );
152 }
153
154 $attachments[] = $attachment;
155 }
156
157 \remove_filter( 'activitypub_link_rel', array( self::class, 'add_rel_me' ) );
158
159 return $attachments;
160 }
161
162 /**
163 * Check if a post type is an extra fields post type.
164 *
165 * @param string $post_type The post type.
166 *
167 * @return bool True if the post type is an extra fields post type, otherwise false.
168 */
169 public static function is_extra_fields_post_type( $post_type ) {
170 return \in_array( $post_type, array( self::USER_POST_TYPE, self::BLOG_POST_TYPE ), true );
171 }
172
173 /**
174 * Check if a post type is the `ap_extrafield` post type.
175 *
176 * @param string $post_type The post type.
177 *
178 * @return bool True if the post type is `ap_extrafield`, otherwise false.
179 */
180 public static function is_extra_field_post_type( $post_type ) {
181 return self::USER_POST_TYPE === $post_type;
182 }
183
184 /**
185 * Check if a post type is the `ap_extrafield_blog` post type.
186 *
187 * @param string $post_type The post type.
188 *
189 * @return bool True if the post type is `ap_extrafield_blog`, otherwise false.
190 */
191 public static function is_extra_field_blog_post_type( $post_type ) {
192 return self::BLOG_POST_TYPE === $post_type;
193 }
194
195 /**
196 * Add default extra fields to an actor.
197 *
198 * @param array $extra_fields The extra fields.
199 * @param int $user_id The User-ID.
200 *
201 * @return array The extra fields.
202 */
203 public static function default_actor_extra_fields( $extra_fields, $user_id ) {
204 // We'll only take action when there are none yet.
205 if ( ! empty( $extra_fields ) ) {
206 return $extra_fields;
207 }
208
209 $is_blog = self::is_blog( $user_id );
210 $already_migrated = $is_blog
211 ? \get_option( 'activitypub_default_extra_fields' )
212 : \get_user_meta( $user_id, 'activitypub_default_extra_fields', true );
213
214 if ( $already_migrated ) {
215 return $extra_fields;
216 }
217
218 \add_filter(
219 'activitypub_link_rel',
220 static function ( $rel ) {
221 $rel .= ' me';
222
223 return $rel;
224 }
225 );
226
227 $defaults = array(
228 \__( 'Blog', 'activitypub' ) => \home_url( '/' ),
229 );
230
231 if ( ! $is_blog ) {
232 $author_url = \get_the_author_meta( 'user_url', $user_id );
233 $author_posts_url = \get_author_posts_url( $user_id );
234
235 $defaults[ \__( 'Profile', 'activitypub' ) ] = $author_posts_url;
236 if ( $author_url !== $author_posts_url ) {
237 $defaults[ \__( 'Homepage', 'activitypub' ) ] = $author_url;
238 }
239 }
240
241 $post_type = $is_blog ? self::BLOG_POST_TYPE : self::USER_POST_TYPE;
242 $menu_order = 10;
243
244 foreach ( $defaults as $title => $url ) {
245 if ( ! $url ) {
246 continue;
247 }
248
249 $extra_field = array(
250 'post_type' => $post_type,
251 'post_title' => $title,
252 'post_status' => 'publish',
253 'post_author' => $user_id,
254 'post_content' => self::make_paragraph_block( Link::the_content( $url ) ),
255 'comment_status' => 'closed',
256 'menu_order' => $menu_order,
257 );
258
259 $menu_order += 10;
260 $extra_field_id = wp_insert_post( $extra_field );
261 $extra_fields[] = get_post( $extra_field_id );
262 }
263
264 $is_blog
265 ? \update_option( 'activitypub_default_extra_fields', true )
266 : \update_user_meta( $user_id, 'activitypub_default_extra_fields', true );
267
268 return $extra_fields;
269 }
270
271 /**
272 * Create a paragraph block.
273 *
274 * @param string $content The content.
275 *
276 * @return string The paragraph block.
277 */
278 public static function make_paragraph_block( $content ) {
279 if ( ! site_supports_blocks() ) {
280 return $content;
281 }
282 return '<!-- wp:paragraph --><p>' . $content . '</p><!-- /wp:paragraph -->';
283 }
284
285 /**
286 * Add the 'me' rel to the link.
287 *
288 * @param string $rel The rel attribute.
289 * @return string The modified rel attribute.
290 */
291 public static function add_rel_me( $rel ) {
292 return $rel . ' me';
293 }
294
295 /**
296 * Checks if the user is the blog user.
297 *
298 * @param int $user_id The user ID.
299 * @return bool True if the user is the blog user, otherwise false.
300 */
301 private static function is_blog( $user_id ) {
302 return Actors::BLOG_USER_ID === $user_id;
303 }
304 }
305