PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.1.3
Jetpack – WP Security, Backup, Speed, & Growth v12.1.3
12.0.3 12.1.3 12.2.3 12.3.2 12.4.2 12.5.2 12.6.4 12.7.3 12.8.3 12.9.5 13.0.2 13.1.5 13.2.4 13.3.3 13.4.5 13.5.2 13.6.2 13.7.2 13.8.3 13.9.2 14.0.1 14.1.1 14.2.2 14.3.1 14.4.2 14.5.1 14.6.1 14.7.1 14.8.1 14.9.2 15.0.3 15.1.2 15.2.1 15.3.2 15.4.1 15.5.1 15.6.1 15.7.2 15.8.1 15.9.2 16.0.2 16.1.3 16.2-a.5 16.2-a.3 16.1.2 16.2-a.1 16.1.1 16.1 16.1-beta 16.1-beta.2 16.1-beta.3 16.1-a.5 16.1-a.3 16.0.1 16.1-a.1 16.0 16.0-beta 16.0-a.7 16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / _inc / lib / core-api / wpcom-fields / post-fields-publicize-connections.php
jetpack / _inc / lib / core-api / wpcom-fields Last commit date
post-fields-publicize-connections.php 3 years ago theme-fields-is-block-theme.php 3 years ago
post-fields-publicize-connections.php
422 lines
1 <?php // phpcs:ignore WordPress.Files.FileName.InvalidClassFileName
2 /**
3 * Handle Publicize connection information for each post.
4 *
5 * @package automattic/jetpack
6 */
7
8 /**
9 * Add per-post Publicize Connection data.
10 *
11 * { # Post Object
12 * ...
13 * jetpack_publicize_connections: { # Defined below in this file. See schema for more detail.
14 * id: (string) Connection unique_id
15 * service_name: (string) Service slug
16 * display_name: (string) User name/display name of user/connection on Service
17 * profile_picture: (string) Profile picture of user/connection on Service
18 * enabled: (boolean) Is this connection slated to be shared to? context=edit only
19 * done: (boolean) Is this post (or connection) done sharing? context=edit only
20 * toggleable: (boolean) Can the current user change the `enabled` setting for this Connection+Post? context=edit only
21 * }
22 * ...
23 * meta: { # Not defined in this file. Handled in modules/publicize/publicize.php via `register_meta()`
24 * jetpack_publicize_feature_enabled: (boolean) Is this publicize feature enabled?
25 * jetpack_publicize_message: (string) The message to use instead of the post's title when sharing.
26 * jetpack_social_options: {
27 * attached_media: (array) List of media that will be attached to the social media post.
28 * image_generator_settings: (array) List of settings related to the generated image.
29 * }
30 * ...
31 * }
32 *
33 * @since 6.8.0
34 */
35 class WPCOM_REST_API_V2_Post_Publicize_Connections_Field extends WPCOM_REST_API_V2_Field_Controller {
36 /**
37 * Array of post types that can handle Publicize.
38 *
39 * @var array
40 */
41 protected $object_type = array( 'post' );
42
43 /**
44 * Field name
45 *
46 * @var string
47 */
48 protected $field_name = 'jetpack_publicize_connections';
49
50 /**
51 * Array of post IDs that have been updated.
52 *
53 * @var array
54 */
55 private $meta_saved = array();
56
57 /**
58 * Used to memoize the updates for a given post.
59 *
60 * @var array
61 */
62 public $memoized_updates = array();
63
64 /**
65 * Registers the jetpack_publicize_connections field. Called
66 * automatically on `rest_api_init()`.
67 */
68 public function register_fields() {
69 $this->object_type = get_post_types_by_support( 'publicize' );
70 foreach ( $this->object_type as $post_type ) {
71 if ( $this->is_registered( $post_type ) ) {
72 continue;
73 }
74 // Adds meta support for those post types that don't already have it.
75 // Only runs during REST API requests, so it doesn't impact UI.
76 if ( ! post_type_supports( $post_type, 'custom-fields' ) ) {
77 add_post_type_support( $post_type, 'custom-fields' );
78 }
79
80 add_filter( 'rest_pre_insert_' . $post_type, array( $this, 'rest_pre_insert' ), 10, 2 );
81 add_action( 'rest_insert_' . $post_type, array( $this, 'rest_insert' ), 10, 3 );
82 }
83
84 parent::register_fields();
85 }
86
87 /**
88 * Defines data structure and what elements are visible in which contexts
89 */
90 public function get_schema() {
91 return array(
92 '$schema' => 'http://json-schema.org/draft-04/schema#',
93 'title' => 'jetpack-publicize-post-connections',
94 'type' => 'array',
95 'context' => array( 'view', 'edit' ),
96 'items' => $this->post_connection_schema(),
97 'default' => array(),
98 );
99 }
100
101 /**
102 * Schema for the endpoint.
103 */
104 private function post_connection_schema() {
105 return array(
106 '$schema' => 'http://json-schema.org/draft-04/schema#',
107 'title' => 'jetpack-publicize-post-connection',
108 'type' => 'object',
109 'properties' => array(
110 'id' => array(
111 'description' => __( 'Unique identifier for the Jetpack Social connection', 'jetpack' ),
112 'type' => 'string',
113 'context' => array( 'view', 'edit' ),
114 'readonly' => true,
115 ),
116 'service_name' => array(
117 'description' => __( 'Alphanumeric identifier for the Jetpack Social service', 'jetpack' ),
118 'type' => 'string',
119 'context' => array( 'view', 'edit' ),
120 'readonly' => true,
121 ),
122 'display_name' => array(
123 'description' => __( 'Username of the connected account', 'jetpack' ),
124 'type' => 'string',
125 'context' => array( 'view', 'edit' ),
126 'readonly' => true,
127 ),
128 'profile_picture' => array(
129 'description' => __( 'Profile picture of the connected account', 'jetpack' ),
130 'type' => 'string',
131 'context' => array( 'view', 'edit' ),
132 'readonly' => true,
133 ),
134 'enabled' => array(
135 'description' => __( 'Whether to share to this connection', 'jetpack' ),
136 'type' => 'boolean',
137 'context' => array( 'edit' ),
138 ),
139 'done' => array(
140 'description' => __( 'Whether Jetpack Social has already finished sharing for this post', 'jetpack' ),
141 'type' => 'boolean',
142 'context' => array( 'edit' ),
143 'readonly' => true,
144 ),
145 'toggleable' => array(
146 'description' => __( 'Whether `enable` can be changed for this post/connection', 'jetpack' ),
147 'type' => 'boolean',
148 'context' => array( 'edit' ),
149 'readonly' => true,
150 ),
151 ),
152 );
153 }
154
155 /**
156 * Permission check, based on module availability and user capabilities.
157 *
158 * @param int $post_id Post ID.
159 *
160 * @return true|WP_Error
161 */
162 public function permission_check( $post_id ) {
163 global $publicize;
164
165 if ( ! $publicize ) {
166 return new WP_Error(
167 'publicize_not_available',
168 __( 'Sorry, Jetpack Social is not available on your site right now.', 'jetpack' ),
169 array( 'status' => rest_authorization_required_code() )
170 );
171 }
172
173 if ( $publicize->current_user_can_access_publicize_data( $post_id ) ) {
174 return true;
175 }
176
177 return new WP_Error(
178 'invalid_user_permission_publicize',
179 __( 'Sorry, you are not allowed to access Jetpack Social data for this post.', 'jetpack' ),
180 array( 'status' => rest_authorization_required_code() )
181 );
182 }
183
184 /**
185 * Getter permission check
186 *
187 * @param mixed $post_array Response from the post endpoint.
188 * @param WP_REST_Request $request API request.
189 *
190 * @return true|WP_Error
191 */
192 public function get_permission_check( $post_array, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
193 return $this->permission_check( isset( $post_array['id'] ) ? $post_array['id'] : 0 );
194 }
195
196 /**
197 * Setter permission check.
198 *
199 * @param mixed $value The new value for the field.
200 * @param WP_Post $post The post object.
201 * @param WP_REST_Request $request API request.
202 *
203 * @return true|WP_Error
204 */
205 public function update_permission_check( $value, $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
206 return $this->permission_check( isset( $post->ID ) ? $post->ID : 0 );
207 }
208
209 /**
210 * Getter: Retrieve current list of connected social accounts for a given post.
211 *
212 * @see Publicize::get_filtered_connection_data()
213 *
214 * @param array $post_array Response from Post Endpoint.
215 * @param WP_REST_Request $request API request.
216 *
217 * @return array List of connections
218 */
219 public function get( $post_array, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
220 global $publicize;
221
222 if ( ! $publicize ) {
223 return array();
224 }
225
226 $schema = $this->post_connection_schema();
227 $properties = array_keys( $schema['properties'] );
228
229 $connections = $publicize->get_filtered_connection_data( $post_array['id'] );
230
231 $output_connections = array();
232 foreach ( $connections as $connection ) {
233 $output_connection = array();
234 foreach ( $properties as $property ) {
235 if ( isset( $connection[ $property ] ) ) {
236 $output_connection[ $property ] = $connection[ $property ];
237 }
238 }
239
240 $output_connection['id'] = (string) $connection['unique_id'];
241
242 $output_connections[] = $output_connection;
243 }
244
245 return $output_connections;
246 }
247
248 /**
249 * Prior to updating the post, first calculate which Services to
250 * Publicize to and which to skip.
251 *
252 * @param object $post Post data to insert/update.
253 * @param WP_REST_Request $request API request.
254 *
255 * @return Filtered $post
256 */
257 public function rest_pre_insert( $post, $request ) {
258 if ( ! isset( $request['jetpack_publicize_connections'] ) ) {
259 return $post;
260 }
261
262 $permission_check = $this->update_permission_check( $request['jetpack_publicize_connections'], $post, $request );
263 if ( is_wp_error( $permission_check ) ) {
264 return $permission_check;
265 }
266 // memoize.
267 $this->get_meta_to_update( $request['jetpack_publicize_connections'], isset( $post->ID ) ? $post->ID : 0 );
268
269 if ( isset( $post->ID ) ) {
270 // Set the meta before we mark the post as published so that publicize works as expected.
271 // If this is not the case post end up on social media when they are marked as skipped.
272 $this->update( $request['jetpack_publicize_connections'], $post, $request );
273 }
274
275 return $post;
276 }
277
278 /**
279 * After creating a new post, update our cached data to reflect
280 * the new post ID.
281 *
282 * @param WP_Post $post Post data to update.
283 * @param WP_REST_Request $request API request.
284 * @param bool $is_new Is this a new post.
285 */
286 public function rest_insert( $post, $request, $is_new ) {
287 if ( ! $is_new ) {
288 // An existing post was edited - no need to update
289 // our cache - we started out knowing the correct
290 // post ID.
291 return;
292 }
293
294 if ( ! isset( $request['jetpack_publicize_connections'] ) ) {
295 return;
296 }
297
298 if ( ! isset( $this->memoized_updates[0] ) ) {
299 return;
300 }
301
302 $this->memoized_updates[ $post->ID ] = $this->memoized_updates[0];
303 unset( $this->memoized_updates[0] );
304 }
305
306 /**
307 * Get list of meta data to update per post ID.
308 *
309 * @param array $requested_connections Publicize conenctions to update.
310 * Items are either `{ id: (string) }` or `{ service_name: (string) }`.
311 * @param int $post_id Post ID.
312 */
313 protected function get_meta_to_update( $requested_connections, $post_id = 0 ) {
314 global $publicize;
315
316 if ( ! $publicize ) {
317 return array();
318 }
319
320 if ( isset( $this->memoized_updates[ $post_id ] ) ) {
321 return $this->memoized_updates[ $post_id ];
322 }
323
324 $available_connections = $publicize->get_filtered_connection_data( $post_id );
325
326 $changed_connections = array();
327
328 // Build lookup mappings.
329 $available_connections_by_unique_id = array();
330 $available_connections_by_service_name = array();
331 foreach ( $available_connections as $available_connection ) {
332 $available_connections_by_unique_id[ $available_connection['unique_id'] ] = $available_connection;
333
334 if ( ! isset( $available_connections_by_service_name[ $available_connection['service_name'] ] ) ) {
335 $available_connections_by_service_name[ $available_connection['service_name'] ] = array();
336 }
337 $available_connections_by_service_name[ $available_connection['service_name'] ][] = $available_connection;
338 }
339
340 // Handle { service_name: $service_name, enabled: (bool) }.
341 // If the service is not available, it will be skipped.
342 foreach ( $requested_connections as $requested_connection ) {
343 if ( ! isset( $requested_connection['service_name'] ) ) {
344 continue;
345 }
346
347 if ( ! isset( $available_connections_by_service_name[ $requested_connection['service_name'] ] ) ) {
348 continue;
349 }
350
351 foreach ( $available_connections_by_service_name[ $requested_connection['service_name'] ] as $available_connection ) {
352 $changed_connections[ $available_connection['unique_id'] ] = $requested_connection['enabled'];
353 }
354 }
355
356 // Handle { id: $id, enabled: (bool) }
357 // These override the service_name settings.
358 foreach ( $requested_connections as $requested_connection ) {
359 if ( ! isset( $requested_connection['id'] ) ) {
360 continue;
361 }
362
363 if ( ! isset( $available_connections_by_unique_id[ $requested_connection['id'] ] ) ) {
364 continue;
365 }
366
367 $changed_connections[ $requested_connection['id'] ] = $requested_connection['enabled'];
368 }
369
370 // Set all changed connections to their new value.
371 foreach ( $changed_connections as $unique_id => $enabled ) {
372 $connection = $available_connections_by_unique_id[ $unique_id ];
373
374 if ( $connection['done'] || ! $connection['toggleable'] ) {
375 continue;
376 }
377
378 $available_connections_by_unique_id[ $unique_id ]['enabled'] = $enabled;
379 }
380
381 $meta_to_update = array();
382 // For all connections, ensure correct post_meta.
383 foreach ( $available_connections_by_unique_id as $unique_id => $available_connection ) {
384 if ( $available_connection['enabled'] ) {
385 $meta_to_update[ $publicize->POST_SKIP . $unique_id ] = null; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
386 } else {
387 $meta_to_update[ $publicize->POST_SKIP . $unique_id ] = 1; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
388 }
389 }
390
391 $this->memoized_updates[ $post_id ] = $meta_to_update;
392
393 return $meta_to_update;
394 }
395
396 /**
397 * Update the connections slated to be shared to.
398 *
399 * @param array $requested_connections Publicize conenctions to update.
400 * Items are either `{ id: (string) }` or `{ service_name: (string) }`.
401 * @param WP_Post $post Post data.
402 * @param WP_REST_Request $request API request.
403 */
404 public function update( $requested_connections, $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
405 if ( isset( $this->meta_saved[ $post->ID ] ) ) { // Make sure we only save it once - per request.
406 return;
407 }
408 foreach ( $this->get_meta_to_update( $requested_connections, $post->ID ) as $meta_key => $meta_value ) {
409 if ( $meta_value === null ) {
410 delete_post_meta( $post->ID, $meta_key );
411 } else {
412 update_post_meta( $post->ID, $meta_key, $meta_value );
413 }
414 }
415 $this->meta_saved[ $post->ID ] = true;
416 }
417 }
418
419 if ( Jetpack::is_module_active( 'publicize' ) ) {
420 wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Post_Publicize_Connections_Field' );
421 }
422