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
← All changes | includes/functions-post.php +28 -125 8.3.08.0.2 View file →
@@ -8,65 +8,54 @@
8 8 */
9 9
10 10 namespace Activitypub;
11 11
12 -use Activitypub\Collection\Remote_Posts;
12 +use Activitypub\Collection\Posts;
13 13
14 14 /**
15 - * Check whether ActivityPub processing should be skipped for this post.
15 + * Check if a post is disabled for ActivityPub.
16 16 *
17 - * Pipeline-level gate. Used by schedulers, transformers, and the outbox to
18 - * decide whether a post participates in federation processing at all.
19 - *
20 - * Intentionally returns `false` for posts that are undergoing a federation
21 - * lifecycle transition — e.g., a previously federated post whose visibility
22 - * was changed to private, or a previously deleted post that was restored —
23 - * so that the Delete or Create activity can still be emitted to notify
24 - * remote servers.
25 - *
26 - * DO NOT use this as a content-exposure gate for REST metadata, block
27 - * rendering, content-negotiated frontend JSON, or any other surface that
28 - * reveals a post's current content or existence to unauthenticated readers.
29 - * Use {@see is_post_publicly_queryable()} for those: it answers the simpler
30 - * "is this post currently public?" question with no lifecycle escape hatch.
31 - *
32 - * @see is_post_publicly_queryable() For the current-visibility gate used by
33 - * content-exposure surfaces.
34 - *
35 17 * @param mixed $post The post object or ID.
36 18 *
37 - * @return boolean True if ActivityPub processing should be skipped for this post, false otherwise.
19 + * @return boolean True if the post is disabled, false otherwise.
38 20 */
39 21 function is_post_disabled( $post ) {
40 - // Refuse empty input so `get_post()` doesn't silently resolve to the global $post.
41 - if ( empty( $post ) ) {
22 + $post = \get_post( $post );
23 + $disabled = false;
24 +
25 + if ( ! $post ) {
42 26 return true;
43 27 }
44 28
45 - $post = \get_post( $post );
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 );
46 31
47 - if ( ! $post ) {
48 - return true;
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;
49 43 }
50 44
51 - $disabled = ! is_post_publicly_queryable( $post );
52 -
53 45 /*
54 - * Lifecycle-transition override.
55 - *
56 - * A previously federated post that has since been moved to any non-
57 - * publicly-queryable state (local/private visibility, non-public
58 - * status, password-protected, or whose post type no longer supports
59 - * federation) still needs the pipeline to run so it can emit a Delete
60 - * activity. A post that was deleted but later restored needs the
61 - * pipeline to emit Create. In both cases we flip the gate back open
62 - * even though the post is not currently publicly queryable.
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.
63 49 */
64 50 $object_state = get_wp_object_state( $post );
65 51
66 52 if (
67 53 ACTIVITYPUB_OBJECT_STATE_DELETED === $object_state ||
68 - ( ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_state && $disabled )
54 + (
55 + ACTIVITYPUB_OBJECT_STATE_FEDERATED === $object_state &&
56 + ( $is_local_or_private || ! $is_public_status )
57 + )
69 58 ) {
70 59 $disabled = false;
71 60 }
72 61
@@ -79,94 +68,8 @@
79 68 return \apply_filters( 'activitypub_is_post_disabled', $disabled, $post );
80 69 }
81 70
82 71 /**
83 - * Check whether a post's current content is publicly queryable via ActivityPub.
84 - *
85 - * Content-exposure gate. Use wherever a post's current content, metadata, or
86 - * mere existence could leak to an unauthenticated request. Unlike
87 - * {@see is_post_disabled()}, this function ignores the federation lifecycle
88 - * state: a post that was federated publicly and has since been made private,
89 - * local, trashed, or password-protected returns `false` here, even while its
90 - * Delete activity is still pending in the outbox.
91 - *
92 - * Use for: per-post REST metadata routes (reactions, replies, context,
93 - * remote-reply), block server-side render callbacks that expose post
94 - * content, content-negotiated frontend JSON. Do NOT use for federation
95 - * pipeline decisions — that's what {@see is_post_disabled()} is for.
96 - *
97 - * A post is publicly queryable when it satisfies ALL of the following:
98 - * - `post_status` is `publish` (or a well-defined equivalent: published
99 - * attachments inheriting from a public parent, or a preview requested
100 - * by a user with edit capability).
101 - * - Its `activitypub_content_visibility` meta is neither `local` nor
102 - * `private`.
103 - * - The post type supports the `activitypub` feature.
104 - * - No `post_password` is set.
105 - *
106 - * @since 8.1.0
107 - *
108 - * @see is_post_disabled() For the pipeline-level federation gate.
109 - *
110 - * @param mixed $post The post object or ID.
111 - *
112 - * @return boolean True if the post is currently publicly queryable, false otherwise.
113 - */
114 -function is_post_publicly_queryable( $post ) {
115 - /*
116 - * Refuse to resolve an empty/zero input through `get_post()`. A bare
117 - * `get_post( null )` or `get_post( 0 )` falls back to the global
118 - * `$post` during a WordPress loop, which would silently check the
119 - * wrong post and potentially leak reactions/replies/metadata for a
120 - * looped-over post instead of the one the caller intended.
121 - */
122 - if ( empty( $post ) ) {
123 - return false;
124 - }
125 -
126 - $post = \get_post( $post );
127 -
128 - if ( ! $post ) {
129 - return false;
130 - }
131 -
132 - $visibility = \get_post_meta( $post->ID, 'activitypub_content_visibility', true );
133 - $is_local_or_private = in_array( $visibility, array( ACTIVITYPUB_CONTENT_VISIBILITY_LOCAL, ACTIVITYPUB_CONTENT_VISIBILITY_PRIVATE ), true );
134 -
135 - /*
136 - * An attachment (`inherit` status) inherits its parent's visibility.
137 - * Recurse into the parent so the attachment also picks up the parent's
138 - * content-visibility meta, password protection, and post-type support,
139 - * not just its post_status. Unattached attachments are allowed through.
140 - */
141 - $is_attachment_public = 'inherit' === $post->post_status &&
142 - 'attachment' === $post->post_type &&
143 - ( ! $post->post_parent || is_post_publicly_queryable( $post->post_parent ) );
144 -
145 - // Drafts and pending posts are allowed during preview requests so the Fediverse Preview works.
146 - $is_preview = in_array( $post->post_status, array( 'draft', 'pending' ), true ) &&
147 - \get_query_var( 'preview' ) &&
148 - \current_user_can( 'edit_post', $post->ID );
149 -
150 - $is_public_status = 'publish' === $post->post_status || $is_attachment_public || $is_preview;
151 -
152 - $queryable = $is_public_status &&
153 - ! $is_local_or_private &&
154 - \post_type_supports( $post->post_type, 'activitypub' ) &&
155 - empty( $post->post_password );
156 -
157 - /**
158 - * Filter whether a post is publicly queryable via ActivityPub.
159 - *
160 - * @since 8.1.0
161 - *
162 - * @param boolean $queryable True if the post is publicly queryable, false otherwise.
163 - * @param \WP_Post $post The post object.
164 - */
165 - return \apply_filters( 'activitypub_is_post_publicly_queryable', $queryable, $post );
166 -}
167 -
168 -/**
169 72 * Check if a post is an ActivityPub post.
170 73 *
171 74 * @param mixed $post The post object or ID.
172 75 *
@@ -179,9 +82,9 @@
179 82 return false;
180 83 }
181 84
182 85 // Check for ap_post post type.
183 - return Remote_Posts::POST_TYPE === $post->post_type;
86 + return Posts::POST_TYPE === $post->post_type;
184 87 }
185 88
186 89 /**
187 90 * Get the description of a post type.