PluginProbe
ActivityPub / 8.0.2
ActivityPub v8.0.2
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 / functions-post.php

functions-post.php in ActivityPub 8.0.2, at includes/functions-post.php

307 lines 8.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Post functions.
4 *
5 * Functions for working with posts in ActivityPub context.
6 *
7 * @package Activitypub
8 */
9
10 namespace Activitypub;
11
12 use Activitypub\Collection\Posts;
13
14 /**
15 * Check if a post is disabled for ActivityPub.
16 *
17 * @param mixed $post The post object or ID.
18 *
19 * @return boolean True if the post is disabled, false otherwise.
20 */
21 function is_post_disabled( $post ) {
22 $post = \get_post( $post );
23 $disabled = false;
24
25 if ( ! $post ) {
26 return true;
27 }
28
29 $visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true );
30 $is_local_or_private = in_array( $visibility, array( ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE ), true );
31
32 // Only 'publish' is public. 'inherit' is allowed only for attachments.
33 $is_public_status = 'publish' === $post->post_status ||
34 ( 'inherit' === $post->post_status && 'attachment' === $post->post_type );
35
36 if (
37 $is_local_or_private ||
38 ! \post_type_supports( $post->post_type, 'activitypub' ) ||
39 ! $is_public_status ||
40 ! empty( $post->post_password )
41 ) {
42 $disabled = true;
43 }
44
45 /*
46 * Check for posts that need special handling.
47 * Federated posts changed to local/private or non-public status need Delete activity.
48 * Deleted posts restored to public need Create activity.
49 */
50 $object_state = get_wp_object_state( $post );
51
52 if (
53 ACTIVITYPUB_OBJECT_STATE_DELETED === $object_state ||
54 (
55 ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_state &&
56 ( $is_local_or_private || ! $is_public_status )
57 )
58 ) {
59 $disabled = false;
60 }
61
62 /**
63 * Allow plugins to disable posts for ActivityPub.
64 *
65 * @param boolean $disabled True if the post is disabled, false otherwise.
66 * @param \WP_Post $post The post object.
67 */
68 return \apply_filters( 'activitypub_is_post_disabled', $disabled, $post );
69 }
70
71 /**
72 * Check if a post is an ActivityPub post.
73 *
74 * @param mixed $post The post object or ID.
75 *
76 * @return boolean True if the post is an ActivityPub post, false otherwise.
77 */
78 function is_ap_post( $post ) {
79 $post = \get_post( $post );
80
81 if ( ! $post ) {
82 return false;
83 }
84
85 // Check for ap_post post type.
86 return Posts::POST_TYPE === $post->post_type;
87 }
88
89 /**
90 * Get the description of a post type.
91 *
92 * Set some default descriptions for the default post types.
93 *
94 * @param \WP_Post_Type $post_type The post type object.
95 *
96 * @return string The description of the post type.
97 */
98 function get_post_type_description( $post_type ) {
99 switch ( $post_type->name ) {
100 case 'post':
101 case 'page':
102 $description = '';
103 break;
104 case 'attachment':
105 $description = ' - ' . __( 'Files uploaded to the media library (such as images, videos, documents, or other attachments). Note: This federates every file upload, not just published content.', 'activitypub' );
106 break;
107 default:
108 $description = '';
109 if ( ! empty( $post_type->description ) ) {
110 $description = ' - ' . $post_type->description;
111 }
112 }
113
114 /**
115 * Allow plugins to get the description of a post type.
116 *
117 * @param string $description The description of the post type.
118 * @param string $post_type_name The post type name.
119 * @param \WP_Post_Type $post_type The post type object.
120 */
121 return apply_filters( 'activitypub_post_type_description', $description, $post_type->name, $post_type );
122 }
123
124 /**
125 * Get the enclosures of a post.
126 *
127 * @param int $post_id The post ID.
128 *
129 * @return array The enclosures.
130 */
131 function get_enclosures( $post_id ) {
132 $enclosures = get_post_meta( $post_id, 'enclosure', false );
133
134 if ( ! $enclosures ) {
135 return array();
136 }
137
138 $enclosures = array_map(
139 static function ( $enclosure ) {
140 // Check if the enclosure is a string.
141 if ( ! $enclosure || ! is_string( $enclosure ) ) {
142 return false;
143 }
144
145 $attributes = explode( "\n", $enclosure );
146
147 if ( ! isset( $attributes[0] ) || ! \wp_http_validate_url( $attributes[0] ) ) {
148 return false;
149 }
150
151 return array(
152 'url' => $attributes[0],
153 'length' => $attributes[1] ?? null,
154 'mediaType' => $attributes[2] ?? 'application/octet-stream',
155 );
156 },
157 $enclosures
158 );
159
160 return array_filter( $enclosures );
161 }
162
163 /**
164 * Generates a summary of a post.
165 *
166 * This function generates a summary based on the post's excerpt or content.
167 *
168 * @param int|\WP_Post $post The post ID or post object.
169 * @param integer $length The maximum length of the summary.
170 * Default is 500. It will be ignored if the post excerpt
171 * and the content above the <!--more--> tag.
172 *
173 * @return string The generated post summary.
174 */
175 function generate_post_summary( $post, $length = 500 ) {
176 $post = get_post( $post );
177
178 if ( ! $post ) {
179 return '';
180 }
181
182 /**
183 * Filters the excerpt more value.
184 *
185 * @param string $excerpt_more The excerpt more.
186 */
187 $excerpt_more = \apply_filters( 'activitypub_excerpt_more', '[…]' );
188 $length = $length - \mb_strlen( $excerpt_more, 'UTF-8' );
189
190 $content = \sanitize_post_field( 'post_excerpt', $post->post_excerpt, $post->ID );
191
192 if ( $content ) {
193 // Ignore length if excerpt is set.
194 $length = null;
195 } else {
196 $content = \sanitize_post_field( 'post_content', $post->post_content, $post->ID );
197 $content_parts = \get_extended( $content );
198
199 // Check for the <!--more--> tag.
200 if (
201 ! empty( $content_parts['extended'] ) &&
202 ! empty( $content_parts['main'] )
203 ) {
204 $content = \trim( $content_parts['main'] ) . ' ' . $excerpt_more;
205 $length = null;
206 }
207 }
208
209 $content = \strip_shortcodes( $content );
210 $content = \wp_strip_all_tags( $content );
211 $content = \html_entity_decode( $content, ENT_QUOTES, 'UTF-8' );
212 $content = \trim( $content );
213 $content = \preg_replace( '/\R+/mu', "\n\n", $content );
214 $content = \preg_replace( '/[\r\t]/u', '', $content );
215
216 if ( $length && \mb_strlen( $content, 'UTF-8' ) > $length ) {
217 $content = \wordwrap( $content, $length, '</activitypub-summary>' );
218 $content = \explode( '</activitypub-summary>', $content, 2 );
219 $content = $content[0] . ' ' . $excerpt_more;
220 }
221
222 /*
223 There is no proper support for HTML in ActivityPub summaries yet.
224 // This filter is documented in wp-includes/post-template.php.
225 return \apply_filters( 'the_excerpt', $content );
226 */
227 return $content;
228 }
229
230 /**
231 * Get the content warning of a post.
232 *
233 * @param int|\WP_Post $post_id The post ID or post object.
234 *
235 * @return string|false The content warning or false if not found.
236 */
237 function get_content_warning( $post_id ) {
238 $post = get_post( $post_id );
239 if ( ! $post ) {
240 return false;
241 }
242
243 $warning = get_post_meta( $post->ID, 'activitypub_content_warning', true );
244 if ( empty( $warning ) ) {
245 return false;
246 }
247
248 return $warning;
249 }
250
251 /**
252 * Get the ActivityPub ID of a Post by the WordPress Post ID.
253 *
254 * @param int $id The WordPress Post ID.
255 *
256 * @return string The ActivityPub ID (a URL) of the Post.
257 */
258 function get_post_id( $id ) {
259 $last_legacy_id = (int) \get_option( 'activitypub_last_post_with_permalink_as_id', 0 );
260 $post_id = (int) $id;
261
262 if ( $post_id > $last_legacy_id ) {
263 // Generate URI based on post ID.
264 return \add_query_arg( 'p', $post_id, \home_url( '/' ) );
265 }
266
267 return \get_permalink( $post_id );
268 }
269
270 /**
271 * Get the visibility of a post.
272 *
273 * @param int $post_id The post ID.
274 *
275 * @return string|false The visibility of the post or false if not found.
276 */
277 function get_content_visibility( $post_id ) {
278 $post = get_post( $post_id );
279 if ( ! $post ) {
280 return false;
281 }
282
283 $visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true );
284 $_visibility = ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC;
285 $options = array(
286 ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC,
287 ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE,
288 ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL,
289 );
290
291 if ( in_array( $visibility, $options, true ) ) {
292 $_visibility = $visibility;
293 }
294
295 /**
296 * Filters the visibility of a post.
297 *
298 * @param string $_visibility The visibility of the post. Possible values are:
299 * - ACTIVITYPUB_CONTENT_VISIBILITY_PUBLIC
300 * - ACTIVITYPUB_CONTENT_VISIBILITY_QUIET_PUBLIC
301 * - ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE
302 * - ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL
303 * @param \WP_Post $post The post object.
304 */
305 return \apply_filters( 'activitypub_content_visibility', $_visibility, $post );
306 }
307