PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 12.2.3
Jetpack – WP Security, Backup, Speed, & Growth v12.2.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
431 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' => __( 'Display name of the connected account', 'jetpack' ),
124 'type' => 'string',
125 'context' => array( 'view', 'edit' ),
126 'readonly' => true,
127 ),
128 'username' => array(
129 'description' => __( 'Username of the connected account', 'jetpack' ),
130 'type' => 'string',
131 'context' => array( 'view', 'edit' ),
132 'readonly' => true,
133 ),
134 'profile_picture' => array(
135 'description' => __( 'Profile picture of the connected account', 'jetpack' ),
136 'type' => 'string',
137 'context' => array( 'view', 'edit' ),
138 'readonly' => true,
139 ),
140 'enabled' => array(
141 'description' => __( 'Whether to share to this connection', 'jetpack' ),
142 'type' => 'boolean',
143 'context' => array( 'edit' ),
144 ),
145 'done' => array(
146 'description' => __( 'Whether Jetpack Social has already finished sharing for this post', 'jetpack' ),
147 'type' => 'boolean',
148 'context' => array( 'edit' ),
149 'readonly' => true,
150 ),
151 'toggleable' => array(
152 'description' => __( 'Whether `enable` can be changed for this post/connection', 'jetpack' ),
153 'type' => 'boolean',
154 'context' => array( 'edit' ),
155 'readonly' => true,
156 ),
157 ),
158 );
159 }
160
161 /**
162 * Permission check, based on module availability and user capabilities.
163 *
164 * @param int $post_id Post ID.
165 *
166 * @return true|WP_Error
167 */
168 public function permission_check( $post_id ) {
169 global $publicize;
170
171 if ( ! $publicize ) {
172 return new WP_Error(
173 'publicize_not_available',
174 __( 'Sorry, Jetpack Social is not available on your site right now.', 'jetpack' ),
175 array( 'status' => rest_authorization_required_code() )
176 );
177 }
178
179 if ( $publicize->current_user_can_access_publicize_data( $post_id ) ) {
180 return true;
181 }
182
183 return new WP_Error(
184 'invalid_user_permission_publicize',
185 __( 'Sorry, you are not allowed to access Jetpack Social data for this post.', 'jetpack' ),
186 array( 'status' => rest_authorization_required_code() )
187 );
188 }
189
190 /**
191 * Getter permission check
192 *
193 * @param mixed $post_array Response from the post endpoint.
194 * @param WP_REST_Request $request API request.
195 *
196 * @return true|WP_Error
197 */
198 public function get_permission_check( $post_array, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
199 return $this->permission_check( isset( $post_array['id'] ) ? $post_array['id'] : 0 );
200 }
201
202 /**
203 * Setter permission check.
204 *
205 * @param mixed $value The new value for the field.
206 * @param WP_Post $post The post object.
207 * @param WP_REST_Request $request API request.
208 *
209 * @return true|WP_Error
210 */
211 public function update_permission_check( $value, $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
212 return $this->permission_check( isset( $post->ID ) ? $post->ID : 0 );
213 }
214
215 /**
216 * Getter: Retrieve current list of connected social accounts for a given post.
217 *
218 * @see Publicize::get_filtered_connection_data()
219 *
220 * @param array $post_array Response from Post Endpoint.
221 * @param WP_REST_Request $request API request.
222 *
223 * @return array List of connections
224 */
225 public function get( $post_array, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
226 global $publicize;
227
228 if ( ! $publicize ) {
229 return array();
230 }
231
232 $schema = $this->post_connection_schema();
233 $properties = array_keys( $schema['properties'] );
234
235 $connections = $publicize->get_filtered_connection_data( $post_array['id'] );
236
237 $output_connections = array();
238 foreach ( $connections as $connection ) {
239 $output_connection = array();
240 foreach ( $properties as $property ) {
241 if ( isset( $connection[ $property ] ) ) {
242 $output_connection[ $property ] = $connection[ $property ];
243 }
244 }
245 $output_connection['id'] = (string) $connection['unique_id'];
246 $output_connection['connection_id'] = (string) $connection['id'];
247
248 $output_connections[] = $output_connection;
249 }
250
251 return $output_connections;
252 }
253
254 /**
255 * Prior to updating the post, first calculate which Services to
256 * Publicize to and which to skip.
257 *
258 * @param object $post Post data to insert/update.
259 * @param WP_REST_Request $request API request.
260 *
261 * @return Filtered $post
262 */
263 public function rest_pre_insert( $post, $request ) {
264 if ( ! isset( $request['jetpack_publicize_connections'] ) ) {
265 return $post;
266 }
267
268 $permission_check = $this->update_permission_check( $request['jetpack_publicize_connections'], $post, $request );
269 if ( is_wp_error( $permission_check ) ) {
270 return $permission_check;
271 }
272 // memoize.
273 $this->get_meta_to_update( $request['jetpack_publicize_connections'], isset( $post->ID ) ? $post->ID : 0 );
274
275 if ( isset( $post->ID ) ) {
276 // Set the meta before we mark the post as published so that publicize works as expected.
277 // If this is not the case post end up on social media when they are marked as skipped.
278 $this->update( $request['jetpack_publicize_connections'], $post, $request );
279 }
280
281 return $post;
282 }
283
284 /**
285 * After creating a new post, update our cached data to reflect
286 * the new post ID.
287 *
288 * @param WP_Post $post Post data to update.
289 * @param WP_REST_Request $request API request.
290 * @param bool $is_new Is this a new post.
291 */
292 public function rest_insert( $post, $request, $is_new ) {
293 if ( ! $is_new ) {
294 // An existing post was edited - no need to update
295 // our cache - we started out knowing the correct
296 // post ID.
297 return;
298 }
299
300 if ( ! isset( $request['jetpack_publicize_connections'] ) ) {
301 return;
302 }
303
304 if ( ! isset( $this->memoized_updates[0] ) ) {
305 return;
306 }
307
308 $this->memoized_updates[ $post->ID ] = $this->memoized_updates[0];
309 unset( $this->memoized_updates[0] );
310 }
311
312 /**
313 * Get list of meta data to update per post ID.
314 *
315 * @param array $requested_connections Publicize connections to update.
316 * Items are either `{ id: (string) }` or `{ service_name: (string) }`.
317 * @param int $post_id Post ID.
318 */
319 protected function get_meta_to_update( $requested_connections, $post_id = 0 ) {
320 global $publicize;
321
322 if ( ! $publicize ) {
323 return array();
324 }
325
326 if ( isset( $this->memoized_updates[ $post_id ] ) ) {
327 return $this->memoized_updates[ $post_id ];
328 }
329
330 $available_connections = $publicize->get_filtered_connection_data( $post_id );
331
332 $changed_connections = array();
333
334 // Build lookup mappings.
335 $available_connections_by_connection_id = array();
336 $available_connections_by_service_name = array();
337 foreach ( $available_connections as $available_connection ) {
338 $available_connections_by_connection_id[ $available_connection['id'] ] = $available_connection;
339
340 if ( ! isset( $available_connections_by_service_name[ $available_connection['service_name'] ] ) ) {
341 $available_connections_by_service_name[ $available_connection['service_name'] ] = array();
342 }
343 $available_connections_by_service_name[ $available_connection['service_name'] ][] = $available_connection;
344 }
345
346 // Handle { service_name: $service_name, enabled: (bool) }.
347 // If the service is not available, it will be skipped.
348 foreach ( $requested_connections as $requested_connection ) {
349 if ( ! isset( $requested_connection['service_name'] ) ) {
350 continue;
351 }
352
353 if ( ! isset( $available_connections_by_service_name[ $requested_connection['service_name'] ] ) ) {
354 continue;
355 }
356
357 foreach ( $available_connections_by_service_name[ $requested_connection['service_name'] ] as $available_connection ) {
358 if ( $requested_connection['connection_id'] === $available_connection['id'] ) {
359 $changed_connections[ $available_connection['id'] ] = $requested_connection['enabled'];
360 break;
361 }
362 }
363 }
364
365 // Handle { id: $id, enabled: (bool) }
366 // These override the service_name settings.
367 foreach ( $requested_connections as $requested_connection ) {
368 if ( ! isset( $requested_connection['connection_id'] ) ) {
369 continue;
370 }
371
372 if ( ! isset( $available_connections_by_connection_id[ $requested_connection['connection_id'] ] ) ) {
373 continue;
374 }
375
376 $changed_connections[ $requested_connection['connection_id'] ] = $requested_connection['enabled'];
377 }
378
379 // Set all changed connections to their new value.
380 foreach ( $changed_connections as $id => $enabled ) {
381 $connection = $available_connections_by_connection_id[ $id ];
382
383 if ( $connection['done'] || ! $connection['toggleable'] ) {
384 continue;
385 }
386
387 $available_connections_by_connection_id[ $id ]['enabled'] = $enabled;
388 }
389
390 $meta_to_update = array();
391 // For all connections, ensure correct post_meta.
392 foreach ( $available_connections_by_connection_id as $connection_id => $available_connection ) {
393 if ( $available_connection['enabled'] ) {
394 $meta_to_update[ $publicize->POST_SKIP_PUBLICIZE . $connection_id ] = null; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
395 } else {
396 $meta_to_update[ $publicize->POST_SKIP_PUBLICIZE . $connection_id ] = 1; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
397 }
398 }
399
400 $this->memoized_updates[ $post_id ] = $meta_to_update;
401
402 return $meta_to_update;
403 }
404
405 /**
406 * Update the connections slated to be shared to.
407 *
408 * @param array $requested_connections Publicize conenctions to update.
409 * Items are either `{ id: (string) }` or `{ service_name: (string) }`.
410 * @param WP_Post $post Post data.
411 * @param WP_REST_Request $request API request.
412 */
413 public function update( $requested_connections, $post, $request ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
414 if ( isset( $this->meta_saved[ $post->ID ] ) ) { // Make sure we only save it once - per request.
415 return;
416 }
417 foreach ( $this->get_meta_to_update( $requested_connections, $post->ID ) as $meta_key => $meta_value ) {
418 if ( $meta_value === null ) {
419 delete_post_meta( $post->ID, $meta_key );
420 } else {
421 update_post_meta( $post->ID, $meta_key, $meta_value );
422 }
423 }
424 $this->meta_saved[ $post->ID ] = true;
425 }
426 }
427
428 if ( Jetpack::is_module_active( 'publicize' ) ) {
429 wpcom_rest_api_v2_load_plugin( 'WPCOM_REST_API_V2_Post_Publicize_Connections_Field' );
430 }
431